// Package queryapi: Milestone 3 handler for // POST /super-admin/documents/{id}/reset-metadata. // // This file is the M3-owned partition (see tracking ยง2.9). It must not // introduce new types into models.go or customschemas.go. package queryapi import ( "errors" "log/slog" "net/http" "queryorchestration/internal/cognitoauth" "queryorchestration/internal/customschema" "github.com/google/uuid" "github.com/labstack/echo/v4" "github.com/oapi-codegen/nullable" openapi_types "github.com/oapi-codegen/runtime/types" ) // ResetDocumentMetadata is POST /super-admin/documents/{id}/reset-metadata. // It wipes the document's custom metadata history and clears the schema // binding in a single atomic transaction. The operation is idempotent; // already-clean documents return 200 with metadataVersionsDeleted: 0. // Restricted to super_admin (enforced by Permit.io middleware upstream). func (s *Controllers) ResetDocumentMetadata(ctx echo.Context, id openapi_types.UUID) error { actor, ok := cognitoauth.GetUserSubject(ctx) if !ok { return echo.NewHTTPError(http.StatusUnauthorized, "missing user subject") } result, err := s.svc.CustomSchema.ResetDocumentMetadata(ctx.Request().Context(), uuid.UUID(id), actor) if err != nil { return mapResetError(err) } resp := DocumentMetadataResetResponse{ DocumentId: openapi_types.UUID(result.DocumentID), MetadataVersionsDeleted: int32(result.MetadataVersionsDeleted), //nolint:gosec // bounded by row count ResetAt: result.ResetAt, ResetBy: result.ResetBy, } if result.PreviousSchemaID != nil { resp.PreviousSchemaId = nullable.NewNullableWithValue(openapi_types.UUID(*result.PreviousSchemaID)) } else { resp.PreviousSchemaId = nullable.NewNullNullable[openapi_types.UUID]() } if result.PreviousSchemaName != nil { resp.PreviousSchemaName = nullable.NewNullableWithValue(*result.PreviousSchemaName) } else { resp.PreviousSchemaName = nullable.NewNullNullable[string]() } if result.PreviousSchemaVersion != nil { resp.PreviousSchemaVersion = nullable.NewNullableWithValue(int32(*result.PreviousSchemaVersion)) //nolint:gosec // schema version is a small counter } else { resp.PreviousSchemaVersion = nullable.NewNullNullable[int32]() } return ctx.JSON(http.StatusOK, resp) } // mapResetError converts reset-specific service sentinels to HTTP errors. // Errors not recognized here are treated as unexpected server failures. func mapResetError(err error) error { switch { case errors.Is(err, customschema.ErrDocumentNotFound): return echo.NewHTTPError(http.StatusNotFound, "document not found") case errors.Is(err, customschema.ErrMutualExclusivityViolation): return echo.NewHTTPError(http.StatusConflict, err.Error()) default: slog.Error("reset document metadata: unexpected error", "error", err) return echo.NewHTTPError(http.StatusInternalServerError, "internal server error") } }