parcoursmob/servers/web/web.go

142 lines
4.8 KiB
Go

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
}