lot of new functionalities

This commit is contained in:
Arnaud Delcasse
2025-10-14 18:11:13 +02:00
parent a6f70a6e85
commit d992a7984f
164 changed files with 15113 additions and 9442 deletions

38
servers/web/api/auth.go Normal file
View File

@@ -0,0 +1,38 @@
package api
import (
"net/http"
"github.com/rs/zerolog/log"
)
func (h *Handler) OAuth2Callback(w http.ResponseWriter, r *http.Request) {
code := r.URL.Query().Get("code")
if code == "" {
w.WriteHeader(http.StatusBadRequest)
return
}
session, _ := h.idp.SessionsStore.Get(r, "parcoursmob_session")
redirectSession := ""
if session.Values["redirect"] != nil && session.Values["redirect"] != "" {
redirectSession = session.Values["redirect"].(string)
delete(session.Values, "redirect")
}
result, err := h.applicationHandler.ProcessOAuth2Callback(code, redirectSession)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
session.Values["idtoken"] = result.IDToken
if err = session.Save(r, w); err != nil {
log.Error().Err(err).Msg("Cannot save session")
w.WriteHeader(http.StatusInternalServerError)
return
}
http.Redirect(w, r, result.RedirectURL, http.StatusFound)
}

48
servers/web/api/cache.go Normal file
View File

@@ -0,0 +1,48 @@
package api
import (
"net/http"
"git.coopgo.io/coopgo-apps/parcoursmob/core/utils/cache"
"github.com/gorilla/mux"
"github.com/rs/zerolog/log"
)
func (h *Handler) GetCache(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
cacheID := vars["cacheid"]
// Parse query parameters
limitsMinStr := r.URL.Query().Get("limits.min")
limitsMaxStr := r.URL.Query().Get("limits.max")
limitsMin, limitsMax := cache.ParseLimits(limitsMinStr, limitsMaxStr)
// Use a channel to synchronize the goroutines
ch := make(chan []byte)
// Fetch data from cache asynchronously
go func() {
result, err := h.cacheService.GetCacheData(cacheID, limitsMin, limitsMax)
if err != nil {
log.Error().Err(err).Msg("Failed to get cache data")
w.WriteHeader(http.StatusNotFound)
ch <- nil
return
}
ch <- result.Data // Signal that the data has been fetched successfully
close(ch)
}()
// Wait for the JSON marshaling goroutine to finish
data := <-ch
if data == nil {
return // Stop processing if an error occurred
}
// Send the JSON response to the client
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(data)
<-ch
}

View File

@@ -0,0 +1,51 @@
package api
import (
"net/http"
"github.com/gorilla/mux"
"github.com/rs/zerolog/log"
)
func (h *Handler) CalendarGlobal(w http.ResponseWriter, r *http.Request) {
enabled := h.config.GetBool("modules.agenda.enabled") && h.config.GetBool("modules.agenda.calendars.global.enabled")
if !enabled {
log.Error().Msg("global calendar not activated in configuration")
w.WriteHeader(http.StatusForbidden)
return
}
result, err := h.applicationHandler.GenerateGlobalCalendar(r.Context())
if err != nil {
log.Error().Err(err).Msg("error generating global calendar")
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/calendar; charset=utf-8")
w.WriteHeader(http.StatusOK)
w.Write([]byte(result.CalendarData))
}
func (h *Handler) CalendarOrganizations(w http.ResponseWriter, r *http.Request) {
enabled := h.config.GetBool("modules.agenda.enabled") && h.config.GetBool("modules.agenda.calendars.organizations.enabled")
if !enabled {
log.Error().Msg("organizations calendar not activated in configuration")
w.WriteHeader(http.StatusForbidden)
return
}
vars := mux.Vars(r)
groupID := vars["groupid"]
result, err := h.applicationHandler.GenerateOrganizationCalendar(r.Context(), groupID)
if err != nil {
log.Error().Err(err).Msg("error generating organization calendar")
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/calendar; charset=utf-8")
w.WriteHeader(http.StatusOK)
w.Write([]byte(result.CalendarData))
}

31
servers/web/api/export.go Normal file
View File

@@ -0,0 +1,31 @@
package api
import (
"encoding/csv"
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/rs/zerolog/log"
)
func (h *Handler) CacheExport(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
cacheID := vars["cacheid"]
result, err := h.applicationHandler.ExportCacheAsCSV(cacheID)
if err != nil {
log.Error().Err(err).Msg("Error exporting cache")
w.WriteHeader(http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "text/csv")
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=export-%s.csv", cacheID))
csvWriter := csv.NewWriter(w)
defer csvWriter.Flush()
csvWriter.Write(result.Headers)
csvWriter.WriteAll(result.Values)
}

32
servers/web/api/geo.go Normal file
View File

@@ -0,0 +1,32 @@
package api
import (
"encoding/json"
"net/http"
)
func (h *Handler) GeoAutocomplete(w http.ResponseWriter, r *http.Request) {
t, ok := r.URL.Query()["text"]
if !ok || len(t[0]) < 1 {
w.WriteHeader(http.StatusBadRequest)
return
}
text := t[0]
result, err := h.geoService.Autocomplete(text)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
j, err := json.Marshal(result.Features)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(j)
}

View File

@@ -0,0 +1,37 @@
package api
import (
"net/http"
"git.coopgo.io/coopgo-apps/parcoursmob/core/application"
"git.coopgo.io/coopgo-apps/parcoursmob/core/utils/cache"
"git.coopgo.io/coopgo-apps/parcoursmob/core/utils/geo"
"git.coopgo.io/coopgo-apps/parcoursmob/core/utils/identification"
cacheStorage "git.coopgo.io/coopgo-apps/parcoursmob/core/utils/storage"
"github.com/spf13/viper"
)
type Handler struct {
config *viper.Viper
idp *identification.IdentificationProvider
applicationHandler *application.ApplicationHandler
cacheService *cache.CacheService
geoService *geo.GeoService
}
func NewHandler(cfg *viper.Viper, idp *identification.IdentificationProvider, appHandler *application.ApplicationHandler, cacheHandler cacheStorage.CacheHandler) *Handler {
cacheService := cache.NewCacheService(cacheHandler)
geoService := geo.NewGeoService(cfg.GetString("geo.pelias.url"))
return &Handler{
config: cfg,
idp: idp,
applicationHandler: appHandler,
cacheService: cacheService,
geoService: geoService,
}
}
func (h *Handler) NotFound(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
}

View File

@@ -0,0 +1,26 @@
package protected
import (
"net/http"
"git.coopgo.io/coopgo-apps/parcoursmob/core/application"
"github.com/spf13/viper"
)
type Handler struct {
apiKey string
config *viper.Viper
applicationHandler *application.ApplicationHandler
}
func NewHandler(cfg *viper.Viper, appHandler *application.ApplicationHandler) *Handler {
return &Handler{
apiKey: cfg.GetString("services.api.api_key"),
config: cfg,
applicationHandler: appHandler,
}
}
func (h *Handler) NotFound(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
}

View File

@@ -0,0 +1,29 @@
package protected
import (
"context"
"encoding/json"
"net/http"
"git.coopgo.io/coopgo-platform/mobility-accounts/storage"
"github.com/rs/zerolog/log"
)
func (h *Handler) RegisterUserHTTP(w http.ResponseWriter, r *http.Request) {
var user storage.Account
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
result, err := h.applicationHandler.RegisterUser(context.Background(), user)
if err != nil {
log.Error().Err(err).Msg("Failed to register user")
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(result)
}