package application import ( "encoding/json" "fmt" "io" "net/http" "strconv" "strings" "time" formvalidators "git.coopgo.io/coopgo-apps/parcoursmob/core/utils/form-validators" "github.com/gorilla/mux" "github.com/rs/zerolog/log" ) type EventsForm struct { Name string `json:"name" validate:"required"` Type string `json:"type" validate:"required"` Description string `json:"description"` Address any `json:"address,omitempty"` Allday bool `json:"allday"` Startdate *time.Time `json:"startdate"` Enddate *time.Time `json:"enddate"` Starttime string `json:"starttime"` Endtime string `json:"endtime"` MaxSubscribers int `json:"max_subscribers"` } func parseEventsForm(r *http.Request) (*EventsForm, error) { if err := r.ParseForm(); err != nil { return nil, err } var startdate *time.Time var enddate *time.Time if r.PostFormValue("startdate") != "" { d, err := time.Parse("2006-01-02", r.PostFormValue("startdate")) if err != nil { return nil, err } startdate = &d } if r.PostFormValue("enddate") != "" { d, err := time.Parse("2006-01-02", r.PostFormValue("enddate")) if err != nil { return nil, err } enddate = &d } max_subscribers, err := strconv.Atoi(r.PostFormValue("max_subscribers")) if err != nil { return nil, err } formData := &EventsForm{ Name: r.PostFormValue("name"), Type: r.PostFormValue("type"), Description: r.PostFormValue("description"), Startdate: startdate, Enddate: enddate, Starttime: r.PostFormValue("starttime"), Endtime: r.PostFormValue("endtime"), MaxSubscribers: max_subscribers, } if r.PostFormValue("allday") == "true" { formData.Allday = true } if r.PostFormValue("address") != "" { var a any json.Unmarshal([]byte(r.PostFormValue("address")), &a) formData.Address = a } validate := formvalidators.New() if err := validate.Struct(formData); err != nil { return nil, err } return formData, nil } func (h *Handler) AgendaHomeHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { today := time.Now().Truncate(24 * time.Hour) result, err := h.applicationHandler.GetAgendaEvents(r.Context(), &today, nil) if err != nil { log.Error().Err(err).Msg("error retrieving agenda events") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } h.renderer.AgendaHome(w, r, result.Events, result.Groups) } } func (h *Handler) AgendaHistoryHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { result, err := h.applicationHandler.GetAgendaEvents(r.Context(), nil, nil) if err != nil { log.Error().Err(err).Msg("error retrieving agenda events") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } h.renderer.AgendaHistory(w, r, result.Events, result.Groups) } } func (h *Handler) AgendaCreateEventHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { // Parse form data eventForm, err := parseEventsForm(r) if err != nil { log.Error().Err(err).Msg("error parsing event form") http.Error(w, "Bad Request", http.StatusBadRequest) return } // Handle file upload if present var file io.Reader var filename string var fileSize int64 var documentType, documentName string contentType := r.Header.Get("Content-Type") if strings.HasPrefix(contentType, "multipart/form-data") { err = r.ParseMultipartForm(100 * 1024 * 1024) // 100 MB limit if err != nil { log.Error().Err(err).Msg("error parsing multipart form") http.Error(w, "Bad Request", http.StatusBadRequest) return } uploadedFile, header, err := r.FormFile("file-upload") if err == nil { defer uploadedFile.Close() file = uploadedFile filename = header.Filename fileSize = header.Size documentType = r.FormValue("file_type") documentName = r.FormValue("file_name") } else if err != http.ErrMissingFile { log.Error().Err(err).Msg("error retrieving file") http.Error(w, "Bad Request", http.StatusBadRequest) return } } eventID, err := h.applicationHandler.CreateAgendaEvent( r.Context(), eventForm.Name, eventForm.Type, eventForm.Description, eventForm.Address, eventForm.Allday, eventForm.Startdate, eventForm.Enddate, eventForm.Starttime, eventForm.Endtime, eventForm.MaxSubscribers, file, filename, fileSize, documentType, documentName, ) if err != nil { log.Error().Err(err).Msg("error creating agenda event") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/agenda/%s", eventID), http.StatusFound) return } // For GET requests, render the create event form with config data documentTypes := h.cfg.GetStringSlice("modules.agenda.documents_types") fileTypes := h.cfg.GetStringMapString("storage.files.file_types") h.renderer.AgendaCreateEvent(w, r, documentTypes, fileTypes, nil) } } func (h *Handler) AgendaDisplayEventHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) eventID := vars["eventid"] result, err := h.applicationHandler.GetAgendaEvent(r.Context(), eventID) if err != nil { log.Error().Err(err).Msg("error retrieving agenda event") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } documentTypes := h.cfg.GetStringSlice("modules.agenda.documents_types") fileTypes := h.cfg.GetStringMapString("storage.files.file_types") h.renderer.AgendaDisplayEvent(w, r, result.Event, result.Group, documentTypes, fileTypes, result.Documents, result.Subscribers, result.Accounts) } } func (h *Handler) AgendaUpdateEventHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) eventID := vars["eventid"] if r.Method == "POST" { // Parse form data eventForm, err := parseEventsForm(r) if err != nil { log.Error().Err(err).Msg("error parsing event form") http.Error(w, "Bad Request", http.StatusBadRequest) return } updatedEventID, err := h.applicationHandler.UpdateAgendaEvent( r.Context(), eventID, eventForm.Name, eventForm.Type, eventForm.Description, eventForm.Address, eventForm.Allday, eventForm.Startdate, eventForm.Enddate, eventForm.Starttime, eventForm.Endtime, eventForm.MaxSubscribers, ) if err != nil { log.Error().Err(err).Msg("error updating agenda event") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/agenda/%s", updatedEventID), http.StatusFound) return } // For GET requests, render the update event form result, err := h.applicationHandler.GetAgendaEvent(r.Context(), eventID) if err != nil { log.Error().Err(err).Msg("error retrieving agenda event") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } h.renderer.AgendaUpdateEvent(w, r, result.Event) } } func (h *Handler) AgendaDeleteEventHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) eventID := vars["eventid"] if r.Method == "POST" { if err := h.applicationHandler.DeleteAgendaEvent(r.Context(), eventID); err != nil { log.Error().Err(err).Msg("error deleting agenda event") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } http.Redirect(w, r, "/app/agenda/", http.StatusFound) return } // For GET requests, render the delete confirmation form result, err := h.applicationHandler.GetAgendaEvent(r.Context(), eventID) if err != nil { log.Error().Err(err).Msg("error retrieving agenda event") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } h.renderer.AgendaDeleteEvent(w, r, result.Event) } } func (h *Handler) AgendaSubscribeEventHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) eventID := vars["eventid"] if r.Method == "POST" { if err := r.ParseForm(); err != nil { log.Error().Err(err).Msg("error parsing form") http.Error(w, "Bad Request", http.StatusBadRequest) return } subscriber := r.FormValue("subscriber") // Get current user and group information current_group, err := h.currentGroup(r) if err != nil { log.Error().Err(err).Msg("error getting current group") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } current_user_token, current_user_claims, err := h.currentUser(r) if err != nil { log.Error().Err(err).Msg("error getting current user") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } subscriptionData := map[string]any{ "subscribed_by": map[string]any{ "user": map[string]any{ "id": current_user_token.Subject, "display_name": current_user_claims["first_name"].(string) + " " + current_user_claims["last_name"].(string), "email": current_user_claims["email"].(string), }, "group": map[string]any{ "id": current_group.ID, "name": current_group.Data["name"], }, }, } if err := h.applicationHandler.SubscribeToAgendaEvent(r.Context(), eventID, subscriber, subscriptionData); err != nil { log.Error().Err(err).Msg("error subscribing to agenda event") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/agenda/%s", eventID), http.StatusFound) return } // For GET requests, redirect to event display http.Redirect(w, r, fmt.Sprintf("/app/agenda/%s", eventID), http.StatusFound) } } func (h *Handler) AgendaDeleteSubscribeEventHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) eventID := vars["eventid"] subscribeID := vars["subscribeid"] if r.Method == "POST" { if err := r.ParseForm(); err != nil { log.Error().Err(err).Msg("error parsing form") http.Error(w, "Bad Request", http.StatusBadRequest) return } motif := r.FormValue("motif") // Get current user and group information current_group, err := h.currentGroup(r) if err != nil { log.Error().Err(err).Msg("error getting current group") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } current_user_token, current_user_claims, err := h.currentUser(r) if err != nil { log.Error().Err(err).Msg("error getting current user") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } if err := h.applicationHandler.UnsubscribeFromAgendaEvent( r.Context(), eventID, subscribeID, motif, current_user_token.Subject, current_user_claims["first_name"].(string)+" "+current_user_claims["last_name"].(string), current_user_claims["email"].(string), current_group.ID, current_group.Data["name"].(string), ); err != nil { log.Error().Err(err).Msg("error unsubscribing from agenda event") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/agenda/%s", eventID), http.StatusFound) return } // For GET requests, render the delete subscription form h.renderer.AgendaDeleteSubscribeEvent(w, r, eventID) } } func (h *Handler) AgendaHistoryEventHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) eventID := vars["eventid"] result, err := h.applicationHandler.GetAgendaEventHistory(r.Context(), eventID) if err != nil { log.Error().Err(err).Msg("error retrieving agenda event history") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } h.renderer.AgendaHistoryEvent(w, r, result.Event, result.Group, result.Subscribers, result.Accounts) } } func (h *Handler) EventDocumentsHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) eventID := vars["eventid"] if err := r.ParseMultipartForm(100 * 1024 * 1024); err != nil { // 100 MB limit log.Error().Err(err).Msg("error parsing multipart form") http.Error(w, "Bad Request", http.StatusBadRequest) return } documentType := r.FormValue("type") documentName := r.FormValue("name") file, header, err := r.FormFile("file-upload") if err != nil { log.Error().Err(err).Msg("error retrieving file") http.Error(w, "Bad Request", http.StatusBadRequest) return } defer file.Close() if err := h.applicationHandler.AddEventDocument(r.Context(), eventID, file, header.Filename, header.Size, documentType, documentName); err != nil { log.Error().Err(err).Msg("error adding event document") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/agenda/%s", eventID), http.StatusFound) } } func (h *Handler) EventDocumentDownloadHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) eventID := vars["eventid"] document := vars["document"] file, info, err := h.applicationHandler.GetEventDocument(r.Context(), eventID, document) if err != nil { log.Error().Err(err).Msg("error retrieving event document") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } w.Header().Set("Content-Type", info.ContentType) if _, err = io.Copy(w, file); err != nil { log.Error().Err(err).Msg("error copying file content") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/agenda/%s", eventID), http.StatusFound) } }