refac: debt on role backend
This commit is contained in:
1 parent
de142f6c5f
commit
a043f7f41a
130 files changed
+3591
-512
No files matched your search
@@ -1,8 +1,8 @@
|
||||
package article
|
||||
|
||||
import (
|
||||
"RenewCMS/api/pkg/access"
|
||||
"RenewCMS/api/pkg/apperr"
|
||||
"RenewCMS/api/pkg/claims"
|
||||
validator "RenewCMS/api/pkg/validator"
|
||||
domain "RenewCMS/internal/domain/article"
|
||||
"RenewCMS/internal/domain/author"
|
||||
@@ -26,12 +26,11 @@ import (
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
CreateUseCase *useCases.CreateArticleUseCase
|
||||
GetUseCase *useCases.GetArticleUseCase
|
||||
ListUseCase *useCases.ListArticlesUseCase
|
||||
DeleteUseCase *useCases.DeleteArticleUseCase
|
||||
UpdateUseCase *useCases.UpdateArticleUseCase
|
||||
GetUserUseCase *useCases.GetUserUseCase
|
||||
CreateUseCase *useCases.CreateArticleUseCase
|
||||
GetUseCase *useCases.GetArticleUseCase
|
||||
ListUseCase *useCases.ListArticlesUseCase
|
||||
DeleteUseCase *useCases.DeleteArticleUseCase
|
||||
UpdateUseCase *useCases.UpdateArticleUseCase
|
||||
}
|
||||
|
||||
type PostArticle struct {
|
||||
@@ -39,14 +38,13 @@ type PostArticle struct {
|
||||
Body string `json:"body"`
|
||||
}
|
||||
|
||||
func NewHandler(create *useCases.CreateArticleUseCase, get *useCases.GetArticleUseCase, list *useCases.ListArticlesUseCase, delete *useCases.DeleteArticleUseCase, update *useCases.UpdateArticleUseCase, getUser *useCases.GetUserUseCase) *Handler {
|
||||
func NewHandler(create *useCases.CreateArticleUseCase, get *useCases.GetArticleUseCase, list *useCases.ListArticlesUseCase, delete *useCases.DeleteArticleUseCase, update *useCases.UpdateArticleUseCase) *Handler {
|
||||
return &Handler{
|
||||
CreateUseCase: create,
|
||||
GetUseCase: get,
|
||||
ListUseCase: list,
|
||||
DeleteUseCase: delete,
|
||||
UpdateUseCase: update,
|
||||
GetUserUseCase: getUser,
|
||||
CreateUseCase: create,
|
||||
GetUseCase: get,
|
||||
ListUseCase: list,
|
||||
DeleteUseCase: delete,
|
||||
UpdateUseCase: update,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,12 +178,7 @@ func (h *Handler) GetArticle(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
var article domain.Article
|
||||
if h.callerIsVerified(r) {
|
||||
article, err = h.GetUseCase.GetArticle(id, format)
|
||||
} else {
|
||||
article, err = h.GetUseCase.GetOnlineArticle(id, format)
|
||||
}
|
||||
article, err := h.GetUseCase.GetArticle(id, format, access.CallerOf(r))
|
||||
if err != nil {
|
||||
if errors.Is(err, domain.ErrArticleNotFound) {
|
||||
http.Error(w, apperr.ArticleNotFoundErrorMessage, http.StatusNotFound)
|
||||
@@ -223,12 +216,11 @@ func (h *Handler) PostArticle(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
creatorId, _ := claims.UserId(r)
|
||||
createdArticle, err := h.CreateUseCase.CreateArticle(r.Context(), useCases.CreateArticleCommand{
|
||||
Title: localArticle.Title,
|
||||
Body: localArticle.Body,
|
||||
Format: format,
|
||||
CreatedBy: creatorId,
|
||||
Title: localArticle.Title,
|
||||
Body: localArticle.Body,
|
||||
Format: format,
|
||||
Caller: access.CallerOf(r),
|
||||
})
|
||||
if err != nil {
|
||||
if errors.Is(err, domain.ErrInvalidTitle) {
|
||||
@@ -251,6 +243,9 @@ func writeArticleErrorResponse(w http.ResponseWriter, err error) {
|
||||
}
|
||||
|
||||
func writeKnownArticleError(w http.ResponseWriter, err error) bool {
|
||||
if access.WriteIfMissingPermission(w, err) {
|
||||
return true
|
||||
}
|
||||
if errors.Is(err, domain.ErrArticleNotFound) {
|
||||
http.Error(w, apperr.ArticleNotFoundErrorMessage, http.StatusNotFound)
|
||||
return true
|
||||
@@ -330,7 +325,7 @@ func (h *Handler) setIsOnline(w http.ResponseWriter, r *http.Request, isOnline b
|
||||
return
|
||||
}
|
||||
|
||||
updatedArticle, err := h.UpdateUseCase.UpdateIsOnline(r.Context(), id, isOnline, format)
|
||||
updatedArticle, err := h.UpdateUseCase.UpdateIsOnline(r.Context(), id, access.CallerOf(r), isOnline, format)
|
||||
if err != nil {
|
||||
writeArticleErrorResponse(w, err)
|
||||
return
|
||||
@@ -457,7 +452,7 @@ func (h *Handler) UpdateArticleBody(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
updatedArticle, err := h.UpdateUseCase.Update(r.Context(), id, useCases.UpdateArticleCommand{
|
||||
updatedArticle, err := h.UpdateUseCase.Update(r.Context(), id, access.CallerOf(r), useCases.UpdateArticleCommand{
|
||||
Body: request.Body,
|
||||
SiteID: request.SiteID,
|
||||
AuthorIDs: request.AuthorIDs,
|
||||
@@ -491,29 +486,6 @@ func (h *Handler) UnpublishArticle(w http.ResponseWriter, r *http.Request) {
|
||||
h.setIsOnline(w, r, false)
|
||||
}
|
||||
|
||||
func (h *Handler) callerIsVerified(r *http.Request) bool {
|
||||
return isVerifiedCaller(r, h.GetUserUseCase)
|
||||
}
|
||||
|
||||
func isVerifiedCaller(r *http.Request, getUser *useCases.GetUserUseCase) bool {
|
||||
userId, ok := claims.UserId(r)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
currentUser, err := getUser.GetUser(userId)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
tokenVersion, ok := claims.TokenVersion(r)
|
||||
if !ok || tokenVersion != currentUser.TokenVersion {
|
||||
return false
|
||||
}
|
||||
|
||||
return currentUser.IsVerified
|
||||
}
|
||||
|
||||
const (
|
||||
defaultListPage = 1
|
||||
defaultListSize = 25
|
||||
@@ -596,15 +568,15 @@ func (h *Handler) ListArticles(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
page, err := h.ListUseCase.ListArticlesPage(useCases.ListArticlesCommand{
|
||||
Format: format,
|
||||
Verified: h.callerIsVerified(r),
|
||||
Page: query.Page,
|
||||
Size: query.Size,
|
||||
Q: query.Q,
|
||||
Status: query.Status,
|
||||
Sort: parseSort(query.Sort),
|
||||
SiteKey: query.Site,
|
||||
SEO: query.SEO,
|
||||
Format: format,
|
||||
Caller: access.CallerOf(r),
|
||||
Page: query.Page,
|
||||
Size: query.Size,
|
||||
Q: query.Q,
|
||||
Status: query.Status,
|
||||
Sort: parseSort(query.Sort),
|
||||
SiteKey: query.Site,
|
||||
SEO: query.SEO,
|
||||
})
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to retrieve articles", http.StatusInternalServerError)
|
||||
@@ -639,11 +611,14 @@ func (h *Handler) DeleteArticle(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.DeleteUseCase.DeleteArticle(r.Context(), id); err != nil {
|
||||
if err := h.DeleteUseCase.DeleteArticle(r.Context(), id, access.CallerOf(r)); err != nil {
|
||||
if errors.Is(err, domain.ErrArticleNotFound) {
|
||||
http.Error(w, apperr.ArticleNotFoundErrorMessage, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
if access.WriteIfMissingPermission(w, err) {
|
||||
return
|
||||
}
|
||||
http.Error(w, "Failed to delete article", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package article
|
||||
|
||||
import (
|
||||
"RenewCMS/api/pkg/access"
|
||||
"RenewCMS/api/pkg/apperr"
|
||||
validator "RenewCMS/api/pkg/validator"
|
||||
"RenewCMS/internal/infrastructure/useCases"
|
||||
@@ -14,11 +15,10 @@ import (
|
||||
type SEOHandler struct {
|
||||
ResolveUseCase *useCases.ResolveArticleSEOUseCase
|
||||
CheckUseCase *useCases.CheckArticleSEOUseCase
|
||||
GetUserUseCase *useCases.GetUserUseCase
|
||||
}
|
||||
|
||||
func NewSEOHandler(resolve *useCases.ResolveArticleSEOUseCase, check *useCases.CheckArticleSEOUseCase, getUser *useCases.GetUserUseCase) *SEOHandler {
|
||||
return &SEOHandler{ResolveUseCase: resolve, CheckUseCase: check, GetUserUseCase: getUser}
|
||||
func NewSEOHandler(resolve *useCases.ResolveArticleSEOUseCase, check *useCases.CheckArticleSEOUseCase) *SEOHandler {
|
||||
return &SEOHandler{ResolveUseCase: resolve, CheckUseCase: check}
|
||||
}
|
||||
|
||||
type CheckArticleSEOBody struct {
|
||||
@@ -68,7 +68,7 @@ func (h *SEOHandler) Resolve(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
resolved, err := h.ResolveUseCase.Resolve(id, isVerifiedCaller(r, h.GetUserUseCase))
|
||||
resolved, err := h.ResolveUseCase.Resolve(id, access.CallerOf(r))
|
||||
if err != nil {
|
||||
writeArticleErrorResponse(w, err)
|
||||
return
|
||||
@@ -93,7 +93,7 @@ func (h *SEOHandler) Check(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
checked, err := h.CheckUseCase.Check(id, useCases.CheckArticleSEOCommand{
|
||||
checked, err := h.CheckUseCase.Check(id, access.CallerOf(r), useCases.CheckArticleSEOCommand{
|
||||
Body: request.Body,
|
||||
Slug: request.Slug,
|
||||
Excerpt: request.Excerpt,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package entry
|
||||
|
||||
import (
|
||||
"RenewCMS/api/pkg/access"
|
||||
"RenewCMS/api/pkg/apperr"
|
||||
"RenewCMS/api/pkg/claims"
|
||||
"RenewCMS/api/pkg/response"
|
||||
validator "RenewCMS/api/pkg/validator"
|
||||
"RenewCMS/internal/domain/contenttype"
|
||||
@@ -178,6 +178,9 @@ func parseEntryId(r *http.Request) (uint32, error) {
|
||||
}
|
||||
|
||||
func writeEntryError(w http.ResponseWriter, err error) {
|
||||
if access.WriteIfMissingPermission(w, err) {
|
||||
return
|
||||
}
|
||||
var fieldError domain.FieldError
|
||||
switch {
|
||||
case errors.Is(err, contenttype.ErrContentTypeNotFound):
|
||||
@@ -211,21 +214,13 @@ func readBody(w http.ResponseWriter, r *http.Request) (EntryBody, bool) {
|
||||
return body, true
|
||||
}
|
||||
|
||||
func currentUserId(w http.ResponseWriter, r *http.Request) (uint32, bool) {
|
||||
userId, ok := claims.UserId(r)
|
||||
if !ok {
|
||||
http.Error(w, apperr.UnauthorizedErrorMessage, http.StatusUnauthorized)
|
||||
}
|
||||
return userId, ok
|
||||
}
|
||||
|
||||
func (h *Handler) List(w http.ResponseWriter, r *http.Request) {
|
||||
query, err := readListQuery(r.URL.Query())
|
||||
if err != nil || validator.Validate.Struct(query) != nil {
|
||||
http.Error(w, apperr.BodyErrorMessage, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
page, err := h.ListUseCase.ListPage(useCases.ListEntriesCommand{ContentTypeKey: chi.URLParam(r, "key"), Page: query.Page, Size: query.Size, Sort: query.Sort, Query: r.URL.Query().Get("q")})
|
||||
page, err := h.ListUseCase.ListPage(useCases.ListEntriesCommand{ContentTypeKey: chi.URLParam(r, "key"), Page: query.Page, Size: query.Size, Sort: query.Sort, Query: r.URL.Query().Get("q"), Caller: access.CallerOf(r)})
|
||||
if err != nil {
|
||||
writeEntryError(w, err)
|
||||
return
|
||||
@@ -243,7 +238,7 @@ func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, apperr.IdUint32ErrorMessage, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
found, err := h.GetUseCase.Get(chi.URLParam(r, "key"), id)
|
||||
found, err := h.GetUseCase.Get(chi.URLParam(r, "key"), id, access.CallerOf(r))
|
||||
if err != nil {
|
||||
writeEntryError(w, err)
|
||||
return
|
||||
@@ -252,15 +247,11 @@ func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (h *Handler) Create(w http.ResponseWriter, r *http.Request) {
|
||||
userId, ok := currentUserId(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
body, ok := readBody(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
created, err := h.CreateUseCase.Create(useCases.CreateEntryCommand{ContentTypeKey: chi.URLParam(r, "key"), Data: body.Data, UserID: userId})
|
||||
created, err := h.CreateUseCase.Create(useCases.CreateEntryCommand{ContentTypeKey: chi.URLParam(r, "key"), Data: body.Data, Caller: access.CallerOf(r)})
|
||||
if err != nil {
|
||||
writeEntryError(w, err)
|
||||
return
|
||||
@@ -274,15 +265,11 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, apperr.IdUint32ErrorMessage, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
userId, ok := currentUserId(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
body, ok := readBody(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
updated, err := h.UpdateUseCase.Update(useCases.UpdateEntryCommand{ContentTypeKey: chi.URLParam(r, "key"), ID: id, Data: body.Data, UserID: userId})
|
||||
updated, err := h.UpdateUseCase.Update(useCases.UpdateEntryCommand{ContentTypeKey: chi.URLParam(r, "key"), ID: id, Data: body.Data, Caller: access.CallerOf(r)})
|
||||
if err != nil {
|
||||
writeEntryError(w, err)
|
||||
return
|
||||
@@ -296,7 +283,7 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, apperr.IdUint32ErrorMessage, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if err := h.DeleteUseCase.Delete(chi.URLParam(r, "key"), id); err != nil {
|
||||
if err := h.DeleteUseCase.Delete(chi.URLParam(r, "key"), id, access.CallerOf(r)); err != nil {
|
||||
writeEntryError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ func decodeRestartKind(w http.ResponseWriter, r *http.Request) (string, bool) {
|
||||
}
|
||||
|
||||
func canApply(r *http.Request) bool {
|
||||
return access.Grants(r).Holds(role.KeyApplyUpdates)
|
||||
return access.Grants(r).Holds(role.KeySystemApplyUpdates)
|
||||
}
|
||||
|
||||
func writeDownloadError(w http.ResponseWriter, err error) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"RenewCMS/api/pkg/access"
|
||||
"RenewCMS/api/pkg/claims"
|
||||
"RenewCMS/internal/domain/audit"
|
||||
"RenewCMS/internal/infrastructure/useCases"
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
func AuditContext(getUser *useCases.GetUserUseCase, trustedProxies []string) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
r = access.WithCurrentUser(r)
|
||||
origin := audit.Origin{
|
||||
Actor: auditActor(getUser, r),
|
||||
Source: auditSource(r),
|
||||
@@ -29,7 +31,7 @@ func auditActor(getUser *useCases.GetUserUseCase, r *http.Request) audit.Actor {
|
||||
if !ok {
|
||||
return audit.AnonymousActor("")
|
||||
}
|
||||
current, err := getUser.GetUser(userId)
|
||||
current, err := access.LoadUser(getUser, r, userId)
|
||||
if err != nil {
|
||||
return audit.AnonymousActor("")
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"RenewCMS/api/pkg/access"
|
||||
"RenewCMS/api/pkg/apperr"
|
||||
"RenewCMS/api/pkg/claims"
|
||||
"RenewCMS/internal/domain/user"
|
||||
@@ -23,7 +24,7 @@ func resolveCurrentUser(getUser *useCases.GetUserUseCase, w http.ResponseWriter,
|
||||
return user.User{}, false
|
||||
}
|
||||
|
||||
currentUser, err := getUser.GetUser(userId)
|
||||
currentUser, err := access.LoadUser(getUser, r, userId)
|
||||
if err != nil {
|
||||
if errors.Is(err, user.ErrUserNotFound) {
|
||||
http.Error(w, apperr.UnauthorizedErrorMessage, http.StatusUnauthorized)
|
||||
@@ -39,6 +40,7 @@ func resolveCurrentUser(getUser *useCases.GetUserUseCase, w http.ResponseWriter,
|
||||
func RequireCurrentToken(getUser *useCases.GetUserUseCase) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
r = access.WithCurrentUser(r)
|
||||
currentUser, ok := resolveCurrentUser(getUser, w, r)
|
||||
if !ok {
|
||||
return
|
||||
@@ -63,6 +65,7 @@ func RequireCurrentToken(getUser *useCases.GetUserUseCase) func(http.Handler) ht
|
||||
func RequireVerifiedUser(getUser *useCases.GetUserUseCase) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
r = access.WithCurrentUser(r)
|
||||
currentUser, ok := resolveCurrentUser(getUser, w, r)
|
||||
if !ok {
|
||||
return
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"RenewCMS/api/pkg/access"
|
||||
"RenewCMS/api/pkg/claims"
|
||||
"RenewCMS/internal/domain/user"
|
||||
"RenewCMS/internal/infrastructure/useCases"
|
||||
"errors"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func OptionalAccess(getUser *useCases.GetUserUseCase, check *useCases.CheckPermissionUseCase) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
r = access.WithCurrentUser(r)
|
||||
account, signedIn, err := verifiedAccount(getUser, r)
|
||||
if err != nil {
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if !signedIn {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
grants, err := check.Grants(account)
|
||||
if err != nil {
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
caller := access.Caller{UserID: account.ID, Grants: grants}
|
||||
next.ServeHTTP(w, r.WithContext(access.WithCaller(r.Context(), caller)))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func verifiedAccount(getUser *useCases.GetUserUseCase, r *http.Request) (user.User, bool, error) {
|
||||
userID, ok := claims.UserId(r)
|
||||
if !ok {
|
||||
return user.User{}, false, nil
|
||||
}
|
||||
account, err := access.LoadUser(getUser, r, userID)
|
||||
if errors.Is(err, user.ErrUserNotFound) {
|
||||
return user.User{}, false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return user.User{}, false, err
|
||||
}
|
||||
tokenVersion, ok := claims.TokenVersion(r)
|
||||
if !ok || tokenVersion != account.TokenVersion {
|
||||
return user.User{}, false, nil
|
||||
}
|
||||
return account, account.IsVerified, nil
|
||||
}
|
||||
@@ -2,31 +2,52 @@ package middleware
|
||||
|
||||
import (
|
||||
"RenewCMS/api/pkg/access"
|
||||
"RenewCMS/internal/domain/builtintype"
|
||||
"RenewCMS/internal/domain/role"
|
||||
"RenewCMS/internal/domain/user"
|
||||
"RenewCMS/internal/infrastructure/useCases"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type grantCheck func(account user.User, key string) (role.GrantSet, error)
|
||||
type grantCheck func(account user.User, r *http.Request) (role.GrantSet, error)
|
||||
|
||||
func ArticleTypeKey(*http.Request) string {
|
||||
return builtintype.KeyArticle
|
||||
}
|
||||
|
||||
func PathTypeKey(r *http.Request) string {
|
||||
return chi.URLParam(r, "key")
|
||||
}
|
||||
|
||||
func RequirePermission(getUser *useCases.GetUserUseCase, check *useCases.CheckPermissionUseCase, key string) func(http.Handler) http.Handler {
|
||||
return enforce(getUser, check.Require, key)
|
||||
return enforce(getUser, func(account user.User, _ *http.Request) (role.GrantSet, error) {
|
||||
return check.Require(account, key)
|
||||
})
|
||||
}
|
||||
|
||||
func RequireFullScope(getUser *useCases.GetUserUseCase, check *useCases.CheckPermissionUseCase, key string) func(http.Handler) http.Handler {
|
||||
return enforce(getUser, check.RequireAll, key)
|
||||
return enforce(getUser, func(account user.User, _ *http.Request) (role.GrantSet, error) {
|
||||
return check.RequireAll(account, key)
|
||||
})
|
||||
}
|
||||
|
||||
func enforce(getUser *useCases.GetUserUseCase, verify grantCheck, key string) func(http.Handler) http.Handler {
|
||||
func RequireTypedPermission(getUser *useCases.GetUserUseCase, check *useCases.CheckPermissionUseCase, key string, typeKey func(r *http.Request) string) func(http.Handler) http.Handler {
|
||||
return enforce(getUser, func(account user.User, r *http.Request) (role.GrantSet, error) {
|
||||
return check.RequireFor(account, key, typeKey(r))
|
||||
})
|
||||
}
|
||||
|
||||
func enforce(getUser *useCases.GetUserUseCase, verify grantCheck) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
r = access.WithCurrentUser(r)
|
||||
currentUser, ok := resolveCurrentUser(getUser, w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
grants, err := verify(currentUser, key)
|
||||
grants, err := verify(currentUser, r)
|
||||
if err != nil {
|
||||
if !access.WriteIfMissingPermission(w, err) {
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
@@ -34,7 +55,8 @@ func enforce(getUser *useCases.GetUserUseCase, verify grantCheck, key string) fu
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r.WithContext(access.NewContext(r.Context(), grants)))
|
||||
caller := access.Caller{UserID: currentUser.ID, Grants: grants}
|
||||
next.ServeHTTP(w, r.WithContext(access.WithCaller(r.Context(), caller)))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -3,20 +3,27 @@ package access
|
||||
import (
|
||||
"RenewCMS/api/pkg/apperr"
|
||||
"RenewCMS/internal/domain/role"
|
||||
"RenewCMS/internal/infrastructure/useCases"
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type grantsContextKey struct{}
|
||||
type Caller = useCases.ContentCaller
|
||||
|
||||
func NewContext(ctx context.Context, grants role.GrantSet) context.Context {
|
||||
return context.WithValue(ctx, grantsContextKey{}, grants)
|
||||
type callerContextKey struct{}
|
||||
|
||||
func WithCaller(ctx context.Context, caller Caller) context.Context {
|
||||
return context.WithValue(ctx, callerContextKey{}, caller)
|
||||
}
|
||||
|
||||
func CallerOf(r *http.Request) Caller {
|
||||
caller, _ := r.Context().Value(callerContextKey{}).(Caller)
|
||||
return caller
|
||||
}
|
||||
|
||||
func Grants(r *http.Request) role.GrantSet {
|
||||
grants, _ := r.Context().Value(grantsContextKey{}).(role.GrantSet)
|
||||
return grants
|
||||
return CallerOf(r).Grants
|
||||
}
|
||||
|
||||
func WriteMissingPermission(w http.ResponseWriter, key string) {
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package access
|
||||
|
||||
import (
|
||||
"RenewCMS/internal/domain/user"
|
||||
"RenewCMS/internal/infrastructure/useCases"
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type currentUserContextKey struct{}
|
||||
|
||||
type currentUserHolder struct {
|
||||
loaded bool
|
||||
userID uint32
|
||||
account user.User
|
||||
err error
|
||||
}
|
||||
|
||||
func WithCurrentUser(r *http.Request) *http.Request {
|
||||
if _, present := r.Context().Value(currentUserContextKey{}).(*currentUserHolder); present {
|
||||
return r
|
||||
}
|
||||
return r.WithContext(context.WithValue(r.Context(), currentUserContextKey{}, ¤tUserHolder{}))
|
||||
}
|
||||
|
||||
func LoadUser(getUser *useCases.GetUserUseCase, r *http.Request, userID uint32) (user.User, error) {
|
||||
holder, present := r.Context().Value(currentUserContextKey{}).(*currentUserHolder)
|
||||
if !present {
|
||||
return getUser.GetUser(userID)
|
||||
}
|
||||
if !holder.loaded || holder.userID != userID {
|
||||
holder.account, holder.err = getUser.GetUser(userID)
|
||||
holder.userID = userID
|
||||
holder.loaded = true
|
||||
}
|
||||
return holder.account, holder.err
|
||||
}
|
||||
+78
-64
@@ -21,6 +21,7 @@ import (
|
||||
"RenewCMS/api/handlers/user"
|
||||
"RenewCMS/api/middleware"
|
||||
"RenewCMS/api/pkg/authtoken"
|
||||
"RenewCMS/internal/domain/role"
|
||||
"RenewCMS/internal/infrastructure/config"
|
||||
"RenewCMS/internal/infrastructure/llmdocs"
|
||||
"encoding/json"
|
||||
@@ -62,6 +63,18 @@ func (c *UseCases) require(key string) func(http.Handler) http.Handler {
|
||||
return middleware.RequirePermission(c.GetUserUseCase, c.CheckPermissionUseCase, key)
|
||||
}
|
||||
|
||||
func (c *UseCases) requireTyped(key string, typeKey func(*http.Request) string) func(http.Handler) http.Handler {
|
||||
return middleware.RequireTypedPermission(c.GetUserUseCase, c.CheckPermissionUseCase, key, typeKey)
|
||||
}
|
||||
|
||||
func (c *UseCases) requireArticle(key string) func(http.Handler) http.Handler {
|
||||
return c.requireTyped(key, middleware.ArticleTypeKey)
|
||||
}
|
||||
|
||||
func (c *UseCases) requireEntry(key string) func(http.Handler) http.Handler {
|
||||
return c.requireTyped(key, middleware.PathTypeKey)
|
||||
}
|
||||
|
||||
func (c *UseCases) requireAll(key string) func(http.Handler) http.Handler {
|
||||
return middleware.RequireFullScope(c.GetUserUseCase, c.CheckPermissionUseCase, key)
|
||||
}
|
||||
@@ -71,11 +84,12 @@ func NewArticleRouter(container *UseCases, trustedProxies []string) http.Handler
|
||||
r.Use(container.apiKeyAuth())
|
||||
r.Use(middleware.AuditContext(container.GetUserUseCase, trustedProxies))
|
||||
|
||||
articleHandler := article.NewHandler(container.CreateArticleUseCase, container.GetArticleUseCase, container.ListArticlesUseCase, container.DeleteArticleUseCase, container.UpdateArticleUseCase, container.GetUserUseCase)
|
||||
articleHandler := article.NewHandler(container.CreateArticleUseCase, container.GetArticleUseCase, container.ListArticlesUseCase, container.DeleteArticleUseCase, container.UpdateArticleUseCase)
|
||||
|
||||
seoHandler := article.NewSEOHandler(container.ResolveArticleSEOUseCase, container.CheckArticleSEOUseCase, container.GetUserUseCase)
|
||||
seoHandler := article.NewSEOHandler(container.ResolveArticleSEOUseCase, container.CheckArticleSEOUseCase)
|
||||
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(middleware.OptionalAccess(container.GetUserUseCase, container.CheckPermissionUseCase))
|
||||
r.Get("/", articleHandler.ListArticles)
|
||||
r.Get("/{id}", articleHandler.GetArticle)
|
||||
r.Get("/{id}/seo", seoHandler.Resolve)
|
||||
@@ -84,12 +98,12 @@ func NewArticleRouter(container *UseCases, trustedProxies []string) http.Handler
|
||||
r.Use(authtoken.Authenticator)
|
||||
r.Use(middleware.RequireCurrentToken(container.GetUserUseCase))
|
||||
r.Use(middleware.RequireVerifiedUser(container.GetUserUseCase))
|
||||
r.Post("/", articleHandler.PostArticle)
|
||||
r.Delete("/{id}", articleHandler.DeleteArticle)
|
||||
r.Patch("/{id}", articleHandler.UpdateArticleBody)
|
||||
r.Patch("/{id}/publish", articleHandler.PublishArticle)
|
||||
r.Patch("/{id}/unpublish", articleHandler.UnpublishArticle)
|
||||
r.Post("/{id}/seo/check", seoHandler.Check)
|
||||
r.With(container.requireArticle(role.KeyContentCreate)).Post("/", articleHandler.PostArticle)
|
||||
r.With(container.requireArticle(role.KeyContentDelete)).Delete("/{id}", articleHandler.DeleteArticle)
|
||||
r.With(container.requireArticle(role.KeyContentUpdate)).Patch("/{id}", articleHandler.UpdateArticleBody)
|
||||
r.With(container.requireArticle(role.KeyContentPublish)).Patch("/{id}/publish", articleHandler.PublishArticle)
|
||||
r.With(container.requireArticle(role.KeyContentPublish)).Patch("/{id}/unpublish", articleHandler.UnpublishArticle)
|
||||
r.With(container.requireArticle(role.KeyContentRead)).Post("/{id}/seo/check", seoHandler.Check)
|
||||
})
|
||||
return r
|
||||
}
|
||||
@@ -157,10 +171,10 @@ func NewUserRouter(container *UseCases, rateLimit config.AuthRateLimitSettings,
|
||||
r.Use(middleware.RequireCurrentToken(container.GetUserUseCase))
|
||||
r.Use(middleware.RequireVerifiedUser(container.GetUserUseCase))
|
||||
r.Patch("/me", userHandler.UpdateMe)
|
||||
r.With(container.require("users.view")).Get("/", inviteHandler.ListUsers)
|
||||
r.With(container.require(role.KeyUsersView)).Get("/", inviteHandler.ListUsers)
|
||||
r.Get("/lookup", lookupHandler.Lookup)
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(container.require("users.invite"))
|
||||
r.Use(container.require(role.KeyUsersInvite))
|
||||
r.Use(middleware.TrustedProxyRealIP(trustedProxies))
|
||||
r.Use(middleware.NewRateLimiter(rateLimit.MaxAttempts, rateLimit.Window))
|
||||
r.Post("/invite", inviteHandler.CreateInvite)
|
||||
@@ -181,7 +195,7 @@ func NewSettingsRouter(container *UseCases, trustedProxies []string) http.Handle
|
||||
r.Use(authtoken.Authenticator)
|
||||
r.Use(middleware.RequireCurrentToken(container.GetUserUseCase))
|
||||
r.Use(middleware.RequireVerifiedUser(container.GetUserUseCase))
|
||||
r.Use(container.require("settings.view"))
|
||||
r.Use(container.require(role.KeySettingsView))
|
||||
r.Get("/", settingsHandler.GetSettings)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
@@ -192,7 +206,7 @@ func NewSettingsRouter(container *UseCases, trustedProxies []string) http.Handle
|
||||
r.Use(authtoken.Authenticator)
|
||||
r.Use(middleware.RequireCurrentToken(container.GetUserUseCase))
|
||||
r.Use(middleware.RequireVerifiedUser(container.GetUserUseCase))
|
||||
r.Use(container.require("system.edit_retention"))
|
||||
r.Use(container.require(role.KeySystemEditRetention))
|
||||
r.Patch("/", settingsHandler.UpdateSettings)
|
||||
})
|
||||
return r
|
||||
@@ -222,10 +236,10 @@ func NewSiteRouter(container *UseCases, trustedProxies []string) http.Handler {
|
||||
r.Use(authtoken.Authenticator)
|
||||
r.Use(middleware.RequireCurrentToken(container.GetUserUseCase))
|
||||
r.Use(middleware.RequireVerifiedUser(container.GetUserUseCase))
|
||||
r.With(container.require("settings.manage_sites")).Post("/", siteHandler.Create)
|
||||
r.With(container.require("settings.manage_sites")).Patch("/{id}", siteHandler.Update)
|
||||
r.With(container.require("settings.manage_sites")).Patch("/{id}/default", siteHandler.SetDefault)
|
||||
r.With(container.require("settings.delete_site")).Delete("/{id}", siteHandler.Delete)
|
||||
r.With(container.require(role.KeySettingsManageSites)).Post("/", siteHandler.Create)
|
||||
r.With(container.require(role.KeySettingsManageSites)).Patch("/{id}", siteHandler.Update)
|
||||
r.With(container.require(role.KeySettingsManageSites)).Patch("/{id}/default", siteHandler.SetDefault)
|
||||
r.With(container.require(role.KeySettingsDeleteSite)).Delete("/{id}", siteHandler.Delete)
|
||||
})
|
||||
return r
|
||||
}
|
||||
@@ -241,7 +255,7 @@ func NewAuthorRouter(container *UseCases, trustedProxies []string) http.Handler
|
||||
r.Use(authtoken.Authenticator)
|
||||
r.Use(middleware.RequireCurrentToken(container.GetUserUseCase))
|
||||
r.Use(middleware.RequireVerifiedUser(container.GetUserUseCase))
|
||||
r.Use(container.require("authors.view"))
|
||||
r.Use(container.require(role.KeyAuthorsView))
|
||||
r.Get("/", authorHandler.List)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
@@ -253,9 +267,9 @@ func NewAuthorRouter(container *UseCases, trustedProxies []string) http.Handler
|
||||
r.Use(middleware.RequireCurrentToken(container.GetUserUseCase))
|
||||
r.Use(middleware.RequireVerifiedUser(container.GetUserUseCase))
|
||||
r.Post("/me", authorHandler.CreateMine)
|
||||
r.With(container.require("authors.edit")).Patch("/{id}", authorHandler.Update)
|
||||
r.With(container.require("authors.create")).Post("/", authorHandler.Create)
|
||||
r.With(container.require("authors.delete")).Delete("/{id}", authorHandler.Delete)
|
||||
r.With(container.require(role.KeyAuthorsEdit)).Patch("/{id}", authorHandler.Update)
|
||||
r.With(container.require(role.KeyAuthorsCreate)).Post("/", authorHandler.Create)
|
||||
r.With(container.require(role.KeyAuthorsDelete)).Delete("/{id}", authorHandler.Delete)
|
||||
})
|
||||
return r
|
||||
}
|
||||
@@ -274,16 +288,16 @@ func NewContentTypeRouter(container *UseCases, trustedProxies []string) http.Han
|
||||
r.Use(authtoken.Authenticator)
|
||||
r.Use(middleware.RequireCurrentToken(container.GetUserUseCase))
|
||||
r.Use(middleware.RequireVerifiedUser(container.GetUserUseCase))
|
||||
r.With(container.require("schema.view")).Get("/", contentTypeHandler.List)
|
||||
r.With(container.require("schema.view")).Get("/{key}", contentTypeHandler.Get)
|
||||
r.With(container.require("schema.edit")).Post("/", contentTypeHandler.Create)
|
||||
r.With(container.require("schema.edit")).Put("/{key}", contentTypeHandler.Update)
|
||||
r.With(container.require("schema.delete")).Delete("/{key}", contentTypeHandler.Delete)
|
||||
r.Get("/{key}/entry", entryHandler.List)
|
||||
r.Post("/{key}/entry", entryHandler.Create)
|
||||
r.Get("/{key}/entry/{id}", entryHandler.Get)
|
||||
r.Put("/{key}/entry/{id}", entryHandler.Update)
|
||||
r.Delete("/{key}/entry/{id}", entryHandler.Delete)
|
||||
r.With(container.require(role.KeySchemaView)).Get("/", contentTypeHandler.List)
|
||||
r.With(container.require(role.KeySchemaView)).Get("/{key}", contentTypeHandler.Get)
|
||||
r.With(container.require(role.KeySchemaEdit)).Post("/", contentTypeHandler.Create)
|
||||
r.With(container.require(role.KeySchemaEdit)).Put("/{key}", contentTypeHandler.Update)
|
||||
r.With(container.require(role.KeySchemaDelete)).Delete("/{key}", contentTypeHandler.Delete)
|
||||
r.With(container.requireEntry(role.KeyContentRead)).Get("/{key}/entry", entryHandler.List)
|
||||
r.With(container.requireEntry(role.KeyContentCreate)).Post("/{key}/entry", entryHandler.Create)
|
||||
r.With(container.requireEntry(role.KeyContentRead)).Get("/{key}/entry/{id}", entryHandler.Get)
|
||||
r.With(container.requireEntry(role.KeyContentUpdate)).Put("/{key}/entry/{id}", entryHandler.Update)
|
||||
r.With(container.requireEntry(role.KeyContentDelete)).Delete("/{key}/entry/{id}", entryHandler.Delete)
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -299,7 +313,7 @@ func NewBuiltinTypeRouter(container *UseCases, trustedProxies []string) http.Han
|
||||
r.Use(authtoken.Authenticator)
|
||||
r.Use(middleware.RequireCurrentToken(container.GetUserUseCase))
|
||||
r.Use(middleware.RequireVerifiedUser(container.GetUserUseCase))
|
||||
r.Use(container.require("schema.view"))
|
||||
r.Use(container.require(role.KeySchemaView))
|
||||
r.Get("/", builtinTypeHandler.List)
|
||||
r.Get("/{key}", builtinTypeHandler.Get)
|
||||
return r
|
||||
@@ -317,9 +331,9 @@ func NewActivityRouter(container *UseCases, trustedProxies []string) http.Handle
|
||||
r.Use(authtoken.Authenticator)
|
||||
r.Use(middleware.RequireCurrentToken(container.GetUserUseCase))
|
||||
r.Use(middleware.RequireVerifiedUser(container.GetUserUseCase))
|
||||
r.With(container.require("activity.view")).Get("/", activityHandler.List)
|
||||
r.With(container.requireAll("activity.view")).Get("/summary", activityHandler.Summary)
|
||||
r.With(container.require("activity.export"), container.require("activity.view")).Get("/export", activityHandler.Export)
|
||||
r.With(container.require(role.KeyActivityView)).Get("/", activityHandler.List)
|
||||
r.With(container.requireAll(role.KeyActivityView)).Get("/summary", activityHandler.Summary)
|
||||
r.With(container.require(role.KeyActivityExport), container.require(role.KeyActivityView)).Get("/export", activityHandler.Export)
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -341,19 +355,19 @@ func NewSystemRouter(container *UseCases, trustedProxies []string) http.Handler
|
||||
r.Use(authtoken.Authenticator)
|
||||
r.Use(middleware.RequireCurrentToken(container.GetUserUseCase))
|
||||
r.Use(middleware.RequireVerifiedUser(container.GetUserUseCase))
|
||||
r.With(container.require("settings.view")).Get("/update", updateHandler.GetStatus)
|
||||
r.With(container.require(role.KeySettingsView)).Get("/update", updateHandler.GetStatus)
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(container.require("system.apply_updates"))
|
||||
r.Use(container.require(role.KeySystemApplyUpdates))
|
||||
r.Use(middleware.NewUserRateLimiter(updateCheckMaxAttempts, updateCheckWindow))
|
||||
r.Post("/update/check", updateHandler.Check)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(container.require("system.apply_updates"))
|
||||
r.Use(container.require(role.KeySystemApplyUpdates))
|
||||
r.Use(middleware.NewUserRateLimiter(updateDownloadMaxAttempts, updateDownloadWindow))
|
||||
r.Post("/update/download", updateHandler.Download)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(container.require("system.apply_updates"))
|
||||
r.Use(container.require(role.KeySystemApplyUpdates))
|
||||
r.Post("/update/restart", updateHandler.Restart)
|
||||
})
|
||||
return r
|
||||
@@ -370,9 +384,9 @@ func NewAPIKeyRouter(container *UseCases, trustedProxies []string) http.Handler
|
||||
r.Use(authtoken.Authenticator)
|
||||
r.Use(middleware.RequireCurrentToken(container.GetUserUseCase))
|
||||
r.Use(middleware.RequireVerifiedUser(container.GetUserUseCase))
|
||||
r.With(container.require("apikeys.create")).Post("/", apiKeyHandler.Create)
|
||||
r.With(container.require("apikeys.view")).Get("/", apiKeyHandler.List)
|
||||
r.With(container.require("apikeys.revoke")).Delete("/{id}", apiKeyHandler.Revoke)
|
||||
r.With(container.require(role.KeyAPIKeysCreate)).Post("/", apiKeyHandler.Create)
|
||||
r.With(container.require(role.KeyAPIKeysView)).Get("/", apiKeyHandler.List)
|
||||
r.With(container.require(role.KeyAPIKeysRevoke)).Delete("/{id}", apiKeyHandler.Revoke)
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -402,24 +416,24 @@ func NewMediaRouter(container *UseCases, trustedProxies []string) http.Handler {
|
||||
r.Use(authtoken.Authenticator)
|
||||
r.Use(middleware.RequireCurrentToken(container.GetUserUseCase))
|
||||
r.Use(middleware.RequireVerifiedUser(container.GetUserUseCase))
|
||||
r.With(container.require("settings.view")).Get("/purge-settings", mediaHandler.GetPurgeSettings)
|
||||
r.With(container.require("settings.edit_general")).Patch("/purge-settings", mediaHandler.UpdatePurgeSettings)
|
||||
r.With(container.requireAll("media.delete")).Get("/purge-preview", mediaHandler.PreviewPurge)
|
||||
r.With(container.requireAll("media.delete")).Post("/purge", mediaHandler.RunPurge)
|
||||
r.With(container.require(role.KeySettingsView)).Get("/purge-settings", mediaHandler.GetPurgeSettings)
|
||||
r.With(container.require(role.KeySettingsEditGeneral)).Patch("/purge-settings", mediaHandler.UpdatePurgeSettings)
|
||||
r.With(container.requireAll(role.KeyMediaDelete)).Get("/purge-preview", mediaHandler.PreviewPurge)
|
||||
r.With(container.requireAll(role.KeyMediaDelete)).Post("/purge", mediaHandler.RunPurge)
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(middleware.RejectAPIKey)
|
||||
r.With(container.require("media.view")).Get("/{id}/variants", mediaHandler.ListVariants)
|
||||
r.With(container.require("settings.edit_general")).Post("/{id}/variants", mediaHandler.GenerateAllVariants)
|
||||
r.With(container.require("settings.edit_general")).Post("/{id}/variants/{name}", mediaHandler.GenerateVariant)
|
||||
r.With(container.require("settings.edit_general")).Delete("/{id}/variants/{name}", mediaHandler.PurgeVariant)
|
||||
r.With(container.require(role.KeyMediaView)).Get("/{id}/variants", mediaHandler.ListVariants)
|
||||
r.With(container.require(role.KeySettingsEditGeneral)).Post("/{id}/variants", mediaHandler.GenerateAllVariants)
|
||||
r.With(container.require(role.KeySettingsEditGeneral)).Post("/{id}/variants/{name}", mediaHandler.GenerateVariant)
|
||||
r.With(container.require(role.KeySettingsEditGeneral)).Delete("/{id}/variants/{name}", mediaHandler.PurgeVariant)
|
||||
})
|
||||
r.With(container.require("media.view")).Get("/", mediaHandler.List)
|
||||
r.With(container.require("media.upload")).Post("/", mediaHandler.Upload)
|
||||
r.With(container.requireAll("media.delete")).Post("/merge", mediaHandler.Merge)
|
||||
r.With(container.require("media.upload")).Patch("/{id}", mediaHandler.Rename)
|
||||
r.With(container.requireAll("media.delete")).Delete("/{id}", mediaHandler.Delete)
|
||||
r.With(container.require("media.view")).Get("/{id}", mediaHandler.Get)
|
||||
r.With(container.require("media.view")).Get("/{id}/usage", mediaHandler.Usage)
|
||||
r.With(container.require(role.KeyMediaView)).Get("/", mediaHandler.List)
|
||||
r.With(container.require(role.KeyMediaUpload)).Post("/", mediaHandler.Upload)
|
||||
r.With(container.requireAll(role.KeyMediaDelete)).Post("/merge", mediaHandler.Merge)
|
||||
r.With(container.require(role.KeyMediaUpload)).Patch("/{id}", mediaHandler.Rename)
|
||||
r.With(container.requireAll(role.KeyMediaDelete)).Delete("/{id}", mediaHandler.Delete)
|
||||
r.With(container.require(role.KeyMediaView)).Get("/{id}", mediaHandler.Get)
|
||||
r.With(container.require(role.KeyMediaView)).Get("/{id}/usage", mediaHandler.Usage)
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -434,14 +448,14 @@ func NewImageVariantRouter(container *UseCases, trustedProxies []string) http.Ha
|
||||
r.Use(authtoken.Authenticator)
|
||||
r.Use(middleware.RequireCurrentToken(container.GetUserUseCase))
|
||||
r.Use(middleware.RequireVerifiedUser(container.GetUserUseCase))
|
||||
r.With(container.require("media.view")).Get("/", variantHandler.List)
|
||||
r.With(container.require("settings.edit_general")).Post("/", variantHandler.Create)
|
||||
r.With(container.require("settings.view")).Get("/cache", variantHandler.CacheStats)
|
||||
r.With(container.require("settings.edit_general")).Post("/cache/purge", variantHandler.PurgeCache)
|
||||
r.With(container.require("settings.edit_general")).Put("/{name}", variantHandler.Update)
|
||||
r.With(container.require("settings.edit_general")).Patch("/{name}", variantHandler.SetEnabled)
|
||||
r.With(container.require("settings.edit_general")).Delete("/{name}", variantHandler.Delete)
|
||||
r.With(container.require("settings.edit_general")).Post("/{name}/purge", variantHandler.Purge)
|
||||
r.With(container.require(role.KeyMediaView)).Get("/", variantHandler.List)
|
||||
r.With(container.require(role.KeySettingsEditGeneral)).Post("/", variantHandler.Create)
|
||||
r.With(container.require(role.KeySettingsView)).Get("/cache", variantHandler.CacheStats)
|
||||
r.With(container.require(role.KeySettingsEditGeneral)).Post("/cache/purge", variantHandler.PurgeCache)
|
||||
r.With(container.require(role.KeySettingsEditGeneral)).Put("/{name}", variantHandler.Update)
|
||||
r.With(container.require(role.KeySettingsEditGeneral)).Patch("/{name}", variantHandler.SetEnabled)
|
||||
r.With(container.require(role.KeySettingsEditGeneral)).Delete("/{name}", variantHandler.Delete)
|
||||
r.With(container.require(role.KeySettingsEditGeneral)).Post("/{name}/purge", variantHandler.Purge)
|
||||
return r
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user