Go · 2200 bytes Raw Blame History
1 // SPDX-License-Identifier: AGPL-3.0-or-later
2
3 package api
4
5 import (
6 "net/http"
7
8 "github.com/tenseleyFlow/shithub/internal/entitlements"
9 "github.com/tenseleyFlow/shithub/internal/orgs"
10 orgsdb "github.com/tenseleyFlow/shithub/internal/orgs/sqlc"
11 "github.com/tenseleyFlow/shithub/internal/web/middleware"
12 )
13
14 func (h *Handlers) requireAPIOrgOwner(w http.ResponseWriter, r *http.Request, org orgsdb.Org) bool {
15 auth := middleware.PATAuthFromContext(r.Context())
16 if auth.UserID == 0 {
17 writeAPIError(w, http.StatusUnauthorized, "unauthenticated")
18 return false
19 }
20 if auth.IsSuspended {
21 writeAPIError(w, http.StatusForbidden, "account is suspended")
22 return false
23 }
24 if auth.IsSiteAdmin {
25 return true
26 }
27
28 odeps := orgs.Deps{Pool: h.d.Pool, Logger: h.d.Logger}
29 isMember, err := orgs.IsMember(r.Context(), odeps, org.ID, auth.UserID)
30 if err != nil {
31 h.d.Logger.ErrorContext(r.Context(), "api: org member check", "org_id", org.ID, "error", err)
32 writeAPIError(w, http.StatusInternalServerError, "authorization failed")
33 return false
34 }
35 if !isMember {
36 writeAPIError(w, http.StatusNotFound, "org not found")
37 return false
38 }
39
40 isOwner, err := orgs.IsOwner(r.Context(), odeps, org.ID, auth.UserID)
41 if err != nil {
42 h.d.Logger.ErrorContext(r.Context(), "api: org owner check", "org_id", org.ID, "error", err)
43 writeAPIError(w, http.StatusInternalServerError, "authorization failed")
44 return false
45 }
46 if !isOwner {
47 writeAPIError(w, http.StatusForbidden, "organization owner access required")
48 return false
49 }
50 return true
51 }
52
53 func (h *Handlers) requireOrgFeature(w http.ResponseWriter, r *http.Request, org orgsdb.Org, feature entitlements.Feature, label string) bool {
54 decision, err := entitlements.CheckOrgFeature(r.Context(), entitlements.Deps{Pool: h.d.Pool}, org.ID, feature)
55 if err != nil {
56 h.d.Logger.ErrorContext(r.Context(), "api: org entitlement check", "org_id", org.ID, "feature", feature, "error", err)
57 writeAPIError(w, http.StatusInternalServerError, "entitlement check failed")
58 return false
59 }
60 if !decision.Allowed {
61 banner := decision.UpgradeBanner(label, org.Slug)
62 writeAPIError(w, banner.StatusCode, banner.Message)
63 return false
64 }
65 return true
66 }
67