-
Notifications
You must be signed in to change notification settings - Fork 325
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WPB-10658: invite personal users into teams.
failing test basic implementation with holes email sending function no impl dummy endpoint for accepting invitation failing test that user is added to team todo honor timeout refactoring to make findInvitation reuseable accept invitation extend test, publich events test for team id, include team in es doc version assert notification to user sent when fanoutsize is low Add email invitation placeholder Revert "when fanoutsize is low" This reverts commit 0834e48. update nginz confs added errors clean up/renaming email sending Add change logs setting invite url in configmap verify invitation url query parameter release notes clean up move code to http helpers extend golden tests renaming use same timeout settings for all invitations fix format email html add password test (failing) Check if the user password is correct fix test in CI test user cannot join multiple teams Simplify a helper function type Guard against accepting multiple team invitations Throw a suitable invitation not found error
- Loading branch information
Showing
34 changed files
with
693 additions
and
119 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
With this release it will be possible to invite personal users to teams. In `brig`'s config, `emailSMS.team.tExistingUserInvitationUrl` is required to be set to a value that points to the correct teams/account page. | ||
If `emailSMS.team` is not defined at all in the current environment, the value of `externalUrls.teamSettings` (or, if not present, `externalUrls.nginz`) will be used to construct the correct url, and no configuration change is necessary. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
A new endpoint `POST /teams/invitations/accept` allows a non-team user to accept an invitation to join a team |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Allow an existing non-team user to migrate to a team |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -149,6 +149,7 @@ library | |
Test.Services | ||
Test.Spar | ||
Test.Swagger | ||
Test.Teams | ||
Test.TeamSettings | ||
Test.User | ||
Test.Version | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
-- This file is part of the Wire Server implementation. | ||
-- | ||
-- Copyright (C) 2024 Wire Swiss GmbH <[email protected]> | ||
-- | ||
-- This program is free software: you can redistribute it and/or modify it under | ||
-- the terms of the GNU Affero General Public License as published by the Free | ||
-- Software Foundation, either version 3 of the License, or (at your option) any | ||
-- later version. | ||
-- | ||
-- This program is distributed in the hope that it will be useful, but WITHOUT | ||
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more | ||
-- details. | ||
-- | ||
-- You should have received a copy of the GNU Affero General Public License along | ||
-- with this program. If not, see <https://www.gnu.org/licenses/>. | ||
|
||
module Test.Teams where | ||
|
||
import API.Brig | ||
import API.BrigInternal (createUser, getInvitationCode, refreshIndex) | ||
import API.Common | ||
import API.Galley (getTeamMembers) | ||
import API.GalleyInternal (setTeamFeatureStatus) | ||
import Control.Monad.Codensity (Codensity (runCodensity)) | ||
import Control.Monad.Reader (asks) | ||
import Notifications (isUserUpdatedNotif) | ||
import SetupHelpers | ||
import Testlib.JSON | ||
import Testlib.Prelude | ||
import Testlib.ResourcePool (acquireResources) | ||
|
||
testInvitePersonalUserToTeam :: (HasCallStack) => App () | ||
testInvitePersonalUserToTeam = do | ||
resourcePool <- asks (.resourcePool) | ||
runCodensity (acquireResources 1 resourcePool) $ \[testBackend] -> do | ||
let domain = testBackend.berDomain | ||
(owner, tid, tm) <- runCodensity (startDynamicBackend testBackend def) $ \_ -> do | ||
(owner, tid, tm : _) <- createTeam domain 2 | ||
pure (owner, tid, tm) | ||
|
||
runCodensity | ||
( startDynamicBackend | ||
testBackend | ||
(def {galleyCfg = setField "settings.exposeInvitationURLsTeamAllowlist" [tid]}) | ||
) | ||
$ \_ -> do | ||
ownerId <- owner %. "id" & asString | ||
setTeamFeatureStatus domain tid "exposeInvitationURLsToTeamAdmin" "enabled" >>= assertSuccess | ||
user <- createUser domain def >>= getJSON 201 | ||
uid <- user %. "id" >>= asString | ||
email <- user %. "email" >>= asString | ||
inv <- postInvitation owner (PostInvitation $ Just email) >>= getJSON 201 | ||
code <- getInvitationCode owner inv >>= getJSON 200 >>= (%. "code") & asString | ||
queryParam <- inv %. "url" & asString <&> getQueryParam "team-code" | ||
queryParam `shouldMatch` Just (Just code) | ||
acceptTeamInvitation user code Nothing >>= assertStatus 400 | ||
acceptTeamInvitation user code (Just "wrong-password") >>= assertStatus 403 | ||
void $ withWebSockets [user] $ \wss -> do | ||
acceptTeamInvitation user code (Just defPassword) >>= assertSuccess | ||
for wss $ \ws -> do | ||
n <- awaitMatch isUserUpdatedNotif ws | ||
n %. "payload.0.user.team" `shouldMatch` tid | ||
bindResponse (getSelf user) $ \resp -> do | ||
resp.status `shouldMatchInt` 200 | ||
resp.json %. "team" `shouldMatch` tid | ||
-- a team member can now find the former personal user in the team | ||
bindResponse (getTeamMembers tm tid) $ \resp -> do | ||
resp.status `shouldMatchInt` 200 | ||
members <- resp.json %. "members" >>= asList | ||
ids <- for members ((%. "user") >=> asString) | ||
ids `shouldContain` [uid] | ||
-- the former personal user can now see other team members | ||
bindResponse (getTeamMembers user tid) $ \resp -> do | ||
resp.status `shouldMatchInt` 200 | ||
members <- resp.json %. "members" >>= asList | ||
ids <- for members ((%. "user") >=> asString) | ||
tmId <- tm %. "id" & asString | ||
ids `shouldContain` [ownerId] | ||
ids `shouldContain` [tmId] | ||
-- the former personal user can now search for the owner | ||
bindResponse (searchContacts user (owner %. "name") domain) $ \resp -> do | ||
resp.status `shouldMatchInt` 200 | ||
documents <- resp.json %. "documents" >>= asList | ||
ids <- for documents ((%. "id") >=> asString) | ||
ids `shouldContain` [ownerId] | ||
refreshIndex domain | ||
-- a team member can now search for the former personal user | ||
bindResponse (searchContacts tm (user %. "name") domain) $ \resp -> do | ||
resp.status `shouldMatchInt` 200 | ||
document <- resp.json %. "documents" >>= asList >>= assertOne | ||
document %. "id" `shouldMatch` uid | ||
document %. "team" `shouldMatch` tid | ||
|
||
testInvitePersonalUserToTeamMultipleInvitations :: (HasCallStack) => App () | ||
testInvitePersonalUserToTeamMultipleInvitations = do | ||
(owner, tid, _) <- createTeam OwnDomain 0 | ||
(owner2, _, _) <- createTeam OwnDomain 0 | ||
user <- createUser OwnDomain def >>= getJSON 201 | ||
email <- user %. "email" >>= asString | ||
inv <- postInvitation owner (PostInvitation $ Just email) >>= getJSON 201 | ||
inv2 <- postInvitation owner2 (PostInvitation $ Just email) >>= getJSON 201 | ||
code <- getInvitationCode owner inv >>= getJSON 200 >>= (%. "code") & asString | ||
acceptTeamInvitation user code (Just defPassword) >>= assertSuccess | ||
bindResponse (getSelf user) $ \resp -> do | ||
resp.status `shouldMatchInt` 200 | ||
resp.json %. "team" `shouldMatch` tid | ||
code2 <- getInvitationCode owner2 inv2 >>= getJSON 200 >>= (%. "code") & asString | ||
bindResponse (acceptTeamInvitation user code2 (Just defPassword)) $ \resp -> do | ||
resp.status `shouldMatchInt` 403 | ||
resp.json %. "label" `shouldMatch` "cannot-join-multiple-teams" | ||
bindResponse (getSelf user) $ \resp -> do | ||
resp.status `shouldMatchInt` 200 | ||
resp.json %. "team" `shouldMatch` tid | ||
acceptTeamInvitation user code (Just defPassword) >>= assertStatus 400 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.