package web import ( "errors" "net/http" "time" "github.com/gorilla/mux" "github.com/rs/zerolog/log" "github.com/spf13/viper" "git.coopgo.io/coopgo-apps/parcoursmob/core/application" "git.coopgo.io/coopgo-apps/parcoursmob/renderer" webapi "git.coopgo.io/coopgo-apps/parcoursmob/servers/web/api" webapplication "git.coopgo.io/coopgo-apps/parcoursmob/servers/web/application" webauth "git.coopgo.io/coopgo-apps/parcoursmob/servers/web/auth" webexports "git.coopgo.io/coopgo-apps/parcoursmob/servers/web/exports" webexternal "git.coopgo.io/coopgo-apps/parcoursmob/servers/web/external" webprotectedapi "git.coopgo.io/coopgo-apps/parcoursmob/servers/web/protected_api" "git.coopgo.io/coopgo-apps/parcoursmob/services" "git.coopgo.io/coopgo-apps/parcoursmob/core/utils/identification" cacheStorage "git.coopgo.io/coopgo-apps/parcoursmob/core/utils/storage" "git.coopgo.io/coopgo-platform/groups-management/storage" "github.com/coreos/go-oidc/v3/oidc" ) type WebServer struct { cfg *viper.Viper services *services.ServicesHandler renderer *renderer.Renderer applicationHandler *application.ApplicationHandler exportsHandler *webexports.Handler authHandler *webauth.Handler idp *identification.IdentificationProvider // Web handler subpackages appHandler *webapplication.Handler extHandler *webexternal.Handler protectedAPIHandler *webprotectedapi.Handler webAPIHandler *webapi.Handler } func Run(cfg *viper.Viper, services *services.ServicesHandler, renderer *renderer.Renderer, applicationHandler *application.ApplicationHandler, idp *identification.IdentificationProvider, cacheHandler cacheStorage.CacheHandler, filestorage cacheStorage.FileStorage) { var ( address = cfg.GetString("server.web.listen") service_name = cfg.GetString("service_name") templates_public_dir = cfg.GetString("templates.public_dir") dev_env = cfg.GetBool("dev_env") ) webServer := &WebServer{ cfg: cfg, services: services, renderer: renderer, applicationHandler: applicationHandler, idp: idp, // Initialize web handler subpackages appHandler: webapplication.NewHandler(cfg, renderer, applicationHandler, idp, services), authHandler: webauth.NewHandler(cfg, applicationHandler, idp, renderer), exportsHandler: webexports.NewHandler(cfg, applicationHandler, idp, renderer), extHandler: webexternal.NewHandler(cfg, applicationHandler, filestorage), protectedAPIHandler: webprotectedapi.NewHandler(cfg, applicationHandler), webAPIHandler: webapi.NewHandler(cfg, idp, applicationHandler, cacheHandler), } r := mux.NewRouter() // Static files r.PathPrefix("/public/").Handler(http.StripPrefix("/public/", http.FileServer(http.Dir(templates_public_dir)))) // Root redirect r.HandleFunc("/", redirectApp) // Development middleware if dev_env { r.Use(trackPage) } // Setup all route groups webServer.setupAuthRoutes(r) webServer.setupCalendarsRoutes(r) webServer.setupExternalRoutes(r) webServer.setupAPIRoutes(r) webServer.setupProtectedAPIRoutes(r) webServer.setupApplicationRoutes(r) webServer.setupExportsRoutes(r) srv := &http.Server{ Handler: r, Addr: address, WriteTimeout: 30 * time.Second, ReadTimeout: 15 * time.Second, } log.Info().Str("service_name", service_name).Str("address", address).Msg("Running HTTP server") err := srv.ListenAndServe() log.Error().Err(err).Msg("Web server error") } func redirectApp(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/app/", http.StatusFound) } func trackPage(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { log.Trace().Str("requested_uri", r.RequestURI).Msg("New request") next.ServeHTTP(w, r.WithContext(r.Context())) }) } // Helper functions for extracting user and group information from request context func currentGroup(r *http.Request) (current_group storage.Group, err error) { g := r.Context().Value(identification.GroupKey) if g == nil { return storage.Group{}, errors.New("current group not found") } current_group = g.(storage.Group) return current_group, nil } func currentUser(r *http.Request) (current_user_token *oidc.IDToken, current_user_claims map[string]any, err error) { // Get current user ID u := r.Context().Value(identification.IdtokenKey) if u == nil { return nil, nil, errors.New("current user not found") } current_user_token = u.(*oidc.IDToken) // Get current user claims c := r.Context().Value(identification.ClaimsKey) if c == nil { return current_user_token, nil, errors.New("current user claims not found") } current_user_claims = c.(map[string]any) return current_user_token, current_user_claims, nil }