Skip to content

Commit

Permalink
[SQSERVICES-1773] Allow pagination for team search endpoint (#2895)
Browse files Browse the repository at this point in the history
  • Loading branch information
battermann authored Dec 5, 2022
1 parent a51e419 commit 1518191
Show file tree
Hide file tree
Showing 19 changed files with 332 additions and 64 deletions.
1 change: 1 addition & 0 deletions changelog.d/2-features/pr-2895
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Team search endpoint now supports pagination
9 changes: 8 additions & 1 deletion libs/wire-api/src/Wire/API/Routes/Public/Brig.hs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ import Wire.API.User.Client.Prekey
import Wire.API.User.Handle
import Wire.API.User.Password (CompletePasswordReset, NewPasswordReset, PasswordReset, PasswordResetKey)
import Wire.API.User.RichInfo (RichInfoAssocList)
import Wire.API.User.Search (Contact, RoleFilter, SearchResult, TeamContact, TeamUserSearchSortBy, TeamUserSearchSortOrder)
import Wire.API.User.Search (Contact, PagingState, RoleFilter, SearchResult, TeamContact, TeamUserSearchSortBy, TeamUserSearchSortOrder)
import Wire.API.UserMap

type BrigAPI =
Expand Down Expand Up @@ -1159,6 +1159,13 @@ type SearchAPI =
]
"size"
(Range 1 500 Int32)
:> QueryParam'
[ Optional,
Strict,
Description "Paging state for the next page of results"
]
"pagingState"
PagingState
:> MultiVerb
'GET
'[JSON]
Expand Down
37 changes: 35 additions & 2 deletions libs/wire-api/src/Wire/API/User/Search.hs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StrictData #-}
{-# LANGUAGE TemplateHaskell #-}

Expand Down Expand Up @@ -28,6 +29,7 @@ module Wire.API.User.Search
TeamUserSearchSortOrder (..),
TeamUserSearchSortBy (..),
FederatedUserSearchPolicy (..),
PagingState (..),

-- * Swagger
modelSearchResult,
Expand All @@ -43,22 +45,51 @@ import qualified Data.Aeson as Aeson
import Data.Attoparsec.ByteString (sepBy)
import Data.Attoparsec.ByteString.Char8 (char, string)
import Data.ByteString.Conversion (FromByteString (..), ToByteString (..))
import Data.Either.Combinators (mapLeft)
import Data.Id (TeamId, UserId)
import Data.Json.Util (UTCTimeMillis)
import Data.Proxy
import Data.Qualified
import Data.Schema
import Data.String.Conversions (cs)
import Data.Swagger (ToParamSchema (..))
import qualified Data.Swagger as S
import qualified Data.Swagger.Build.Api as Doc
import qualified Data.Text as T
import Data.Text.Ascii (AsciiBase64Url, toText, validateBase64Url)
import Imports
import Servant.API (FromHttpApiData)
import Servant.API (FromHttpApiData, ToHttpApiData (..))
import Web.Internal.HttpApiData (parseQueryParam)
import Wire.API.Team.Role (Role)
import Wire.API.User (ManagedBy)
import Wire.API.User.Identity (Email (..))
import Wire.Arbitrary (Arbitrary, GenericUniform (..))

-------------------------------------------------------------------------------
-- PagingState

newtype PagingState = PagingState {unPagingState :: AsciiBase64Url}
deriving newtype (Eq, Show, Arbitrary)
deriving (ToJSON, FromJSON, S.ToSchema) via Schema PagingState

instance ToSchema PagingState where
schema = (toText . unPagingState) .= parsedText "PagingState" (fmap PagingState . validateBase64Url)

instance ToParamSchema PagingState where
toParamSchema _ = toParamSchema (Proxy @Text)

instance FromHttpApiData PagingState where
parseQueryParam s = mapLeft cs $ PagingState <$> validateBase64Url s

instance ToHttpApiData PagingState where
toQueryParam = toText . unPagingState

instance ToByteString PagingState where
builder = builder . unPagingState

instance FromByteString PagingState where
parser = fmap PagingState parser

--------------------------------------------------------------------------------
-- SearchResult

Expand All @@ -67,7 +98,8 @@ data SearchResult a = SearchResult
searchReturned :: Int,
searchTook :: Int,
searchResults :: [a],
searchPolicy :: FederatedUserSearchPolicy
searchPolicy :: FederatedUserSearchPolicy,
searchPagingState :: Maybe PagingState
}
deriving stock (Eq, Show, Generic, Functor)
deriving (Arbitrary) via (GenericUniform (SearchResult a))
Expand All @@ -89,6 +121,7 @@ instance ToSchema a => ToSchema (SearchResult a) where
<*> searchTook .= fieldWithDocModifier "took" (S.description ?~ "Search time in ms") schema
<*> searchResults .= fieldWithDocModifier "documents" (S.description ?~ "List of contacts found") (array schema)
<*> searchPolicy .= fieldWithDocModifier "search_policy" (S.description ?~ "Search policy that was applied when searching for users") schema
<*> searchPagingState .= maybe_ (optFieldWithDocModifier "paging_state" (S.description ?~ "Paging state for the next page of results") schema)

