package application import ( "context" "encoding/json" "errors" "fmt" "io" // "io" "net/http" // "strconv" "strings" "time" "git.coopgo.io/coopgo-apps/parcoursmob/services" "git.coopgo.io/coopgo-apps/parcoursmob/utils/identification" filestorage "git.coopgo.io/coopgo-apps/parcoursmob/utils/storage" // filestorage "git.coopgo.io/coopgo-apps/parcoursmob/utils/storage" diags "git.coopgo.io/coopgo-platform/diags/grpcapi" diagsstorage "git.coopgo.io/coopgo-platform/diags/storage" // groupsmanagement "git.coopgo.io/coopgo-platform/groups-management/grpcapi" // "git.coopgo.io/coopgo-platform/groups-management/storage" // mobilityaccounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi" // "github.com/google/uuid" "github.com/google/uuid" "github.com/gorilla/mux" "github.com/rs/zerolog/log" "google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/timestamppb" ) type DiagsForm struct { Name string `json:"name" validate:"required"` Namespace string `json:"namespace" validate:"required"` JsonSchema string `json:"json_schema"` UiSchema string `json:"ui_schema"` Data map[string]any `json:"data"` Deleted bool `json:"deleted"` Diagdate *time.Time `json:"diagdate"` } func (h *ApplicationHandler) DiagsHome(w http.ResponseWriter, r *http.Request) { resp, err := h.services.GRPC.Diags.GetDiags(context.TODO(), &diags.GetDiagsRequest{ Namespaces: []string{"parcoursmob_beneficiaries", "parcoursmob_diagnostiques", "parcoursmob_vehicles", "parcoursmob_bookings"}, }) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } responses := []diagsstorage.Diag{} for _, e := range resp.Diags { responses = append(responses, e.ToStorageType()) } h.Renderer.DiagsHome(w, r, responses) } func (h *ApplicationHandler) DiagsHistory(w http.ResponseWriter, r *http.Request) { resp, err := h.services.GRPC.Diags.GetDiags(context.TODO(), &diags.GetDiagsRequest{ Namespaces: []string{"parcoursmob_beneficiaries", "parcoursmob_diagnostiques", "parcoursmob_vehicles", "parcoursmob_bookings"}, }) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } responses := []diagsstorage.Diag{} for _, e := range resp.Diags { if e.Deleted { responses = append(responses, e.ToStorageType()) } } h.Renderer.DiagsHistory(w, r, responses) } func (h *ApplicationHandler) BeneficiariesCreateDiag(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) beneficiaryID := vars["beneficiaryid"] if h.services == nil || (h.services.GRPC == services.GRPCServices{}) || h.services.GRPC.Diags == nil { log.Error().Msg("Diags service is not initialized") http.Error(w, "Internal server error", http.StatusInternalServerError) return } if r.Method == http.MethodPost { g := r.Context().Value(identification.GroupKey) if g == nil { http.Error(w, "Missing group information", http.StatusBadRequest) return } diagForm, err := parseDiagsForm(r) if err != nil { log.Error().Err(err).Msg("Invalid form data") http.Error(w, err.Error(), http.StatusBadRequest) return } log.Debug().Interface("diagForm", diagForm).Msg("Form data parsed") data, err := structpb.NewStruct(map[string]any{ "beneficiary": beneficiaryID, }) if err != nil { log.Error().Err(err).Msg("Failed to create protobuf struct") w.WriteHeader(http.StatusInternalServerError) return } request := &diags.CreateDiagRequest{ Diag: &diags.Diag{ Name: diagForm.Name, Namespace: diagForm.Namespace, JsonSchema: diagForm.JsonSchema, UiSchema: diagForm.UiSchema, Data: data, Deleted: diagForm.Deleted, Diagdate: timestamppb.New(time.Now()), }, } resp, err := h.services.GRPC.Diags.CreateDiag(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("Failed to create diagnostic") w.WriteHeader(http.StatusInternalServerError) return } 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") w.WriteHeader(http.StatusBadRequest) return } file, header, err := r.FormFile("file-upload") if err == nil { defer file.Close() document_type := r.FormValue("file_type") document_name := r.FormValue("file_name") fileid := uuid.NewString() metadata := map[string]string{ "file_type": document_type, "file_name": document_name, } if err := h.filestorage.Put(file, filestorage.PREFIX_DIAGS, fmt.Sprintf("%s/%s_%s", resp.Diag.Id, fileid, header.Filename), header.Size, metadata); err != nil { log.Error().Err(err).Msg("Error uploading file") w.WriteHeader(http.StatusInternalServerError) return } } else if err != http.ErrMissingFile { log.Error().Err(err).Msg("Error retrieving file") w.WriteHeader(http.StatusInternalServerError) return } } http.Redirect(w, r, fmt.Sprintf("/app/diags/%s", resp.Diag.Id), http.StatusFound) return } h.Renderer.BeneficiariesCreateDiag(w, r, beneficiaryID, h.config.GetStringSlice("modules.diags.documents_types"), h.config.GetStringMapString("storage.files.file_types"), nil) } func (h *ApplicationHandler) VehiclesCreateDiag(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) vehicleID := vars["vehicleid"] if h.services == nil || (h.services.GRPC == services.GRPCServices{}) || h.services.GRPC.Diags == nil { log.Error().Msg("Diags service is not initialized") http.Error(w, "Internal server error", http.StatusInternalServerError) return } if r.Method == http.MethodPost { g := r.Context().Value(identification.GroupKey) if g == nil { http.Error(w, "Missing group information", http.StatusBadRequest) return } diagForm, err := parseDiagsForm(r) if err != nil { log.Error().Err(err).Msg("Invalid form data") http.Error(w, err.Error(), http.StatusBadRequest) return } log.Debug().Interface("diagForm", diagForm).Msg("Form data parsed") data, err := structpb.NewStruct(map[string]any{ "vehicle": vehicleID, }) if err != nil { log.Error().Err(err).Msg("Failed to create protobuf struct") w.WriteHeader(http.StatusInternalServerError) return } request := &diags.CreateDiagRequest{ Diag: &diags.Diag{ Name: diagForm.Name, Namespace: diagForm.Namespace, JsonSchema: diagForm.JsonSchema, UiSchema: diagForm.UiSchema, Data: data, Deleted: diagForm.Deleted, Diagdate: timestamppb.New(time.Now()), }, } resp, err := h.services.GRPC.Diags.CreateDiag(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("Failed to create diagnostic") w.WriteHeader(http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/diags/%s", resp.Diag.Id), http.StatusFound) return } h.Renderer.VehiclesCreateDiag(w, r, vehicleID) } func (h *ApplicationHandler) BookingsCreateDiag(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) bookingID := vars["bookingid"] if h.services == nil || (h.services.GRPC == services.GRPCServices{}) || h.services.GRPC.Diags == nil { log.Error().Msg("Diags service is not initialized") http.Error(w, "Internal server error", http.StatusInternalServerError) return } if r.Method == http.MethodPost { g := r.Context().Value(identification.GroupKey) if g == nil { http.Error(w, "Missing group information", http.StatusBadRequest) return } diagForm, err := parseDiagsForm(r) if err != nil { log.Error().Err(err).Msg("Invalid form data") http.Error(w, err.Error(), http.StatusBadRequest) return } log.Debug().Interface("diagForm", diagForm).Msg("Form data parsed") data, err := structpb.NewStruct(map[string]any{ "booking": bookingID, }) if err != nil { log.Error().Err(err).Msg("Failed to create protobuf struct") w.WriteHeader(http.StatusInternalServerError) return } request := &diags.CreateDiagRequest{ Diag: &diags.Diag{ Name: diagForm.Name, Namespace: diagForm.Namespace, JsonSchema: diagForm.JsonSchema, UiSchema: diagForm.UiSchema, Data: data, Deleted: diagForm.Deleted, Diagdate: timestamppb.New(time.Now()), }, } resp, err := h.services.GRPC.Diags.CreateDiag(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("Failed to create diagnostic") w.WriteHeader(http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/diags/%s", resp.Diag.Id), http.StatusFound) return } h.Renderer.BookingsCreateDiag(w, r, bookingID) } func (h *ApplicationHandler) VehicleBookingsCreateDiag(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) bookingID := vars["bookingid"] if h.services == nil || (h.services.GRPC == services.GRPCServices{}) || h.services.GRPC.Diags == nil { log.Error().Msg("Diags service is not initialized") http.Error(w, "Internal server error", http.StatusInternalServerError) return } if r.Method == http.MethodPost { g := r.Context().Value(identification.GroupKey) if g == nil { http.Error(w, "Missing group information", http.StatusBadRequest) return } diagForm, err := parseDiagsForm(r) if err != nil { log.Error().Err(err).Msg("Invalid form data") http.Error(w, err.Error(), http.StatusBadRequest) return } log.Debug().Interface("diagForm", diagForm).Msg("Form data parsed") data, err := structpb.NewStruct(map[string]any{ "booking": bookingID, }) if err != nil { log.Error().Err(err).Msg("Failed to create protobuf struct") w.WriteHeader(http.StatusInternalServerError) return } request := &diags.CreateDiagRequest{ Diag: &diags.Diag{ Name: diagForm.Name, Namespace: diagForm.Namespace, JsonSchema: diagForm.JsonSchema, UiSchema: diagForm.UiSchema, Data: data, Deleted: diagForm.Deleted, Diagdate: timestamppb.New(time.Now()), }, } resp, err := h.services.GRPC.Diags.CreateDiag(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("Failed to create diagnostic") w.WriteHeader(http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/diags/%s", resp.Diag.Id), http.StatusFound) return } h.Renderer.VehicleBookingsCreateDiag(w, r, bookingID) } func (h *ApplicationHandler) DiagsDisplayDiag(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) diagid := vars["diagid"] request := &diags.GetDiagRequest{ Id: diagid, } resp, err := h.services.GRPC.Diags.GetDiag(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } g := r.Context().Value(identification.GroupKey) if g == nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } documents := h.filestorage.List(filestorage.PREFIX_DIAGS + "/" + diagid) events_file_types := h.config.GetStringSlice("modules.diags.documents_types") file_types_map := h.config.GetStringMapString("storage.files.file_types") h.Renderer.DiagsDisplayDiag(w, r, resp.Diag.ToStorageType(), events_file_types, file_types_map, documents) } func parseDiagsForm(r *http.Request) (*DiagsForm, error) { if err := r.ParseForm(); err != nil { return nil, err } formData := &DiagsForm{ Name: r.PostFormValue("name"), Namespace: r.PostFormValue("namespace"), // Récupère le namespace JsonSchema: r.PostFormValue("json_schema"), UiSchema: r.PostFormValue("ui_schema"), Deleted: false, } if formData.Name == "" || formData.Namespace == "" { return nil, errors.New("missing required fields: 'name' or 'namespace'") } // Gestion de la valeur JSON dans `data` if rawData := r.PostFormValue("data"); rawData != "" { data := map[string]any{} if err := json.Unmarshal([]byte(rawData), &data); err != nil { return nil, errors.New("invalid 'data' field: must be a valid JSON object") } formData.Data = data } return formData, nil } func (h *ApplicationHandler) DiagUpdate(w http.ResponseWriter, r *http.Request) { adm := strings.Split(r.URL.Path, "/") diagID := adm[3] request := &diags.GetDiagRequest{ Id: diagID, } resp, err := h.services.GRPC.Diags.GetDiag(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } if r.Method == "POST" { g := r.Context().Value(identification.GroupKey) if g == nil { w.WriteHeader(http.StatusBadRequest) return } diagForm, err := parseDiagsForm(r) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusBadRequest) return } data, _ := structpb.NewStruct(map[string]any{}) request := &diags.UpdateDiagRequest{ Diag: &diags.Diag{ Namespace: diagForm.Namespace, Id: diagID, Name: diagForm.Name, JsonSchema: diagForm.JsonSchema, UiSchema: diagForm.UiSchema, Data: data, Diagdate: timestamppb.New(time.Now()), }, } resp, err := h.services.GRPC.Diags.UpdateDiag(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/diags/%s", resp.Diag.Id), http.StatusFound) return } h.Renderer.DiagUpdate(w, r, resp.Diag.ToStorageType()) } func (h *ApplicationHandler) DiagDelete(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) diagID := vars["diagid"] request := &diags.GetDiagRequest{ Id: diagID, } resp, err := h.services.GRPC.Diags.GetDiag(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } if r.Method == "POST" { request := &diags.UpdateDiagRequest{ Diag: &diags.Diag{ Namespace: resp.Diag.Namespace, Id: resp.Diag.Id, Name: resp.Diag.Name, JsonSchema: resp.Diag.JsonSchema, UiSchema: resp.Diag.UiSchema, Data: resp.Diag.Data, Deleted: true, Diagdate: resp.Diag.Diagdate, }, } _, err := h.services.GRPC.Diags.UpdateDiag(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } http.Redirect(w, r, "/app/diags/", http.StatusFound) return } h.Renderer.DiagDelete(w, r, resp.Diag.ToStorageType()) } func (h *ApplicationHandler) DiagsHistoryDiag(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) diagId := vars["diagid"] request := &diags.GetDiagRequest{ Id: diagId, } resp, err := h.services.GRPC.Diags.GetDiag(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } h.Renderer.DiagsHistoryDiag(w, r, resp.Diag.ToStorageType()) } // //// ADD DOCUMENTS ////// func (h *ApplicationHandler) DiagsDocuments(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) diagID := vars["diagid"] //r.ParseForm() r.ParseMultipartForm(100 * 1024 * 1024) document_type := r.FormValue("type") document_name := r.FormValue("name") file, header, err := r.FormFile("file-upload") if err != nil { log.Error().Err(err).Msg("") return } defer file.Close() fileid := uuid.NewString() metadata := map[string]string{ "type": document_type, "name": document_name, } if err := h.filestorage.Put(file, filestorage.PREFIX_DIAGS, fmt.Sprintf("%s/%s_%s", diagID, fileid, header.Filename), header.Size, metadata); err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/diags/%s", diagID), http.StatusFound) } func (h *ApplicationHandler) DiagsDocumentDownload(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) diagID := vars["diagid"] document := vars["document"] file, info, err := h.filestorage.Get(filestorage.PREFIX_DIAGS, fmt.Sprintf("%s/%s", diagID, document)) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } w.Header().Set("Content-Type", info.ContentType) if _, err = io.Copy(w, file); err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/diags/%s", diagID), http.StatusFound) }