FDN-01: repository & projektgerüst
Git-Repository für bestehenden archivdms-Code initialisiert, Branch-/Commit-Konvention (feature/<ticket>-<slug>-Branches, Ticket-Prefix in Commit-Nachricht) etabliert.
This commit is contained in:
@@ -0,0 +1,458 @@
|
||||
// Permission-model HTTP handlers (see internal/storage/permissions.go):
|
||||
//
|
||||
// POST/GET/DELETE /api/permission-groups
|
||||
// GET/POST/DELETE /api/permission-groups/{id}/members
|
||||
// GET/POST/DELETE /api/document-types/{id}/grants
|
||||
// GET/POST/DELETE /api/tags/{id}/grants
|
||||
// GET/POST/DELETE /api/documents/{id}/grants (access may be 'deny')
|
||||
//
|
||||
// Group and grant administration require domain_admin (s.authAdmin). Ownership
|
||||
// is enforced in the store layer (id + tenant_id). Every mutation is
|
||||
// audit-logged (EventPermissionGrantChanged), including failures.
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"archivdms/internal/audit"
|
||||
"archivdms/internal/storage"
|
||||
)
|
||||
|
||||
// logGrant records a permission mutation, success or failure.
|
||||
func (s *Server) logGrant(r *http.Request, tenantID *int64, username, detail string, ok bool) {
|
||||
s.audlog.Log(audit.Entry{
|
||||
EventType: audit.EventPermissionGrantChanged, Username: username, TenantID: tenantID,
|
||||
IPAddress: s.remoteIP(r), Success: ok, Detail: detail,
|
||||
})
|
||||
}
|
||||
|
||||
// grantStatus maps store errors to an HTTP status.
|
||||
func grantStatus(err error) int {
|
||||
switch {
|
||||
case errors.Is(err, storage.ErrPermissionGroupNotFound):
|
||||
return http.StatusNotFound
|
||||
case errors.Is(err, storage.ErrGrantNotFound):
|
||||
return http.StatusNotFound
|
||||
case errors.Is(err, storage.ErrDuplicatePermissionGroup):
|
||||
return http.StatusConflict
|
||||
default:
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
}
|
||||
|
||||
// --- permission groups ---
|
||||
|
||||
type permissionGroupRequest struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// handleListPermissionGroups handles GET /api/permission-groups.
|
||||
func (s *Server) handleListPermissionGroups(w http.ResponseWriter, r *http.Request) {
|
||||
sess := sessionFromCtx(r.Context())
|
||||
if sess.TenantID == nil {
|
||||
writeError(w, http.StatusForbidden, "tenant context required")
|
||||
return
|
||||
}
|
||||
groups, err := s.store.ListPermissionGroups(r.Context(), *sess.TenantID)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "list permission groups failed")
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, groups)
|
||||
}
|
||||
|
||||
// handleCreatePermissionGroup handles POST /api/permission-groups (domain_admin+).
|
||||
func (s *Server) handleCreatePermissionGroup(w http.ResponseWriter, r *http.Request) {
|
||||
sess := sessionFromCtx(r.Context())
|
||||
if sess.TenantID == nil {
|
||||
writeError(w, http.StatusForbidden, "tenant context required")
|
||||
return
|
||||
}
|
||||
var req permissionGroupRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid request body")
|
||||
return
|
||||
}
|
||||
if req.Name == "" {
|
||||
writeError(w, http.StatusBadRequest, "name is required")
|
||||
return
|
||||
}
|
||||
g, err := s.store.CreatePermissionGroup(r.Context(), *sess.TenantID, req.Name)
|
||||
if err != nil {
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "group_create name:"+req.Name+" err:"+err.Error(), false)
|
||||
writeError(w, grantStatus(err), "create permission group failed")
|
||||
return
|
||||
}
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "group_create id:"+strconv.FormatInt(g.ID, 10)+" name:"+g.Name, true)
|
||||
writeJSON(w, http.StatusCreated, g)
|
||||
}
|
||||
|
||||
// handleDeletePermissionGroup handles DELETE /api/permission-groups/{id} (domain_admin+).
|
||||
func (s *Server) handleDeletePermissionGroup(w http.ResponseWriter, r *http.Request) {
|
||||
sess := sessionFromCtx(r.Context())
|
||||
if sess.TenantID == nil {
|
||||
writeError(w, http.StatusForbidden, "tenant context required")
|
||||
return
|
||||
}
|
||||
id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid id")
|
||||
return
|
||||
}
|
||||
if err := s.store.DeletePermissionGroup(r.Context(), id, *sess.TenantID); err != nil {
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "group_delete id:"+strconv.FormatInt(id, 10)+" err:"+err.Error(), false)
|
||||
writeError(w, grantStatus(err), "delete permission group failed")
|
||||
return
|
||||
}
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "group_delete id:"+strconv.FormatInt(id, 10), true)
|
||||
writeJSON(w, http.StatusOK, map[string]string{"status": "deleted"})
|
||||
}
|
||||
|
||||
// --- group membership ---
|
||||
|
||||
type groupMemberRequest struct {
|
||||
UserID int64 `json:"user_id"`
|
||||
}
|
||||
|
||||
// handleAddGroupMember handles POST /api/permission-groups/{id}/members (domain_admin+).
|
||||
func (s *Server) handleAddGroupMember(w http.ResponseWriter, r *http.Request) {
|
||||
sess := sessionFromCtx(r.Context())
|
||||
if sess.TenantID == nil {
|
||||
writeError(w, http.StatusForbidden, "tenant context required")
|
||||
return
|
||||
}
|
||||
groupID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid group id")
|
||||
return
|
||||
}
|
||||
var req groupMemberRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid request body")
|
||||
return
|
||||
}
|
||||
if req.UserID == 0 {
|
||||
writeError(w, http.StatusBadRequest, "user_id is required")
|
||||
return
|
||||
}
|
||||
if err := s.store.AddGroupMember(r.Context(), groupID, req.UserID, *sess.TenantID); err != nil {
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "member_add group:"+strconv.FormatInt(groupID, 10)+" user:"+strconv.FormatInt(req.UserID, 10)+" err:"+err.Error(), false)
|
||||
writeError(w, grantStatus(err), "add group member failed")
|
||||
return
|
||||
}
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "member_add group:"+strconv.FormatInt(groupID, 10)+" user:"+strconv.FormatInt(req.UserID, 10), true)
|
||||
writeJSON(w, http.StatusOK, map[string]string{"status": "added"})
|
||||
}
|
||||
|
||||
// handleRemoveGroupMember handles DELETE /api/permission-groups/{id}/members/{userId} (domain_admin+).
|
||||
func (s *Server) handleRemoveGroupMember(w http.ResponseWriter, r *http.Request) {
|
||||
sess := sessionFromCtx(r.Context())
|
||||
if sess.TenantID == nil {
|
||||
writeError(w, http.StatusForbidden, "tenant context required")
|
||||
return
|
||||
}
|
||||
groupID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid group id")
|
||||
return
|
||||
}
|
||||
userID, err := strconv.ParseInt(r.PathValue("userId"), 10, 64)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid user id")
|
||||
return
|
||||
}
|
||||
if err := s.store.RemoveGroupMember(r.Context(), groupID, userID, *sess.TenantID); err != nil {
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "member_remove group:"+strconv.FormatInt(groupID, 10)+" user:"+strconv.FormatInt(userID, 10)+" err:"+err.Error(), false)
|
||||
writeError(w, grantStatus(err), "remove group member failed")
|
||||
return
|
||||
}
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "member_remove group:"+strconv.FormatInt(groupID, 10)+" user:"+strconv.FormatInt(userID, 10), true)
|
||||
writeJSON(w, http.StatusOK, map[string]string{"status": "removed"})
|
||||
}
|
||||
|
||||
// handleListGroupMembers handles GET /api/permission-groups/{id}/members (domain_admin+).
|
||||
func (s *Server) handleListGroupMembers(w http.ResponseWriter, r *http.Request) {
|
||||
sess := sessionFromCtx(r.Context())
|
||||
if sess.TenantID == nil {
|
||||
writeError(w, http.StatusForbidden, "tenant context required")
|
||||
return
|
||||
}
|
||||
groupID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid group id")
|
||||
return
|
||||
}
|
||||
members, err := s.store.ListGroupMembersDetailed(r.Context(), groupID, *sess.TenantID)
|
||||
if err != nil {
|
||||
writeError(w, grantStatus(err), "list group members failed")
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, members)
|
||||
}
|
||||
|
||||
// --- grants (document-type / tag / document) ---
|
||||
|
||||
type grantRequest struct {
|
||||
GroupID int64 `json:"group_id"`
|
||||
Access string `json:"access"`
|
||||
}
|
||||
|
||||
// handleSetDocumentTypeGrant handles POST /api/document-types/{id}/grants (domain_admin+).
|
||||
func (s *Server) handleSetDocumentTypeGrant(w http.ResponseWriter, r *http.Request) {
|
||||
sess := sessionFromCtx(r.Context())
|
||||
if sess.TenantID == nil {
|
||||
writeError(w, http.StatusForbidden, "tenant context required")
|
||||
return
|
||||
}
|
||||
docTypeID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid document type id")
|
||||
return
|
||||
}
|
||||
var req grantRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid request body")
|
||||
return
|
||||
}
|
||||
if req.Access == "" {
|
||||
req.Access = "read"
|
||||
}
|
||||
if err := s.store.SetDocumentTypeGrant(r.Context(), *sess.TenantID, docTypeID, req.GroupID, req.Access); err != nil {
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "type_grant_set type:"+strconv.FormatInt(docTypeID, 10)+" group:"+strconv.FormatInt(req.GroupID, 10)+" err:"+err.Error(), false)
|
||||
writeError(w, grantStatusValidated(err), "set document type grant failed")
|
||||
return
|
||||
}
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "type_grant_set type:"+strconv.FormatInt(docTypeID, 10)+" group:"+strconv.FormatInt(req.GroupID, 10)+" access:"+req.Access, true)
|
||||
writeJSON(w, http.StatusOK, map[string]string{"status": "granted"})
|
||||
}
|
||||
|
||||
// handleListDocumentTypeGrants handles GET /api/document-types/{id}/grants (domain_admin+).
|
||||
func (s *Server) handleListDocumentTypeGrants(w http.ResponseWriter, r *http.Request) {
|
||||
sess := sessionFromCtx(r.Context())
|
||||
if sess.TenantID == nil {
|
||||
writeError(w, http.StatusForbidden, "tenant context required")
|
||||
return
|
||||
}
|
||||
docTypeID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid document type id")
|
||||
return
|
||||
}
|
||||
grants, err := s.store.ListDocumentTypeGrants(r.Context(), *sess.TenantID, docTypeID)
|
||||
if err != nil {
|
||||
writeError(w, grantStatus(err), "list document type grants failed")
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, grants)
|
||||
}
|
||||
|
||||
// handleDeleteDocumentTypeGrant handles DELETE /api/document-types/{id}/grants (domain_admin+).
|
||||
func (s *Server) handleDeleteDocumentTypeGrant(w http.ResponseWriter, r *http.Request) {
|
||||
sess := sessionFromCtx(r.Context())
|
||||
if sess.TenantID == nil {
|
||||
writeError(w, http.StatusForbidden, "tenant context required")
|
||||
return
|
||||
}
|
||||
docTypeID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid document type id")
|
||||
return
|
||||
}
|
||||
groupID, err := grantGroupID(r)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "group_id is required")
|
||||
return
|
||||
}
|
||||
if err := s.store.DeleteDocumentTypeGrant(r.Context(), *sess.TenantID, docTypeID, groupID); err != nil {
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "type_grant_delete type:"+strconv.FormatInt(docTypeID, 10)+" group:"+strconv.FormatInt(groupID, 10)+" err:"+err.Error(), false)
|
||||
writeError(w, grantStatus(err), "delete document type grant failed")
|
||||
return
|
||||
}
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "type_grant_delete type:"+strconv.FormatInt(docTypeID, 10)+" group:"+strconv.FormatInt(groupID, 10), true)
|
||||
writeJSON(w, http.StatusOK, map[string]string{"status": "revoked"})
|
||||
}
|
||||
|
||||
// handleSetTagGrant handles POST /api/tags/{id}/grants (domain_admin+).
|
||||
func (s *Server) handleSetTagGrant(w http.ResponseWriter, r *http.Request) {
|
||||
sess := sessionFromCtx(r.Context())
|
||||
if sess.TenantID == nil {
|
||||
writeError(w, http.StatusForbidden, "tenant context required")
|
||||
return
|
||||
}
|
||||
tagID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid tag id")
|
||||
return
|
||||
}
|
||||
var req grantRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid request body")
|
||||
return
|
||||
}
|
||||
if req.Access == "" {
|
||||
req.Access = "read"
|
||||
}
|
||||
if err := s.store.SetTagGrant(r.Context(), *sess.TenantID, tagID, req.GroupID, req.Access); err != nil {
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "tag_grant_set tag:"+strconv.FormatInt(tagID, 10)+" group:"+strconv.FormatInt(req.GroupID, 10)+" err:"+err.Error(), false)
|
||||
writeError(w, grantStatusValidated(err), "set tag grant failed")
|
||||
return
|
||||
}
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "tag_grant_set tag:"+strconv.FormatInt(tagID, 10)+" group:"+strconv.FormatInt(req.GroupID, 10)+" access:"+req.Access, true)
|
||||
writeJSON(w, http.StatusOK, map[string]string{"status": "granted"})
|
||||
}
|
||||
|
||||
// handleListTagGrants handles GET /api/tags/{id}/grants (domain_admin+).
|
||||
func (s *Server) handleListTagGrants(w http.ResponseWriter, r *http.Request) {
|
||||
sess := sessionFromCtx(r.Context())
|
||||
if sess.TenantID == nil {
|
||||
writeError(w, http.StatusForbidden, "tenant context required")
|
||||
return
|
||||
}
|
||||
tagID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid tag id")
|
||||
return
|
||||
}
|
||||
grants, err := s.store.ListTagGrants(r.Context(), *sess.TenantID, tagID)
|
||||
if err != nil {
|
||||
writeError(w, grantStatus(err), "list tag grants failed")
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, grants)
|
||||
}
|
||||
|
||||
// handleDeleteTagGrant handles DELETE /api/tags/{id}/grants (domain_admin+).
|
||||
func (s *Server) handleDeleteTagGrant(w http.ResponseWriter, r *http.Request) {
|
||||
sess := sessionFromCtx(r.Context())
|
||||
if sess.TenantID == nil {
|
||||
writeError(w, http.StatusForbidden, "tenant context required")
|
||||
return
|
||||
}
|
||||
tagID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid tag id")
|
||||
return
|
||||
}
|
||||
groupID, err := grantGroupID(r)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "group_id is required")
|
||||
return
|
||||
}
|
||||
if err := s.store.DeleteTagGrant(r.Context(), *sess.TenantID, tagID, groupID); err != nil {
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "tag_grant_delete tag:"+strconv.FormatInt(tagID, 10)+" group:"+strconv.FormatInt(groupID, 10)+" err:"+err.Error(), false)
|
||||
writeError(w, grantStatus(err), "delete tag grant failed")
|
||||
return
|
||||
}
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "tag_grant_delete tag:"+strconv.FormatInt(tagID, 10)+" group:"+strconv.FormatInt(groupID, 10), true)
|
||||
writeJSON(w, http.StatusOK, map[string]string{"status": "revoked"})
|
||||
}
|
||||
|
||||
// handleSetDocumentGrant handles POST /api/documents/{id}/grants (domain_admin+).
|
||||
// access may be 'read', 'write' or 'deny'.
|
||||
func (s *Server) handleSetDocumentGrant(w http.ResponseWriter, r *http.Request) {
|
||||
sess := sessionFromCtx(r.Context())
|
||||
if sess.TenantID == nil {
|
||||
writeError(w, http.StatusForbidden, "tenant context required")
|
||||
return
|
||||
}
|
||||
docID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid document id")
|
||||
return
|
||||
}
|
||||
var req grantRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid request body")
|
||||
return
|
||||
}
|
||||
if req.Access == "" {
|
||||
writeError(w, http.StatusBadRequest, "access is required (read|write|deny)")
|
||||
return
|
||||
}
|
||||
if err := s.store.SetDocumentGrant(r.Context(), *sess.TenantID, docID, req.GroupID, sess.UserID, req.Access); err != nil {
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "doc_grant_set doc:"+strconv.FormatInt(docID, 10)+" group:"+strconv.FormatInt(req.GroupID, 10)+" err:"+err.Error(), false)
|
||||
writeError(w, grantStatusValidated(err), "set document grant failed")
|
||||
return
|
||||
}
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "doc_grant_set doc:"+strconv.FormatInt(docID, 10)+" group:"+strconv.FormatInt(req.GroupID, 10)+" access:"+req.Access, true)
|
||||
writeJSON(w, http.StatusOK, map[string]string{"status": "granted"})
|
||||
}
|
||||
|
||||
// handleListDocumentGrants handles GET /api/documents/{id}/grants (domain_admin+).
|
||||
// access may be 'read', 'write' or 'deny'.
|
||||
func (s *Server) handleListDocumentGrants(w http.ResponseWriter, r *http.Request) {
|
||||
sess := sessionFromCtx(r.Context())
|
||||
if sess.TenantID == nil {
|
||||
writeError(w, http.StatusForbidden, "tenant context required")
|
||||
return
|
||||
}
|
||||
docID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid document id")
|
||||
return
|
||||
}
|
||||
grants, err := s.store.ListDocumentGrants(r.Context(), *sess.TenantID, docID)
|
||||
if err != nil {
|
||||
writeError(w, grantStatus(err), "list document grants failed")
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, grants)
|
||||
}
|
||||
|
||||
// handleDeleteDocumentGrant handles DELETE /api/documents/{id}/grants (domain_admin+).
|
||||
func (s *Server) handleDeleteDocumentGrant(w http.ResponseWriter, r *http.Request) {
|
||||
sess := sessionFromCtx(r.Context())
|
||||
if sess.TenantID == nil {
|
||||
writeError(w, http.StatusForbidden, "tenant context required")
|
||||
return
|
||||
}
|
||||
docID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid document id")
|
||||
return
|
||||
}
|
||||
groupID, err := grantGroupID(r)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "group_id is required")
|
||||
return
|
||||
}
|
||||
if err := s.store.DeleteDocumentGrant(r.Context(), *sess.TenantID, docID, groupID); err != nil {
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "doc_grant_delete doc:"+strconv.FormatInt(docID, 10)+" group:"+strconv.FormatInt(groupID, 10)+" err:"+err.Error(), false)
|
||||
writeError(w, grantStatus(err), "delete document grant failed")
|
||||
return
|
||||
}
|
||||
s.logGrant(r, sess.TenantID, sess.Username, "doc_grant_delete doc:"+strconv.FormatInt(docID, 10)+" group:"+strconv.FormatInt(groupID, 10), true)
|
||||
writeJSON(w, http.StatusOK, map[string]string{"status": "revoked"})
|
||||
}
|
||||
|
||||
// grantGroupID resolves the target group for a grant DELETE, from either the
|
||||
// ?group_id query param or a JSON body {"group_id": N}.
|
||||
func grantGroupID(r *http.Request) (int64, error) {
|
||||
if q := r.URL.Query().Get("group_id"); q != "" {
|
||||
return strconv.ParseInt(q, 10, 64)
|
||||
}
|
||||
var req grantRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if req.GroupID == 0 {
|
||||
return 0, errors.New("group_id is required")
|
||||
}
|
||||
return req.GroupID, nil
|
||||
}
|
||||
|
||||
// grantStatusValidated maps an "invalid access" validation error to 400,
|
||||
// otherwise defers to grantStatus.
|
||||
func grantStatusValidated(err error) int {
|
||||
if err == nil {
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
if strings.Contains(err.Error(), "invalid access") {
|
||||
return http.StatusBadRequest
|
||||
}
|
||||
return grantStatus(err)
|
||||
}
|
||||
Reference in New Issue
Block a user