add: register and login with DB query AND some struct type correction
This commit is contained in:
@@ -69,6 +69,12 @@ go-ohif-proxy/
|
||||
└── README.md # Project documentation
|
||||
```
|
||||
|
||||
## 2c. Alur Kerja Kode
|
||||
Secara umum kode di repo ini kurang lebih memiliki alur:
|
||||
```
|
||||
Routes --> Handlers --> Service --> Repository
|
||||
```
|
||||
|
||||
## 3. Instalasi dan Penggunaan
|
||||
|
||||
### Prasyarat
|
||||
|
||||
68
internal/api/handlers/register.go
Normal file
68
internal/api/handlers/register.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/api/service"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// RegisterHandler handles user registration requests
|
||||
type RegisterHandler struct {
|
||||
logger *zap.Logger
|
||||
registerService *service.RegisterService
|
||||
}
|
||||
|
||||
// NewRegisterHandler creates a new registration handler
|
||||
func NewRegisterHandler(logger *zap.Logger, registerService *service.RegisterService) *RegisterHandler {
|
||||
return &RegisterHandler{
|
||||
logger: logger,
|
||||
registerService: registerService,
|
||||
}
|
||||
}
|
||||
|
||||
// Register handles the creation of new users, patients, and doctors
|
||||
func (h *RegisterHandler) Register(w http.ResponseWriter, r *http.Request) {
|
||||
// Parse registration request
|
||||
var req service.RegisterRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
h.logger.Error("Failed to parse registration request", zap.Error(err))
|
||||
http.Error(w, "Invalid request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Validate required fields
|
||||
if req.Email == "" || req.Password == "" || req.Name == "" || req.Role == "" {
|
||||
http.Error(w, "Missing required fields", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Perform registration
|
||||
user, err := h.registerService.Register(&req)
|
||||
if err != nil {
|
||||
switch err {
|
||||
case service.ErrEmailExists:
|
||||
http.Error(w, "Email already exists", http.StatusConflict)
|
||||
case service.ErrInvalidRole:
|
||||
http.Error(w, "Invalid user role", http.StatusBadRequest)
|
||||
case service.ErrInvalidPatient:
|
||||
http.Error(w, "Invalid patient data", http.StatusBadRequest)
|
||||
case service.ErrInvalidDoctor:
|
||||
http.Error(w, "Invalid doctor data", http.StatusBadRequest)
|
||||
default:
|
||||
h.logger.Error("Registration failed", zap.Error(err))
|
||||
http.Error(w, "Registration failed", http.StatusInternalServerError)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Return created user
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
|
||||
// Don't include password in response
|
||||
user.Password = ""
|
||||
|
||||
json.NewEncoder(w).Encode(user)
|
||||
}
|
||||
@@ -71,7 +71,7 @@ func Auth(authService *service.AuthService, logger *zap.Logger) func(http.Handle
|
||||
// Add user info to request context
|
||||
ctx := context.WithValue(r.Context(), UserIDKey, claims.UserID)
|
||||
ctx = context.WithValue(ctx, UserRoleKey, claims.Role)
|
||||
ctx = context.WithValue(ctx, UserEmailKey, claims.Email)
|
||||
ctx = context.WithValue(ctx, UserEmailKey, claims.Email) // TODO: Apakah kita perlu param email untuk generate access token?
|
||||
|
||||
// Store the claims with the defined context key
|
||||
ctx = context.WithValue(ctx, ClaimsKey, claims)
|
||||
|
||||
@@ -4,6 +4,7 @@ package models
|
||||
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"`
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/api/models"
|
||||
"devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/database"
|
||||
)
|
||||
|
||||
@@ -42,3 +43,16 @@ func (r *DoctorRepository) GetDoctorDetailsByUserID(userID string) (*DBDoctor, e
|
||||
|
||||
return &dbDoctor, nil
|
||||
}
|
||||
|
||||
// CreateDoctor creates a new doctor record
|
||||
func (r *DoctorRepository) CreateDoctor(doctorDetails *models.DoctorDetails, userID string) error {
|
||||
query := `INSERT INTO doctor (Doctor_UsersID, DoctorID, DoctorName, DoctorCreatedAt, DoctorLastUpdatedAt)
|
||||
VALUES (?, ?, ?, NOW(), NOW())`
|
||||
|
||||
_, err := database.DB.Exec(query, userID, doctorDetails.DoctorID, doctorDetails.DoctorName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("database error creating doctor: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -60,3 +60,22 @@ func (r *PatientRepository) GetPatientDetailsByUserID(userID string) (*models.Pa
|
||||
AccessionNumbers: accessionNumbers,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreatePatient creates a new patient record
|
||||
func (r *PatientRepository) CreatePatient(patientRecord *models.PatientDetails, userID string) error {
|
||||
// Parse DOB to time.Time
|
||||
dob, err := time.Parse("2006-01-02", patientRecord.DateOfBirth)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid date of birth format: %w", err)
|
||||
}
|
||||
|
||||
query := `INSERT INTO patient (Patient_UsersID, PatientMedrec, PatientName, PatientDoB, PatientCreatedAt, PatientUpdatedAt)
|
||||
VALUES (?, ?, ?, ?, NOW(), NOW())`
|
||||
|
||||
_, err = database.DB.Exec(query, userID, patientRecord.PatientID, patientRecord.PatientName, dob)
|
||||
if err != nil {
|
||||
return fmt.Errorf("database error creating patient: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
// DBShortLink represents a shortlink from the database
|
||||
type DBShortLink struct {
|
||||
ShortlinkID int `db:"ShortlinkID"`
|
||||
ShortlinKCode string `db:"ShortlinKCode"`
|
||||
ShortlinkCode string `db:"ShortlinkCode"`
|
||||
Shortlink_PatientID string `db:"Shortlink_PatientID"`
|
||||
Shortlink_Study_IUID string `db:"Shortlink_Study_IUID"`
|
||||
ShortlinkHashDoB string `db:"ShortlinkHashDoB"`
|
||||
@@ -40,7 +40,7 @@ func NewShortLinkRepository() *ShortLinkRepository {
|
||||
func (s *DBShortLink) ToShortLink() *models.ShortLink {
|
||||
return &models.ShortLink{
|
||||
ID: fmt.Sprintf("%d", s.ShortlinkID),
|
||||
Token: s.ShortlinKCode,
|
||||
Token: s.ShortlinkCode,
|
||||
PatientID: s.Shortlink_PatientID,
|
||||
StudyUID: s.Shortlink_Study_IUID,
|
||||
HashedDOB: s.ShortlinkHashDoB,
|
||||
@@ -56,7 +56,7 @@ func (s *DBShortLink) ToShortLink() *models.ShortLink {
|
||||
func (r *ShortLinkRepository) GetShortLinkByToken(token string) (*models.ShortLink, error) {
|
||||
var dbShortLink DBShortLink
|
||||
|
||||
query := `SELECT * FROM shortlink WHERE ShortlinKCode = ?`
|
||||
query := `SELECT * FROM shortlink WHERE ShortlinkCode = ?`
|
||||
err := database.DB.Get(&dbShortLink, query, token)
|
||||
|
||||
if err != nil {
|
||||
@@ -72,7 +72,7 @@ func (r *ShortLinkRepository) GetShortLinkByToken(token string) (*models.ShortLi
|
||||
// CreateShortLink stores a new shortlink in the database
|
||||
func (r *ShortLinkRepository) CreateShortLink(shortLink *models.ShortLink) error {
|
||||
query := `INSERT INTO shortlink (
|
||||
ShortlinKCode,
|
||||
ShortlinkCode,
|
||||
Shortlink_PatientID,
|
||||
Shortlink_Study_IUID,
|
||||
ShortlinkHashDoB,
|
||||
@@ -118,7 +118,7 @@ func (r *ShortLinkRepository) UpdateShortLink(shortLink *models.ShortLink) error
|
||||
ShortlinkIsRevoked = ?,
|
||||
ShortlinkRemainingTries = ?,
|
||||
ShortlinkExpiredAt = ?
|
||||
WHERE ShortlinKCode = ?`
|
||||
WHERE ShortlinkCode = ?`
|
||||
|
||||
expiresAt, err := time.Parse(time.RFC3339, shortLink.ExpiresAt)
|
||||
if err != nil {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/api/models"
|
||||
"devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/database"
|
||||
)
|
||||
|
||||
@@ -11,8 +12,8 @@ import (
|
||||
type DBStudy struct {
|
||||
ID int `db:"id"`
|
||||
Study_PatientID string `db:"Study_PatientID"`
|
||||
Study_IUID string `db:"Study_IUID"`
|
||||
Study_AccessionNumber string `db:"Study_AccessionNumber"`
|
||||
StudyIUID string `db:"StudyIUID"`
|
||||
StudyAccessionNumber string `db:"StudyAccessionNumber"`
|
||||
StudyDate time.Time `db:"StudyDate"`
|
||||
StudyCreatedAt time.Time `db:"StudyCreatedAt"`
|
||||
StudyUpdatedAt time.Time `db:"StudyUpdatedAt"`
|
||||
@@ -45,9 +46,9 @@ func (r *StudyRepository) GetPatientStudies(patientID string) ([]string, []strin
|
||||
var accessionNumbers []string
|
||||
|
||||
for _, study := range studies {
|
||||
studyUIDs = append(studyUIDs, study.Study_IUID)
|
||||
if study.Study_AccessionNumber != "" {
|
||||
accessionNumbers = append(accessionNumbers, study.Study_AccessionNumber)
|
||||
studyUIDs = append(studyUIDs, study.StudyIUID)
|
||||
if study.StudyAccessionNumber != "" {
|
||||
accessionNumbers = append(accessionNumbers, study.StudyAccessionNumber)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +59,7 @@ func (r *StudyRepository) GetPatientStudies(patientID string) ([]string, []strin
|
||||
func (r *StudyRepository) GetStudyByUID(studyUID string) (*DBStudy, error) {
|
||||
var study DBStudy
|
||||
|
||||
query := `SELECT * FROM study WHERE Study_IUID = ?`
|
||||
query := `SELECT * FROM study WHERE StudyIUID = ?`
|
||||
err := database.DB.Get(&study, query, studyUID)
|
||||
|
||||
if err != nil {
|
||||
@@ -67,3 +68,32 @@ func (r *StudyRepository) GetStudyByUID(studyUID string) (*DBStudy, error) {
|
||||
|
||||
return &study, nil
|
||||
}
|
||||
|
||||
// CreateStudy creates a new study record for a patient
|
||||
func (r *StudyRepository) CreateStudy(patientID string, study models.Study) error {
|
||||
// Parse study date if provided
|
||||
var studyDate *time.Time
|
||||
if study.StudyDate != "" {
|
||||
parsedTime, err := time.Parse("2006-01-02", study.StudyDate)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid study date format: %w", err)
|
||||
}
|
||||
studyDate = &parsedTime
|
||||
}
|
||||
|
||||
query := `INSERT INTO study
|
||||
(Study_PatientID, StudyIUID, StudyAccessionNumber, StudyDate, StudyCreatedAt, StudyUpdatedAt)
|
||||
VALUES (?, ?, ?, ?, NOW(), NOW())`
|
||||
|
||||
_, err := database.DB.Exec(query,
|
||||
patientID,
|
||||
study.StudyInstanceUID,
|
||||
study.AccessionNumber,
|
||||
studyDate)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("database error creating study: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/api/models"
|
||||
"devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/database"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// DBUser represents a user from the database
|
||||
@@ -138,3 +139,30 @@ func (r *UserRepository) RevokeRefreshToken(token string) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateUser creates a new user
|
||||
func (r *UserRepository) CreateUser(user *models.User) error {
|
||||
// Hash the password before storing
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to hash password: %w", err)
|
||||
}
|
||||
|
||||
query := `INSERT INTO user (UserEmail, UserPassword, UserRole, UserName, UserCreatedAt, UserUpdatedAt)
|
||||
VALUES (?, ?, ?, ?, NOW(), NOW())`
|
||||
|
||||
result, err := database.DB.Exec(query, user.Email, string(hashedPassword), user.Role, user.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("database error creating user: %w", err)
|
||||
}
|
||||
|
||||
// Get the last inserted ID
|
||||
id, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get last insert ID: %w", err)
|
||||
}
|
||||
|
||||
// Update the user ID
|
||||
user.ID = fmt.Sprintf("%d", id)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -88,6 +88,11 @@ func SetupRouter(cfg *config.Config, logger *zap.Logger) http.Handler {
|
||||
r.Post("/refresh", authHandler.RefreshToken)
|
||||
r.Post("/logout", authHandler.Logout)
|
||||
|
||||
// Registration endpoint
|
||||
registerService := service.NewRegisterService()
|
||||
registerHandler := handlers.NewRegisterHandler(logger, registerService)
|
||||
r.Post("/register", registerHandler.Register)
|
||||
|
||||
// ShortLink authentication - no auth required
|
||||
shortLinkHandler := handlers.NewShortLinkHandler(logger, shortLinkService)
|
||||
r.Post("/shortlink", shortLinkHandler.ShortLinkAuth)
|
||||
|
||||
@@ -43,7 +43,7 @@ func (s *AuthService) Login(email, password string) (*models.LoginResponse, erro
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
return nil, ErrInvalidCredentials
|
||||
return nil, ErrUserNotFound
|
||||
}
|
||||
|
||||
// Verify password
|
||||
@@ -104,6 +104,7 @@ func (s *AuthService) Login(email, password string) (*models.LoginResponse, erro
|
||||
redirectURL = "/"
|
||||
}
|
||||
|
||||
// TODO: Apakah kita perlu param email untuk generate access token?
|
||||
// Generate tokens
|
||||
accessToken, err := s.jwtManager.GenerateAccessToken(user.ID, user.Email, user.Role, user.Name, additionalClaims)
|
||||
if err != nil {
|
||||
|
||||
117
internal/api/service/register_service.go
Normal file
117
internal/api/service/register_service.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/api/models"
|
||||
"devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/api/repository"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrEmailExists = errors.New("email already exists")
|
||||
ErrUserNotCreated = errors.New("failed to create user")
|
||||
ErrInvalidRole = errors.New("invalid user role")
|
||||
ErrInvalidPatient = errors.New("invalid patient data")
|
||||
ErrInvalidDoctor = errors.New("invalid doctor data")
|
||||
)
|
||||
|
||||
// RegisterRequest represents a user registration request
|
||||
type RegisterRequest struct {
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
Name string `json:"name"`
|
||||
Role string `json:"role"` // "patient", "ref_doctor", "expertise_doctor", or "admin"
|
||||
Patient *models.PatientDetails `json:"patient,omitempty"`
|
||||
Doctor *models.DoctorDetails `json:"doctor,omitempty"`
|
||||
Studies []models.Study `json:"studies,omitempty"` // Study records for patient
|
||||
}
|
||||
|
||||
// RegisterService handles user registration
|
||||
type RegisterService struct {
|
||||
userRepo *repository.UserRepository
|
||||
patientRepo *repository.PatientRepository
|
||||
doctorRepo *repository.DoctorRepository
|
||||
studyRepo *repository.StudyRepository
|
||||
}
|
||||
|
||||
// NewRegisterService creates a new register service
|
||||
func NewRegisterService() *RegisterService {
|
||||
return &RegisterService{
|
||||
userRepo: repository.NewUserRepository(),
|
||||
patientRepo: repository.NewPatientRepository(),
|
||||
doctorRepo: repository.NewDoctorRepository(),
|
||||
studyRepo: repository.NewStudyRepository(),
|
||||
}
|
||||
}
|
||||
|
||||
// Register creates a new user with their associated role-specific data
|
||||
func (s *RegisterService) Register(req *RegisterRequest) (*models.User, error) {
|
||||
// Validate role
|
||||
if req.Role != "patient" && req.Role != "ref_doctor" && req.Role != "expertise_doctor" && req.Role != "admin" {
|
||||
return nil, ErrInvalidRole
|
||||
}
|
||||
|
||||
// Check role-specific data
|
||||
if req.Role == "patient" && (req.Patient == nil || req.Patient.PatientID == "" || req.Patient.DateOfBirth == "") {
|
||||
return nil, ErrInvalidPatient
|
||||
}
|
||||
|
||||
if (req.Role == "ref_doctor" || req.Role == "expertise_doctor") && (req.Doctor == nil || req.Doctor.DoctorID == "") {
|
||||
return nil, ErrInvalidDoctor
|
||||
}
|
||||
|
||||
// Check if email already exists
|
||||
existingUser, err := s.userRepo.GetUserByEmail(req.Email)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return nil, fmt.Errorf("error checking existing user: %w", err)
|
||||
}
|
||||
|
||||
if existingUser != nil {
|
||||
return nil, ErrEmailExists
|
||||
}
|
||||
|
||||
// Create user
|
||||
newUser := &models.User{
|
||||
Email: req.Email,
|
||||
Password: req.Password, // Will be hashed in repository
|
||||
Role: req.Role,
|
||||
Name: req.Name,
|
||||
}
|
||||
|
||||
if err := s.userRepo.CreateUser(newUser); err != nil {
|
||||
return nil, fmt.Errorf("error creating user: %w", err)
|
||||
}
|
||||
|
||||
// Create role-specific data
|
||||
if req.Role == "patient" {
|
||||
err = s.patientRepo.CreatePatient(req.Patient, newUser.ID)
|
||||
if err != nil {
|
||||
// TODO: Consider rollback user creation if this fails
|
||||
return nil, fmt.Errorf("error creating patient: %w", err)
|
||||
}
|
||||
|
||||
// Create associated study records if provided
|
||||
if len(req.Studies) > 0 {
|
||||
for _, study := range req.Studies {
|
||||
if study.StudyInstanceUID == "" {
|
||||
continue // Skip studies without UIDs
|
||||
}
|
||||
|
||||
err = s.studyRepo.CreateStudy(req.Patient.PatientID, study)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating study for patient: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if req.Role == "ref_doctor" || req.Role == "expertise_doctor" {
|
||||
err = s.doctorRepo.CreateDoctor(req.Doctor, newUser.ID)
|
||||
if err != nil {
|
||||
// TODO: Consider rollback user creation if this fails
|
||||
return nil, fmt.Errorf("error creating doctor: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return newUser, nil
|
||||
}
|
||||
@@ -7,8 +7,8 @@ POST {{baseUrl}}/auth/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "patient",
|
||||
"password": "patient"
|
||||
"email": "doctor@example.com",
|
||||
"password": "password123"
|
||||
}
|
||||
|
||||
### Login Admin / Exp_doctor (ALL ACCESS)
|
||||
|
||||
151
test/http/register-flow.http
Normal file
151
test/http/register-flow.http
Normal file
@@ -0,0 +1,151 @@
|
||||
### Register new user, patient, and doctor tests
|
||||
|
||||
# Base URL for the API
|
||||
@baseUrl = http://localhost:5555
|
||||
|
||||
|
||||
### Register a new patient with multiple studies
|
||||
POST {{baseUrl}}/auth/register
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "patient1@example.com",
|
||||
"password": "password123",
|
||||
"name": "DIDIT SUYATNA^R.10049.18",
|
||||
"role": "patient",
|
||||
"patient": {
|
||||
"patient_id": "00211622",
|
||||
"patient_name": "DIDIT SUYATNA^R.10049.18",
|
||||
"date_of_birth": "1980-01-01"
|
||||
},
|
||||
"studies": [
|
||||
{
|
||||
"study_instance_uid": "1.2.826.0.1.3680043.9.7307.1.20180530066",
|
||||
"accession_number": "CR.180530.066",
|
||||
"study_date": "2018-05-30",
|
||||
"study_description": "Chest X-Ray"
|
||||
},
|
||||
{
|
||||
"study_instance_uid": "1.2.826.0.1.3680043.9.7307.1.20180713036",
|
||||
"accession_number": "CR.180713.036",
|
||||
"study_date": "2018-07-13",
|
||||
"study_description": "Follow-up X-Ray"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
### Register another patient with one study
|
||||
POST {{baseUrl}}/auth/register
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "patient2@example.com",
|
||||
"password": "password123",
|
||||
"name": "Bobon Santoso",
|
||||
"role": "patient",
|
||||
"patient": {
|
||||
"patient_id": "MR00000359",
|
||||
"patient_name": "Bobon Santoso",
|
||||
"date_of_birth": "1985-01-01"
|
||||
},
|
||||
"studies": [
|
||||
{
|
||||
"study_instance_uid": "1.2.826.0.1.3680043.9.7307.1.202503196393.01",
|
||||
"accession_number": "CR.250319.6393.01",
|
||||
"study_date": "2025-03-19",
|
||||
"study_description": "MRI Scan"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
### Register another referring doctor
|
||||
POST {{baseUrl}}/auth/register
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "doctor@example.com",
|
||||
"password": "password123",
|
||||
"name": "DR. HERWINDO RIDWAN, SP.OT",
|
||||
"role": "ref_doctor",
|
||||
"doctor": {
|
||||
"doctor_id": "DOC002",
|
||||
"doctor_name": "DR. HERWINDO RIDWAN, SP.OT"
|
||||
}
|
||||
}
|
||||
|
||||
### Register a new expertise doctor
|
||||
POST {{baseUrl}}/auth/register
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "expert@example.com",
|
||||
"password": "expert123",
|
||||
"name": "Dr. Expert Johnson",
|
||||
"role": "expertise_doctor",
|
||||
"doctor": {
|
||||
"doctor_id": "EX456",
|
||||
"doctor_name": "Dr. Expert Johnson"
|
||||
}
|
||||
}
|
||||
|
||||
### Register another referring doctor
|
||||
POST {{baseUrl}}/auth/register
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "doctor2@example.com",
|
||||
"password": "password123",
|
||||
"name": "Referring^Physician",
|
||||
"role": "ref_doctor",
|
||||
"doctor": {
|
||||
"doctor_id": "DOC003",
|
||||
"doctor_name": "Referring^Physician"
|
||||
}
|
||||
}
|
||||
|
||||
### Register an admin user
|
||||
POST {{baseUrl}}/auth/register
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "admin@example.com",
|
||||
"password": "admin123",
|
||||
"name": "Admin User",
|
||||
"role": "admin"
|
||||
}
|
||||
|
||||
### Login with registered user
|
||||
POST {{baseUrl}}/auth/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "patient1@example.com",
|
||||
"password": "password123"
|
||||
}
|
||||
|
||||
### Login with admin user
|
||||
POST {{baseUrl}}/auth/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "admin@example.com",
|
||||
"password": "password123"
|
||||
}
|
||||
|
||||
### Login with patient user
|
||||
POST {{baseUrl}}/auth/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "patient2@example.com",
|
||||
"password": "password123"
|
||||
}
|
||||
|
||||
### Login with doctor user
|
||||
POST {{baseUrl}}/auth/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "doctor@example.com",
|
||||
"password": "password123"
|
||||
}
|
||||
@@ -7,8 +7,8 @@ POST http://localhost:5555/auth/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "admin",
|
||||
"password": "admin"
|
||||
"email": "patient1@example.com",
|
||||
"password": "password123"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ POST {{baseUrl}}/auth/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "patient",
|
||||
"password": "patient"
|
||||
"email": "patient1@example.com",
|
||||
"password": "password123"
|
||||
}
|
||||
|
||||
### Refresh TOken
|
||||
@@ -24,7 +24,7 @@ POST {{baseUrl}}/auth/refresh
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"refresh"
|
||||
"refresh_token": {{ refresh_token}}
|
||||
}
|
||||
|
||||
### 2. QIDO-RS: Search for Studies
|
||||
|
||||
Reference in New Issue
Block a user