Files
go-ohif-proxy/internal/api/handlers/shortlink.go
2025-05-13 15:44:11 +07:00

130 lines
4.0 KiB
Go

package handlers
import (
"encoding/json"
"net/http"
"devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/api/middleware"
"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"
)
// ShortLinkHandler handles shortlink operations
type ShortLinkHandler struct {
logger *zap.Logger
shortLinkService *service.ShortLinkService
}
// NewShortLinkHandler creates a new shortlink handler
func NewShortLinkHandler(logger *zap.Logger, shortLinkService *service.ShortLinkService) *ShortLinkHandler {
return &ShortLinkHandler{
logger: logger,
shortLinkService: shortLinkService,
}
}
// GenerateShortLink handles shortlink generation requests
func (h *ShortLinkHandler) GenerateShortLink(w http.ResponseWriter, r *http.Request) {
// Only allow admin or expertise_doctor roles to generate shortlinks
userRole, ok := r.Context().Value(middleware.UserRoleKey).(string)
if !ok || (userRole != "admin" && userRole != "expertise_doctor") {
h.logger.Warn("Unauthorized attempt to generate shortlink",
zap.String("role", userRole))
http.Error(w, "Only admin or expertise doctor can generate short links", http.StatusForbidden)
return
}
// Parse request body
var req models.GenerateShortLinkRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
h.logger.Error("Failed to parse shortlink generation request", zap.Error(err))
http.Error(w, "Invalid request body", http.StatusBadRequest)
return
}
// Get user ID from context
userID, ok := r.Context().Value(middleware.UserIDKey).(string)
if !ok {
h.logger.Error("User ID not found in context")
http.Error(w, "User context not found", http.StatusInternalServerError)
return
}
// Generate shortlink using configured baseURL from service
response, err := h.shortLinkService.GenerateShortLink(&req, userID)
if err != nil {
h.logger.Error("Failed to generate shortlink",
zap.Error(err),
zap.String("patientID", req.PatientID),
zap.String("studyUID", req.StudyUID))
statusCode := http.StatusInternalServerError
message := "Failed to generate shortlink"
if err == service.ErrInvalidStudyUID {
statusCode = http.StatusBadRequest
message = "Invalid StudyInstanceUID"
}
http.Error(w, message, statusCode)
return
}
// Log successful shortlink generation
h.logger.Info("Shortlink generated successfully",
zap.String("token", response.ShortToken),
zap.String("patientID", req.PatientID),
zap.String("studyUID", req.StudyUID),
zap.String("createdBy", userID))
// Return response
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(response)
}
// ShortLinkAuth handles authentication requests using shortlinks
func (h *ShortLinkHandler) ShortLinkAuth(w http.ResponseWriter, r *http.Request) {
// Parse request body
var req models.ShortLinkAuthRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
h.logger.Error("Failed to parse shortlink auth request", zap.Error(err))
http.Error(w, "Invalid request body", http.StatusBadRequest)
return
}
// Validate and authenticate
response, err := h.shortLinkService.AuthenticateWithShortLink(&req)
if err != nil {
h.logger.Warn("Shortlink authentication failed",
zap.Error(err),
zap.String("token", req.ShortToken))
statusCode := http.StatusUnauthorized
message := "Authentication failed"
switch err {
case service.ErrShortLinkNotFound, service.ErrShortLinkExpired:
message = "Short link not found or expired"
case service.ErrInvalidDOB:
message = "Invalid date of birth"
case service.ErrTooManyAttempts:
message = "Too many failed attempts"
}
http.Error(w, message, statusCode)
return
}
// Log successful authentication
h.logger.Info("Shortlink authentication successful",
zap.String("token", req.ShortToken))
// Return response
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(response)
}