From 368b0461bc14044d153e2c4455cb2329843b17d9 Mon Sep 17 00:00:00 2001 From: Paolo Capriotti Date: Mon, 11 Nov 2024 13:26:05 +0100 Subject: [PATCH] Preserve old invitation behaviour in v6 (#4336) * Add allowExisting field to invitation request * Honor allowExisting flag in InvitationRequest * Test legacy invitation behaviour * Add CHANGELOG entry * Update golden tests --- changelog.d/1-api-changes/invitation | 1 + integration/test/Test/Teams.hs | 20 ++++++ .../src/Wire/API/Routes/Public/Brig.hs | 33 +++++++++- libs/wire-api/src/Wire/API/Team/Invitation.hs | 37 +++++++---- .../Generated/InvitationRequest_team.hs | 62 ++++++++++++------- .../testObject_InvitationRequest_team_1.json | 1 + .../testObject_InvitationRequest_team_10.json | 1 + .../testObject_InvitationRequest_team_11.json | 1 + .../testObject_InvitationRequest_team_12.json | 1 + .../testObject_InvitationRequest_team_13.json | 1 + .../testObject_InvitationRequest_team_14.json | 1 + .../testObject_InvitationRequest_team_15.json | 1 + .../testObject_InvitationRequest_team_16.json | 1 + .../testObject_InvitationRequest_team_17.json | 1 + .../testObject_InvitationRequest_team_18.json | 1 + .../testObject_InvitationRequest_team_19.json | 1 + .../testObject_InvitationRequest_team_2.json | 1 + .../testObject_InvitationRequest_team_20.json | 1 + .../testObject_InvitationRequest_team_3.json | 1 + .../testObject_InvitationRequest_team_4.json | 1 + .../testObject_InvitationRequest_team_5.json | 1 + .../testObject_InvitationRequest_team_6.json | 1 + .../testObject_InvitationRequest_team_7.json | 1 + .../testObject_InvitationRequest_team_8.json | 1 + .../testObject_InvitationRequest_team_9.json | 1 + .../TeamInvitationSubsystem/Interpreter.hs | 10 +-- services/brig/src/Brig/Team/API.hs | 6 +- .../brig/test/integration/API/Team/Util.hs | 2 +- services/galley/test/integration/API/Util.hs | 2 +- services/spar/test-integration/Util/Core.hs | 2 +- tools/stern/test/integration/Util.hs | 2 +- 31 files changed, 152 insertions(+), 45 deletions(-) create mode 100644 changelog.d/1-api-changes/invitation diff --git a/changelog.d/1-api-changes/invitation b/changelog.d/1-api-changes/invitation new file mode 100644 index 00000000000..517345b4224 --- /dev/null +++ b/changelog.d/1-api-changes/invitation @@ -0,0 +1 @@ +The endpoint `POST /teams/:tid/invitations` gained a new optional field `allow_existing`, which controls whether an existing personal user should should be invited to the team diff --git a/integration/test/Test/Teams.hs b/integration/test/Test/Teams.hs index 0633463ca16..200f7758fca 100644 --- a/integration/test/Test/Teams.hs +++ b/integration/test/Test/Teams.hs @@ -237,6 +237,26 @@ testInvitePersonalUserToTeamMultipleInvitations = do resp.json %. "team" `shouldMatch` tid acceptTeamInvitation user code (Just defPassword) >>= assertStatus 400 +testInvitePersonalUserToTeamLegacy :: (HasCallStack) => App () +testInvitePersonalUserToTeamLegacy = withAPIVersion 6 $ do + (owner, tid, _) <- createTeam OwnDomain 0 + user <- I.createUser OwnDomain def >>= getJSON 201 + + -- inviting an existing user should fail + do + email <- user %. "email" >>= asString + bindResponse (postInvitation owner (PostInvitation (Just email) Nothing)) $ \resp -> do + resp.status `shouldMatchInt` 409 + resp.json %. "label" `shouldMatch` "email-exists" + + -- inviting a new user should succeed + do + email <- randomEmail + bindResponse (postInvitation owner (PostInvitation (Just email) Nothing)) $ \resp -> do + resp.status `shouldMatchInt` 201 + resp.json %. "email" `shouldMatch` email + resp.json %. "team" `shouldMatch` tid + testInvitationTypesAreDistinct :: (HasCallStack) => App () testInvitationTypesAreDistinct = do -- We are only testing one direction because the other is not possible diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Brig.hs b/libs/wire-api/src/Wire/API/Routes/Public/Brig.hs index c08b688d032..9895edccc97 100644 --- a/libs/wire-api/src/Wire/API/Routes/Public/Brig.hs +++ b/libs/wire-api/src/Wire/API/Routes/Public/Brig.hs @@ -1546,8 +1546,9 @@ type CallingAPI = type TeamsAPI = Named - "send-team-invitation" + "send-team-invitation@v6" ( Summary "Create and send a new team invitation." + :> Until V7 :> Description "Invitations are sent by email. The maximum allowed number of \ \pending team invitations is equal to the team size." @@ -1562,7 +1563,7 @@ type TeamsAPI = :> "teams" :> Capture "tid" TeamId :> "invitations" - :> ReqBody '[JSON] InvitationRequest + :> VersionedReqBody V6 '[JSON] InvitationRequest :> MultiVerb1 'POST '[JSON] @@ -1572,6 +1573,34 @@ type TeamsAPI = (Respond 201 "Invitation was created and sent." Invitation) ) ) + :<|> Named + "send-team-invitation" + ( Summary "Create and send a new team invitation." + :> From V7 + :> Description + "Invitations are sent by email. The maximum allowed number of \ + \pending team invitations is equal to the team size." + :> CanThrow 'NoEmail + :> CanThrow 'NoIdentity + :> CanThrow 'InvalidEmail + :> CanThrow 'BlacklistedEmail + :> CanThrow 'TooManyTeamInvitations + :> CanThrow 'InsufficientTeamPermissions + :> CanThrow 'InvalidInvitationCode + :> ZLocalUser + :> "teams" + :> Capture "tid" TeamId + :> "invitations" + :> ReqBody '[JSON] InvitationRequest + :> MultiVerb1 + 'POST + '[JSON] + ( WithHeaders + '[Header "Location" InvitationLocation] + (Invitation, InvitationLocation) + (Respond 201 "Invitation was created and sent." Invitation) + ) + ) :<|> Named "get-team-invitations" ( Summary "List the sent team invitations" diff --git a/libs/wire-api/src/Wire/API/Team/Invitation.hs b/libs/wire-api/src/Wire/API/Team/Invitation.hs index 5c5b5c455a5..96d268c8258 100644 --- a/libs/wire-api/src/Wire/API/Team/Invitation.hs +++ b/libs/wire-api/src/Wire/API/Team/Invitation.hs @@ -46,6 +46,8 @@ import URI.ByteString import Wire.API.Error import Wire.API.Error.Brig import Wire.API.Routes.MultiVerb +import Wire.API.Routes.Version +import Wire.API.Routes.Versioned import Wire.API.Team.Role (Role, defaultRole) import Wire.API.User import Wire.Arbitrary (Arbitrary, GenericUniform (..)) @@ -57,24 +59,35 @@ data InvitationRequest = InvitationRequest { locale :: Maybe Locale, role :: Maybe Role, inviteeName :: Maybe Name, - inviteeEmail :: EmailAddress + inviteeEmail :: EmailAddress, + allowExisting :: Bool } deriving stock (Eq, Show, Generic) deriving (Arbitrary) via (GenericUniform InvitationRequest) deriving (A.FromJSON, A.ToJSON, S.ToSchema) via (Schema InvitationRequest) +instance ToSchema (Versioned V6 InvitationRequest) where + schema = Versioned <$> unVersioned .= invitationRequestSchema False + instance ToSchema InvitationRequest where - schema = - objectWithDocModifier "InvitationRequest" (description ?~ "A request to join a team on Wire.") $ - InvitationRequest - <$> locale - .= optFieldWithDocModifier "locale" (description ?~ "Locale to use for the invitation.") (maybeWithDefault A.Null schema) - <*> (.role) - .= optFieldWithDocModifier "role" (description ?~ "Role of the invitee (invited user).") (maybeWithDefault A.Null schema) - <*> (.inviteeName) - .= optFieldWithDocModifier "name" (description ?~ "Name of the invitee (1 - 128 characters).") (maybeWithDefault A.Null schema) - <*> (.inviteeEmail) - .= fieldWithDocModifier "email" (description ?~ "Email of the invitee.") schema + schema = invitationRequestSchema True + +invitationRequestSchema :: Bool -> ValueSchema NamedSwaggerDoc InvitationRequest +invitationRequestSchema allowExisting = + objectWithDocModifier "InvitationRequest" (description ?~ "A request to join a team on Wire.") $ + InvitationRequest + <$> locale + .= optFieldWithDocModifier "locale" (description ?~ "Locale to use for the invitation.") (maybeWithDefault A.Null schema) + <*> (.role) + .= optFieldWithDocModifier "role" (description ?~ "Role of the invitee (invited user).") (maybeWithDefault A.Null schema) + <*> (.inviteeName) + .= optFieldWithDocModifier "name" (description ?~ "Name of the invitee (1 - 128 characters).") (maybeWithDefault A.Null schema) + <*> (.inviteeEmail) + .= fieldWithDocModifier "email" (description ?~ "Email of the invitee.") schema + <*> (.allowExisting) + .= ( fromMaybe allowExisting + <$> optFieldWithDocModifier "allow_existing" (description ?~ "Whether invitations to existing users are allowed.") schema + ) -------------------------------------------------------------------------------- -- Invitation diff --git a/libs/wire-api/test/golden/Test/Wire/API/Golden/Generated/InvitationRequest_team.hs b/libs/wire-api/test/golden/Test/Wire/API/Golden/Generated/InvitationRequest_team.hs index f9f7c8ca50a..1987a7369a5 100644 --- a/libs/wire-api/test/golden/Test/Wire/API/Golden/Generated/InvitationRequest_team.hs +++ b/libs/wire-api/test/golden/Test/Wire/API/Golden/Generated/InvitationRequest_team.hs @@ -19,7 +19,7 @@ module Test.Wire.API.Golden.Generated.InvitationRequest_team where import Data.ISO3166_CountryCodes (CountryCode (BJ, FJ, GH, LB, ME, NL, OM, PA, TC, TZ)) import Data.LanguageCodes qualified (ISO639_1 (AF, AR, DA, DV, KJ, KS, KU, LG, NN, NY, OM, SI)) -import Imports (Maybe (Just, Nothing)) +import Imports import Wire.API.Locale import Wire.API.Team.Invitation (InvitationRequest (..)) import Wire.API.Team.Role (Role (RoleAdmin, RoleExternalPartner, RoleMember, RoleOwner)) @@ -32,7 +32,8 @@ testObject_InvitationRequest_team_1 = { locale = Just (Locale {lLanguage = Language Data.LanguageCodes.NN, lCountry = Nothing}), role = Just RoleOwner, inviteeName = Nothing, - inviteeEmail = unsafeEmailAddress "some" "example" + inviteeEmail = unsafeEmailAddress "some" "example", + allowExisting = True } testObject_InvitationRequest_team_2 :: InvitationRequest @@ -42,7 +43,8 @@ testObject_InvitationRequest_team_2 = Just (Locale {lLanguage = Language Data.LanguageCodes.AF, lCountry = Just (Country {fromCountry = GH})}), role = Nothing, inviteeName = Nothing, - inviteeEmail = unsafeEmailAddress "some" "example" + inviteeEmail = unsafeEmailAddress "some" "example", + allowExisting = False } testObject_InvitationRequest_team_3 :: InvitationRequest @@ -58,7 +60,8 @@ testObject_InvitationRequest_team_3 = "\27175\1085444\v\182035\144967G\189107\1042607\ETX\180573\1047918\ETX\1075522ZG\1087064\STX+i\46576Ux\FS\FS5\ESC\ae\10301\36223(3\1009347\\\t\EOT\v@\ENQs\r#R\136368G'N^?\NAKB\f\FS\NULx\1024041@\34031\1105463\1058551`A]@\34846\133788*\1025332N;\ETX\FSh\bS\US\US\SO`^qU<\21803\SYN\1094791\ETX\1112073M\SI\1019355\4619=zM[\181520\161190\n\SI}\ENQ\1008012\aaZI\18628\ACKE#G^t\148685\DLE\157774LY\182624\&6vt\\" } ), - inviteeEmail = unsafeEmailAddress "some" "example" + inviteeEmail = unsafeEmailAddress "some" "example", + allowExisting = False } testObject_InvitationRequest_team_4 :: InvitationRequest @@ -67,7 +70,8 @@ testObject_InvitationRequest_team_4 = { locale = Nothing, role = Just RoleMember, inviteeName = Nothing, - inviteeEmail = unsafeEmailAddress "some" "example" + inviteeEmail = unsafeEmailAddress "some" "example", + allowExisting = True } testObject_InvitationRequest_team_5 :: InvitationRequest @@ -76,7 +80,8 @@ testObject_InvitationRequest_team_5 = { locale = Nothing, role = Just RoleAdmin, inviteeName = Just (Name {fromName = "\171800\1076860\1103443\CAN8=\n;}\169054M\ao\v3+\n"}), - inviteeEmail = unsafeEmailAddress "some" "example" + inviteeEmail = unsafeEmailAddress "some" "example", + allowExisting = True } testObject_InvitationRequest_team_6 :: InvitationRequest @@ -92,7 +97,8 @@ testObject_InvitationRequest_team_6 = "\RSD[alw\RS\ACKP \999760\rO\175510'8\989959\1082925g W:8\v:-(`+\131521\ESC_\CAN\1105214\44926(\"&\DC2NZ\1082341\ACKS\SYNLOW|p\EM\194645\&1\175388" } ), - inviteeEmail = unsafeEmailAddress "some" "example" + inviteeEmail = unsafeEmailAddress "some" "example", + allowExisting = True } testObject_InvitationRequest_team_7 :: InvitationRequest @@ -101,7 +107,8 @@ testObject_InvitationRequest_team_7 = { locale = Nothing, role = Just RoleAdmin, inviteeName = Nothing, - inviteeEmail = unsafeEmailAddress "some" "example" + inviteeEmail = unsafeEmailAddress "some" "example", + allowExisting = True } testObject_InvitationRequest_team_8 :: InvitationRequest @@ -112,7 +119,8 @@ testObject_InvitationRequest_team_8 = role = Nothing, inviteeName = Just (Name {fromName = "\1036838&f\1104978\1021739j5\CANv]k\1034960\993099c[\1019257\1047325\EOTw.uL~/"}), - inviteeEmail = unsafeEmailAddress "some" "example" + inviteeEmail = unsafeEmailAddress "some" "example", + allowExisting = False } testObject_InvitationRequest_team_9 :: InvitationRequest @@ -123,7 +131,8 @@ testObject_InvitationRequest_team_9 = role = Just RoleAdmin, inviteeName = Just (Name {fromName = "|H\181717/%\RSu\1019619\&7V\142010\62451*G\SOHE\993531,\1015423WGtY\SYN*Nd\156695{Pl"}), - inviteeEmail = unsafeEmailAddress "some" "example" + inviteeEmail = unsafeEmailAddress "some" "example", + allowExisting = False } testObject_InvitationRequest_team_10 :: InvitationRequest @@ -139,7 +148,8 @@ testObject_InvitationRequest_team_10 = "H\1008404\RS\45861\92335uv\1045159\DC2\1045852\SUB \160164=a\ESC4H,B\CAN\1039540GpV0\1044935;_\NUL\173370Z\DC1\28376\NAK6\32784'W9z\11986\t\59610r\150374\1057016\SYN_ge\35917\EOTD\94732o\an>\993583" } ), - inviteeEmail = unsafeEmailAddress "some" "example" + inviteeEmail = unsafeEmailAddress "some" "example", + allowExisting = False } testObject_InvitationRequest_team_11 :: InvitationRequest @@ -154,7 +164,8 @@ testObject_InvitationRequest_team_11 = "\167004\41433\11577\74832h_5bb2}\46841\166935P\NUL\SOT*\US`b\170964\SI:4\n5\SUB\GS*T\1016149Bv\ESC\ETX\GS\1050773\175887Uu\r_\DLE)y\153990\EOT\b\US\DC4\FS\CAN?\1050027\149716\22398\NAK\SUB4\v 5\NULi\43113o=\tnG\37464\ETBiC\DC39\SOP\1026840\n\v\EM\SYNU\7800%\49334\DC2\USF\FS" } ), - inviteeEmail = unsafeEmailAddress "some" "example" + inviteeEmail = unsafeEmailAddress "some" "example", + allowExisting = False } testObject_InvitationRequest_team_12 :: InvitationRequest @@ -170,7 +181,8 @@ testObject_InvitationRequest_team_12 = "_\EM@\GS0\52658\1041209\1014911\FS\DLE\1100406!\1081838\SOc\US\NUL\SOH>\1074611\168456\EM\175538\&1}!h0\DLE\1053201w\EOT\1073681\&1aJ6c\GS\986890b\131925{\996638\131443\a\1094281" } ), - inviteeEmail = unsafeEmailAddress "some" "example" + inviteeEmail = unsafeEmailAddress "some" "example", + allowExisting = True } testObject_InvitationRequest_team_13 :: InvitationRequest @@ -185,7 +197,8 @@ testObject_InvitationRequest_team_13 = "C\990664+\1033671\n#s\1072813\FSpb\SOH\1015233\1073302\&1\ETBE_\CANj\EMV\US\1063126\15431\1099470lO8\ACK\1056562\FS\SYN\CAN\DLE6\137862-beR!s\48584\ETB\v\1049375\984016xt\SIRf~w\1030329\DEL+_\70046\&91:,\1034030#cf\1056279\3624\2548\6959B\"\1097722F\t\1109914\1069782/\DEL\DLE'\1004715*\171262\&7\156200w\1061410H\59715x\DC32\EMt\163668o6\DC4F%=t\1003324\1097336=\NUL\ENQA\1101771\1011923\NUL\EOT[i\992519@\b\FS\f" } ), - inviteeEmail = unsafeEmailAddress "some" "example" + inviteeEmail = unsafeEmailAddress "some" "example", + allowExisting = True } testObject_InvitationRequest_team_14 :: InvitationRequest @@ -195,7 +208,8 @@ testObject_InvitationRequest_team_14 = Just (Locale {lLanguage = Language Data.LanguageCodes.DV, lCountry = Just (Country {fromCountry = LB})}), role = Just RoleAdmin, inviteeName = Just (Name {fromName = "\NAKwGn\996611\149528\&1}\EOTgY.>=}"}), - inviteeEmail = unsafeEmailAddress "some" "example" + inviteeEmail = unsafeEmailAddress "some" "example", + allowExisting = True } testObject_InvitationRequest_team_15 :: InvitationRequest @@ -210,7 +224,8 @@ testObject_InvitationRequest_team_15 = "y\1104714\&5\1000317\710S\1019005\DC4\rH/_\DC3A\ETX\119343\&0w\GS?TQd*1&[?cHW}\21482\1021206\CAN\180566Q+\ETXmh\995371X\SO\ENQ\DC1^g\144398\bqrNV\SO\1095058WMe\a\ENQ" } ), - inviteeEmail = unsafeEmailAddress "some" "example" + inviteeEmail = unsafeEmailAddress "some" "example", + allowExisting = True } testObject_InvitationRequest_team_16 :: InvitationRequest @@ -220,7 +235,8 @@ testObject_InvitationRequest_team_16 = Just (Locale {lLanguage = Language Data.LanguageCodes.OM, lCountry = Just (Country {fromCountry = BJ})}), role = Just RoleAdmin, inviteeName = Nothing, - inviteeEmail = unsafeEmailAddress "some" "example" + inviteeEmail = unsafeEmailAddress "some" "example", + allowExisting = True } testObject_InvitationRequest_team_17 :: InvitationRequest @@ -230,7 +246,8 @@ testObject_InvitationRequest_team_17 = Just (Locale {lLanguage = Language Data.LanguageCodes.KJ, lCountry = Just (Country {fromCountry = TC})}), role = Just RoleExternalPartner, inviteeName = Nothing, - inviteeEmail = unsafeEmailAddress "some" "example" + inviteeEmail = unsafeEmailAddress "some" "example", + allowExisting = True } testObject_InvitationRequest_team_18 :: InvitationRequest @@ -245,7 +262,8 @@ testObject_InvitationRequest_team_18 = "8VPAp\137681\&2L󲤯", diff --git a/libs/wire-api/test/golden/testObject_InvitationRequest_team_11.json b/libs/wire-api/test/golden/testObject_InvitationRequest_team_11.json index 4d0cd645404..250cfa56be0 100644 --- a/libs/wire-api/test/golden/testObject_InvitationRequest_team_11.json +++ b/libs/wire-api/test/golden/testObject_InvitationRequest_team_11.json @@ -1,4 +1,5 @@ { + "allow_existing": false, "email": "some@example", "locale": "si", "name": "𨱜ꇙⴹ𒑐h_5bb2}뛹𨰗P\u0000\u000eT*\u001f`b𩯔\u000f:4\n5\u001a\u001d*T󸅕Bv\u001b\u0003\u001d􀢕𪼏Uu\r_\u0010)y𥦆\u0004\u0008\u001f\u0014\u001c\u0018?􀖫𤣔坾\u0015\u001a4\u000b 5\u0000iꡩo=\tnG鉘\u0017iC\u00139\u000eP󺬘\n\u000b\u0019\u0016UṸ%삶\u0012\u001fF\u001c", diff --git a/libs/wire-api/test/golden/testObject_InvitationRequest_team_12.json b/libs/wire-api/test/golden/testObject_InvitationRequest_team_12.json index 4ea54084e75..4da71773da2 100644 --- a/libs/wire-api/test/golden/testObject_InvitationRequest_team_12.json +++ b/libs/wire-api/test/golden/testObject_InvitationRequest_team_12.json @@ -1,4 +1,5 @@ { + "allow_existing": true, "email": "some@example", "locale": "ar-PA", "name": "_\u0019@\u001d0춲󾌹󷱿\u001c\u0010􌩶!􈇮\u000ec\u001f\u0000\u0001>􆖳𩈈\u0019𪶲1}!h0\u0010􁈑w\u0004􆈑1aJ6c\u001d󰼊b𠍕{󳔞𠅳\u0007􋊉", diff --git a/libs/wire-api/test/golden/testObject_InvitationRequest_team_13.json b/libs/wire-api/test/golden/testObject_InvitationRequest_team_13.json index af76a81bc0a..de0f1ee5167 100644 --- a/libs/wire-api/test/golden/testObject_InvitationRequest_team_13.json +++ b/libs/wire-api/test/golden/testObject_InvitationRequest_team_13.json @@ -1,4 +1,5 @@ { + "allow_existing": true, "email": "some@example", "locale": null, "name": "C󱷈+󼗇\n#s􅺭\u001cpb\u0001󷷁􆂖1\u0017E_\u0018j\u0019V\u001f􃣖㱇􌛎lO8\u0006􁼲\u001c\u0016\u0018\u00106𡪆-beR!s뷈\u0017\u000b􀌟󰏐xt\u000fRf~w󻢹+_𑆞91:,󼜮#cf􁸗ศ৴ᬯB\"􋿺F\t􎾚􅋖/\u0010'󵒫*𩳾7𦈨w􃈢Hx\u00132\u0019t𧽔o6\u0014F%=t󴼼􋹸=\u0000\u0005A􌿋󷃓\u0000\u0004[i󲔇@\u0008\u001c\u000c", diff --git a/libs/wire-api/test/golden/testObject_InvitationRequest_team_14.json b/libs/wire-api/test/golden/testObject_InvitationRequest_team_14.json index 8aa099fd0d0..ab034bba36a 100644 --- a/libs/wire-api/test/golden/testObject_InvitationRequest_team_14.json +++ b/libs/wire-api/test/golden/testObject_InvitationRequest_team_14.json @@ -1,4 +1,5 @@ { + "allow_existing": true, "email": "some@example", "locale": "dv-LB", "name": "\u0015wGn󳔃𤠘1}\u0004gY.>=}", diff --git a/libs/wire-api/test/golden/testObject_InvitationRequest_team_15.json b/libs/wire-api/test/golden/testObject_InvitationRequest_team_15.json index d4ac032590e..b5314fc4545 100644 --- a/libs/wire-api/test/golden/testObject_InvitationRequest_team_15.json +++ b/libs/wire-api/test/golden/testObject_InvitationRequest_team_15.json @@ -1,4 +1,5 @@ { + "allow_existing": true, "email": "some@example", "locale": null, "name": "y􍭊5󴍽ˆS󸱽\u0014\rH/_\u0013A\u0003𝈯0w\u001d?TQd*1&[?cHW}只󹔖\u0018𬅖Q+\u0003mh󳀫X\u000e\u0005\u0011^g𣐎\u0008qrNV\u000e􋖒WMe\u0007\u0005", diff --git a/libs/wire-api/test/golden/testObject_InvitationRequest_team_16.json b/libs/wire-api/test/golden/testObject_InvitationRequest_team_16.json index 89de798ef5c..110def35df3 100644 --- a/libs/wire-api/test/golden/testObject_InvitationRequest_team_16.json +++ b/libs/wire-api/test/golden/testObject_InvitationRequest_team_16.json @@ -1,4 +1,5 @@ { + "allow_existing": true, "email": "some@example", "locale": "om-BJ", "name": null, diff --git a/libs/wire-api/test/golden/testObject_InvitationRequest_team_17.json b/libs/wire-api/test/golden/testObject_InvitationRequest_team_17.json index 8c154e43f07..0af527236d8 100644 --- a/libs/wire-api/test/golden/testObject_InvitationRequest_team_17.json +++ b/libs/wire-api/test/golden/testObject_InvitationRequest_team_17.json @@ -1,4 +1,5 @@ { + "allow_existing": true, "email": "some@example", "locale": "kj-TC", "name": null, diff --git a/libs/wire-api/test/golden/testObject_InvitationRequest_team_18.json b/libs/wire-api/test/golden/testObject_InvitationRequest_team_18.json index 9021ab1aa62..96b1c3d619e 100644 --- a/libs/wire-api/test/golden/testObject_InvitationRequest_team_18.json +++ b/libs/wire-api/test/golden/testObject_InvitationRequest_team_18.json @@ -1,4 +1,5 @@ { + "allow_existing": true, "email": "some@example", "locale": "ku", "name": "8VPAp𡧑2L pure False - Just user -> - if (user.userStatus == Active && isNothing user.userTeam) - then pure True - else throw TeamInvitationEmailTaken + Just user + | invRequest.allowExisting + && user.userStatus == Active + && isNothing user.userTeam -> + pure True + | otherwise -> throw TeamInvitationEmailTaken maxSize <- maxTeamSize <$> input pending <- Store.countInvitations tid diff --git a/services/brig/src/Brig/Team/API.hs b/services/brig/src/Brig/Team/API.hs index 9cfd621c9bf..fa24e2b4cf6 100644 --- a/services/brig/src/Brig/Team/API.hs +++ b/services/brig/src/Brig/Team/API.hs @@ -96,7 +96,8 @@ servantAPI :: ) => ServerT TeamsAPI (Handler r) servantAPI = - Named @"send-team-invitation" (\luid tid invreq -> lift . liftSem $ inviteUser luid tid invreq) + Named @"send-team-invitation@v6" (\luid tid invreq -> lift . liftSem $ inviteUser luid tid invreq) + :<|> Named @"send-team-invitation" (\luid tid invreq -> lift . liftSem $ inviteUser luid tid invreq) :<|> Named @"get-team-invitations" (\u t inv s -> lift . liftSem $ listInvitations u t inv s) :<|> Named @"get-team-invitation" (\u t inv -> lift . liftSem $ getInvitation u t inv) :<|> Named @"delete-team-invitation" (\u t inv -> lift . liftSem $ deleteInvitation u t inv) @@ -155,7 +156,8 @@ createInvitationViaScim tid newUser@(NewUserScimInvitation _tid _uid@(Id (Id -> { locale = loc, role = Nothing, -- (unused, it's in the type for 'createInvitationV5') inviteeName = Just name, - inviteeEmail = email + inviteeEmail = email, + allowExisting = True } context = diff --git a/services/brig/test/integration/API/Team/Util.hs b/services/brig/test/integration/API/Team/Util.hs index 12258c5dbd5..ccfd18e9c21 100644 --- a/services/brig/test/integration/API/Team/Util.hs +++ b/services/brig/test/integration/API/Team/Util.hs @@ -428,7 +428,7 @@ stdInvitationRequest = stdInvitationRequest' Nothing Nothing stdInvitationRequest' :: Maybe Locale -> Maybe Role -> EmailAddress -> InvitationRequest stdInvitationRequest' loc role email = - InvitationRequest loc role Nothing email + InvitationRequest loc role Nothing email True setTeamTeamSearchVisibilityAvailable :: (HasCallStack, MonadHttp m, MonadIO m, MonadCatch m) => Galley -> TeamId -> FeatureStatus -> m () setTeamTeamSearchVisibilityAvailable galley tid status = diff --git a/services/galley/test/integration/API/Util.hs b/services/galley/test/integration/API/Util.hs index 243a8a723cf..4e10d03a738 100644 --- a/services/galley/test/integration/API/Util.hs +++ b/services/galley/test/integration/API/Util.hs @@ -426,7 +426,7 @@ addUserToTeamWithRole' :: (HasCallStack) => Maybe Role -> UserId -> TeamId -> Te addUserToTeamWithRole' role inviter tid = do brig <- viewBrig inviteeEmail <- randomEmail - let invite = InvitationRequest Nothing role Nothing inviteeEmail + let invite = InvitationRequest Nothing role Nothing inviteeEmail True invResponse <- postInvitation tid inviter invite inv <- responseJsonError invResponse inviteeCode <- recoverAll (exponentialBackoff 1000 <> limitRetries 11) $ diff --git a/services/spar/test-integration/Util/Core.hs b/services/spar/test-integration/Util/Core.hs index 6d92d56e0df..add4f3b35d1 100644 --- a/services/spar/test-integration/Util/Core.hs +++ b/services/spar/test-integration/Util/Core.hs @@ -1263,7 +1263,7 @@ stdInvitationRequest = stdInvitationRequest' Nothing Nothing -- | copied from brig integration tests stdInvitationRequest' :: Maybe User.Locale -> Maybe Role -> EmailAddress -> TeamInvitation.InvitationRequest stdInvitationRequest' loc role email = - TeamInvitation.InvitationRequest loc role Nothing email + TeamInvitation.InvitationRequest loc role Nothing email True setRandomHandleBrig :: (HasCallStack) => UserId -> TestSpar () setRandomHandleBrig uid = do diff --git a/tools/stern/test/integration/Util.hs b/tools/stern/test/integration/Util.hs index d151434f164..41608bc2d44 100644 --- a/tools/stern/test/integration/Util.hs +++ b/tools/stern/test/integration/Util.hs @@ -150,7 +150,7 @@ addUserToTeamWithRole' :: (HasCallStack) => Maybe Role -> UserId -> TeamId -> Te addUserToTeamWithRole' role inviter tid = do brig <- view tsBrig email <- randomEmail - let invite = InvitationRequest Nothing role Nothing email + let invite = InvitationRequest Nothing role Nothing email True invResponse <- postInvitation tid inviter invite inv <- responseJsonError invResponse inviteeCode <- getInvitationCode tid inv.invitationId