Squashed commit of the following:
commitd2ec8c0f07Author: mario <dev.mario@sismedika@gmail.com> Date: Thu May 15 15:42:33 2025 +0700 add: db tx commit and rollback implementation commit264435f67eAuthor: mario <dev.mario@sismedika@gmail.com> Date: Thu May 15 14:34:20 2025 +0700 fix: shortlink generation logic update/create commit047ab1937aAuthor: mario <dev.mario@sismedika@gmail.com> Date: Thu May 15 11:06:04 2025 +0700 fix: if multiple studies patient, show first study by default commitc13f834b92Author: mario <dev.mario@sismedika@gmail.com> Date: Thu May 15 09:46:32 2025 +0700 add: register and login with DB query AND some struct type correction commitdd4451c2a8Author: mario <dev.mario@sismedika@gmail.com> Date: Wed May 14 10:23:33 2025 +0700 new file structure & koneksi ke DB commit8289881df3Author: mario <dev.mario@sismedika@gmail.com> Date: Tue May 13 16:49:07 2025 +0700 edit: rm debug route commitdd784da232Author: mario <dev.mario@sismedika@gmail.com> Date: Tue May 13 15:44:11 2025 +0700 add: implement shortlink commit2687a761ccAuthor: mario <dev.mario@sismedika@gmail.com> Date: Tue May 13 11:47:19 2025 +0700 add new dummy doctor user commiteb67eaca46Author: mario <dev.mario@sismedika@gmail.com> Date: Tue May 13 11:46:28 2025 +0700 add: ref_doctor studylist filter commit0d4825d152Author: mario <dev.mario@sismedika@gmail.com> Date: Tue May 13 10:07:16 2025 +0700 edit study_iuids & accNum in patient jwt to array commit2d1f135fdaAuthor: mario <dev.mario@sismedika@gmail.com> Date: Tue May 13 09:52:45 2025 +0700 patient see their multiple studies commit13bb380f51Author: mario <dev.mario@sismedika@gmail.com> Date: Fri May 9 10:13:16 2025 +0700 add: cors handler route and readme commit6c9ab574ceAuthor: mario <dev.mario@sismedika@gmail.com> Date: Mon May 5 11:50:36 2025 +0700 add: login & token validation tapi belum connect ke DB commit297c9a6a01Author: mario <dev.mario@sismedika@gmail.com> Date: Mon Apr 28 15:37:02 2025 +0700 add readme.md commit9b8e0260f3Author: mario <dev.mario@sismedika@gmail.com> Date: Mon Apr 7 15:46:07 2025 +0700 connected-to-google commitf340bc5916Author: mario <dev.mario@sismedika.com> Date: Mon Apr 7 11:14:18 2025 +0700 init
This commit is contained in:
8
internal/api/models/doctor.go
Normal file
8
internal/api/models/doctor.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package models
|
||||
|
||||
// DoctorDetails contains doctor-specific data
|
||||
type DoctorDetails struct {
|
||||
DoctorID string `json:"doctor_id"`
|
||||
DoctorName string `json:"doctor_name"`
|
||||
Type string `json:"type"` // "ref_doctor" or "expertise_doctor"
|
||||
}
|
||||
112
internal/api/models/mock_data.go
Normal file
112
internal/api/models/mock_data.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package models
|
||||
|
||||
// MockUsers represents a mock database of users
|
||||
var MockUsers = []User{
|
||||
{
|
||||
ID: "1",
|
||||
Email: "admin",
|
||||
Role: "expertise_doctor",
|
||||
Name: "Admin User",
|
||||
CreatedAt: "2025-01-01T00:00:00Z",
|
||||
UpdatedAt: "2025-01-01T00:00:00Z",
|
||||
},
|
||||
{
|
||||
ID: "2",
|
||||
Email: "patient",
|
||||
Role: "patient",
|
||||
Name: "Patient User",
|
||||
CreatedAt: "2025-01-01T00:00:00Z",
|
||||
UpdatedAt: "2025-01-01T00:00:00Z",
|
||||
},
|
||||
{
|
||||
ID: "3",
|
||||
Email: "doctor",
|
||||
Role: "ref_doctor",
|
||||
Name: "DR. HERWINDO RIDWAN, SP.OT",
|
||||
CreatedAt: "2025-01-01T00:00:00Z",
|
||||
UpdatedAt: "2025-01-01T00:00:00Z",
|
||||
},
|
||||
{
|
||||
ID: "4",
|
||||
Email: "patient2",
|
||||
Role: "patient",
|
||||
Name: "Patient Two",
|
||||
CreatedAt: "2025-01-01T00:00:00Z",
|
||||
UpdatedAt: "2025-01-01T00:00:00Z",
|
||||
},
|
||||
{
|
||||
ID: "5",
|
||||
Email: "doctor2",
|
||||
Role: "ref_doctor",
|
||||
Name: "Referring^Physician",
|
||||
CreatedAt: "2025-01-01T00:00:00Z",
|
||||
UpdatedAt: "2025-01-01T00:00:00Z",
|
||||
},
|
||||
}
|
||||
|
||||
// PatientData represents additional data for patients
|
||||
type PatientData struct {
|
||||
PatientID string `json:"patient_id"`
|
||||
UserID string `json:"user_id"`
|
||||
StudyIUIDs []string `json:"study_iuids"`
|
||||
AccessionNumbers []string `json:"accession_numbers"`
|
||||
PatientName string `json:"patient_name"`
|
||||
ReferringPhysician string `json:"referring_physician"`
|
||||
}
|
||||
|
||||
// MockPatients represents a mock database of patient data
|
||||
var MockPatients = []PatientData{
|
||||
{
|
||||
PatientID: "00211622",
|
||||
UserID: "2",
|
||||
StudyIUIDs: []string{"1.2.826.0.1.3680043.9.7307.1.20180530066", "1.2.826.0.1.3680043.9.7307.1.20180713036"},
|
||||
AccessionNumbers: []string{"CR.180530.066", "CR.180713.036"},
|
||||
PatientName: "DIDIT SUYATNA^R.10049.18",
|
||||
ReferringPhysician: "DR. HERWINDO RIDWAN, SP.OT",
|
||||
},
|
||||
{
|
||||
PatientID: "MR00000359",
|
||||
UserID: "4",
|
||||
StudyIUIDs: []string{"1.2.826.0.1.3680043.9.7307.1.202503196393.01"},
|
||||
AccessionNumbers: []string{"CR.250319.6393.01"},
|
||||
PatientName: "Bobon Santoso",
|
||||
ReferringPhysician: "DR. HERWINDO RIDWAN, SP.OT",
|
||||
},
|
||||
}
|
||||
|
||||
// FindUserByCredentials finds a user by email and password (mock authentication)
|
||||
func FindUserByCredentials(email, password string) *User {
|
||||
// In a real implementation, you would hash passwords
|
||||
// For the mock, we'll just match email and assume password is the same as email
|
||||
if password != email {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, user := range MockUsers {
|
||||
if user.Email == email {
|
||||
return &user
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindPatientDataByUserID finds patient data by user ID
|
||||
func FindPatientDataByUserID(userID string) *PatientData {
|
||||
for _, patient := range MockPatients {
|
||||
if patient.UserID == userID {
|
||||
return &patient
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindStudiesByReferringPhysician returns all study IUIDs that belong to a referring physician
|
||||
func FindStudiesByReferringPhysician(physicianName string) []string {
|
||||
var studies []string
|
||||
for _, patient := range MockPatients {
|
||||
if patient.ReferringPhysician == physicianName {
|
||||
studies = append(studies, patient.StudyIUIDs...)
|
||||
}
|
||||
}
|
||||
return studies
|
||||
}
|
||||
19
internal/api/models/patient.go
Normal file
19
internal/api/models/patient.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package models
|
||||
|
||||
// PatientDetails contains patient-specific data
|
||||
type PatientDetails struct {
|
||||
PatientID string `json:"patient_id"`
|
||||
PatientName string `json:"patient_name"`
|
||||
DateOfBirth string `json:"date_of_birth"` // YYYY-MM-DD format
|
||||
StudyInstanceUIDs []string `json:"study_instance_uids,omitempty"`
|
||||
AccessionNumbers []string `json:"accession_numbers,omitempty"`
|
||||
}
|
||||
|
||||
// Study represents a DICOM study associated with a patient
|
||||
type Study struct {
|
||||
StudyInstanceUID string `json:"study_instance_uid"`
|
||||
AccessionNumber string `json:"accession_number,omitempty"`
|
||||
StudyDate string `json:"study_date,omitempty"`
|
||||
StudyDescription string `json:"study_description,omitempty"`
|
||||
Modalities string `json:"modalities,omitempty"`
|
||||
}
|
||||
53
internal/api/models/shortlink.go
Normal file
53
internal/api/models/shortlink.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package models
|
||||
|
||||
// ShortLink represents a short URL token for patient access
|
||||
type ShortLink struct {
|
||||
ID string `db:"id" json:"id"`
|
||||
Token string `db:"token" json:"token"` // The short token used in the URL
|
||||
PatientID string `db:"patient_id" json:"patient_id"`
|
||||
StudyUID string `db:"study_uid" json:"study_uid"` // The StudyInstanceUID this token grants access to
|
||||
HashedDOB string `db:"hashed_dob" json:"-"` // Hashed Date of Birth for verification
|
||||
ExpiresAt string `db:"expires_at" json:"expires_at"`
|
||||
IsRevoked bool `db:"is_revoked" json:"is_revoked"`
|
||||
CreatedAt string `db:"created_at" json:"created_at"`
|
||||
CreatedByID string `db:"created_by_id" json:"created_by_id"` // ID of admin who created this
|
||||
RemainingTries int `db:"remaining_tries" json:"-"` // Number of failed attempts allowed
|
||||
}
|
||||
|
||||
// GenerateShortLinkRequest represents request to create a short URL
|
||||
type GenerateShortLinkRequest struct {
|
||||
PatientID string `json:"patient_id"`
|
||||
StudyUID string `json:"study_uid"`
|
||||
DOB string `json:"dob"` // Date of birth in YYYY-MM-DD format
|
||||
ExpiresIn int `json:"expires_in"` // Expiry in hours (optional, defaults to 72)
|
||||
}
|
||||
|
||||
// GenerateShortLinkResponse is the response for a generated short link
|
||||
type GenerateShortLinkResponse struct {
|
||||
ShortToken string `json:"short_token"`
|
||||
FullURL string `json:"full_url"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
IsExisting bool `json:"is_existing"` // Indicates if this is an existing link that was reused
|
||||
}
|
||||
|
||||
// ShortLinkAuthRequest represents the shortlink authentication request
|
||||
type ShortLinkAuthRequest struct {
|
||||
ShortToken string `json:"short_token,omitempty"` // The original field
|
||||
ShortTokenAlt string `json:"shortToken,omitempty"` // Support for camelCase naming from OHIF
|
||||
DOB string `json:"dob"` // Date of birth in YYYY-MM-DD format
|
||||
}
|
||||
|
||||
func (r *ShortLinkAuthRequest) GetToken() string {
|
||||
// Use ShortTokenAlt if ShortToken is empty
|
||||
if r.ShortToken == "" {
|
||||
return r.ShortTokenAlt
|
||||
}
|
||||
return r.ShortToken
|
||||
}
|
||||
|
||||
// ShortLinkAuthResponse is the response for successful shortlink authentication
|
||||
type ShortLinkAuthResponse struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
ExpiresIn int `json:"expires_in"` // Token expiry in seconds
|
||||
RedirectURL string `json:"redirect_url"`
|
||||
}
|
||||
46
internal/api/models/user.go
Normal file
46
internal/api/models/user.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package models
|
||||
|
||||
// User represents a system user
|
||||
type User struct {
|
||||
ID string `db:"id" json:"id"`
|
||||
Email string `db:"email" json:"email"`
|
||||
Password string `db:"password" json:"-"` // Never expose password in JSON
|
||||
Role string `db:"role" json:"role"`
|
||||
Name string `db:"name" json:"name"`
|
||||
CreatedAt string `db:"created_at" json:"created_at"`
|
||||
UpdatedAt string `db:"updated_at" json:"updated_at"`
|
||||
}
|
||||
|
||||
// RefreshToken represents a refresh token stored in the database
|
||||
type RefreshToken struct {
|
||||
ID string `db:"id" json:"id"`
|
||||
UserID string `db:"user_id" json:"user_id"`
|
||||
Token string `db:"token" json:"token"`
|
||||
ExpiresAt string `db:"expires_at" json:"expires_at"`
|
||||
IsRevoked bool `db:"is_revoked" json:"is_revoked"`
|
||||
CreatedAt string `db:"created_at" json:"created_at"`
|
||||
}
|
||||
|
||||
// LoginRequest represents the login form data
|
||||
type LoginRequest struct {
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
// LoginResponse is the response sent after successful login
|
||||
type LoginResponse struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
User *User `json:"user"`
|
||||
RedirectURL string `json:"redirect_url"`
|
||||
}
|
||||
|
||||
// RefreshRequest represents the refresh token request
|
||||
type RefreshRequest struct {
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
}
|
||||
|
||||
// RefreshResponse is the response for a token refresh
|
||||
type RefreshResponse struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
}
|
||||
Reference in New Issue
Block a user