deriving via (Schema (SearchResult Contact)) instance ToJSON (SearchResult Contact)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,29 @@ import Data.Id (Id (Id))
import Data.Qualified (Qualified (Qualified, qDomain, qUnqualified))
import qualified Data.UUID as UUID (fromString)
import Imports (Maybe (Just, Nothing), fromJust)
import Wire.API.User.Search (Contact (..), FederatedUserSearchPolicy (ExactHandleSearch, FullSearch), SearchResult (..))
import Wire.API.User.Search (Contact (..), FederatedUserSearchPolicy (ExactHandleSearch, FullSearch), PagingState (..), SearchResult (..))

testObject_SearchResult_20Contact_user_1 :: SearchResult Contact
testObject_SearchResult_20Contact_user_1 =
SearchResult {searchFound = -6, searchReturned = 0, searchTook = 1, searchResults = [], searchPolicy = FullSearch}
SearchResult
{ searchFound = -6,
searchReturned = 0,
searchTook = 1,
searchResults = [],
searchPolicy = FullSearch,
searchPagingState = Just (PagingState "WzE2Njk5OTQ5MzIyNjdd")
}

testObject_SearchResult_20Contact_user_2 :: SearchResult Contact
testObject_SearchResult_20Contact_user_2 =
SearchResult {searchFound = -4, searchReturned = 6, searchTook = -5, searchResults = [], searchPolicy = FullSearch}
SearchResult
{ searchFound = -4,
searchReturned = 6,
searchTook = -5,
searchResults = [],
searchPolicy = FullSearch,
searchPagingState = Nothing
}

testObject_SearchResult_20Contact_user_3 :: SearchResult Contact
testObject_SearchResult_20Contact_user_3 =
Expand All @@ -53,7 +67,8 @@ testObject_SearchResult_20Contact_user_3 =
contactTeam = Just (Id (fromJust (UUID.fromString "00000000-0000-0000-0000-000100000000")))
}
],
searchPolicy = FullSearch
searchPolicy = FullSearch,
searchPagingState = Nothing
}

testObject_SearchResult_20Contact_user_4 :: SearchResult Contact
Expand Down Expand Up @@ -130,7 +145,8 @@ testObject_SearchResult_20Contact_user_4 =
contactTeam = Just (Id (fromJust (UUID.fromString "00000000-0000-0000-0000-000000000000")))
}
],
searchPolicy = FullSearch
searchPolicy = FullSearch,
searchPagingState = Nothing
}

testObject_SearchResult_20Contact_user_5 :: SearchResult Contact
Expand All @@ -152,12 +168,20 @@ testObject_SearchResult_20Contact_user_5 =
contactTeam = Just (Id (fromJust (UUID.fromString "00000001-0000-0000-0000-000100000001")))
}
],
searchPolicy = FullSearch
searchPolicy = FullSearch,
searchPagingState = Nothing
}

testObject_SearchResult_20Contact_user_6 :: SearchResult Contact
testObject_SearchResult_20Contact_user_6 =
SearchResult {searchFound = -5, searchReturned = -4, searchTook = 5, searchResults = [], searchPolicy = FullSearch}
SearchResult
{ searchFound = -5,
searchReturned = -4,
searchTook = 5,
searchResults = [],
searchPolicy = FullSearch,
searchPagingState = Nothing
}

testObject_SearchResult_20Contact_user_7 :: SearchResult Contact
testObject_SearchResult_20Contact_user_7 =
Expand Down Expand Up @@ -189,7 +213,8 @@ testObject_SearchResult_20Contact_user_7 =
contactTeam = Just (Id (fromJust (UUID.fromString "00000000-0000-0001-0000-000100000000")))
}
],
searchPolicy = FullSearch
searchPolicy = FullSearch,
searchPagingState = Nothing
}

testObject_SearchResult_20Contact_user_8 :: SearchResult Contact
Expand All @@ -211,16 +236,31 @@ testObject_SearchResult_20Contact_user_8 =
contactTeam = Just (Id (fromJust (UUID.fromString "00000000-0000-0001-0000-000100000000")))
}
],
searchPolicy = FullSearch
searchPolicy = FullSearch,
searchPagingState = Nothing
}

testObject_SearchResult_20Contact_user_9 :: SearchResult Contact
testObject_SearchResult_20Contact_user_9 =
SearchResult {searchFound = -5, searchReturned = -6, searchTook = 3, searchResults = [], searchPolicy = FullSearch}
SearchResult
{ searchFound = -5,
searchReturned = -6,
searchTook = 3,
searchResults = [],
searchPolicy = FullSearch,
searchPagingState = Nothing
}

