Skip to content

Commit 6765c65

Browse files
committed
Create endpoint for getting handle info by qualified handle
Federation is not implemented yet, so remote handles will always return 404.
1 parent 02f948d commit 6765c65

File tree

3 files changed

+68
-28
lines changed

3 files changed

+68
-28
lines changed

libs/types-common/src/Data/Handle.hs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@ where
2828

2929
import Data.Aeson hiding ((<?>))
3030
import qualified Data.Attoparsec.ByteString.Char8 as Atto
31+
import Data.Bifunctor (Bifunctor (first))
3132
import qualified Data.ByteString as BS
3233
import Data.ByteString.Conversion (FromByteString (parser), ToByteString)
3334
import Data.Hashable (Hashable)
34-
import Data.Swagger (ToSchema (..))
35+
import Data.Swagger (ToParamSchema, ToSchema (..))
3536
import qualified Data.Text as Text
3637
import qualified Data.Text.Encoding as Text.E
3738
import Imports
39+
import Servant (FromHttpApiData (..))
3840
import Test.QuickCheck (Arbitrary (arbitrary), choose, elements, oneof)
3941
import Util.Attoparsec (takeUpToWhile)
4042

@@ -45,7 +47,11 @@ import Util.Attoparsec (takeUpToWhile)
4547
newtype Handle = Handle
4648
{fromHandle :: Text}
4749
deriving stock (Eq, Show, Generic)
48-
deriving newtype (ToJSON, ToByteString, Hashable, ToSchema)
50+
deriving newtype (ToJSON, ToByteString, Hashable, ToSchema, ToParamSchema)
51+
52+
instance FromHttpApiData Handle where
53+
parseUrlPiece =
54+
first Text.pack . parseHandleEither
4955

5056
instance FromByteString Handle where
5157
parser = handleParser

libs/wire-api/src/Wire/API/User/Handle.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ where
3232
import Data.Aeson
3333
import Data.Id (UserId)
3434
import Data.Range
35+
import Data.Swagger (ToSchema)
3536
import qualified Data.Swagger.Build.Api as Doc
37+
import Deriving.Swagger (CustomSwagger, FieldLabelModifier, LabelMapping ((:->)), LabelMappings)
3638
import Imports
3739
import Wire.API.Arbitrary (Arbitrary, GenericUniform (..))
3840

