From 80e031d6c97f39e6237e6e6434b676dae659a2c3 Mon Sep 17 00:00:00 2001 From: bagas Date: Sun, 1 Mar 2026 20:58:05 +0700 Subject: [PATCH] update: allow deleting form with responses, block editing form with responses --- .../migrations/000003_init_responses.up.sql | 2 +- internal/handler/form.go | 30 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/internal/db/sqlc/migrations/000003_init_responses.up.sql b/internal/db/sqlc/migrations/000003_init_responses.up.sql index 3e5965d..026b72f 100644 --- a/internal/db/sqlc/migrations/000003_init_responses.up.sql +++ b/internal/db/sqlc/migrations/000003_init_responses.up.sql @@ -2,7 +2,7 @@ BEGIN; CREATE TABLE form_responses ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - form_id UUID NOT NULL REFERENCES forms(id) ON DELETE RESTRICT, + form_id UUID NOT NULL REFERENCES forms(id) ON DELETE CASCADE, user_id UUID REFERENCES users(id) ON DELETE SET NULL, submitted_at TIMESTAMPTZ NOT NULL DEFAULT now() ); diff --git a/internal/handler/form.go b/internal/handler/form.go index 160ffab..bdd5a18 100644 --- a/internal/handler/form.go +++ b/internal/handler/form.go @@ -354,7 +354,7 @@ func (h *Handler) FormGet(w http.ResponseWriter, r *http.Request) { // FormPut updates an existing form // // @Summary Update a form -// @Description Replace a form's title, description, and questions. Only the form owner can update it +// @Description Replace a form's title, description, and questions. Only the form owner can update it. Editing is blocked if the form already has responses // @Tags forms // @Accept json // @Produce json @@ -366,6 +366,7 @@ func (h *Handler) FormGet(w http.ResponseWriter, r *http.Request) { // @Failure 401 {string} string "Unauthorized" // @Failure 403 {string} string "Forbidden (not the form owner)" // @Failure 404 {string} string "Form not found" +// @Failure 409 {string} string "Conflict (form already has responses)" // @Failure 500 {string} string "Internal server error" // @Router /api/form/{id} [put] func (h *Handler) FormPut(w http.ResponseWriter, r *http.Request) { @@ -410,6 +411,18 @@ func (h *Handler) FormPut(w http.ResponseWriter, r *http.Request) { return } + hasResponses, err := h.repository.FormHasResponses(ctx, formID) + if err != nil { + internalServerError(w, err) + log.Printf("failed to check responses: %s", err) + return + } + if hasResponses { + w.WriteHeader(http.StatusConflict) + _, _ = w.Write([]byte("form already has responses and cannot be edited")) + return + } + updated, err := h.repository.UpdateForm(ctx, repository.UpdateFormParams{ ID: formID, Title: req.Title, @@ -450,7 +463,7 @@ func (h *Handler) FormPut(w http.ResponseWriter, r *http.Request) { // FormDelete deletes a form // // @Summary Delete a form -// @Description Delete a form by ID. Only the form owner can delete it. Deletion is blocked if the form already has responses +// @Description Delete a form by ID. Only the form owner can delete it // @Tags forms // @Produce json // @Security BearerAuth @@ -460,7 +473,6 @@ func (h *Handler) FormPut(w http.ResponseWriter, r *http.Request) { // @Failure 401 {string} string "Unauthorized" // @Failure 403 {string} string "Forbidden (not the form owner)" // @Failure 404 {string} string "Form not found" -// @Failure 409 {string} string "Conflict (form already has responses)" // @Failure 500 {string} string "Internal server error" // @Router /api/form/{id} [delete] func (h *Handler) FormDelete(w http.ResponseWriter, r *http.Request) { @@ -494,18 +506,6 @@ func (h *Handler) FormDelete(w http.ResponseWriter, r *http.Request) { return } - hasResponses, err := h.repository.FormHasResponses(ctx, formID) - if err != nil { - internalServerError(w, err) - log.Printf("failed to check responses: %s", err) - return - } - if hasResponses { - w.WriteHeader(http.StatusConflict) - _, _ = w.Write([]byte("form already has responses and cannot be deleted")) - return - } - if err := h.repository.DeleteForm(ctx, formID); err != nil { internalServerError(w, err) log.Printf("failed to delete form: %s", err)