package handlers import ( "encoding/json" "fmt" "net/http" "devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/api/models" "devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/api/service" "go.uber.org/zap" ) // PydicomHandler handles operations related to PYDICOM uploads type PydicomHandler struct { logger *zap.Logger shortLinkService *service.ShortLinkService registerService *service.RegisterService } // NewPydicomHandler creates a new PydicomHandler func NewPydicomHandler(logger *zap.Logger, shortLinkService *service.ShortLinkService, registerService *service.RegisterService) *PydicomHandler { return &PydicomHandler{ logger: logger, shortLinkService: shortLinkService, registerService: registerService, } } // HandleUploadedDicom processes a request from the PYDICOM uploader service to register a patient and generate a shortlink func (h *PydicomHandler) HandleUploadedDicom(w http.ResponseWriter, r *http.Request) { // Parse the request body into a temporary struct that matches the expected JSON var reqData struct { Email string `json:"email"` Password string `json:"password"` Name string `json:"name"` Role string `json:"role"` Patient struct { PatientID string `json:"patient_id"` PatientName string `json:"patient_name"` DateOfBirth string `json:"date_of_birth"` } `json:"patient"` Studies []struct { StudyInstanceUID string `json:"study_instance_uid"` AccessionNumber string `json:"accession_number"` StudyDate string `json:"study_date"` StudyDescription string `json:"study_description"` } `json:"studies"` } if err := json.NewDecoder(r.Body).Decode(&reqData); err != nil { h.logger.Error("Failed to parse uploaded DICOM request", zap.Error(err)) http.Error(w, "Invalid request body", http.StatusBadRequest) return } // Validate the request if reqData.Email == "" || reqData.Password == "" || reqData.Name == "" { h.logger.Error("Missing required user fields in uploaded DICOM request") http.Error(w, "Missing required user fields", http.StatusBadRequest) return } if reqData.Patient.PatientID == "" || reqData.Patient.DateOfBirth == "" { h.logger.Error("Missing required patient fields in uploaded DICOM request") http.Error(w, "Missing required patient fields", http.StatusBadRequest) return } if len(reqData.Studies) == 0 || reqData.Studies[0].StudyInstanceUID == "" { h.logger.Error("Missing required study fields in uploaded DICOM request") http.Error(w, "Missing required study fields", http.StatusBadRequest) return } // Convert to our internal models patientDetails := &models.PatientDetails{ PatientID: reqData.Patient.PatientID, PatientName: reqData.Patient.PatientName, DateOfBirth: reqData.Patient.DateOfBirth, } // Convert studies to our internal model studies := make([]models.Study, len(reqData.Studies)) for i, s := range reqData.Studies { studies[i] = models.Study{ StudyInstanceUID: s.StudyInstanceUID, AccessionNumber: s.AccessionNumber, StudyDate: s.StudyDate, StudyDescription: s.StudyDescription, } } // Create registration request regRequest := &service.RegisterRequest{ Email: reqData.Email, Password: reqData.Password, Name: reqData.Name, Role: "patient", // Force the role to be "patient" regardless of what was sent Patient: patientDetails, Studies: studies, } // Register the patient (or confirm it exists) using the RegisterService user, err := h.registerService.Register(regRequest) if err != nil { // If the error is about duplicate email, we'll continue with generating a shortlink // Otherwise, return the error if err != service.ErrEmailExists { h.logger.Error("Failed to register patient", zap.Error(err)) http.Error(w, fmt.Sprintf("Failed to register patient: %v", err), http.StatusInternalServerError) return } h.logger.Info("Patient already exists, continuing with shortlink generation", zap.String("email", reqData.Email), zap.String("patientID", reqData.Patient.PatientID)) } else { h.logger.Info("Patient registered successfully", zap.String("userID", user.ID), zap.String("email", reqData.Email), zap.String("patientID", reqData.Patient.PatientID)) } // For each study, generate a shortlink // For simplicity, we'll just use the first study in the array study := reqData.Studies[0] // Create a shortlink request shortLinkReq := &models.GenerateShortLinkRequest{ PatientID: reqData.Patient.PatientID, StudyUID: study.StudyInstanceUID, DOB: reqData.Patient.DateOfBirth, ExpiresIn: 0, // Set to 0 to use the default expiry from config } // Generate a shortlink // We set empty string as creatorID because you mentioned ShortlinkCreate_UserID is now nullable shortLinkResp, err := h.shortLinkService.GenerateShortLink(shortLinkReq, "") if err != nil { h.logger.Error("Failed to generate shortlink", zap.Error(err), zap.String("patientID", reqData.Patient.PatientID), zap.String("studyUID", study.StudyInstanceUID)) http.Error(w, fmt.Sprintf("Failed to generate shortlink: %v", err), http.StatusInternalServerError) return } // Log successful shortlink generation h.logger.Info("Shortlink generated for uploaded DICOM", zap.String("patientID", reqData.Patient.PatientID), zap.String("studyUID", study.StudyInstanceUID), zap.String("shortToken", shortLinkResp.ShortToken)) // Return the shortlink response w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(shortLinkResp) }