mirror of
https://github.com/warmbly/warmbly.git
synced 2026-09-13 08:05:05 +00:00
158 lines
3.7 KiB
Go
158 lines
3.7 KiB
Go
package grouph
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
"github.com/warmbly/warmbly/internal/api/middleware"
|
|
"github.com/warmbly/warmbly/internal/errx"
|
|
"github.com/warmbly/warmbly/internal/models"
|
|
)
|
|
|
|
func GetGroupID(c *gin.Context) string {
|
|
return c.Param("gid")
|
|
}
|
|
|
|
// scope resolves the workspace every group call is keyed on, plus the group id
|
|
// on the path for the routes that carry one. Labels belong to the organization,
|
|
// not to whoever created them, so a request without one is refused rather than
|
|
// run against a single member's rows.
|
|
func scope(c *gin.Context, withID bool) (uuid.UUID, uuid.UUID, bool) {
|
|
orgID := middleware.GetOrganizationID(c)
|
|
if orgID == nil {
|
|
errx.Handle(c, errx.ErrNoOrganization)
|
|
return uuid.Nil, uuid.Nil, false
|
|
}
|
|
if !withID {
|
|
return *orgID, uuid.Nil, true
|
|
}
|
|
gid, err := uuid.Parse(GetGroupID(c))
|
|
if err != nil {
|
|
errx.Handle(c, errx.ErrUuid)
|
|
return uuid.Nil, uuid.Nil, false
|
|
}
|
|
return *orgID, gid, true
|
|
}
|
|
|
|
// entityType maps the group's name ("folders"/"tags"/"categories") to the
|
|
// matching audit entity type.
|
|
func (h *Handler) entityType() models.AuditEntityType {
|
|
switch h.name {
|
|
case "tags":
|
|
return models.AuditEntityTag
|
|
case "categories":
|
|
return models.AuditEntityCategory
|
|
default:
|
|
return models.AuditEntityFolder
|
|
}
|
|
}
|
|
|
|
// logAudit records a group mutation in the organization-wide audit trail. It
|
|
// pulls actor/org/IP/user-agent from the gin context; no-op without org context.
|
|
func (h *Handler) logAudit(c *gin.Context, action models.AuditAction, entityID *uuid.UUID, metadata map[string]string) {
|
|
if h.audit == nil {
|
|
return
|
|
}
|
|
orgID := middleware.GetOrganizationID(c)
|
|
if orgID == nil {
|
|
return
|
|
}
|
|
actorID, err := middleware.GetUserUUID(c)
|
|
if err != nil {
|
|
return
|
|
}
|
|
h.audit.LogAction(c.Request.Context(), *orgID, actorID, action, h.entityType(), entityID, c.ClientIP(), c.Request.UserAgent(), nil, metadata)
|
|
}
|
|
|
|
func (h *Handler) Create(c *gin.Context) {
|
|
orgID, _, ok := scope(c, false)
|
|
if !ok {
|
|
return
|
|
}
|
|
// Attribution only; an API key has no human behind it, so a failed parse
|
|
// records a nil creator rather than refusing the write.
|
|
uid, _ := middleware.GetUserUUID(c)
|
|
|
|
var data models.GroupCreate
|
|
|
|
if err := c.ShouldBindJSON(&data); err != nil {
|
|
errx.Handle(c, errx.ErrInvalid)
|
|
return
|
|
}
|
|
|
|
group, xerr := h.service.Create(c.Request.Context(), orgID, uid, &data)
|
|
if xerr != nil {
|
|
errx.Handle(c, xerr)
|
|
return
|
|
}
|
|
|
|
h.logAudit(c, models.AuditActionCreate, &group.ID, map[string]string{"title": group.Title})
|
|
|
|
c.JSON(http.StatusOK, group)
|
|
}
|
|
|
|
func (h *Handler) Update(c *gin.Context) {
|
|
orgID, gid, ok := scope(c, true)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
var data models.GroupUpdate
|
|
|
|
if err := c.ShouldBindJSON(&data); err != nil {
|
|
errx.Handle(c, errx.ErrInvalid)
|
|
return
|
|
}
|
|
|
|
group, xerr := h.service.Update(c.Request.Context(), orgID, gid, &data)
|
|
if xerr != nil {
|
|
errx.Handle(c, xerr)
|
|
return
|
|
}
|
|
|
|
h.logAudit(c, models.AuditActionUpdate, &gid, map[string]string{"title": group.Title})
|
|
|
|
c.JSON(http.StatusOK, group)
|
|
}
|
|
|
|
func (h *Handler) Move(c *gin.Context) {
|
|
orgID, gid, ok := scope(c, true)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
var data models.Move
|
|
|
|
if err := c.ShouldBindJSON(&data); err != nil {
|
|
errx.Handle(c, errx.ErrInvalid)
|
|
return
|
|
}
|
|
|
|
orders, xerr := h.service.Move(c.Request.Context(), orgID, gid, data.Position)
|
|
if xerr != nil {
|
|
errx.Handle(c, xerr)
|
|
return
|
|
}
|
|
|
|
h.logAudit(c, models.AuditActionUpdate, &gid, map[string]string{"moved": "true"})
|
|
|
|
c.JSON(http.StatusOK, orders)
|
|
}
|
|
|
|
func (h *Handler) Delete(c *gin.Context) {
|
|
orgID, gid, ok := scope(c, true)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
if xerr := h.service.Delete(c.Request.Context(), orgID, gid); xerr != nil {
|
|
errx.Handle(c, xerr)
|
|
return
|
|
}
|
|
|
|
h.logAudit(c, models.AuditActionDelete, &gid, nil)
|
|
|
|
c.Status(http.StatusNoContent)
|
|
}
|