@@ -42,6 +44,7 @@ import Wire.API.Arbitrary (Arbitrary, GenericUniform (..))
4244
newtype UserHandleInfo = UserHandleInfo {userHandleId :: UserId}
4345
deriving stock (Eq, Show, Generic)
4446
deriving newtype (Arbitrary)
47+
deriving (ToSchema) via (CustomSwagger '[FieldLabelModifier (LabelMappings '["userHandleId" ':-> "user"])] UserHandleInfo)
4548

4649
modelUserHandleInfo :: Doc.Model
4750
modelUserHandleInfo = Doc.defineModel "UserHandleInfo" $ do

services/brig/src/Brig/API/Public.hs

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -224,12 +224,41 @@ type GetSelf =
224224
:> "self"
225225
:> Get '[Servant.JSON] Public.SelfProfile
226226

227+
-- See Note [document responses]
228+
-- The responses looked like this:
229+
-- Doc.returns (Doc.ref Public.modelUserHandleInfo)
230+
-- Doc.response 200 "Handle info" Doc.end
231+
-- Doc.errorResponse handleNotFound
232+
type GetHandleInfoUnqualified =
233+
Summary "Get information on a user handle"
234+
:> ZAuthServant
235+
:> "users"
236+
:> "handles"
237+
:> Capture' '[Description "The user handle"] "handle" Handle
238+
:> Get '[Servant.JSON] Public.UserHandleInfo
239+
240+
-- See Note [document responses]
241+
-- The responses looked like this:
242+
-- Doc.returns (Doc.ref Public.modelUserHandleInfo)
243+
-- Doc.response 200 "Handle info" Doc.end
244+
-- Doc.errorResponse handleNotFound
245+
type GetHandleInfoQualified =
246+
Summary "Get information on a user handle"
247+
:> ZAuthServant
248+
:> "users"
249+
:> "handles"
250+
:> Capture "domain" Domain
251+
:> Capture' '[Description "The user handle"] "handle" Handle
252+
:> Get '[Servant.JSON] Public.UserHandleInfo
253+
227254
type OutsideWorldAPI =
228255
CheckUserExistsUnqualified
229256
:<|> CheckUserExistsQualified
230257
:<|> GetUserUnqualified
231258
:<|> GetUserQualified
232259
:<|> GetSelf
260+
:<|> GetHandleInfoUnqualified
261+
:<|> GetHandleInfoQualified
233262

234263
type SwaggerDocsAPI = "api" :> SwaggerSchemaUI "swagger-ui" "swagger.json"
235264

@@ -253,6 +282,8 @@ servantSitemap =
253282
:<|> getUserUnqualifiedH
254283
:<|> getUserH
255284
:<|> getSelf
285+
:<|> getHandleInfoUnqualifiedH
286+
:<|> getHandleInfoH
256287

257288
-- Note [ephemeral user sideeffect]
258289
-- If the user is ephemeral and expired, it will be removed upon calling
@@ -287,18 +318,7 @@ sitemap o = do
287318
Doc.errorResponse invalidHandle
288319
Doc.errorResponse handleNotFound
289320

290-
get "/users/handles/:handle" (continue getHandleInfoH) $
291-
accept "application" "json"
292-
.&. zauthUserId
293-
.&. capture "handle"
294-
document "GET" "getUserHandleInfo" $ do
295-
Doc.summary "Get information on a user handle"
296-
Doc.parameter Doc.Path "handle" Doc.bytes' $
297-
Doc.description "The user handle"
298-
Doc.returns (Doc.ref Public.modelUserHandleInfo)
299-
Doc.response 200 "Handle info" Doc.end
300-
Doc.errorResponse handleNotFound
301-
321+
-- some APIs moved to servant
302322
-- end User Handle API
303323

304324
-- If the user is ephemeral and expired, it will be removed, see 'Brig.API.User.userGC'.
@@ -1297,23 +1317,34 @@ checkHandlesH (_ ::: _ ::: req) = do
12971317
free <- lift $ API.checkHandles handles (fromRange num)
12981318
return $ json (free :: [Handle])
12991319

1300-
getHandleInfoH :: JSON ::: UserId ::: Handle -> Handler Response
1301-
getHandleInfoH (_ ::: self ::: handle) =
1302-
maybe (setStatus status404 empty) json
1303-
<$> getHandleInfo self handle
1320+
getHandleInfoUnqualifiedH :: UserId -> Handle -> Handler Public.UserHandleInfo
1321+
getHandleInfoUnqualifiedH self handle = do
1322+
domain <- API.viewFederationDomain
1323+
getHandleInfoH self domain handle
1324+
1325+
getHandleInfoH :: UserId -> Domain -> Handle -> Handler Public.UserHandleInfo
1326+
getHandleInfoH self domain handle =
1327+
ifNothing (notFound "handle not found")
1328+
=<< getHandleInfo self (Qualified handle domain)
13041329

13051330
-- FUTUREWORK: use 'runMaybeT' to simplify this.
1306-
getHandleInfo :: UserId -> Handle -> Handler (Maybe Public.UserHandleInfo)
1331+
getHandleInfo :: UserId -> Qualified Handle -> Handler (Maybe Public.UserHandleInfo)
13071332
getHandleInfo self handle = do
1308-
ownerProfile <- do
1309-
-- FUTUREWORK(federation, #1268): resolve qualified handles, too
1310-
domain <- viewFederationDomain
1311-
maybeOwnerId <- fmap (flip Qualified domain) <$> (lift $ API.lookupHandle handle)
1312-
case maybeOwnerId of
1313-
Just ownerId -> lift $ API.lookupProfile self ownerId
1314-
Nothing -> return Nothing
1315-
owner <- filterHandleResults self (maybeToList ownerProfile)
1316-
return $ Public.UserHandleInfo . Public.profileId <$> listToMaybe owner
1333+
domain <- API.viewFederationDomain
1334+
if _qDomain handle == domain
1335+
then getLocalHandleInfo domain
1336+
else getRemoteHandleInfo
1337+
where
1338+
getLocalHandleInfo domain = do
1339+
maybeOwnerId <- lift $ API.lookupHandle (_qLocalPart handle)
1340+
case maybeOwnerId of
1341+
Nothing -> return Nothing
1342+
Just ownerId -> do
1343+
ownerProfile <- lift $ API.lookupProfile self (Qualified ownerId domain)
1344+
owner <- filterHandleResults self (maybeToList ownerProfile)
1345+
return $ Public.UserHandleInfo . Public.profileId <$> listToMaybe owner
1346+
-- FUTUREWORK: Federate with remote backends
1347+
getRemoteHandleInfo = return Nothing
13171348

13181349
changeHandleH :: UserId ::: ConnId ::: JsonRequest Public.HandleUpdate -> Handler Response
13191350
changeHandleH (u ::: conn ::: req) = do

0 commit comments

Comments
 (0)