1
+ {-# LANGUAGE RecordWildCards #-}
2
+
1
3
module Wire.UserGroupSubsystem.Interpreter where
2
4
3
5
import Control.Error (MaybeT (.. ))
4
6
import Control.Lens ((^.) )
5
7
import Data.Default
6
8
import Data.Id
7
- import Data.Json.Util ( ToJSONObject ( toJSONObject ))
9
+ import Data.Json.Util
8
10
import Data.Qualified (Local , Qualified (qUnqualified ), qualifyAs , tUnqualified )
9
11
import Data.Set qualified as Set
12
+ import Data.Text qualified as T
10
13
import Imports
11
14
import Polysemy
12
15
import Polysemy.Error
@@ -49,6 +52,7 @@ data UserGroupSubsystemError
49
52
= UserGroupNotATeamAdmin
50
53
| UserGroupMemberIsNotInTheSameTeam
51
54
| UserGroupNotFound
55
+ | UserGroupInvalidQueryParams Text
52
56
deriving (Show , Eq )
53
57
54
58
userGroupSubsystemErrorToHttpError :: UserGroupSubsystemError -> HttpError
@@ -57,6 +61,7 @@ userGroupSubsystemErrorToHttpError =
57
61
UserGroupNotATeamAdmin -> errorToWai @ E. UserGroupNotATeamAdmin
58
62
UserGroupMemberIsNotInTheSameTeam -> errorToWai @ E. UserGroupMemberIsNotInTheSameTeam
59
63
UserGroupNotFound -> errorToWai @ E. UserGroupNotFound
64
+ UserGroupInvalidQueryParams msg -> _ msg
60
65
61
66
createUserGroupImpl ::
62
67
( Member UserSubsystem r ,
@@ -134,24 +139,83 @@ getUserGroupImpl ::
134
139
Sem r (Maybe UserGroup )
135
140
getUserGroupImpl getter gid = runMaybeT $ do
136
141
team <- MaybeT $ getUserTeam getter
137
- getterCanSeeAll <- do
138
- creatorTeamMember <- MaybeT $ getTeamMember getter team
139
- pure . isAdminOrOwner $ creatorTeamMember ^. permissions
142
+ getterCanSeeAll <- mkGetterCanSeeAll getter team
140
143
userGroup <- MaybeT $ Store. getUserGroup team gid
141
144
if getterCanSeeAll || getter `elem` (toList userGroup. members)
142
145
then pure userGroup
143
146
else MaybeT $ pure Nothing
144
147
148
+ mkGetterCanSeeAll ::
149
+ forall r .
150
+ (Member GalleyAPIAccess r ) =>
151
+ UserId ->
152
+ TeamId ->
153
+ MaybeT (Sem r ) Bool
154
+ mkGetterCanSeeAll getter team = do
155
+ creatorTeamMember <- MaybeT $ getTeamMember getter team
156
+ pure . isAdminOrOwner $ creatorTeamMember ^. permissions
157
+
145
158
getUserGroupsImpl ::
146
159
forall r .
160
+ ( Member UserSubsystem r ,
161
+ Member Store. UserGroupStore r ,
162
+ Member GalleyAPIAccess r ,
163
+ Member (Error UserGroupSubsystemError ) r
164
+ ) =>
147
165
UserId ->
148
166
Maybe Text ->
149
167
Maybe SortBy ->
150
168
Maybe SortOrder ->
151
169
Maybe PageSize ->
152
170
Maybe PaginationState ->
153
171
Sem r (PaginationResult UserGroup )
154
- getUserGroupsImpl = undefined
172
+ getUserGroupsImpl getter q sortByKeys' sortOrder' pSize pState = do
173
+ team :: TeamId <- getUserTeam getter >>= ifNothing UserGroupNotATeamAdmin {- sic! -}
174
+ getterCanSeeAll :: Bool <- fromMaybe False <$> runMaybeT (mkGetterCanSeeAll getter team)
175
+ unless (getterCanSeeAll) $ throw UserGroupNotATeamAdmin
176
+ checkPaginationState `mapM_` pState
177
+ details <- either (throw . UserGroupInvalidQueryParams ) pure (mkQueryDetails team)
178
+ page :: [UserGroup ] <- Store. getUserGroups details
179
+ pure (PaginationResult page (newPaginationState page))
180
+ where
181
+ ifNothing :: UserGroupSubsystemError -> Maybe a -> Sem r a
182
+ ifNothing e = maybe (throw e) pure
183
+
184
+ -- TODO: try to push most of this to Wire.API.Pagination
185
+
186
+ checkPaginationState :: PaginationState -> Sem r ()
187
+ checkPaginationState st = do
188
+ let badState = throw . UserGroupInvalidQueryParams . (<> " mismatch" )
189
+ forM_ q $ \ x -> unless (st. searchString == x) (badState " searchString" )
190
+ forM_ sortByKeys' $ \ x -> unless (st. sortByKeys == x) (badState " sortBy" )
191
+ forM_ sortOrder' $ \ x -> unless (st. sortOrder == x) (badState " sortOrder" )
192
+ forM_ pSize $ \ x -> unless (st. pageSize == x) (badState " pageSize" )
193
+
194
+ newPaginationState :: [UserGroup ] -> PaginationState
195
+ newPaginationState ugs = case pState of
196
+ Just oldState -> oldState {lastRowSent = lastRowSent}
197
+ Nothing -> PaginationState {.. }
198
+ where
199
+ searchString :: Text = fromMaybe " " q
200
+ sortByKeys :: SortBy = fromMaybe (SortBy [" created_at" , " name" ]) sortByKeys'
201
+ sortOrder :: SortOrder = fromMaybe def sortOrder'
202
+ pageSize :: PageSize = fromMaybe def pSize
203
+ lastRowSent :: (Text , UTCTimeMillis ) = let l = last ugs in (userGroupNameToText l. name, l. createdAt)
204
+
205
+ mkQueryDetails :: TeamId -> Either Text Store. ListUserGroupsQuery
206
+ mkQueryDetails team = do
207
+ let lastRowSent = (. lastRowSent) <$> pState
208
+ sortDescending = maybe True (== Desc ) sortOrder'
209
+ pageSize = pageSizeToInt $ fromMaybe def pSize
210
+ sortByName <- case sortByKeys' of
211
+ Nothing -> pure False
212
+ Just (SortBy [" name" ]) -> pure True
213
+ Just (SortBy [" name" , " created_at" ]) -> pure True
214
+ Just (SortBy [" created_at" ]) -> pure False
215
+ Just (SortBy [" created_at" , " name" ]) -> pure False
216
+ Just (SortBy bad) ->
217
+ Left $ " invalid sort keys (allowed: name,created_at); received: " <> T. intercalate " ," bad <> " )"
218
+ pure Store. ListUserGroupsQuery {.. }
155
219
156
220
updateGroupImpl ::
157
221
( Member UserSubsystem r ,
0 commit comments