diff --git a/libs/api-client/src/Network/Wire/Client/API/Conversation.hs b/libs/api-client/src/Network/Wire/Client/API/Conversation.hs index 8983b7f8c85..80345558b11 100644 --- a/libs/api-client/src/Network/Wire/Client/API/Conversation.hs +++ b/libs/api-client/src/Network/Wire/Client/API/Conversation.hs @@ -140,6 +140,6 @@ createConv users name = sessionRequest req rsc readBody method POST . path "conversations" . acceptJson - . json (NewConvUnmanaged (NewConv users name mempty Nothing Nothing Nothing Nothing roleNameWireAdmin)) + . json (NewConvUnmanaged (NewConv users [] name mempty Nothing Nothing Nothing Nothing roleNameWireAdmin)) $ empty rsc = status201 :| [] diff --git a/libs/wire-api/src/Wire/API/Conversation.hs b/libs/wire-api/src/Wire/API/Conversation.hs index fd2e35dee60..fa9fc57bae4 100644 --- a/libs/wire-api/src/Wire/API/Conversation.hs +++ b/libs/wire-api/src/Wire/API/Conversation.hs @@ -384,6 +384,8 @@ modelNewConversation = Doc.defineModel "NewConversation" $ do Doc.description "JSON object to create a new conversation" Doc.property "users" (Doc.unique $ Doc.array Doc.bytes') $ Doc.description "List of user IDs (excluding the requestor) to be part of this conversation" + Doc.property "qualified_users" (Doc.unique . Doc.array $ Doc.bytes') $ + Doc.description "List of qualified user IDs to be part of this conversation" Doc.property "name" Doc.string' $ do Doc.description "The conversation name" Doc.optional @@ -414,6 +416,9 @@ instance Arbitrary NewConvUnmanaged where data NewConv = NewConv { newConvUsers :: [UserId], + -- | A list of qualified users, which can include some local qualified users + -- too. + newConvQualifiedUsers :: [Qualified UserId], newConvName :: Maybe Text, newConvAccess :: Set Access, newConvAccessRole :: Maybe AccessRole, @@ -437,6 +442,13 @@ newConvSchema = "users" (description ?~ usersDesc) (array schema) + <*> newConvQualifiedUsers + .= ( fieldWithDocModifier + "qualified_users" + (description ?~ qualifiedUsersDesc) + (array schema) + <|> pure [] + ) <*> newConvName .= opt (field "name" schema) <*> (Set.toList . newConvAccess) .= ( field "access" (Set.fromList <$> array schema) @@ -465,7 +477,10 @@ newConvSchema = where usersDesc = "List of user IDs (excluding the requestor) to be \ - \part of this conversation" + \part of this conversation (deprecated)" + qualifiedUsersDesc = + "List of qualified user IDs (excluding the requestor) \ + \to be part of this conversation" newConvIsManaged :: NewConv -> Bool newConvIsManaged = maybe False cnvManaged . newConvTeam diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_1.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_1.json index d0d5e76b057..6236cbb2ef1 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_1.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_1.json @@ -8,5 +8,6 @@ "teamid": "00000001-0000-0001-0000-000200000000" }, "receipt_mode": 4, - "message_timer": 193643728192048 + "message_timer": 193643728192048, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_10.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_10.json index 0223225ebb3..c2daf4e3a7c 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_10.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_10.json @@ -12,5 +12,6 @@ "teamid": "00000001-0000-0001-0000-000000000001" }, "receipt_mode": 1, - "message_timer": 8061252799624904 + "message_timer": 8061252799624904, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_11.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_11.json index 142a6d0d1f4..6c529a22ee9 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_11.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_11.json @@ -11,5 +11,6 @@ "teamid": "00000001-0000-0000-0000-000200000001" }, "receipt_mode": -2, - "message_timer": 6292627004994884 + "message_timer": 6292627004994884, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_12.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_12.json index d2504f314a5..4fcadb414c4 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_12.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_12.json @@ -14,5 +14,6 @@ "managed": true, "teamid": "00000000-0000-0001-0000-000100000000" }, - "message_timer": 7043412511612101 + "message_timer": 7043412511612101, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_13.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_13.json index ae4e7f50d05..c9ef6cba2b8 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_13.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_13.json @@ -12,5 +12,6 @@ "managed": true, "teamid": "00000000-0000-0001-0000-000100000001" }, - "receipt_mode": 0 + "receipt_mode": 0, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_14.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_14.json index c4f0faee5f7..7ffb20118c5 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_14.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_14.json @@ -20,5 +20,6 @@ "managed": true, "teamid": "00000001-0000-0001-0000-000000000000" }, - "message_timer": 8669416711689656 + "message_timer": 8669416711689656, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_15.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_15.json index a92993fe12b..4897835141b 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_15.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_15.json @@ -17,5 +17,6 @@ "teamid": "00000001-0000-0001-0000-000000000000" }, "receipt_mode": 2, - "message_timer": 1166285470102499 + "message_timer": 1166285470102499, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_16.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_16.json index 1934d39888e..01aeef6c744 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_16.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_16.json @@ -10,5 +10,6 @@ "managed": true, "teamid": "00000002-0000-0001-0000-000000000001" }, - "message_timer": 4425819976591162 + "message_timer": 4425819976591162, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_17.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_17.json index d73ce51661a..b8d1bb81cf9 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_17.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_17.json @@ -17,5 +17,6 @@ "managed": true, "teamid": "00000000-0000-0000-0000-000000000000" }, - "message_timer": 5065871950676797 + "message_timer": 5065871950676797, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_18.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_18.json index 1120207cbce..862a990ee99 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_18.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_18.json @@ -8,5 +8,6 @@ "managed": true, "teamid": "00000001-0000-0000-0000-000100000001" }, - "receipt_mode": -1 + "receipt_mode": -1, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_19.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_19.json index 46a4e152ffc..1f29a6a2939 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_19.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_19.json @@ -12,5 +12,6 @@ "managed": true, "teamid": "00000001-0000-0000-0000-000100000001" }, - "message_timer": 8428756728484885 + "message_timer": 8428756728484885, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_2.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_2.json index d186ff4b00f..3944598bbc6 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_2.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_2.json @@ -14,5 +14,11 @@ "managed": true, "teamid": "00000002-0000-0002-0000-000200000002" }, - "message_timer": 5509522199847054 + "message_timer": 5509522199847054, + "qualified_users": [ + { + "domain": "test.example.com", + "id": "00000000-0000-0000-0000-000100000001" + } + ] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_20.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_20.json index 7a67aa24955..7634af079d0 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_20.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_20.json @@ -15,5 +15,6 @@ "managed": true, "teamid": "00000000-0000-0000-0000-000000000001" }, - "message_timer": 6168723896440273 + "message_timer": 6168723896440273, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_3.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_3.json index 4dea92bc2ea..07019eaaeab 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_3.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_3.json @@ -14,5 +14,11 @@ "teamid": "00000001-0000-0001-0000-000000000000" }, "receipt_mode": 2, - "message_timer": 582808797322573 + "message_timer": 582808797322573, + "qualified_users": [ + { + "domain": "test.example.com", + "id": "00000000-0000-0000-0000-000100000001" + } + ] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_4.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_4.json index 1b1f6259c82..70d83c053d2 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_4.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_4.json @@ -14,5 +14,6 @@ "team": { "managed": true, "teamid": "00000001-0000-0001-0000-000100000002" - } + }, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_5.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_5.json index 0bb397139b5..c54f6a917f6 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_5.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_5.json @@ -13,5 +13,6 @@ "teamid": "00000001-0000-0000-0000-000100000000" }, "receipt_mode": -1, - "message_timer": 1570858821505994 + "message_timer": 1570858821505994, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_6.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_6.json index 1e64c83bd3b..9663fd804a0 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_6.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_6.json @@ -15,5 +15,6 @@ "managed": true, "teamid": "00000000-0000-0000-0000-000000000001" }, - "message_timer": 6614365418177275 + "message_timer": 6614365418177275, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_7.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_7.json index 085917605a6..39582d207b7 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_7.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_7.json @@ -12,5 +12,6 @@ "teamid": "00000001-0000-0001-0000-000100000000" }, "receipt_mode": 0, - "message_timer": 7417375067718994 + "message_timer": 7417375067718994, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_8.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_8.json index 5f7c0d496cc..ae8c6078685 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_8.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_8.json @@ -11,5 +11,6 @@ "managed": true, "teamid": "00000001-0000-0000-0000-000100000001" }, - "receipt_mode": 2 + "receipt_mode": 2, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvManaged_user_9.json b/libs/wire-api/test/golden/testObject_NewConvManaged_user_9.json index cc918ca9b6c..9edd2c8c3d3 100644 --- a/libs/wire-api/test/golden/testObject_NewConvManaged_user_9.json +++ b/libs/wire-api/test/golden/testObject_NewConvManaged_user_9.json @@ -12,5 +12,6 @@ "teamid": "00000001-0000-0000-0000-000000000000" }, "receipt_mode": 1, - "message_timer": 2550845209410146 + "message_timer": 2550845209410146, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_1.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_1.json index bb91c95bdc9..edf0282f535 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_1.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_1.json @@ -14,5 +14,6 @@ "teamid": "00000000-0000-0001-0000-000000000000" }, "receipt_mode": 1, - "message_timer": 3320987366258987 + "message_timer": 3320987366258987, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_10.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_10.json index 053072f59a0..e35128c1deb 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_10.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_10.json @@ -11,5 +11,6 @@ "conversation_role": "30mnzwj79jo9ear300qs4k_x2262nyaqxt9qga1_zaqmto43q2935t4dzaan_qnlstgjix7efmqfljkpww2lz", "name": "", "receipt_mode": 2, - "message_timer": 5041503034744095 + "message_timer": 5041503034744095, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_11.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_11.json index d8208e917eb..69680bdfa2e 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_11.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_11.json @@ -10,5 +10,6 @@ "teamid": "00000000-0000-0000-0000-000000000000" }, "receipt_mode": 1, - "message_timer": 6019134025424754 + "message_timer": 6019134025424754, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_12.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_12.json index f4b4ae0d413..844cd30e634 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_12.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_12.json @@ -3,5 +3,6 @@ "users": [], "conversation_role": "wqhaeljk9zpp5nmspwl", "name": ">+", - "receipt_mode": 1 + "receipt_mode": 1, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_13.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_13.json index cb760bbf05d..04278d46724 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_13.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_13.json @@ -13,5 +13,6 @@ "teamid": "00000000-0000-0000-0000-000000000001" }, "receipt_mode": -2, - "message_timer": 211460552735402 + "message_timer": 211460552735402, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_14.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_14.json index cbf228dbd47..6690d68083a 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_14.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_14.json @@ -10,5 +10,6 @@ "conversation_role": "fga_hfm9uzn_5z883y6r_kumb", "name": "", "receipt_mode": -2, - "message_timer": 854777662274030 + "message_timer": 854777662274030, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_15.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_15.json index 181966845c5..6fda451288c 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_15.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_15.json @@ -14,5 +14,6 @@ "teamid": "00000001-0000-0001-0000-000200000002" }, "receipt_mode": 1, - "message_timer": 4005602882980532 + "message_timer": 4005602882980532, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_16.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_16.json index 1d351204ce8..4b11912e073 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_16.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_16.json @@ -11,5 +11,6 @@ "managed": false, "teamid": "00000000-0000-0001-0000-000100000000" }, - "receipt_mode": 1 + "receipt_mode": 1, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_17.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_17.json index 45a12afa84f..cfab3503e9b 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_17.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_17.json @@ -22,5 +22,6 @@ "teamid": "00000000-0000-0001-0000-000100000001" }, "receipt_mode": 0, - "message_timer": 880163555151907 + "message_timer": 880163555151907, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_18.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_18.json index c245ea066da..43f14dfd5af 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_18.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_18.json @@ -12,5 +12,6 @@ "conversation_role": "ugehcdyu_ob9_woawlths95ez8cgtb6wjqypp7vbjaooiczerb5zpc6srxszgkrdu8l24ygz_", "name": "sd\u0006", "receipt_mode": -2, - "message_timer": 3120553871655858 + "message_timer": 3120553871655858, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_19.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_19.json index f3d6cf50c57..d9086140b52 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_19.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_19.json @@ -9,5 +9,6 @@ "conversation_role": "xik7vc3wp82gw4r934rad_bhmf2orany3qgu_tx9huwfrlxy8m0id71x20uddebps30zdahe_ffcxxhc", "name": "Cu\u0011", "receipt_mode": -1, - "message_timer": 864918593306344 + "message_timer": 864918593306344, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_2.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_2.json index b5fe627bd56..eefa9c41791 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_2.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_2.json @@ -9,5 +9,11 @@ "teamid": "00000000-0000-0001-0000-000000000001" }, "receipt_mode": -1, - "message_timer": 2406292360203739 + "message_timer": 2406292360203739, + "qualified_users": [ + { + "domain": "testdomain.example.com", + "id": "00000000-0000-0000-0000-000100000001" + } + ] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_20.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_20.json index 7974cdee0a4..f6acbbccc1d 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_20.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_20.json @@ -6,5 +6,6 @@ "conversation_role": "udhi2sbf7tzyshrh", "name": "\u000f􅚶", "receipt_mode": -1, - "message_timer": 3641984282941906 + "message_timer": 3641984282941906, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_3.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_3.json index 0448c8d6ae4..b695ab354d0 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_3.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_3.json @@ -13,5 +13,6 @@ "teamid": "00000000-0000-0001-0000-000000000001" }, "receipt_mode": 0, - "message_timer": 6764297310186120 + "message_timer": 6764297310186120, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_4.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_4.json index 25f2a9d5f99..4eb17cc8734 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_4.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_4.json @@ -9,5 +9,6 @@ "managed": false, "teamid": "00000000-0000-0001-0000-000000000000" }, - "receipt_mode": -2 + "receipt_mode": -2, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_5.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_5.json index 333b08ad340..8c3300d8268 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_5.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_5.json @@ -13,5 +13,6 @@ "team": { "managed": false, "teamid": "00000001-0000-0001-0000-000100000000" - } + }, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_6.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_6.json index f416efa308e..9ad3210f5e9 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_6.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_6.json @@ -7,5 +7,6 @@ "conversation_role": "5zlsxm_95e5j1lk04d6rka_1svnnk65pov7tqs", "name": "`3", "receipt_mode": 2, - "message_timer": 3993332602038581 + "message_timer": 3993332602038581, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_7.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_7.json index ac18846f376..7864d68fd0e 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_7.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_7.json @@ -11,5 +11,6 @@ "teamid": "00000001-0000-0002-0000-000200000000" }, "receipt_mode": -3, - "message_timer": 5300164242243961 + "message_timer": 5300164242243961, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_8.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_8.json index 1767aace79f..adcf1b3067a 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_8.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_8.json @@ -13,5 +13,6 @@ "teamid": "00000000-0000-0001-0000-000100000001" }, "receipt_mode": -1, - "message_timer": 5317293791913533 + "message_timer": 5317293791913533, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_9.json b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_9.json index 0f13c872607..52bf3a61ab4 100644 --- a/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_9.json +++ b/libs/wire-api/test/golden/testObject_NewConvUnmanaged_user_9.json @@ -11,5 +11,6 @@ ], "conversation_role": "n8cjajmyhnw3hqv8sohb8674nwnpsv7g57i2hjhexg9tww", "name": "L", - "message_timer": 7179840365742041 + "message_timer": 7179840365742041, + "qualified_users": [] } \ No newline at end of file diff --git a/libs/wire-api/test/unit/Test/Wire/API/Golden/Generated/NewConvManaged_user.hs b/libs/wire-api/test/unit/Test/Wire/API/Golden/Generated/NewConvManaged_user.hs index ee0c0afee55..8711efb108f 100644 --- a/libs/wire-api/test/unit/Test/Wire/API/Golden/Generated/NewConvManaged_user.hs +++ b/libs/wire-api/test/unit/Test/Wire/API/Golden/Generated/NewConvManaged_user.hs @@ -18,8 +18,10 @@ -- with this program. If not, see . module Test.Wire.API.Golden.Generated.NewConvManaged_user where +import Data.Domain import Data.Id (Id (Id)) import Data.Misc (Milliseconds (Ms, ms)) +import Data.Qualified import qualified Data.Set as Set (fromList) import qualified Data.UUID as UUID (fromString) import Imports (Bool (True), Maybe (Just, Nothing), fromJust) @@ -38,6 +40,7 @@ import Wire.API.Conversation newConvAccessRole, newConvMessageTimer, newConvName, + newConvQualifiedUsers, newConvReceiptMode, newConvTeam, newConvUsers, @@ -48,11 +51,15 @@ import Wire.API.Conversation ) import Wire.API.Conversation.Role (parseRoleName) +testDomain :: Domain +testDomain = Domain "test.example.com" + testObject_NewConvManaged_user_1 :: NewConvManaged testObject_NewConvManaged_user_1 = NewConvManaged ( NewConv { newConvUsers = [], + newConvQualifiedUsers = [], newConvName = Nothing, newConvAccess = Set.fromList [], newConvAccessRole = Just ActivatedAccessRole, @@ -74,6 +81,7 @@ testObject_NewConvManaged_user_2 = NewConvManaged ( NewConv { newConvUsers = [(Id (fromJust (UUID.fromString "00000002-0000-0001-0000-000400000000")))], + newConvQualifiedUsers = [Qualified (Id (fromJust (UUID.fromString "00000000-0000-0000-0000-000100000001"))) testDomain], newConvName = Just "\995491\SUB5", newConvAccess = Set.fromList [PrivateAccess, InviteAccess, LinkAccess], newConvAccessRole = Just NonActivatedAccessRole, @@ -98,6 +106,7 @@ testObject_NewConvManaged_user_3 = [ (Id (fromJust (UUID.fromString "00000001-0000-0001-0000-000100000000"))), (Id (fromJust (UUID.fromString "00000001-0000-0000-0000-000100000001"))) ], + newConvQualifiedUsers = [Qualified (Id (fromJust (UUID.fromString "00000000-0000-0000-0000-000100000001"))) testDomain], newConvName = Just "NwK", newConvAccess = Set.fromList [CodeAccess], newConvAccessRole = Just TeamAccessRole, @@ -128,6 +137,7 @@ testObject_NewConvManaged_user_4 = (Id (fromJust (UUID.fromString "00000001-0000-0000-0000-000100000001"))), (Id (fromJust (UUID.fromString "00000000-0000-0001-0000-000000000000"))) ], + newConvQualifiedUsers = [], newConvName = Just "k\61561-", newConvAccess = Set.fromList [PrivateAccess, LinkAccess], newConvAccessRole = Just TeamAccessRole, @@ -159,6 +169,7 @@ testObject_NewConvManaged_user_5 = (Id (fromJust (UUID.fromString "00000000-0000-0000-0000-000100000001"))), (Id (fromJust (UUID.fromString "00000000-0000-0001-0000-000100000000"))) ], + newConvQualifiedUsers = [], newConvName = Just "v", newConvAccess = Set.fromList [], newConvAccessRole = Nothing, @@ -184,6 +195,7 @@ testObject_NewConvManaged_user_6 = (Id (fromJust (UUID.fromString "00000000-0000-0000-0000-000000000000"))), (Id (fromJust (UUID.fromString "00000001-0000-0000-0000-000000000001"))) ], + newConvQualifiedUsers = [], newConvName = Just "P\1098873\r", newConvAccess = Set.fromList [InviteAccess, CodeAccess], newConvAccessRole = Just PrivateAccessRole, @@ -213,6 +225,7 @@ testObject_NewConvManaged_user_7 = [ (Id (fromJust (UUID.fromString "00000000-0000-0000-0000-000100000000"))), (Id (fromJust (UUID.fromString "00000001-0000-0001-0000-000000000001"))) ], + newConvQualifiedUsers = [], newConvName = Just "\CAN", newConvAccess = Set.fromList [], newConvAccessRole = Just ActivatedAccessRole, @@ -242,6 +255,7 @@ testObject_NewConvManaged_user_8 = [ (Id (fromJust (UUID.fromString "00000001-0000-0001-0000-000100000000"))), (Id (fromJust (UUID.fromString "00000001-0000-0001-0000-000000000000"))) ], + newConvQualifiedUsers = [], newConvName = Just "&", newConvAccess = Set.fromList [], newConvAccessRole = Just ActivatedAccessRole, @@ -263,6 +277,7 @@ testObject_NewConvManaged_user_9 = NewConvManaged ( NewConv { newConvUsers = [], + newConvQualifiedUsers = [], newConvName = Nothing, newConvAccess = Set.fromList [PrivateAccess, InviteAccess, LinkAccess], newConvAccessRole = Just NonActivatedAccessRole, @@ -284,6 +299,7 @@ testObject_NewConvManaged_user_10 = NewConvManaged ( NewConv { newConvUsers = [(Id (fromJust (UUID.fromString "00000001-0000-0001-0000-000100000001")))], + newConvQualifiedUsers = [], newConvName = Just "z\1112901", newConvAccess = Set.fromList [LinkAccess], newConvAccessRole = Nothing, @@ -310,6 +326,7 @@ testObject_NewConvManaged_user_11 = NewConvManaged ( NewConv { newConvUsers = [], + newConvQualifiedUsers = [], newConvName = Just "r", newConvAccess = Set.fromList [InviteAccess], newConvAccessRole = Just NonActivatedAccessRole, @@ -334,6 +351,7 @@ testObject_NewConvManaged_user_12 = [ (Id (fromJust (UUID.fromString "00000001-0000-0000-0000-000000000001"))), (Id (fromJust (UUID.fromString "00000000-0000-0000-0000-000100000000"))) ], + newConvQualifiedUsers = [], newConvName = Just "", newConvAccess = Set.fromList [PrivateAccess, CodeAccess], newConvAccessRole = Just TeamAccessRole, @@ -360,6 +378,7 @@ testObject_NewConvManaged_user_13 = NewConvManaged ( NewConv { newConvUsers = [], + newConvQualifiedUsers = [], newConvName = Just "\tB", newConvAccess = Set.fromList [PrivateAccess, InviteAccess, LinkAccess], newConvAccessRole = Just NonActivatedAccessRole, @@ -397,6 +416,7 @@ testObject_NewConvManaged_user_14 = (Id (fromJust (UUID.fromString "00000001-0000-0000-0000-000000000000"))), (Id (fromJust (UUID.fromString "00000001-0000-0000-0000-000100000001"))) ], + newConvQualifiedUsers = [], newConvName = Just "", newConvAccess = Set.fromList [CodeAccess], newConvAccessRole = Nothing, @@ -424,6 +444,7 @@ testObject_NewConvManaged_user_15 = (Id (fromJust (UUID.fromString "00000000-0000-0000-0000-000000000001"))), (Id (fromJust (UUID.fromString "00000000-0000-0000-0000-000000000000"))) ], + newConvQualifiedUsers = [], newConvName = Nothing, newConvAccess = Set.fromList [PrivateAccess, CodeAccess], newConvAccessRole = Just NonActivatedAccessRole, @@ -445,6 +466,7 @@ testObject_NewConvManaged_user_16 = NewConvManaged ( NewConv { newConvUsers = [], + newConvQualifiedUsers = [], newConvName = Just "", newConvAccess = Set.fromList [InviteAccess, CodeAccess], newConvAccessRole = Nothing, @@ -478,6 +500,7 @@ testObject_NewConvManaged_user_17 = (Id (fromJust (UUID.fromString "00000000-0000-0001-0000-000100000000"))), (Id (fromJust (UUID.fromString "00000000-0000-0000-0000-000100000000"))) ], + newConvQualifiedUsers = [], newConvName = Just "", newConvAccess = Set.fromList [LinkAccess], newConvAccessRole = Just TeamAccessRole, @@ -499,6 +522,7 @@ testObject_NewConvManaged_user_18 = NewConvManaged ( NewConv { newConvUsers = [], + newConvQualifiedUsers = [], newConvName = Just "\36412\tJ", newConvAccess = Set.fromList [], newConvAccessRole = Just ActivatedAccessRole, @@ -520,6 +544,7 @@ testObject_NewConvManaged_user_19 = NewConvManaged ( NewConv { newConvUsers = [(Id (fromJust (UUID.fromString "00000003-0000-0004-0000-000400000002")))], + newConvQualifiedUsers = [], newConvName = Just "", newConvAccess = Set.fromList [PrivateAccess], newConvAccessRole = Just ActivatedAccessRole, @@ -546,6 +571,7 @@ testObject_NewConvManaged_user_20 = (Id (fromJust (UUID.fromString "00000001-0000-0000-0000-000000000001"))), (Id (fromJust (UUID.fromString "00000001-0000-0001-0000-000100000000"))) ], + newConvQualifiedUsers = [], newConvName = Just "\SOH?(", newConvAccess = Set.fromList [PrivateAccess, InviteAccess], newConvAccessRole = Just NonActivatedAccessRole, diff --git a/libs/wire-api/test/unit/Test/Wire/API/Golden/Generated/NewConvUnmanaged_user.hs b/libs/wire-api/test/unit/Test/Wire/API/Golden/Generated/NewConvUnmanaged_user.hs index a135ebb6385..b7ff8111f6f 100644 --- a/libs/wire-api/test/unit/Test/Wire/API/Golden/Generated/NewConvUnmanaged_user.hs +++ b/libs/wire-api/test/unit/Test/Wire/API/Golden/Generated/NewConvUnmanaged_user.hs @@ -18,8 +18,10 @@ -- with this program. If not, see . module Test.Wire.API.Golden.Generated.NewConvUnmanaged_user where +import Data.Domain (Domain (Domain)) import Data.Id (Id (Id)) import Data.Misc (Milliseconds (Ms, ms)) +import Data.Qualified (Qualified (Qualified)) import qualified Data.Set as Set (fromList) import qualified Data.UUID as UUID (fromString) import Imports (Bool (False), Maybe (Just, Nothing), fromJust) @@ -38,6 +40,7 @@ import Wire.API.Conversation newConvAccessRole, newConvMessageTimer, newConvName, + newConvQualifiedUsers, newConvReceiptMode, newConvTeam, newConvUsers, @@ -48,6 +51,9 @@ import Wire.API.Conversation ) import Wire.API.Conversation.Role (parseRoleName) +testDomain :: Domain +testDomain = Domain "testdomain.example.com" + testObject_NewConvUnmanaged_user_1 :: NewConvUnmanaged testObject_NewConvUnmanaged_user_1 = NewConvUnmanaged @@ -56,6 +62,7 @@ testObject_NewConvUnmanaged_user_1 = [ (Id (fromJust (UUID.fromString "00000001-0000-0000-0000-000000000001"))), (Id (fromJust (UUID.fromString "00000000-0000-0000-0000-000000000000"))) ], + newConvQualifiedUsers = [], newConvName = Nothing, newConvAccess = Set.fromList [PrivateAccess, InviteAccess], newConvAccessRole = Just ActivatedAccessRole, @@ -77,6 +84,7 @@ testObject_NewConvUnmanaged_user_2 = NewConvUnmanaged ( NewConv { newConvUsers = [], + newConvQualifiedUsers = [Qualified (Id (fromJust (UUID.fromString "00000000-0000-0000-0000-000100000001"))) testDomain], newConvName = Just "\128527\1061495", newConvAccess = Set.fromList [], newConvAccessRole = Just PrivateAccessRole, @@ -103,6 +111,7 @@ testObject_NewConvUnmanaged_user_3 = NewConvUnmanaged ( NewConv { newConvUsers = [], + newConvQualifiedUsers = [], newConvName = Just "f", newConvAccess = Set.fromList [InviteAccess, LinkAccess, CodeAccess], newConvAccessRole = Just ActivatedAccessRole, @@ -129,6 +138,7 @@ testObject_NewConvUnmanaged_user_4 = NewConvUnmanaged ( NewConv { newConvUsers = [], + newConvQualifiedUsers = [], newConvName = Just "\135359\70751z", newConvAccess = Set.fromList [CodeAccess], newConvAccessRole = Nothing, @@ -159,6 +169,7 @@ testObject_NewConvUnmanaged_user_5 = (Id (fromJust (UUID.fromString "00000000-0000-0001-0000-000100000001"))), (Id (fromJust (UUID.fromString "00000000-0000-0001-0000-000100000001"))) ], + newConvQualifiedUsers = [], newConvName = Just "X9", newConvAccess = Set.fromList [InviteAccess, LinkAccess], newConvAccessRole = Nothing, @@ -185,6 +196,7 @@ testObject_NewConvUnmanaged_user_6 = NewConvUnmanaged ( NewConv { newConvUsers = [], + newConvQualifiedUsers = [], newConvName = Just "`3", newConvAccess = Set.fromList [LinkAccess], newConvAccessRole = Just TeamAccessRole, @@ -200,6 +212,7 @@ testObject_NewConvUnmanaged_user_7 = NewConvUnmanaged ( NewConv { newConvUsers = [(Id (fromJust (UUID.fromString "00000001-0000-0000-0000-000400000004")))], + newConvQualifiedUsers = [], newConvName = Just "\1038759\b\1057989'", newConvAccess = Set.fromList [], newConvAccessRole = Just ActivatedAccessRole, @@ -221,6 +234,7 @@ testObject_NewConvUnmanaged_user_8 = NewConvUnmanaged ( NewConv { newConvUsers = [(Id (fromJust (UUID.fromString "00000000-0000-0000-0000-000100000000")))], + newConvQualifiedUsers = [], newConvName = Just "", newConvAccess = Set.fromList [InviteAccess], newConvAccessRole = Just ActivatedAccessRole, @@ -250,6 +264,7 @@ testObject_NewConvUnmanaged_user_9 = [ (Id (fromJust (UUID.fromString "00000001-0000-0000-0000-000100000001"))), (Id (fromJust (UUID.fromString "00000001-0000-0000-0000-000100000000"))) ], + newConvQualifiedUsers = [], newConvName = Just "L", newConvAccess = Set.fromList [PrivateAccess, InviteAccess, LinkAccess], newConvAccessRole = Just ActivatedAccessRole, @@ -268,6 +283,7 @@ testObject_NewConvUnmanaged_user_10 = [ (Id (fromJust (UUID.fromString "00000000-0000-0000-0000-000100000001"))), (Id (fromJust (UUID.fromString "00000000-0000-0001-0000-000000000000"))) ], + newConvQualifiedUsers = [], newConvName = Just "", newConvAccess = Set.fromList [PrivateAccess, CodeAccess], newConvAccessRole = Just ActivatedAccessRole, @@ -289,6 +305,7 @@ testObject_NewConvUnmanaged_user_11 = [ (Id (fromJust (UUID.fromString "00000000-0000-0001-0000-000100000000"))), (Id (fromJust (UUID.fromString "00000000-0000-0001-0000-000000000000"))) ], + newConvQualifiedUsers = [], newConvName = Nothing, newConvAccess = Set.fromList [], newConvAccessRole = Nothing, @@ -310,6 +327,7 @@ testObject_NewConvUnmanaged_user_12 = NewConvUnmanaged ( NewConv { newConvUsers = [], + newConvQualifiedUsers = [], newConvName = Just ">+", newConvAccess = Set.fromList [], newConvAccessRole = Nothing, @@ -330,6 +348,7 @@ testObject_NewConvUnmanaged_user_13 = (Id (fromJust (UUID.fromString "00000000-0000-0000-0000-000000000001"))), (Id (fromJust (UUID.fromString "00000001-0000-0000-0000-000100000001"))) ], + newConvQualifiedUsers = [], newConvName = Just ".L'", newConvAccess = Set.fromList [], newConvAccessRole = Nothing, @@ -359,6 +378,7 @@ testObject_NewConvUnmanaged_user_14 = [ (Id (fromJust (UUID.fromString "00000001-0000-0001-0000-000100000001"))), (Id (fromJust (UUID.fromString "00000000-0000-0001-0000-000000000000"))) ], + newConvQualifiedUsers = [], newConvName = Just "", newConvAccess = Set.fromList [CodeAccess], newConvAccessRole = Just NonActivatedAccessRole, @@ -374,6 +394,7 @@ testObject_NewConvUnmanaged_user_15 = NewConvUnmanaged ( NewConv { newConvUsers = [(Id (fromJust (UUID.fromString "00000002-0000-0003-0000-000300000003")))], + newConvQualifiedUsers = [], newConvName = Just "b\1008988", newConvAccess = Set.fromList [PrivateAccess, InviteAccess, CodeAccess], newConvAccessRole = Nothing, @@ -395,6 +416,7 @@ testObject_NewConvUnmanaged_user_16 = NewConvUnmanaged ( NewConv { newConvUsers = [], + newConvQualifiedUsers = [], newConvName = Just "!", newConvAccess = Set.fromList [PrivateAccess, CodeAccess], newConvAccessRole = Just PrivateAccessRole, @@ -426,6 +448,7 @@ testObject_NewConvUnmanaged_user_17 = (Id (fromJust (UUID.fromString "00000001-0000-0001-0000-000000000000"))), (Id (fromJust (UUID.fromString "00000000-0000-0000-0000-000100000000"))) ], + newConvQualifiedUsers = [], newConvName = Just "\ETXB\119338", newConvAccess = Set.fromList [PrivateAccess, LinkAccess, CodeAccess], newConvAccessRole = Nothing, @@ -457,6 +480,7 @@ testObject_NewConvUnmanaged_user_18 = (Id (fromJust (UUID.fromString "00000001-0000-0001-0000-000000000001"))), (Id (fromJust (UUID.fromString "00000000-0000-0001-0000-000100000000"))) ], + newConvQualifiedUsers = [], newConvName = Just "sd\ACK", newConvAccess = Set.fromList [PrivateAccess, CodeAccess], newConvAccessRole = Nothing, @@ -473,6 +497,7 @@ testObject_NewConvUnmanaged_user_19 = NewConvUnmanaged ( NewConv { newConvUsers = [(Id (fromJust (UUID.fromString "00000002-0000-0001-0000-000000000002")))], + newConvQualifiedUsers = [], newConvName = Just "Cu\DC1", newConvAccess = Set.fromList [InviteAccess, LinkAccess], newConvAccessRole = Nothing, @@ -489,6 +514,7 @@ testObject_NewConvUnmanaged_user_20 = NewConvUnmanaged ( NewConv { newConvUsers = [], + newConvQualifiedUsers = [], newConvName = Just "\SI\1070774", newConvAccess = Set.fromList [PrivateAccess], newConvAccessRole = Nothing, diff --git a/services/brig/test/integration/API/Provider.hs b/services/brig/test/integration/API/Provider.hs index 7c73826f5ca..e5d8dde4a02 100644 --- a/services/brig/test/integration/API/Provider.hs +++ b/services/brig/test/integration/API/Provider.hs @@ -1252,7 +1252,7 @@ createConv g u us = . contentJson . body (RequestBodyLBS (encode (NewConvUnmanaged conv))) where - conv = NewConv us Nothing Set.empty Nothing Nothing Nothing Nothing roleNameWireAdmin + conv = NewConv us [] Nothing Set.empty Nothing Nothing Nothing Nothing roleNameWireAdmin postMessage :: Galley -> diff --git a/services/brig/test/integration/API/Team/Util.hs b/services/brig/test/integration/API/Team/Util.hs index 32b4b20b7a3..f2bea23d82a 100644 --- a/services/brig/test/integration/API/Team/Util.hs +++ b/services/brig/test/integration/API/Team/Util.hs @@ -206,7 +206,7 @@ createTeamConv g tid u us mtimer = do let tinfo = Just $ ConvTeamInfo tid False let conv = NewConvUnmanaged $ - NewConv us Nothing (Set.fromList []) Nothing tinfo mtimer Nothing roleNameWireAdmin + NewConv us [] Nothing (Set.fromList []) Nothing tinfo mtimer Nothing roleNameWireAdmin r <- post ( g @@ -228,7 +228,7 @@ createManagedConv g tid u us mtimer = do let tinfo = Just $ ConvTeamInfo tid True let conv = NewConvManaged $ - NewConv us Nothing (Set.fromList []) Nothing tinfo mtimer Nothing roleNameWireAdmin + NewConv us [] Nothing (Set.fromList []) Nothing tinfo mtimer Nothing roleNameWireAdmin r <- post ( g diff --git a/services/brig/test/integration/Federation/End2end.hs b/services/brig/test/integration/Federation/End2end.hs index 44a284847ba..2ae3bf71b0a 100644 --- a/services/brig/test/integration/Federation/End2end.hs +++ b/services/brig/test/integration/Federation/End2end.hs @@ -212,7 +212,7 @@ testAddRemoteUsersToLocalConv brig1 galley1 brig2 = do alice <- randomUser brig1 bob <- randomUser brig2 - let conv = NewConvUnmanaged $ NewConv [] (Just "gossip") mempty Nothing Nothing Nothing Nothing roleNameWireAdmin + let conv = NewConvUnmanaged $ NewConv [] [] (Just "gossip") mempty Nothing Nothing Nothing Nothing roleNameWireAdmin convId <- cnvId . responseJsonUnsafe <$> post diff --git a/services/galley/galley.cabal b/services/galley/galley.cabal index 3b591fb7d51..8b2b0dabc1f 100644 --- a/services/galley/galley.cabal +++ b/services/galley/galley.cabal @@ -4,7 +4,7 @@ cabal-version: 1.12 -- -- see: https://github.com/sol/hpack -- --- hash: c1d012009b1ef15dcf63843768bedfcf8ca4b2e86ac33d5f43ab680cb82e7450 +-- hash: 63f50e23b5853d8dd4b8b87b8588dc8499783ec5e7e72a181b0ccb399089a6ed name: galley version: 0.83.0 @@ -215,6 +215,7 @@ executable galley-integration , brig-types , bytestring , bytestring-conversion + , case-insensitive , cassandra-util , cassava , cereal diff --git a/services/galley/package.yaml b/services/galley/package.yaml index 1718f5d333e..b3b28541be1 100644 --- a/services/galley/package.yaml +++ b/services/galley/package.yaml @@ -153,6 +153,7 @@ executables: - brig-types - bytestring - bytestring-conversion + - case-insensitive - cassandra-util - cassava - cereal diff --git a/services/galley/src/Galley/API/Create.hs b/services/galley/src/Galley/API/Create.hs index 788602411fc..c85e175cedb 100644 --- a/services/galley/src/Galley/API/Create.hs +++ b/services/galley/src/Galley/API/Create.hs @@ -29,6 +29,7 @@ import Control.Lens hiding ((??)) import Control.Monad.Catch import Data.Id import Data.List1 (list1) +import Data.Qualified (Qualified (..), partitionRemoteOrLocalIds') import Data.Range import qualified Data.Set as Set import Data.Time @@ -96,17 +97,23 @@ internalCreateManagedConversation zusr zcon (NewConvManaged body) = do createRegularGroupConv :: UserId -> ConnId -> NewConvUnmanaged -> Galley ConversationResponse createRegularGroupConv zusr zcon (NewConvUnmanaged body) = do name <- rangeCheckedMaybe (newConvName body) - _uids <- checkedConvSize (newConvUsers body) -- currently not needed, as we only consider local IDs - let localUserIds = newConvUsers body - ensureConnected zusr localUserIds - localCheckedUsers <- checkedConvSize localUserIds + localDomain <- viewFederationDomain + let unqualifiedUserIds = newConvUsers body + qualifiedUserIds = newConvQualifiedUsers body + let allUsers = map (`Qualified` localDomain) unqualifiedUserIds <> qualifiedUserIds + checkedUsers <- checkedConvSize allUsers + let checkedPartitionedUsers = partitionRemoteOrLocalIds' localDomain <$> checkedUsers + let (remotes, locals) = fromConvSize checkedPartitionedUsers + ensureConnected zusr locals + checkRemoteUsersExist remotes + -- FUTUREWORK: Implement (2) and (3) as per comments for Update.addMembers. (also for createTeamGroupConv) c <- Data.createConversation zusr name (access body) (accessRole body) - localCheckedUsers + checkedPartitionedUsers (newConvTeam body) (newConvMessageTimer body) (newConvReceiptMode body) @@ -118,22 +125,30 @@ createRegularGroupConv zusr zcon (NewConvUnmanaged body) = do -- handlers above. Allows both unmanaged and managed conversations. createTeamGroupConv :: UserId -> ConnId -> Public.ConvTeamInfo -> Public.NewConv -> Galley ConversationResponse createTeamGroupConv zusr zcon tinfo body = do - let localUserIds = newConvUsers body name <- rangeCheckedMaybe (newConvName body) + localDomain <- viewFederationDomain + let unqualifiedUserIds = newConvUsers body + qualifiedUserIds = newConvQualifiedUsers body + allUserIds = map (`Qualified` localDomain) unqualifiedUserIds <> qualifiedUserIds let convTeam = cnvTeamId tinfo zusrMembership <- Data.teamMember convTeam zusr + void $ permissionCheck CreateConversation zusrMembership + checkedUsers <- checkedConvSize allUserIds + let checkedPartitionedUsers = partitionRemoteOrLocalIds' localDomain <$> checkedUsers + (remotes, localUserIds) = fromConvSize checkedPartitionedUsers convMemberships <- mapM (Data.teamMember convTeam) localUserIds ensureAccessRole (accessRole body) (zip localUserIds convMemberships) - void $ permissionCheck CreateConversation zusrMembership - otherConvMems <- + checkedPartitionedUsersManaged <- if cnvManaged tinfo then do -- ConvMaxSize MUST be < than hardlimit so the conv size check is enough maybeAllMembers <- Data.teamMembersForFanout convTeam let otherConvMems = filter (/= zusr) $ map (view userId) $ (maybeAllMembers ^. teamMembers) - checkedConvSize otherConvMems + checkedLocalUsers <- checkedConvSize otherConvMems + -- NOTE: Team members are local, therefore there are no remote users in + -- this case + pure (fmap ([],) checkedLocalUsers) else do - otherConvMems <- checkedConvSize localUserIds -- In teams we don't have 1:1 conversations, only regular conversations. We want -- users without the 'AddRemoveConvMember' permission to still be able to create -- regular conversations, therefore we check for 'AddRemoveConvMember' only if @@ -144,13 +159,15 @@ createTeamGroupConv zusr zcon tinfo body = do -- Not sure at the moment how to best solve this but it is unlikely -- we can ever get rid of the team permission model anyway - the only thing I can -- think of is that 'partners' can create convs but not be admins... - when (length (fromConvSize otherConvMems) > 1) $ do + when (length allUserIds > 1) $ do void $ permissionCheck DoNotUseDeprecatedAddRemoveConvMember zusrMembership -- Team members are always considered to be connected, so we only check -- 'ensureConnected' for non-team-members. - ensureConnectedToLocals zusr (notTeamMember (fromConvSize otherConvMems) (catMaybes convMemberships)) - pure otherConvMems - conv <- Data.createConversation zusr name (access body) (accessRole body) otherConvMems (newConvTeam body) (newConvMessageTimer body) (newConvReceiptMode body) (newConvUsersRole body) + ensureConnectedToLocals zusr (notTeamMember localUserIds (catMaybes convMemberships)) + pure checkedPartitionedUsers + checkRemoteUsersExist remotes + -- FUTUREWORK: Implement (2) and (3) as per comments for Update.addMembers. + conv <- Data.createConversation zusr name (access body) (accessRole body) checkedPartitionedUsersManaged (newConvTeam body) (newConvMessageTimer body) (newConvReceiptMode body) (newConvUsersRole body) now <- liftIO getCurrentTime -- NOTE: We only send (conversation) events to members of the conversation notifyCreatedConversation (Just now) zusr (Just zcon) conv diff --git a/services/galley/src/Galley/API/Update.hs b/services/galley/src/Galley/API/Update.hs index 5d3ed694a98..89ac626cdc5 100644 --- a/services/galley/src/Galley/API/Update.hs +++ b/services/galley/src/Galley/API/Update.hs @@ -66,10 +66,8 @@ import qualified Brig.Types.User as User import Control.Lens import Control.Monad.Catch import Control.Monad.State -import Control.Monad.Trans.Except import Data.ByteString.Conversion (toByteString') import Data.Code -import Data.Domain (Domain) import Data.Id import Data.LegalHold (UserLegalHoldStatus (UserLegalHoldNoConsent), defUserLegalHoldStatus) import Data.List.Extra (nubOrdOn) @@ -79,7 +77,6 @@ import Data.Misc (FutureWork (..)) import Data.Qualified import Data.Range import qualified Data.Set as Set -import Data.Tagged (unTagged) import Data.Time import Galley.API.Error import Galley.API.Mapping @@ -116,9 +113,6 @@ import Wire.API.Conversation (InviteQualified (invQRoleName)) import qualified Wire.API.Conversation as Public import qualified Wire.API.Conversation.Code as Public import qualified Wire.API.Event.Conversation as Public -import Wire.API.Federation.API.Brig as FederatedBrig -import Wire.API.Federation.Client as FederatedBrig -import Wire.API.Federation.Error import qualified Wire.API.Message as Public import qualified Wire.API.Message.Proto as Proto import Wire.API.Routes.Public.Galley (UpdateResponses) @@ -507,7 +501,7 @@ addMembers zusr zcon convId invite = do ensureAccess conv InviteAccess ensureConvRoleNotElevated self (invQRoleName invite) checkLocals conv (Data.convTeam conv) newLocals - checkRemotes newRemotes + checkRemoteUsersExist newRemotes addToConversation mems (zusr, memConvRoleName self) zcon ((,invQRoleName invite) <$> newLocals) ((,invQRoleName invite) <$> newRemotes) conv where userIsMember u = (^. userId . to (== u)) @@ -525,26 +519,6 @@ addMembers zusr zcon convId invite = do ensureAccessRole (Data.convAccessRole conv) (zip newUsers $ repeat Nothing) ensureConnectedOrSameTeam zusr newUsers - checkRemotes :: [Remote UserId] -> Galley () - checkRemotes = - traverse_ (uncurry checkRemotesFor) - . Map.assocs - . partitionQualified - . map unTagged - - checkRemotesFor :: Domain -> [UserId] -> Galley () - checkRemotesFor domain uids = do - let rpc = FederatedBrig.getUsersByIds FederatedBrig.clientRoutes uids - users <- - runExceptT (executeFederated domain rpc) - >>= either (throwM . federationErrorToWai) pure - let uids' = - map - (qUnqualified . User.profileQualifiedId) - (filter (not . User.profileDeleted) users) - unless (Set.fromList uids == Set.fromList uids') $ - throwM unknownRemoteUser - updateSelfMemberH :: UserId ::: ConnId ::: ConvId ::: JsonRequest Public.MemberUpdate -> Galley Response updateSelfMemberH (zusr ::: zcon ::: cid ::: req) = do update <- fromJsonBody req diff --git a/services/galley/src/Galley/API/Util.hs b/services/galley/src/Galley/API/Util.hs index fcc3128a930..bb32dde8bff 100644 --- a/services/galley/src/Galley/API/Util.hs +++ b/services/galley/src/Galley/API/Util.hs @@ -21,12 +21,15 @@ import Brig.Types (Relation (..)) import Brig.Types.Intra (ReAuthUser (..)) import Control.Lens (view, (.~), (^.)) import Control.Monad.Catch +import Control.Monad.Except (runExceptT) import Data.ByteString.Conversion import Data.Domain (Domain) import Data.Id as Id +import qualified Data.Map as Map import Data.Misc (PlainTextPassword (..)) -import Data.Qualified (Remote) +import Data.Qualified (Qualified (qUnqualified), Remote, partitionQualified) import qualified Data.Set as Set +import Data.Tagged (Tagged (unTagged)) import qualified Data.Text.Lazy as LT import Data.Time import Galley.API.Error @@ -48,6 +51,10 @@ import Network.Wai import Network.Wai.Predicate hiding (Error) import Network.Wai.Utilities import UnliftIO (concurrently) +import qualified Wire.API.Federation.API.Brig as FederatedBrig +import qualified Wire.API.Federation.Client as Federation +import Wire.API.Federation.Error (federationErrorToWai) +import qualified Wire.API.User as User type JSON = Media "application" "json" @@ -131,9 +138,9 @@ ensureConvRoleNotElevated origMember targetRole = do (_, _) -> throwM (badRequest "Custom roles not supported") --- | If a team memeber is not given throw 'notATeamMember'; if the given team +-- | If a team member is not given throw 'notATeamMember'; if the given team -- member does not have the given permission, throw 'operationDenied'. --- Otherwise, return unit. +-- Otherwise, return the team member. permissionCheck :: (IsPerm perm, Show perm) => perm -> Maybe TeamMember -> Galley TeamMember permissionCheck p = \case Just m -> do @@ -299,3 +306,24 @@ pushConversationEvent e users bots = do viewFederationDomain :: MonadReader Env m => m Domain viewFederationDomain = view (options . optSettings . setFederationDomain) + +checkRemoteUsersExist :: [Remote UserId] -> Galley () +checkRemoteUsersExist = + -- FUTUREWORK: pooledForConcurrentlyN_ instead of sequential checks per domain + traverse_ (uncurry checkRemotesFor) + . Map.assocs + . partitionQualified + . map unTagged + +checkRemotesFor :: Domain -> [UserId] -> Galley () +checkRemotesFor domain uids = do + let rpc = FederatedBrig.getUsersByIds FederatedBrig.clientRoutes uids + users <- + runExceptT (Federation.executeFederated domain rpc) + >>= either (throwM . federationErrorToWai) pure + let uids' = + map + (qUnqualified . User.profileQualifiedId) + (filter (not . User.profileDeleted) users) + unless (Set.fromList uids == Set.fromList uids') $ + throwM unknownRemoteUser diff --git a/services/galley/src/Galley/Data.hs b/services/galley/src/Galley/Data.hs index a1ab046806c..b0d88886fe5 100644 --- a/services/galley/src/Galley/Data.hs +++ b/services/galley/src/Galley/Data.hs @@ -574,7 +574,7 @@ createConversation :: Maybe (Range 1 256 Text) -> [Access] -> AccessRole -> - ConvSizeChecked [UserId] -> + ConvSizeChecked ([Remote UserId], [UserId]) -> Maybe ConvTeamInfo -> -- | Message timer Maybe Milliseconds -> @@ -592,10 +592,8 @@ createConversation usr name acc role others tinfo mtimer recpt othersConversatio setConsistency Quorum addPrepQuery Cql.insertConv (conv, RegularConv, usr, Set (toList acc), role, fromRange <$> name, Just (cnvTeamId ti), mtimer, recpt) addPrepQuery Cql.insertTeamConv (cnvTeamId ti, conv, cnvManaged ti) - -- FUTUREWORK: split users into list of remote and local users - let remoteUsers :: [Remote UserId] - remoteUsers = [] - (_, mems, rMems) <- addMembersUncheckedWithRole now conv (usr, roleNameWireAdmin) (toList $ list1 (usr, roleNameWireAdmin) ((,othersConversationRole) <$> fromConvSize others)) ((,othersConversationRole) <$> remoteUsers) + let (remoteUsers, localUsers) = fromConvSize others + (_, mems, rMems) <- addMembersUncheckedWithRole now conv (usr, roleNameWireAdmin) (toList $ list1 (usr, roleNameWireAdmin) ((,othersConversationRole) <$> localUsers)) ((,othersConversationRole) <$> remoteUsers) return $ newConv conv RegularConv usr mems rMems acc role name (cnvTeamId <$> tinfo) mtimer recpt createSelfConversation :: MonadClient m => UserId -> Maybe (Range 1 256 Text) -> m Conversation diff --git a/services/galley/src/Galley/Validation.hs b/services/galley/src/Galley/Validation.hs index 305be7f52b9..6473a52be4c 100644 --- a/services/galley/src/Galley/Validation.hs +++ b/services/galley/src/Galley/Validation.hs @@ -50,6 +50,7 @@ rangeCheckedMaybe (Just a) = Just <$> rangeChecked a -- Between 0 and (setMaxConvSize - 1) newtype ConvSizeChecked a = ConvSizeChecked {fromConvSize :: a} + deriving (Functor) -- Between 1 and setMaxConvSize data ConvMemberAddSizeChecked = ConvMemberAddSizeChecked {sizeCheckedLocals :: [(UserId, RoleName)], sizeCheckedRemotes :: [(Remote UserId, RoleName)]} diff --git a/services/galley/test/integration/API.hs b/services/galley/test/integration/API.hs index 99b8537ebe6..c138aaefd2c 100644 --- a/services/galley/test/integration/API.hs +++ b/services/galley/test/integration/API.hs @@ -98,8 +98,14 @@ tests s = test s "fail to get >1000 conversation ids" getConvIdsFailMaxSize, test s "page through conversations" getConvsPagingOk, test s "fail to create conversation when not connected" postConvFailNotConnected, + test s "fail to create conversation with qualified users when not connected" postConvQualifiedFailNotConnected, test s "M:N conversation creation must have view tsMaxConvSize @@ -654,6 +670,16 @@ postConvFailNumMembers = do const 400 === statusCode const (Just "client-error") === fmap label . responseJsonUnsafe +postConvQualifiedFailNumMembers :: TestM () +postConvQualifiedFailNumMembers = do + n <- fromIntegral <$> view tsMaxConvSize + alice <- randomUser + bob : others <- replicateM n randomQualifiedUser + connectLocalQualifiedUsers alice (list1 bob others) + postConvQualified alice (bob : others) Nothing [] Nothing Nothing !!! do + const 400 === statusCode + const (Just "client-error") === fmap label . responseJsonUnsafe + -- | If somebody has blocked a user, that user shouldn't be able to create a -- group conversation which includes them. postConvFailBlocked :: TestM () @@ -668,6 +694,67 @@ postConvFailBlocked = do const 403 === statusCode const (Just "not-connected") === fmap label . responseJsonUnsafe +--- | If somebody has blocked a user, that user shouldn't be able to create a +-- group conversation which includes them. +postConvQualifiedFailBlocked :: TestM () +postConvQualifiedFailBlocked = do + alice <- randomUser + bob <- randomQualifiedUser + jane <- randomQualifiedUser + connectLocalQualifiedUsers alice (list1 bob [jane]) + putConnectionQualified jane alice Blocked + !!! const 200 === statusCode + postConvQualified alice [bob, jane] Nothing [] Nothing Nothing !!! do + const 403 === statusCode + const (Just "not-connected") === fmap label . responseJsonUnsafe + +postConvQualifiedNonExistentDomain :: TestM () +postConvQualifiedNonExistentDomain = do + alice <- randomUser + bob <- flip Qualified (Domain "non-existent.example.com") <$> randomId + postConvQualified alice [bob] Nothing [] Nothing Nothing !!! do + const 422 === statusCode + +postConvQualifiedNonExistentUser :: TestM () +postConvQualifiedNonExistentUser = do + alice <- randomUser + bobId <- randomId + charlieId <- randomId + let remoteDomain = Domain "far-away.example.com" + bob = Qualified bobId remoteDomain + charlie = Qualified charlieId remoteDomain + opts <- view tsGConf + _g <- view tsGalley + (resp, _) <- + withTempMockFederator + opts + remoteDomain + (const [mkProfile charlie (Name "charlie")]) + (postConvQualified alice [bob, charlie] (Just "remote gossip") [] Nothing Nothing) + liftIO $ do + statusCode resp @?= 400 + let err = responseJsonUnsafe resp :: Object + (err ^. at "label") @?= Just "unknown-remote-user" + +postConvQualifiedFederationNotEnabled :: TestM () +postConvQualifiedFederationNotEnabled = do + g <- view tsGalley + alice <- randomUser + bob <- flip Qualified (Domain "some-remote-backend.example.com") <$> randomId + opts <- view tsGConf + let federatorNotConfigured :: Opts = opts & optFederator .~ Nothing + withSettingsOverrides federatorNotConfigured $ + postConvHelper g alice [bob] !!! do + const 400 === statusCode + const (Just "federation-not-enabled") === fmap label . responseJsonUnsafe + +-- like postConvQualified +-- FUTUREWORK: figure out how to use functions in the TestM monad inside withSettingsOverrides and remove this duplication +postConvHelper :: (MonadIO m, MonadHttp m) => (Request -> Request) -> UserId -> [Qualified UserId] -> m ResponseLBS +postConvHelper g zusr newUsers = do + let conv = NewConvUnmanaged $ NewConv [] newUsers (Just "gossip") (Set.fromList []) Nothing Nothing Nothing Nothing roleNameWireAdmin + post $ g . path "/conversations" . zUser zusr . zConn "conn" . zType "access" . json conv + postSelfConvOk :: TestM () postSelfConvOk = do alice <- randomUser @@ -692,7 +779,7 @@ postConvO2OFailWithSelf :: TestM () postConvO2OFailWithSelf = do g <- view tsGalley alice <- randomUser - let inv = NewConvUnmanaged (NewConv [alice] Nothing mempty Nothing Nothing Nothing Nothing roleNameWireAdmin) + let inv = NewConvUnmanaged (NewConv [alice] [] Nothing mempty Nothing Nothing Nothing Nothing roleNameWireAdmin) post (g . path "/conversations/one2one" . zUser alice . zConn "conn" . zType "access" . json inv) !!! do const 403 === statusCode const (Just "invalid-op") === fmap label . responseJsonUnsafe @@ -853,6 +940,17 @@ getConvOk = do getConv bob conv !!! const 200 === statusCode getConv chuck conv !!! const 200 === statusCode +getConvQualifiedOk :: TestM () +getConvQualifiedOk = do + alice <- randomUser + bob <- randomQualifiedUser + chuck <- randomQualifiedUser + connectLocalQualifiedUsers alice (list1 bob [chuck]) + conv <- decodeConvId <$> postConvQualified alice [bob, chuck] (Just "gossip") [] Nothing Nothing + getConv alice conv !!! const 200 === statusCode + getConv (qUnqualified bob) conv !!! const 200 === statusCode + getConv (qUnqualified chuck) conv !!! const 200 === statusCode + accessConvMeta :: TestM () accessConvMeta = do g <- view tsGalley diff --git a/services/galley/test/integration/API/Teams.hs b/services/galley/test/integration/API/Teams.hs index 8cbb2154641..fb72bb73b5f 100644 --- a/services/galley/test/integration/API/Teams.hs +++ b/services/galley/test/integration/API/Teams.hs @@ -880,7 +880,7 @@ testAddManagedConv = do let tinfo = ConvTeamInfo tid True let conv = NewConvManaged $ - NewConv [owner] (Just "blah") (Set.fromList []) Nothing (Just tinfo) Nothing Nothing roleNameWireAdmin + NewConv [owner] [] (Just "blah") (Set.fromList []) Nothing (Just tinfo) Nothing Nothing roleNameWireAdmin post ( g . path "/conversations" diff --git a/services/galley/test/integration/API/Teams/LegalHold.hs b/services/galley/test/integration/API/Teams/LegalHold.hs index 6fe2929b925..a23c1fa1f64 100644 --- a/services/galley/test/integration/API/Teams/LegalHold.hs +++ b/services/galley/test/integration/API/Teams/LegalHold.hs @@ -29,6 +29,7 @@ import qualified API.SQS as SQS import API.Util import Bilge hiding (accept, head, timeout, trace) import Bilge.Assert +import qualified Bilge.TestSession as BilgeTest import Brig.Types.Client import Brig.Types.Intra (ConnectionStatus (ConnectionStatus), UserSet (..)) import Brig.Types.Provider @@ -71,12 +72,10 @@ import Galley.Types.Teams import Gundeck.Types.Notification (ntfPayload) import Imports import Network.HTTP.Types.Status (status200, status400, status404) -import Network.Wai import Network.Wai as Wai import qualified Network.Wai.Handler.Warp as Warp import qualified Network.Wai.Handler.Warp.Internal as Warp import qualified Network.Wai.Handler.WarpTLS as Warp -import qualified Network.Wai.Test as WaiTest import qualified Network.Wai.Utilities.Error as Error import qualified Network.Wai.Utilities.Response as Wai import System.IO (hPutStrLn) @@ -1350,7 +1349,7 @@ withDummyTestServiceForTeamNoService go = do -- it's here for historical reason because we did this in galley.yaml -- at some point in the past rather than in an internal end-point, and that required spawning -- another galley 'Application' with 'withSettingsOverrides'. -withLHWhitelist :: forall a. HasCallStack => TeamId -> WaiTest.Session a -> TestM a +withLHWhitelist :: forall a. HasCallStack => TeamId -> BilgeTest.SessionT TestM a -> TestM a withLHWhitelist tid action = do void $ putLHWhitelistTeam tid opts <- view tsGConf diff --git a/services/galley/test/integration/API/Util.hs b/services/galley/test/integration/API/Util.hs index b4836c8206b..fa9828dd2a1 100644 --- a/services/galley/test/integration/API/Util.hs +++ b/services/galley/test/integration/API/Util.hs @@ -28,7 +28,8 @@ import Brig.Types.Intra (ConnectionStatus (ConnectionStatus), UserAccount (..), import Brig.Types.Team.Invitation import Brig.Types.User.Auth (CookieLabel (..)) import Control.Lens hiding (from, to, (#), (.=)) -import Control.Monad.Catch (MonadCatch, finally) +import Control.Monad.Catch (MonadCatch, MonadMask) +import qualified Control.Monad.Catch as Catch import Control.Monad.Except (ExceptT, runExceptT) import Control.Retry (constantDelay, exponentialBackoff, limitRetries, retrying) import Data.Aeson hiding (json) @@ -47,6 +48,7 @@ import Data.Json.Util (UTCTimeMillis) import Data.LegalHold (defUserLegalHoldStatus) import Data.List.NonEmpty (NonEmpty) import Data.List1 as List1 +import qualified Data.Map as LMap import qualified Data.Map.Strict as Map import Data.Misc import Data.ProtocolBuffers (encodeMessage) @@ -79,12 +81,12 @@ import Gundeck.Types.Notification queuedTime, ) import Imports -import qualified Network.Wai.Test as WaiTest import System.Random import qualified Test.QuickCheck as Q import Test.Tasty.Cannon (TimeoutUnit (..), (#)) import qualified Test.Tasty.Cannon as WS import Test.Tasty.HUnit +import TestHelpers (viewFederationDomain) import TestSetup import UnliftIO.Timeout import Util.Options @@ -118,7 +120,7 @@ createBindingTeam :: HasCallStack => TestM (UserId, TeamId) createBindingTeam = do ownerid <- randomTeamCreator teams <- getTeams ownerid - let [team] = view (teamListTeams) teams + let [team] = view teamListTeams teams let tid = view teamId team SQS.assertQueue "create team" SQS.tActivate refreshIndex @@ -131,7 +133,7 @@ createBindingTeamWithMembers numUsers = do mem <- addUserToTeam owner tid SQS.assertQueue "add member" $ SQS.tUpdate (fromIntegral n) [owner] refreshIndex - return $ view Galley.Types.Teams.userId $ mem + return $ view Galley.Types.Teams.userId mem return (tid, owner, members) @@ -428,13 +430,13 @@ getInvitationCode t ref = do . queryItem "invitation_id" (toByteString' ref) ) let lbs = fromMaybe "" $ responseBody r - return $ fromByteString . Text.encodeUtf8 =<< (lbs ^? key "code" . _String) + return $ fromByteString . Text.encodeUtf8 =<< lbs ^? key "code" . _String fromMaybe (error "No code?") <$> retrying (constantDelay 800000 <> limitRetries 3) (\_ -> pure . isNothing) - (\_ -> getm) + (const getm) -- Note that here we don't make use of the datatype because NewConv has a default -- and therefore cannot be unset. However, given that this is to test the legacy @@ -477,7 +479,7 @@ createTeamConvAccessRaw u tid us name acc role mtimer convRole = do let tinfo = ConvTeamInfo tid False let conv = NewConvUnmanaged $ - NewConv us name (fromMaybe (Set.fromList []) acc) role (Just tinfo) mtimer Nothing (fromMaybe roleNameWireAdmin convRole) + NewConv us [] name (fromMaybe (Set.fromList []) acc) role (Just tinfo) mtimer Nothing (fromMaybe roleNameWireAdmin convRole) post ( g . path "/conversations" @@ -506,7 +508,7 @@ createManagedConv u tid us name acc mtimer = do let tinfo = ConvTeamInfo tid True let conv = NewConvManaged $ - NewConv us name (fromMaybe (Set.fromList []) acc) Nothing (Just tinfo) mtimer Nothing roleNameWireAdmin + NewConv us [] name (fromMaybe (Set.fromList []) acc) Nothing (Just tinfo) mtimer Nothing roleNameWireAdmin r <- post ( g @@ -524,28 +526,34 @@ createOne2OneTeamConv u1 u2 n tid = do g <- view tsGalley let conv = NewConvUnmanaged $ - NewConv [u2] n mempty Nothing (Just $ ConvTeamInfo tid False) Nothing Nothing roleNameWireAdmin + NewConv [u2] [] n mempty Nothing (Just $ ConvTeamInfo tid False) Nothing Nothing roleNameWireAdmin post $ g . path "/conversations/one2one" . zUser u1 . zConn "conn" . zType "access" . json conv postConv :: UserId -> [UserId] -> Maybe Text -> [Access] -> Maybe AccessRole -> Maybe Milliseconds -> TestM ResponseLBS postConv u us name a r mtimer = postConvWithRole u us name a r mtimer roleNameWireAdmin +postConvQualified :: (HasGalley m, MonadIO m, MonadMask m, MonadHttp m) => UserId -> [Qualified UserId] -> Maybe Text -> [Access] -> Maybe AccessRole -> Maybe Milliseconds -> m ResponseLBS +postConvQualified u us name a r mtimer = postConvWithRoleQualified us u [] name a r mtimer roleNameWireAdmin + postTeamConv :: TeamId -> UserId -> [UserId] -> Maybe Text -> [Access] -> Maybe AccessRole -> Maybe Milliseconds -> TestM ResponseLBS postTeamConv tid u us name a r mtimer = do g <- view tsGalley - let conv = NewConvUnmanaged $ NewConv us name (Set.fromList a) r (Just (ConvTeamInfo tid False)) mtimer Nothing roleNameWireAdmin + let conv = NewConvUnmanaged $ NewConv us [] name (Set.fromList a) r (Just (ConvTeamInfo tid False)) mtimer Nothing roleNameWireAdmin post $ g . path "/conversations" . zUser u . zConn "conn" . zType "access" . json conv postConvWithRole :: UserId -> [UserId] -> Maybe Text -> [Access] -> Maybe AccessRole -> Maybe Milliseconds -> RoleName -> TestM ResponseLBS -postConvWithRole u us name a r mtimer role = do - g <- view tsGalley - let conv = NewConvUnmanaged $ NewConv us name (Set.fromList a) r Nothing mtimer Nothing role +postConvWithRole = postConvWithRoleQualified [] + +postConvWithRoleQualified :: (HasGalley m, MonadIO m, MonadMask m, MonadHttp m) => [Qualified UserId] -> UserId -> [UserId] -> Maybe Text -> [Access] -> Maybe AccessRole -> Maybe Milliseconds -> RoleName -> m ResponseLBS +postConvWithRoleQualified qualifiedUsers u unqualifiedUsers name a r mtimer role = do + g <- viewGalley + let conv = NewConvUnmanaged $ NewConv unqualifiedUsers qualifiedUsers name (Set.fromList a) r Nothing mtimer Nothing role post $ g . path "/conversations" . zUser u . zConn "conn" . zType "access" . json conv postConvWithReceipt :: UserId -> [UserId] -> Maybe Text -> [Access] -> Maybe AccessRole -> Maybe Milliseconds -> ReceiptMode -> TestM ResponseLBS postConvWithReceipt u us name a r mtimer rcpt = do g <- view tsGalley - let conv = NewConvUnmanaged $ NewConv us name (Set.fromList a) r Nothing mtimer (Just rcpt) roleNameWireAdmin + let conv = NewConvUnmanaged $ NewConv us [] name (Set.fromList a) r Nothing mtimer (Just rcpt) roleNameWireAdmin post $ g . path "/conversations" . zUser u . zConn "conn" . zType "access" . json conv postSelfConv :: UserId -> TestM ResponseLBS @@ -556,7 +564,7 @@ postSelfConv u = do postO2OConv :: UserId -> UserId -> Maybe Text -> TestM ResponseLBS postO2OConv u1 u2 n = do g <- view tsGalley - let conv = NewConvUnmanaged $ NewConv [u2] n mempty Nothing Nothing Nothing Nothing roleNameWireAdmin + let conv = NewConvUnmanaged $ NewConv [u2] [] n mempty Nothing Nothing Nothing Nothing roleNameWireAdmin post $ g . path "/conversations/one2one" . zUser u1 . zConn "conn" . zType "access" . json conv postConnectConv :: UserId -> UserId -> Text -> Text -> Maybe Text -> TestM ResponseLBS @@ -616,7 +624,7 @@ postOtrBroadcastMessage req usrs clt rcps = do -- | 'postOtrBroadcastMessage' with @"report_missing"@ in body. postOtrBroadcastMessage' :: (Monad m, MonadCatch m, MonadIO m, MonadHttp m, MonadFail m, HasCallStack) => (Request -> Request) -> Maybe [UserId] -> (Request -> Request) -> UserId -> ClientId -> [(UserId, ClientId, Text)] -> m ResponseLBS -postOtrBroadcastMessage' g reportMissingBody f u d rec = do +postOtrBroadcastMessage' g reportMissingBody f u d rec = post $ g . f @@ -935,7 +943,7 @@ deleteUser u = do delete (g . path "/i/user" . zUser u) !!! const 200 === statusCode getTeamQueue :: HasCallStack => UserId -> Maybe NotificationId -> Maybe (Int, Bool) -> Bool -> TestM [(NotificationId, UserId)] -getTeamQueue zusr msince msize onlyLast = do +getTeamQueue zusr msince msize onlyLast = parseEventList . responseJsonUnsafe <$> ( getTeamQueue' zusr msince (fst <$> msize) onlyLast [(NotificationId, UserId)] parseEventList qnl - | isJust msize && qnl ^. queuedHasMore /= (snd $ fromJust msize) = + | isJust msize && qnl ^. queuedHasMore /= snd (fromJust msize) = error $ "expected has_more: " <> show (snd $ fromJust msize) <> "; but found: " <> show (qnl ^. queuedHasMore) - | qnl ^. queuedTime /= Nothing = + | isJust (qnl ^. queuedTime) = error $ "expected time: Nothing; but found: " <> show (qnl ^. queuedTime) | otherwise = fmap (_2 %~ parseEvt) . mconcat . fmap parseEvts . view queuedNotifications $ qnl @@ -1049,7 +1057,7 @@ assertConvWithRole r t c s us n mt role = do assertEqual "self" (Just s) (memId <$> _self) assertEqual "others" (Just . Set.fromList $ us) (Set.fromList . map (qUnqualified . omQualifiedId) . toList <$> others) assertEqual "creator is always and admin" (Just roleNameWireAdmin) (memConvRoleName <$> _self) - assertBool "others role" (all (\x -> x == role) $ fromMaybe (error "Cannot be null") ((map omConvRoleName . toList <$> others))) + assertBool "others role" (all (== role) $ maybe (error "Cannot be null") (map omConvRoleName . toList) others) assertBool "otr muted not false" (Just False == (memOtrMuted <$> _self)) assertBool "otr muted ref not empty" (isNothing (memOtrMutedRef =<< _self)) assertBool "otr archived not false" (Just False == (memOtrArchived <$> _self)) @@ -1075,7 +1083,7 @@ wsAssertOtr' evData conv usr from to txt n = do -- | This assumes the default role name wsAssertMemberJoin :: ConvId -> UserId -> [UserId] -> Notification -> IO () -wsAssertMemberJoin conv usr new n = wsAssertMemberJoinWithRole conv usr new roleNameWireAdmin n +wsAssertMemberJoin conv usr new = wsAssertMemberJoinWithRole conv usr new roleNameWireAdmin wsAssertMemberJoinWithRole :: ConvId -> UserId -> [UserId] -> RoleName -> Notification -> IO () wsAssertMemberJoinWithRole conv usr new role n = do @@ -1084,7 +1092,7 @@ wsAssertMemberJoinWithRole conv usr new role n = do evtConv e @?= conv evtType e @?= MemberJoin evtFrom e @?= usr - evtData e @?= EdMembersJoin (SimpleMembers (fmap (\x -> SimpleMember x role) new)) + evtData e @?= EdMembersJoin (SimpleMembers (fmap (`SimpleMember` role) new)) wsAssertMemberUpdateWithRole :: ConvId -> UserId -> UserId -> RoleName -> Notification -> IO () wsAssertMemberUpdateWithRole conv usr target role n = do @@ -1195,6 +1203,20 @@ zType = header "Z-Type" connectUsers :: UserId -> List1 UserId -> TestM () connectUsers u us = void $ connectUsersWith expect2xx u us +-- TODO: it'd be nicer to just take a list here and handle the cases with 0 +-- users differently +connectLocalQualifiedUsers :: UserId -> List1 (Qualified UserId) -> TestM () +connectLocalQualifiedUsers u us = do + localDomain <- viewFederationDomain + let partitionMap = partitionQualified . toList . toNonEmpty $ us + -- FUTUREWORK: connect all users, not just those on the same domain as 'u' + case LMap.lookup localDomain partitionMap of + Nothing -> err + Just [] -> err + Just (x : xs) -> void $ connectUsersWith expect2xx u (list1 x xs) + where + err = liftIO . assertFailure $ "No user on the domain with " ++ show u + connectUsersUnchecked :: UserId -> List1 UserId -> @@ -1206,7 +1228,7 @@ connectUsersWith :: UserId -> List1 UserId -> TestM (List1 (Response (Maybe Lazy.ByteString), Response (Maybe Lazy.ByteString))) -connectUsersWith fn u us = mapM connectTo us +connectUsersWith fn u = mapM connectTo where connectTo v = do b <- view tsBrig @@ -1260,6 +1282,27 @@ putConnection from to r = do where payload = RequestBodyLBS . encode $ object ["status" .= r] +-- | A slightly modified copy of 'putConnection' from above. +putConnectionQualified :: Qualified UserId -> UserId -> Relation -> TestM ResponseLBS +putConnectionQualified fromQualified to r = do + localDomain <- viewFederationDomain + let (Qualified from qualifiedDomain) = fromQualified + liftIO $ + assertEqual + "The qualified user's domain is not local" + localDomain + qualifiedDomain + brig <- view tsBrig + put $ + brig + . paths ["/connections", toByteString' to] + . contentJson + . body payload + . zUser from + . zConn "conn" + where + payload = RequestBodyLBS . encode $ object ["status" .= r] + -- | A copy of `assertConnections from Brig integration tests. assertConnections :: HasCallStack => UserId -> [ConnectionStatus] -> TestM () assertConnections u cstat = do @@ -1267,7 +1310,7 @@ assertConnections u cstat = do resp <- listConnections brig u show cstat <> " is not a subset of " <> show cstat' where status c = ConnectionStatus (ucFrom c) (ucTo c) (ucStatus c) @@ -1294,7 +1337,7 @@ randomUser' isCreator hasPassword hasEmail = do ["name" .= fromEmail e] <> ["password" .= defPassword | hasPassword] <> ["email" .= fromEmail e | hasEmail] - <> ["team" .= (Team.BindingNewTeam $ Team.newNewTeam (unsafeRange "teamName") (unsafeRange "defaultIcon")) | isCreator] + <> ["team" .= Team.BindingNewTeam (Team.newNewTeam (unsafeRange "teamName") (unsafeRange "defaultIcon")) | isCreator] selfProfile <- responseJsonUnsafe <$> (post (b . path "/i/users" . json p) error $ "getStatus: failed to parse response: " ++ show r Just j -> do - let st = maybeFromJSON =<< (j ^? key "status") + let st = maybeFromJSON =<< j ^? key "status" let decoded = fromMaybe (error $ "getStatus: failed to decode status" ++ show j) st return $ decoded == Deleted where @@ -1567,11 +1610,11 @@ defCookieLabel = CookieLabel "auth" -- | This allows you to run requests against a galley instantiated using the given options. -- Note that ONLY 'galley' calls should occur within the provided action, calls to other -- services will fail. -withSettingsOverrides :: MonadIO m => Opts.Opts -> WaiTest.Session a -> m a -withSettingsOverrides opts action = liftIO $ do - (galleyApp, _, finalizer) <- Run.mkApp opts - WaiTest.runSession action galleyApp - `finally` liftIO finalizer +withSettingsOverrides :: (HasGalley m, MonadIO m, MonadMask m) => Opts.Opts -> SessionT m a -> m a +withSettingsOverrides opts action = do + (galleyApp, _, finalizer) <- liftIO $ Run.mkApp opts + runSessionT action galleyApp + `Catch.finally` liftIO finalizer waitForMemberDeletion :: UserId -> TeamId -> UserId -> TestM () waitForMemberDeletion zusr tid uid = do @@ -1710,13 +1753,13 @@ mkProfile quid name = -- federator response (of an arbitrary JSON-serialisable type a) for every -- expected request. withTempMockFederator :: - (MonadIO m, ToJSON a) => + (MonadIO m, ToJSON a, HasGalley m, MonadMask m) => Opts.Opts -> Domain -> (FederatedRequest -> a) -> - WaiTest.Session b -> + SessionT m b -> m (b, Mock.ReceivedRequests) -withTempMockFederator opts targetDomain resp action = liftIO . assertRightT +withTempMockFederator opts targetDomain resp action = assertRightT . Mock.withTempMockFederator st0 (pure . oresp) $ \st -> lift $ do let opts' = diff --git a/services/galley/test/integration/API/Util/TeamFeature.hs b/services/galley/test/integration/API/Util/TeamFeature.hs index a16be31d0d4..78edbf72342 100644 --- a/services/galley/test/integration/API/Util/TeamFeature.hs +++ b/services/galley/test/integration/API/Util/TeamFeature.hs @@ -20,6 +20,7 @@ module API.Util.TeamFeature where import API.Util (zUser) import qualified API.Util as Util import Bilge +import qualified Bilge.TestSession as BilgeTest import Control.Lens (view, (.~)) import Data.Aeson (ToJSON) import Data.ByteString.Conversion (toByteString') @@ -27,11 +28,10 @@ import Data.Id (TeamId, UserId) import Galley.Options (optSettings, setFeatureFlags) import Galley.Types.Teams import Imports -import qualified Network.Wai.Test as WaiTest import TestSetup import qualified Wire.API.Team.Feature as Public -withCustomSearchFeature :: FeatureTeamSearchVisibility -> WaiTest.Session () -> TestM () +withCustomSearchFeature :: FeatureTeamSearchVisibility -> BilgeTest.SessionT TestM () -> TestM () withCustomSearchFeature flag action = do opts <- view tsGConf let opts' = opts & optSettings . setFeatureFlags . flagTeamSearchVisibility .~ flag