121 lines
3.2 KiB
Go
121 lines
3.2 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
)
|
|
|
|
func (a *app) platformAdminMiddleware(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
claims, _ := r.Context().Value(userClaimsKey).(*accessClaims)
|
|
if claims == nil {
|
|
writeError(w, http.StatusUnauthorized, "no authenticated user")
|
|
return
|
|
}
|
|
if !hasAnyRole(claims, "admin", "platform_owner", "platform_admin") {
|
|
writeError(w, http.StatusForbidden, "platform admin role required")
|
|
return
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
func (a *app) listTenants(w http.ResponseWriter, r *http.Request) {
|
|
docs, err := a.list("tenants", Doc{}, Sort{{Key: "name", Value: 1}})
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, "failed to list tenants")
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, docs)
|
|
}
|
|
|
|
func (a *app) createTenant(w http.ResponseWriter, r *http.Request) {
|
|
var payload map[string]any
|
|
if err := decodeJSON(r, &payload); err != nil {
|
|
writeError(w, http.StatusBadRequest, "invalid payload")
|
|
return
|
|
}
|
|
name := strings.TrimSpace(anyToString(payload["name"]))
|
|
if name == "" {
|
|
writeError(w, http.StatusBadRequest, "name is required")
|
|
return
|
|
}
|
|
payload["name"] = name
|
|
if slug := strings.TrimSpace(anyToString(payload["slug"])); slug != "" {
|
|
payload["slug"] = slugify(slug)
|
|
} else {
|
|
payload["slug"] = slugify(name)
|
|
}
|
|
doc, err := a.create("tenants", Doc(payload))
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, "failed to create tenant")
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusCreated, doc)
|
|
}
|
|
|
|
func (a *app) getTenant(w http.ResponseWriter, r *http.Request) {
|
|
id := chi.URLParam(r, "id")
|
|
doc, err := a.getByID("tenants", id)
|
|
if err != nil {
|
|
if errors.Is(err, ErrNotFound) {
|
|
writeError(w, http.StatusNotFound, "tenant not found")
|
|
return
|
|
}
|
|
writeError(w, http.StatusInternalServerError, "failed to load tenant")
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, doc)
|
|
}
|
|
|
|
func (a *app) patchTenant(w http.ResponseWriter, r *http.Request) {
|
|
id := chi.URLParam(r, "id")
|
|
var patch map[string]any
|
|
if err := decodeJSON(r, &patch); err != nil {
|
|
writeError(w, http.StatusBadRequest, "invalid patch payload")
|
|
return
|
|
}
|
|
if rawName, ok := patch["name"]; ok {
|
|
name := strings.TrimSpace(anyToString(rawName))
|
|
if name == "" {
|
|
writeError(w, http.StatusBadRequest, "name cannot be empty")
|
|
return
|
|
}
|
|
patch["name"] = name
|
|
}
|
|
if rawSlug, ok := patch["slug"]; ok {
|
|
slug := strings.TrimSpace(anyToString(rawSlug))
|
|
if slug == "" {
|
|
delete(patch, "slug")
|
|
} else {
|
|
patch["slug"] = slugify(slug)
|
|
}
|
|
}
|
|
doc, err := a.patch("tenants", id, Doc(patch))
|
|
if err != nil {
|
|
if errors.Is(err, ErrNotFound) {
|
|
writeError(w, http.StatusNotFound, "tenant not found")
|
|
return
|
|
}
|
|
writeError(w, http.StatusInternalServerError, "failed to update tenant")
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, doc)
|
|
}
|
|
|
|
func (a *app) deleteTenant(w http.ResponseWriter, r *http.Request) {
|
|
id := chi.URLParam(r, "id")
|
|
if err := a.deleteByID("tenants", id); err != nil {
|
|
if errors.Is(err, ErrNotFound) {
|
|
writeError(w, http.StatusNotFound, "tenant not found")
|
|
return
|
|
}
|
|
writeError(w, http.StatusInternalServerError, "failed to delete tenant")
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|