testObject_SearchResult_20Contact_user_10 :: SearchResult Contact
testObject_SearchResult_20Contact_user_10 =
SearchResult {searchFound = 0, searchReturned = -7, searchTook = -5, searchResults = [], searchPolicy = FullSearch}
SearchResult
{ searchFound = 0,
searchReturned = -7,
searchTook = -5,
searchResults = [],
searchPolicy = FullSearch,
searchPagingState = Nothing
}

testObject_SearchResult_20Contact_user_11 :: SearchResult Contact
testObject_SearchResult_20Contact_user_11 =
Expand Down Expand Up @@ -252,12 +292,20 @@ testObject_SearchResult_20Contact_user_11 =
contactTeam = Nothing
}
],
searchPolicy = ExactHandleSearch
searchPolicy = ExactHandleSearch,
searchPagingState = Nothing
}

testObject_SearchResult_20Contact_user_12 :: SearchResult Contact
testObject_SearchResult_20Contact_user_12 =
SearchResult {searchFound = 7, searchReturned = 5, searchTook = 3, searchResults = [], searchPolicy = ExactHandleSearch}
SearchResult
{ searchFound = 7,
searchReturned = 5,
searchTook = 3,
searchResults = [],
searchPolicy = ExactHandleSearch,
searchPagingState = Nothing
}

testObject_SearchResult_20Contact_user_13 :: SearchResult Contact
testObject_SearchResult_20Contact_user_13 =
Expand Down Expand Up @@ -311,7 +359,8 @@ testObject_SearchResult_20Contact_user_13 =
contactTeam = Nothing
}
],
searchPolicy = ExactHandleSearch
searchPolicy = ExactHandleSearch,
searchPagingState = Nothing
}

testObject_SearchResult_20Contact_user_14 :: SearchResult Contact
Expand Down Expand Up @@ -344,24 +393,53 @@ testObject_SearchResult_20Contact_user_14 =
contactTeam = Nothing
}
],
searchPolicy = ExactHandleSearch
searchPolicy = ExactHandleSearch,
searchPagingState = Nothing
}

testObject_SearchResult_20Contact_user_15 :: SearchResult Contact
testObject_SearchResult_20Contact_user_15 =
SearchResult {searchFound = 3, searchReturned = 2, searchTook = 4, searchResults = [], searchPolicy = ExactHandleSearch}
SearchResult
{ searchFound = 3,
searchReturned = 2,
searchTook = 4,
searchResults = [],
searchPolicy = ExactHandleSearch,
searchPagingState = Nothing
}

testObject_SearchResult_20Contact_user_16 :: SearchResult Contact
testObject_SearchResult_20Contact_user_16 =
SearchResult {searchFound = -4, searchReturned = 4, searchTook = -7, searchResults = [], searchPolicy = ExactHandleSearch}
SearchResult
{ searchFound = -4,
searchReturned = 4,
searchTook = -7,
searchResults = [],
searchPolicy = ExactHandleSearch,
searchPagingState = Nothing
}

testObject_SearchResult_20Contact_user_17 :: SearchResult Contact
testObject_SearchResult_20Contact_user_17 =
SearchResult {searchFound = 6, searchReturned = -1, searchTook = -1, searchResults = [], searchPolicy = ExactHandleSearch}
SearchResult
{ searchFound = 6,
searchReturned = -1,
searchTook = -1,
searchResults = [],
searchPolicy = ExactHandleSearch,
searchPagingState = Nothing
}

testObject_SearchResult_20Contact_user_18 :: SearchResult Contact
testObject_SearchResult_20Contact_user_18 =
SearchResult {searchFound = -4, searchReturned = 0, searchTook = -5, searchResults = [], searchPolicy = ExactHandleSearch}
SearchResult
{ searchFound = -4,
searchReturned = 0,
searchTook = -5,
searchResults = [],
searchPolicy = ExactHandleSearch,
searchPagingState = Nothing
}

testObject_SearchResult_20Contact_user_19 :: SearchResult Contact
testObject_SearchResult_20Contact_user_19 =
Expand Down Expand Up @@ -393,7 +471,8 @@ testObject_SearchResult_20Contact_user_19 =
contactTeam = Just (Id (fromJust (UUID.fromString "00000000-0000-0000-0000-000000000001")))
}
],
searchPolicy = ExactHandleSearch
searchPolicy = ExactHandleSearch,
searchPagingState = Nothing
}

testObject_SearchResult_20Contact_user_20 :: SearchResult Contact
Expand Down Expand Up @@ -547,5 +626,6 @@ testObject_SearchResult_20Contact_user_20 =
contactTeam = Just (Id (fromJust (UUID.fromString "00000000-0000-0001-0000-000100000000")))
}
],
searchPolicy = ExactHandleSearch
searchPolicy = ExactHandleSearch,
searchPagingState = Nothing
}
Loading

0 comments on commit 1518191

Please sign in to comment.