package application import ( "encoding/json" "fmt" "io" "net/http" "strconv" "time" formvalidators "git.coopgo.io/coopgo-apps/parcoursmob/core/utils/form-validators" "github.com/gorilla/mux" "github.com/rs/zerolog/log" ) type BeneficiariesForm struct { FirstName string `json:"first_name" validate:"required"` LastName string `json:"last_name" validate:"required"` Email string `json:"email" validate:"required,email"` Birthdate *time.Time `json:"birthdate" validate:"required"` PhoneNumber string `json:"phone_number" validate:"required,phoneNumber"` FileNumber string `json:"file_number"` Address any `json:"address,omitempty"` Gender string `json:"gender"` OtherProperties any `json:"other_properties,omitempty"` } func parseBeneficiariesForm(r *http.Request) (*BeneficiariesForm, error) { if err := r.ParseForm(); err != nil { return nil, err } var date *time.Time if r.PostFormValue("birthdate") != "" { d, err := time.Parse("2006-01-02", r.PostFormValue("birthdate")) if err != nil { return nil, err } date = &d } formData := &BeneficiariesForm{ FirstName: r.PostFormValue("first_name"), LastName: r.PostFormValue("last_name"), Email: r.PostFormValue("email"), Birthdate: date, PhoneNumber: r.PostFormValue("phone_number"), FileNumber: r.PostFormValue("file_number"), Gender: r.PostFormValue("gender"), } if r.PostFormValue("address") != "" { var a any json.Unmarshal([]byte(r.PostFormValue("address")), &a) formData.Address = a } if r.PostFormValue("other_properties") != "" { var a any json.Unmarshal([]byte(r.PostFormValue("other_properties")), &a) formData.OtherProperties = a } validate := formvalidators.New() if err := validate.Struct(formData); err != nil { return nil, err } return formData, nil } func (h *Handler) BeneficiariesListHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // Extract search and archived filters from query parameters searchFilter := "" if search := r.URL.Query().Get("search"); search != "" { searchFilter = search } archivedFilter := false if archived := r.URL.Query().Get("archived"); archived == "true" { archivedFilter = true } result, err := h.applicationHandler.GetBeneficiaries(r.Context(), searchFilter, archivedFilter) if err != nil { log.Error().Err(err).Msg("error retrieving beneficiaries") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } h.renderer.BeneficiariesList(w, r, result.Accounts, result.CacheID, archivedFilter) } } func (h *Handler) BeneficiaryCreateHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { beneficiaryForm, err := parseBeneficiariesForm(r) if err != nil { log.Error().Err(err).Msg("error parsing beneficiary form") http.Error(w, "Bad Request", http.StatusBadRequest) return } beneficiaryID, err := h.applicationHandler.CreateBeneficiary( r.Context(), beneficiaryForm.FirstName, beneficiaryForm.LastName, beneficiaryForm.Email, beneficiaryForm.Birthdate, beneficiaryForm.PhoneNumber, beneficiaryForm.FileNumber, beneficiaryForm.Address, beneficiaryForm.Gender, beneficiaryForm.OtherProperties, ) if err != nil { log.Error().Err(err).Msg("error creating beneficiary") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/beneficiaries/%s", beneficiaryID), http.StatusFound) return } h.renderer.BeneficiaryCreate(w, r) } } func (h *Handler) BeneficiaryDisplayHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) beneficiaryID := vars["beneficiaryid"] // Extract tab parameter tab := r.URL.Query().Get("tab") if tab == "" { tab = "documents" // Default tab } result, err := h.applicationHandler.GetBeneficiaryData(r.Context(), beneficiaryID) if err != nil { log.Error().Err(err).Msg("error retrieving beneficiary data") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } beneficiariesFileTypes := h.cfg.GetStringSlice("modules.beneficiaries.documents_types") fileTypesMap := h.cfg.GetStringMapString("storage.files.file_types") h.renderer.BeneficiaryDisplay(w, r, result.Account, result.Bookings, result.Organizations, beneficiariesFileTypes, fileTypesMap, result.Documents, result.EventsList, result.SolidarityTransportStats, result.SolidarityTransportBookings, result.SolidarityDriversMap, result.OrganizedCarpoolStats, result.OrganizedCarpoolBookings, result.OrganizedCarpoolDriversMap, result.WalletBalance, tab) } } func (h *Handler) BeneficiaryUpdateHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) beneficiaryID := vars["beneficiaryid"] if r.Method == "POST" { beneficiaryForm, err := parseBeneficiariesForm(r) if err != nil { log.Error().Err(err).Msg("error parsing beneficiary form") http.Error(w, "Bad Request", http.StatusBadRequest) return } updatedBeneficiaryID, err := h.applicationHandler.UpdateBeneficiary( r.Context(), beneficiaryID, beneficiaryForm.FirstName, beneficiaryForm.LastName, beneficiaryForm.Email, beneficiaryForm.Birthdate, beneficiaryForm.PhoneNumber, beneficiaryForm.FileNumber, beneficiaryForm.Address, beneficiaryForm.Gender, beneficiaryForm.OtherProperties, ) if err != nil { log.Error().Err(err).Msg("error updating beneficiary") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/beneficiaries/%s", updatedBeneficiaryID), http.StatusFound) return } // For GET requests, just get the basic beneficiary account data result, err := h.applicationHandler.GetBeneficiary(r.Context(), beneficiaryID) if err != nil { log.Error().Err(err).Msg("error retrieving beneficiary for update") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } h.renderer.BeneficiaryUpdate(w, r, result.Account) } } func (h *Handler) BeneficiaryArchiveHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) beneficiaryID := vars["beneficiaryid"] if err := h.applicationHandler.ArchiveBeneficiary(r.Context(), beneficiaryID); err != nil { log.Error().Err(err).Msg("error archiving beneficiary") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/beneficiaries/%s", beneficiaryID), http.StatusFound) } } func (h *Handler) BeneficiaryUnarchiveHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) beneficiaryID := vars["beneficiaryid"] if err := h.applicationHandler.UnarchiveBeneficiary(r.Context(), beneficiaryID); err != nil { log.Error().Err(err).Msg("error unarchiving beneficiary") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/beneficiaries/%s", beneficiaryID), http.StatusFound) } } func (h *Handler) BeneficiaryPictureHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) beneficiaryID := vars["beneficiaryid"] imageData, contentType, err := h.applicationHandler.GetBeneficiaryPicture(r.Context(), beneficiaryID) if err != nil { log.Error().Err(err).Msg("error generating beneficiary picture") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } w.Header().Set("Content-Type", contentType) w.Header().Set("Content-Length", strconv.Itoa(len(imageData))) if _, err := w.Write(imageData); err != nil { log.Error().Err(err).Msg("unable to write image") } } } func (h *Handler) BeneficiaryDocumentsHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) beneficiaryID := vars["beneficiaryid"] 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.AddBeneficiaryDocument(r.Context(), beneficiaryID, file, header.Filename, header.Size, documentType, documentName); err != nil { log.Error().Err(err).Msg("error adding beneficiary document") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/beneficiaries/%s", beneficiaryID), http.StatusFound) } } func (h *Handler) BeneficiaryDocumentDownloadHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) beneficiaryID := vars["beneficiaryid"] document := vars["document"] file, info, err := h.applicationHandler.GetBeneficiaryDocument(r.Context(), beneficiaryID, document) if err != nil { log.Error().Err(err).Msg("error retrieving beneficiary 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 } } } func (h *Handler) BeneficiaryDocumentDeleteHTTPHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) beneficiaryID := vars["beneficiaryid"] document := vars["document"] if err := h.applicationHandler.DeleteBeneficiaryDocument(r.Context(), beneficiaryID, document); err != nil { log.Error().Err(err).Msg("error deleting beneficiary document") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/beneficiaries/%s", beneficiaryID), http.StatusFound) } }