Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SQSERVICES-1773] Allow pagination for team search endpoint #2895

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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