mirror of
https://github.com/warmbly/warmbly.git
synced 2026-08-19 08:01:16 +00:00
e0ced97ba1
Move audit logs into org-scoped Postgres storage, wire audit events across backend handlers, and surface actor details in the dashboard activity log. Add realtime audit invalidation and retention pruning so the trail stays current and bounded.
150 lines
4.1 KiB
Go
150 lines
4.1 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/warmbly/warmbly/internal/api/middleware"
|
|
"github.com/warmbly/warmbly/internal/errx"
|
|
"github.com/warmbly/warmbly/internal/models"
|
|
)
|
|
|
|
// ---------- Organization danger zone ----------
|
|
|
|
// GetOrganizationDangerZone returns the danger-zone status (any pending
|
|
// deletion plus the confirmation phrase the client should display).
|
|
func (h *Handler) GetOrganizationDangerZone(c *gin.Context) {
|
|
orgID := middleware.GetOrganizationID(c)
|
|
if orgID == nil {
|
|
errx.JSON(c, errx.New(errx.BadRequest, "no organization selected"))
|
|
return
|
|
}
|
|
|
|
status, xerr := h.DangerZoneService.GetOrganizationStatus(c.Request.Context(), *orgID)
|
|
if xerr != nil {
|
|
errx.JSON(c, xerr)
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, status)
|
|
}
|
|
|
|
// ScheduleOrganizationDeletion schedules the current organization for a
|
|
// delayed hard delete. Owner-only and requires the user to type the org
|
|
// name as confirmation.
|
|
func (h *Handler) ScheduleOrganizationDeletion(c *gin.Context) {
|
|
userID, err := middleware.GetUserUUID(c)
|
|
if err != nil {
|
|
errx.JSON(c, errx.ErrUnauthorized)
|
|
return
|
|
}
|
|
orgID := middleware.GetOrganizationID(c)
|
|
if orgID == nil {
|
|
errx.JSON(c, errx.New(errx.BadRequest, "no organization selected"))
|
|
return
|
|
}
|
|
|
|
var req models.ScheduleDeletionRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
errx.JSON(c, errx.New(errx.BadRequest, "invalid request body"))
|
|
return
|
|
}
|
|
|
|
d, xerr := h.DangerZoneService.ScheduleOrganizationDeletion(c.Request.Context(), *orgID, userID, &req)
|
|
if xerr != nil {
|
|
errx.JSON(c, xerr)
|
|
return
|
|
}
|
|
|
|
h.auditOrg(c, models.AuditActionDelete, models.AuditEntityOrganization, orgID, nil, map[string]string{"scheduled": "true"})
|
|
|
|
c.JSON(http.StatusAccepted, d)
|
|
}
|
|
|
|
// CancelOrganizationDeletion cancels a pending org deletion.
|
|
func (h *Handler) CancelOrganizationDeletion(c *gin.Context) {
|
|
userID, err := middleware.GetUserUUID(c)
|
|
if err != nil {
|
|
errx.JSON(c, errx.ErrUnauthorized)
|
|
return
|
|
}
|
|
orgID := middleware.GetOrganizationID(c)
|
|
if orgID == nil {
|
|
errx.JSON(c, errx.New(errx.BadRequest, "no organization selected"))
|
|
return
|
|
}
|
|
|
|
var req models.CancelDeletionRequest
|
|
_ = c.ShouldBindJSON(&req) // body optional
|
|
|
|
if xerr := h.DangerZoneService.CancelOrganizationDeletion(c.Request.Context(), *orgID, userID, &req); xerr != nil {
|
|
errx.JSON(c, xerr)
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "deletion cancelled"})
|
|
}
|
|
|
|
// ---------- Account danger zone ----------
|
|
|
|
// GetAccountDangerZone returns the user's account danger-zone status.
|
|
func (h *Handler) GetAccountDangerZone(c *gin.Context) {
|
|
userID, err := middleware.GetUserUUID(c)
|
|
if err != nil {
|
|
errx.JSON(c, errx.ErrUnauthorized)
|
|
return
|
|
}
|
|
|
|
status, xerr := h.DangerZoneService.GetUserStatus(c.Request.Context(), userID)
|
|
if xerr != nil {
|
|
errx.JSON(c, xerr)
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, status)
|
|
}
|
|
|
|
// ScheduleAccountDeletion schedules the caller's own account for delayed
|
|
// hard delete. Requires the user to type their email as confirmation.
|
|
func (h *Handler) ScheduleAccountDeletion(c *gin.Context) {
|
|
userID, err := middleware.GetUserUUID(c)
|
|
if err != nil {
|
|
errx.JSON(c, errx.ErrUnauthorized)
|
|
return
|
|
}
|
|
|
|
var req models.ScheduleDeletionRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
errx.JSON(c, errx.New(errx.BadRequest, "invalid request body"))
|
|
return
|
|
}
|
|
|
|
d, xerr := h.DangerZoneService.ScheduleUserDeletion(c.Request.Context(), userID, &req)
|
|
if xerr != nil {
|
|
errx.JSON(c, xerr)
|
|
return
|
|
}
|
|
|
|
h.auditOrg(c, models.AuditActionDelete, models.AuditEntityUser, &userID, nil, map[string]string{"scheduled": "true"})
|
|
|
|
c.JSON(http.StatusAccepted, d)
|
|
}
|
|
|
|
// CancelAccountDeletion cancels a pending account deletion.
|
|
func (h *Handler) CancelAccountDeletion(c *gin.Context) {
|
|
userID, err := middleware.GetUserUUID(c)
|
|
if err != nil {
|
|
errx.JSON(c, errx.ErrUnauthorized)
|
|
return
|
|
}
|
|
|
|
var req models.CancelDeletionRequest
|
|
_ = c.ShouldBindJSON(&req)
|
|
|
|
if xerr := h.DangerZoneService.CancelUserDeletion(c.Request.Context(), userID, &req); xerr != nil {
|
|
errx.JSON(c, xerr)
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "deletion cancelled"})
|
|
}
|