package api import ( "net/http" "time" "devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/config" "devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/api/handlers" apiMiddleware "devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/api/middleware" "devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/api/service" "devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/auth" "devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/proxy" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/cors" "go.uber.org/zap" ) // SetupRouter configures and returns the API router func SetupRouter(cfg *config.Config, logger *zap.Logger) http.Handler { r := chi.NewRouter() // Base middleware r.Use(middleware.RequestID) r.Use(middleware.RealIP) r.Use(middleware.Recoverer) r.Use(apiMiddleware.Logger(logger)) // CORS configuration r.Use(cors.Handler(cors.Options{ AllowedOrigins: []string{"*"}, // In production, restrict this to your frontend domains AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token", "X-Requested-With"}, ExposedHeaders: []string{"Link", "Content-Length", "Content-Disposition", "Content-Type"}, AllowCredentials: true, MaxAge: 300, // Maximum value not ignored by any of major browsers })) r.Options("/*", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) // Initialize Google auth client for proxy googleAuth, err := auth.NewGoogleClient(cfg.Google.CredentialsPath) if err != nil { logger.Fatal("Failed to initialize Google auth client", zap.Error(err)) } // Initialize Healthcare API client healthcareClient := proxy.NewClient(googleAuth, cfg.Google) // Initialize JWT auth service jwtSecret := cfg.Auth.JWTSecret if jwtSecret == "" { logger.Warn("JWT secret not provided in config, using default value. This is insecure for production!") jwtSecret = "vQ6PQqUyh7pBNOytClgN+Nw1XBq7F8Qo6VP3VwIqvHY=" } // Convert config values to time.Duration accessExpiry := time.Duration(cfg.Auth.AccessTokenExpiry) * time.Minute refreshExpiry := time.Duration(cfg.Auth.RefreshTokenExpiry) * time.Hour // Create JWT manager with config values jwtManager := auth.NewJWTManager(jwtSecret, accessExpiry, refreshExpiry) // Initialize services with domain-specific repositories authService := service.NewAuthService(jwtManager) // Initialize shortlink service with config values shortLinkService := service.NewShortLinkService( jwtManager, logger, cfg.Shortlink.BaseURL, cfg.Shortlink.DefaultExpiryHours, cfg.Shortlink.MaxAttempts, ) // Public routes that don't require authentication r.Group(func(r chi.Router) { // Health check r.Get("/health", handlers.HealthCheck) // Authentication endpoints r.Route("/auth", func(r chi.Router) { authHandler := handlers.NewAuthHandler(logger, authService) r.Post("/login", authHandler.Login) r.Post("/refresh", authHandler.RefreshToken) r.Post("/logout", authHandler.Logout) // ShortLink authentication - no auth required shortLinkHandler := handlers.NewShortLinkHandler(logger, shortLinkService) r.Post("/shortlink", shortLinkHandler.ShortLinkAuth) }) }) // Protected routes that require authentication r.Group(func(r chi.Router) { // Apply authentication middleware r.Use(apiMiddleware.Auth(authService, logger)) // Shortlink generation - only for admin and expertise_doctor roles shortLinkHandler := handlers.NewShortLinkHandler(logger, shortLinkService) r.Post("/generate-link", shortLinkHandler.GenerateShortLink) // DICOM Web routes r.Route("/dicomWeb", func(r chi.Router) { // Add audit logging middleware to DICOM routes r.Use(apiMiddleware.AuditLog(logger)) // Add patient view restriction for patient role r.Use(apiMiddleware.PatientViewRestriction(logger)) // Create handler for all DICOM requests dicomHandler := handlers.NewDicomHandler(healthcareClient, logger) // Common routes for studies with role-specific handling r.Route("/studies", func(r chi.Router) { // StudyInstanceUID parameter routes - accessible by all roles r.Get("/{studyInstanceUID}", dicomHandler.ForwardRequest) // Study details r.Get("/{studyInstanceUID}/series", dicomHandler.ForwardRequest) // Series list for study // Deep hierarchy routes - accessible by patients and all doctors r.Get("/{studyInstanceUID}/series/{seriesUID}/metadata", dicomHandler.ForwardRequest) r.Get("/{studyInstanceUID}/series/{seriesUID}/instances/{instanceUID}/frames/{frame}", dicomHandler.ForwardRequest) // Query routes - accessible by all roles r.Get("/", dicomHandler.ForwardRequest) // Study list with filters }) // Expertise doctors have full access to all DICOM endpoints r.With(apiMiddleware.RoleRequired("expertise_doctor")).HandleFunc("/*", dicomHandler.ForwardRequest) }) }) return r }