From 3aa155dfbc2543ce06125bb67569786b979096dd Mon Sep 17 00:00:00 2001 From: mario Date: Sat, 17 May 2025 09:38:40 +0700 Subject: [PATCH] edit: field Shortcode dan expire duration --- config/config.yaml | 2 +- internal/api/models/shortlink.go | 3 ++- internal/api/repository/shortlink.go | 6 ++--- internal/api/service/shortlink_service.go | 24 +++++++++++-------- test/http/dicom-proxy.http | 10 +++++++- test/http/ohif-flow.http | 2 +- test/http/pydicom-upload.http | 28 +++++++++++++++++++++-- 7 files changed, 56 insertions(+), 19 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 345cdbc..77a22c2 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -22,7 +22,7 @@ auth: shortlink: base_url: "http://localhost:3333" # The base URL for generated OHIF Auth shortlinks - default_expiry_hours: 30 * 24 # Default expiry time for shortlinks (30 days) + default_expiry_hours: 720 # Default expiry time for shortlinks (30 days = 30 * 24 = 720 hours) max_attempts: 5 # Maximum number of failed login attempts database: diff --git a/internal/api/models/shortlink.go b/internal/api/models/shortlink.go index 2acfb73..70f2ab4 100644 --- a/internal/api/models/shortlink.go +++ b/internal/api/models/shortlink.go @@ -3,7 +3,7 @@ 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 + Shortcode string `db:"shortcode" json:"shortcode"` // 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 @@ -26,6 +26,7 @@ type GenerateShortLinkRequest struct { type GenerateShortLinkResponse struct { ShortToken string `json:"short_token"` FullURL string `json:"full_url"` + URI string `json:"uri"` // The URI path and query without the base URL ExpiresAt string `json:"expires_at"` IsExisting bool `json:"is_existing"` // Indicates if this is an existing link that was reused } diff --git a/internal/api/repository/shortlink.go b/internal/api/repository/shortlink.go index 5d80c80..07b3bce 100644 --- a/internal/api/repository/shortlink.go +++ b/internal/api/repository/shortlink.go @@ -48,7 +48,7 @@ func (s *DBShortLink) ToShortLink() *models.ShortLink { return &models.ShortLink{ ID: fmt.Sprintf("%d", s.ShortlinkID), - Token: s.ShortlinkCode, + Shortcode: s.ShortlinkCode, PatientID: s.Shortlink_PatientID, StudyUID: s.Shortlink_Study_IUID, HashedDOB: s.ShortlinkHashDoB, @@ -113,7 +113,7 @@ func (r *ShortLinkRepository) CreateShortLinkTx(tx *sqlx.Tx, shortLink *models.S _, err = tx.Exec( query, - shortLink.Token, + shortLink.Shortcode, shortLink.PatientID, shortLink.StudyUID, shortLink.HashedDOB, @@ -148,7 +148,7 @@ func (r *ShortLinkRepository) UpdateShortLinkTx(tx *sqlx.Tx, shortLink *models.S shortLink.IsRevoked, shortLink.RemainingTries, expiresAt, - shortLink.Token, + shortLink.Shortcode, ) if err != nil { diff --git a/internal/api/service/shortlink_service.go b/internal/api/service/shortlink_service.go index f6cf760..4d2db75 100644 --- a/internal/api/service/shortlink_service.go +++ b/internal/api/service/shortlink_service.go @@ -110,14 +110,16 @@ func (s *ShortLinkService) GenerateShortLink(req *models.GenerateShortLinkReques s.logger.Info("Returning existing active shortlink", zap.String("patientID", req.PatientID), zap.String("studyUID", req.StudyUID), - zap.String("token", existingShortLink.Token)) + zap.String("token", existingShortLink.Shortcode)) - // Generate the full URL using the configured base URL - fullURL := fmt.Sprintf("%s/short-auth?short=%s", s.baseURL, existingShortLink.Token) + // Generate the full URL and URI + uri := fmt.Sprintf("short-auth?short=%s", existingShortLink.Shortcode) + fullURL := fmt.Sprintf("%s/%s", s.baseURL, uri) return &models.GenerateShortLinkResponse{ - ShortToken: existingShortLink.Token, + ShortToken: existingShortLink.Shortcode, FullURL: fullURL, + URI: uri, ExpiresAt: existingShortLink.ExpiresAt, IsExisting: true, }, nil @@ -161,7 +163,7 @@ func (s *ShortLinkService) GenerateShortLink(req *models.GenerateShortLinkReques // Create the short link record shortLink := &models.ShortLink{ - Token: *unusedShortcode, + Shortcode: *unusedShortcode, PatientID: req.PatientID, StudyUID: req.StudyUID, HashedDOB: hashedDOB, @@ -181,14 +183,14 @@ func (s *ShortLinkService) GenerateShortLink(req *models.GenerateShortLinkReques // Get the ID of the created shortlink var shortlinkID int - err = tx.Get(&shortlinkID, "SELECT ShortlinkID FROM shortlink WHERE ShortlinkCode = ?", shortLink.Token) + err = tx.Get(&shortlinkID, "SELECT ShortlinkID FROM shortlink WHERE ShortlinkCode = ?", shortLink.Shortcode) if err != nil { s.logger.Error("Failed to get shortlink ID", zap.Error(err)) return nil, ErrCreationFailed } // Mark the shortcode as used - err = s.shortCodeRepo.MarkShortCodeAsUsed(tx, shortLink.Token, shortlinkID) + err = s.shortCodeRepo.MarkShortCodeAsUsed(tx, shortLink.Shortcode, shortlinkID) if err != nil { s.logger.Error("Failed to mark shortcode as used", zap.Error(err)) return nil, ErrCreationFailed @@ -203,12 +205,14 @@ func (s *ShortLinkService) GenerateShortLink(req *models.GenerateShortLinkReques // Clear the tx to prevent the deferred rollback tx = nil - // Generate the full URL using the configured base URL - fullURL := fmt.Sprintf("%s/short-auth?short=%s", s.baseURL, shortLink.Token) + // Generate the full URL and URI + uri := fmt.Sprintf("short-auth?short=%s", shortLink.Shortcode) + fullURL := fmt.Sprintf("%s/%s", s.baseURL, uri) return &models.GenerateShortLinkResponse{ - ShortToken: shortLink.Token, + ShortToken: shortLink.Shortcode, FullURL: fullURL, + URI: uri, ExpiresAt: shortLink.ExpiresAt, IsExisting: false, }, nil diff --git a/test/http/dicom-proxy.http b/test/http/dicom-proxy.http index 26225a2..c29c9a0 100644 --- a/test/http/dicom-proxy.http +++ b/test/http/dicom-proxy.http @@ -1,5 +1,5 @@ ### Local OHIF Proxy Test File -@token = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiMSIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJyb2xlIjoiYWRtaW4iLCJ1c2VyX25hbWUiOiJBZG1pbiBVc2VyIiwidG9rZW5fdHlwZSI6ImFjY2VzcyIsImhvbWVfdXJsIjoiLyIsInN0dWR5X2xpc3QiOiJlbmFibGVkIiwiZXhwIjoxNzQ3Mzg0MDE2LCJpYXQiOjE3NDcyOTc2MTZ9.Ak1DECP1MXzQAPyU-AJM6Tsu6-sw04UtWYvY37-SaT4 +@token = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiMSIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJyb2xlIjoiYWRtaW4iLCJ1c2VyX25hbWUiOiJBZG1pbiBVc2VyIiwidG9rZW5fdHlwZSI6ImFjY2VzcyIsImhvbWVfdXJsIjoiLyIsInN0dWR5X2xpc3QiOiJlbmFibGVkIiwiZXhwIjoxNzQ3NDcyMTE5LCJpYXQiOjE3NDczODU3MTl9.rLB8q2Wwt2aL813lf-GwuS14dO5WlJPPS3sP5OGJdO0 @baseUrl = http://localhost:5555 # @baseUrl = http://devone.aplikasi.web.id:5555 @@ -76,4 +76,12 @@ Accept: image/jpeg #### GET {{baseUrl}}/dicomWeb/studies?limit=101&offset=0&fuzzymatching=true&includefield=00081030,00080060&StudyInstanceUID=1.2.826.0.1.3680043.9.7307.1.202503196393.01 +### 13. DELETE Study +# Deletes a specific study +DELETE {{baseUrl}}/dicomWeb/studies/1.2.826.0.1.3680043.0.1252.1.20250516.144411.1639014.3 +Authorization: Bearer {{token}} +### +curl -X DELETE \ + -H "Authorization: Bearer $(gcloud auth print-access-token)" \ + "https://healthcare.googleapis.com/v1/projects/ohifproxy/locations/asia-southeast2/datasets/sas-storage/dicomStores/store-1/dicomWeb/studies/1.2.826.0.1.3680043.0.1252.1.20250516.144411.1639014.3" \ No newline at end of file diff --git a/test/http/ohif-flow.http b/test/http/ohif-flow.http index fa1a47b..49fc1d1 100644 --- a/test/http/ohif-flow.http +++ b/test/http/ohif-flow.http @@ -7,7 +7,7 @@ POST {{baseUrl}}/auth/login Content-Type: application/json { - "email": "doctor@example.com", + "email": "admin@example.com", "password": "password123" } diff --git a/test/http/pydicom-upload.http b/test/http/pydicom-upload.http index 2574da8..cbd4b78 100644 --- a/test/http/pydicom-upload.http +++ b/test/http/pydicom-upload.http @@ -5,7 +5,7 @@ @pydicomApiKey=2f0ff447b2c3aeef2004e83a750ded97e29ba8c0ccc70053d5e26f5d715e42ff ### Test the PYDICOM upload endpoint -POST {{baseUrl}}/uploaded_dicom +POST {{baseUrl}}/uploaded-dicom X-PYDICOM-API-KEY: {{pydicomApiKey}} Content-Type: application/json @@ -35,4 +35,28 @@ Content-Type: application/json # "full_url": "http://localhost:3333/short-auth?short=LDYZX", # "expires_at": "2025-05-18T02:04:46Z", # "is_existing": true -# } \ No newline at end of file +# } + +POST {{baseUrl}}/uploaded_dicom +X-PYDICOM-API-KEY: {{pydicomApiKey}} +Content-Type: application/json + +{ + "email": "randomuser@example.com", + "password": "securepassword456", + "name": "John Doe", + "role": "patient", + "patient": { + "patient_id": "MR00000789", + "patient_name": "John Doe", + "date_of_birth": "1990-07-15" + }, + "studies": [ + { + "study_instance_uid": "1.2.826.0.1.3680043.9.1234.1.202507151234.01", + "accession_number": "CR.150720.1234.01", + "study_date": "2025-07-15", + "study_description": "CT Scan" + } + ] +} \ No newline at end of file