Fix: add persisted project folder deletion

This commit is contained in:
MangoPig
2026-06-24 16:15:30 +01:00
parent 0b368b09fa
commit c64a7b8d44
6 changed files with 292 additions and 33 deletions
+80 -8
View File
@@ -17,6 +17,10 @@ type createProjectFolderRequest struct {
ParentFolderID string `json:"parentFolderId"`
}
type deleteProjectFolderRequest struct {
FolderID string `json:"folderId"`
}
func (routes apiRoutes) handleProjectFolders(w http.ResponseWriter, r *http.Request) {
projectID := strings.TrimSpace(chi.URLParam(r, "projectId"))
if projectID == "" {
@@ -26,7 +30,7 @@ func (routes apiRoutes) handleProjectFolders(w http.ResponseWriter, r *http.Requ
folders, err := routes.bootstrapService().GetProjectHierarchyFolders(r.Context(), projectID)
if err != nil {
routes.writeProjectFolderError(w, r, err)
routes.writeProjectFolderError(w, r, err, "load")
return
}
@@ -66,7 +70,7 @@ func (routes apiRoutes) handleCreateProjectFolder(w http.ResponseWriter, r *http
Name: payload.Name,
})
if err != nil {
routes.writeProjectFolderError(w, r, err)
routes.writeProjectFolderError(w, r, err, "persist")
return
}
@@ -79,6 +83,37 @@ func (routes apiRoutes) handleCreateProjectFolder(w http.ResponseWriter, r *http
})
}
func (routes apiRoutes) handleDeleteProjectFolder(w http.ResponseWriter, r *http.Request) {
projectID := strings.TrimSpace(chi.URLParam(r, "projectId"))
if projectID == "" {
WriteError(w, http.StatusBadRequest, RequestIDFromContext(r.Context()), "invalid_request", "Project ID is required.")
return
}
payload := decodeDeleteProjectFolderRequest(r)
if strings.TrimSpace(payload.FolderID) == "" {
WriteError(w, http.StatusBadRequest, RequestIDFromContext(r.Context()), "invalid_request", "Folder ID is required.")
return
}
result, err := routes.bootstrapService().DeleteProjectFolder(r.Context(), bootstrapservice.DeleteProjectFolderInput{
ProjectID: projectID,
FolderID: payload.FolderID,
})
if err != nil {
routes.writeProjectFolderError(w, r, err, "delete")
return
}
WriteJSON(w, http.StatusOK, map[string]any{
"data": result,
"meta": map[string]any{
"resource": "project-folder-delete",
"persisted": true,
},
})
}
func (routes apiRoutes) handleProjectTreeFolders(w http.ResponseWriter, r *http.Request) {
projectID := strings.TrimSpace(chi.URLParam(r, "projectId"))
if projectID == "" {
@@ -88,7 +123,7 @@ func (routes apiRoutes) handleProjectTreeFolders(w http.ResponseWriter, r *http.
folders, err := routes.bootstrapService().GetProjectTreeFolders(r.Context(), projectID)
if err != nil {
routes.writeProjectFolderError(w, r, err)
routes.writeProjectFolderError(w, r, err, "load")
return
}
@@ -128,7 +163,7 @@ func (routes apiRoutes) handleCreateProjectTreeFolder(w http.ResponseWriter, r *
Name: payload.Name,
})
if err != nil {
routes.writeProjectFolderError(w, r, err)
routes.writeProjectFolderError(w, r, err, "persist")
return
}
@@ -141,17 +176,54 @@ func (routes apiRoutes) handleCreateProjectTreeFolder(w http.ResponseWriter, r *
})
}
func (routes apiRoutes) writeProjectFolderError(w http.ResponseWriter, r *http.Request, err error) {
func (routes apiRoutes) handleDeleteProjectTreeFolder(w http.ResponseWriter, r *http.Request) {
projectID := strings.TrimSpace(chi.URLParam(r, "projectId"))
if projectID == "" {
WriteError(w, http.StatusBadRequest, RequestIDFromContext(r.Context()), "invalid_request", "Project ID is required.")
return
}
payload := decodeDeleteProjectFolderRequest(r)
if strings.TrimSpace(payload.FolderID) == "" {
WriteError(w, http.StatusBadRequest, RequestIDFromContext(r.Context()), "invalid_request", "Folder ID is required.")
return
}
result, err := routes.bootstrapService().DeleteProjectTreeFolder(r.Context(), bootstrapservice.DeleteProjectFolderInput{
ProjectID: projectID,
FolderID: payload.FolderID,
})
if err != nil {
routes.writeProjectFolderError(w, r, err, "delete")
return
}
WriteJSON(w, http.StatusOK, map[string]any{
"data": result,
"meta": map[string]any{
"resource": "project-tree-folder-delete",
"persisted": true,
},
})
}
func (routes apiRoutes) writeProjectFolderError(w http.ResponseWriter, r *http.Request, err error, operation string) {
switch {
case errors.Is(err, bootstrapservice.ErrProjectNotFound), errors.Is(err, bootstrapservice.ErrProjectFolderNotFound):
WriteError(w, http.StatusNotFound, RequestIDFromContext(r.Context()), "not_found", err.Error())
default:
routes.cfg.Logger.Error("persist project folder", "error", err, "path", r.URL.Path)
message := "Failed to persist project folder."
routes.cfg.Logger.Error(operation+" project folder", "error", err, "path", r.URL.Path)
message := "Failed to " + operation + " project folder."
if routes.cfg.Config.IsDevelopment() {
message = message + " " + err.Error()
}
WriteError(w, http.StatusInternalServerError, RequestIDFromContext(r.Context()), "project_folder_persist_failed", message)
WriteError(w, http.StatusInternalServerError, RequestIDFromContext(r.Context()), "project_folder_"+operation+"_failed", message)
}
}
func decodeDeleteProjectFolderRequest(r *http.Request) deleteProjectFolderRequest {
return deleteProjectFolderRequest{
FolderID: strings.TrimSpace(r.URL.Query().Get("folderId")),
}
}
+2
View File
@@ -36,8 +36,10 @@ func (routes apiRoutes) Register(router chi.Router) {
apiRouter.Route("/projects/{projectId}", func(projectRouter chi.Router) {
projectRouter.Get("/folders", routes.handleProjectFolders)
projectRouter.Post("/folders", routes.handleCreateProjectFolder)
projectRouter.Delete("/folders", routes.handleDeleteProjectFolder)
projectRouter.Get("/tree/folders", routes.handleProjectTreeFolders)
projectRouter.Post("/tree/folders", routes.handleCreateProjectTreeFolder)
projectRouter.Delete("/tree/folders", routes.handleDeleteProjectTreeFolder)
})
if routes.cfg.Config.IsDevelopment() {