1+ {-# LANGUAGE DataKinds #-}
2+
13module Share.Web.Share.Orgs.Impl (server ) where
24
35import Control.Lens
@@ -10,6 +12,7 @@ import Share.Postgres qualified as PG
1012import Share.Postgres.Users.Queries qualified as UserQ
1113import Share.Prelude
1214import Share.User (User (.. ))
15+ import Share.Utils.Logging qualified as Logging
1316import Share.Web.App
1417import Share.Web.Authorization qualified as AuthZ
1518import Share.Web.Authorization.Types
@@ -23,6 +26,29 @@ import Share.Web.Share.Roles (canonicalRoleAssignmentOrdering)
2326import Share.Web.Share.Roles.Queries (displaySubjectsOf )
2427import Unison.Util.Set qualified as Set
2528
29+ data OrgError
30+ = OrgMemberOfOrgError
31+ | OrgMustHaveOwnerError
32+ deriving stock (Show , Eq )
33+ deriving (Logging.Loggable ) via (Logging. ShowLoggable Logging. UserFault OrgError )
34+
35+ instance ToServerError OrgError where
36+ toServerError = \ case
37+ OrgMemberOfOrgError ->
38+ ( ErrorID " org:org-member-of-org" ,
39+ err400
40+ { errBody = " Cannot add an org as a member of another org." ,
41+ errReasonPhrase = " Invalid Org Member"
42+ }
43+ )
44+ OrgMustHaveOwnerError ->
45+ ( ErrorID " org:must-have-owner" ,
46+ err400
47+ { errBody = " Cannot remove the only owner of an org." ,
48+ errReasonPhrase = " Invalid Org Member"
49+ }
50+ )
51+
2652server :: ServerT API. API WebApp
2753server =
2854 let orgResourceServer orgHandle =
@@ -75,6 +101,7 @@ addRolesEndpoint :: UserHandle -> UserId -> AddRolesRequest -> WebApp ListRolesR
75101addRolesEndpoint orgHandle caller (AddRolesRequest {roleAssignments}) = do
76102 orgId <- orgIdByHandle orgHandle
77103 _authZReceipt <- AuthZ. permissionGuard $ AuthZ. checkEditOrgRoles caller orgId
104+ assertNoOrgSubjects roleAssignments
78105 PG. runTransaction do
79106 orgRoles <- OrgQ. addOrgRoles orgId roleAssignments
80107 ListRolesResponse True . canonicalRoleAssignmentOrdering <$> displaySubjectsOf (traversed . traversed) orgRoles
@@ -83,8 +110,12 @@ removeRolesEndpoint :: UserHandle -> UserId -> RemoveRolesRequest -> WebApp List
83110removeRolesEndpoint orgHandle caller (RemoveRolesRequest {roleAssignments}) = do
84111 orgId <- orgIdByHandle orgHandle
85112 _authZReceipt <- AuthZ. permissionGuard $ AuthZ. checkEditOrgRoles caller orgId
86- PG. runTransaction do
113+ PG. runTransactionOrRespondError do
87114 orgRoles <- OrgQ. removeOrgRoles orgId roleAssignments
115+ OrgQ. doesOrgHaveOwner orgId >>= \ case
116+ False -> throwError OrgMustHaveOwnerError
117+ True -> pure ()
118+
88119 ListRolesResponse True . canonicalRoleAssignmentOrdering <$> displaySubjectsOf (traversed . traversed) orgRoles
89120
90121listMembersEndpoint :: UserHandle -> UserId -> WebApp OrgMembersListResponse
@@ -98,8 +129,12 @@ addMembersEndpoint :: UserHandle -> UserId -> OrgMembersAddRequest -> WebApp Org
98129addMembersEndpoint orgHandle caller (OrgMembersAddRequest {members}) = do
99130 orgId <- orgIdByHandle orgHandle
100131 _authZReceipt <- AuthZ. permissionGuard $ AuthZ. checkEditOrgMembers caller orgId
101- PG. runTransaction do
132+ PG. runTransactionOrRespondError do
102133 userIds <- UserQ. userIdsByHandlesOf Set. traverse (Set. fromList members)
134+ hasOrgMember <- runMaybeT $ for_ userIds \ userId -> do
135+ MaybeT $ OrgQ. orgByUserId userId
136+ when (isJust hasOrgMember) do
137+ throwError OrgMemberOfOrgError
103138 OrgQ. addOrgMembers orgId userIds
104139 OrgMembersListResponse <$> OrgQ. listOrgMembers orgId
105140
@@ -111,3 +146,15 @@ removeMembersEndpoint orgHandle caller (OrgMembersRemoveRequest {members}) = do
111146 userIds <- UserQ. userIdsByHandlesOf Set. traverse (Set. fromList members)
112147 OrgQ. removeOrgMembers orgId userIds
113148 OrgMembersListResponse <$> OrgQ. listOrgMembers orgId
149+
150+ assertNoOrgSubjects :: [RoleAssignment ResolvedAuthSubject ] -> WebApp ()
151+ assertNoOrgSubjects roleAssignments = do
152+ let hasOrgSubject =
153+ roleAssignments
154+ & any
155+ ( \ RoleAssignment {subject} -> case subject of
156+ OrgSubject {} -> True
157+ _ -> False
158+ )
159+ when hasOrgSubject do
160+ respondError OrgMemberOfOrgError
0 commit comments