diff --git a/changelog.d/1-api-changes/access-role-v3 b/changelog.d/1-api-changes/access-role-v3 new file mode 100644 index 00000000000..9f1c57e8249 --- /dev/null +++ b/changelog.d/1-api-changes/access-role-v3 @@ -0,0 +1,4 @@ +- The endpoints `POST /conversations/list` and `GET /conversations` have been removed. Use `POST /conversations/list-ids` followed by `POST /conversations/list` instead. +- The endpoint `PUT /conversations/:id/access` has been removed. Use its qualified counterpart instead. +- The field `access_role_v2` in the `Conversation` type, in the request body of `POST /conversations`, and in the request body of `PUT /conversations/:domain/:id/access` has been removed. Its content is now contained in the `access_role` field instead. It replaces the legacy access role, previously contained in the `access_role` field. +- Clients implementing the V3 API must be prepared to handle a change in the format of the conversation.access_update event. Namely, the field access_role_v2 has become optional. When missing, its value is to be found in the field access_role. diff --git a/docs/src/developer/developer/api-versioning.md b/docs/src/developer/developer/api-versioning.md index 6e1f3d75b31..539f73decb0 100644 --- a/docs/src/developer/developer/api-versioning.md +++ b/docs/src/developer/developer/api-versioning.md @@ -282,3 +282,52 @@ Many variations on this theme are possible. For example, one could choose to write adapting functions in terms of the new input/output types, or even use a mixed approach. The adapting functions need not be pure in general, and they might even perform further RPC calls. + +## Versioning changes in events + +Making incompatible changes to events is also sometimes necessary, or at least +desirable. Unfortunately, there is no direct way to make API versioning +preserve compatibility with older clients when the format of events changes. +This is because the format of events is decided when they are generated, which +is of course before they are fetched by the clients. By the time the backend is +made aware of the version supported by a client, it is too late to change any +logic of event generation or serialisation. + +However, there are ways to alter the event API in incompatible ways without +breaking older clients. Namely, we can tie a change X in the format of an event +to a specific api version N. This means that in order for a client to support +version N or later, it has to be able to consume events in any format, +before or after X. + +If clients respect this constraint, then the backend only needs to keep the old +format around for as long as version N-1 is supported, and can apply change X as +soon as version N-1 is dropped. + +Conversely, clients need to be advised on when it is ok for them to drop their +legacy event parsing code. Unfortunately, determining this point in time is +complicated by the fact that legacy events may be retained by a backend for +some time after it has been upgraded to a version that emits events in the new +format. Therefore, this has to be worked out on a case by case basis. + +More precisely: When a new version Q of a backend is released, *if* we can +ensure that no version lower than N is running anywhere in production, and +hasn't been for a time at least as long as the maximum event retention time, +*then* we can drop the requirement for clients to be able to read events in the +legacy format, *as long as they support only versions larger or equal to Q*. + +### Example timeline + +- While version 3 is in development: a new format for an event is introduced in + the code base, but not yet used for output events, the new format is + documented for clients. +- Version 3 is finalised: events are still produced using the old format; + clients that implement v3 are able to parse both event formats. +- Versions 4 to 6 are finalised. No changes to events. +- Support for version 2 is dropped while version 7 is in development. The old + format can be removed from the code base, and the backend can start producing + events in the new format. No changes in clients are required. +- Version 7 to 9 are finalised. No further changes to events. +- Version 2 or lower is not used in production anymore. Version 10 is currently + in development. The old event format is removed from the documentation. + Clients that support only version 10 or above are not required to understand + the old format anymore. diff --git a/libs/wire-api-federation/src/Wire/API/Federation/API/Galley.hs b/libs/wire-api-federation/src/Wire/API/Federation/API/Galley.hs index e7d86ab700e..1528545efcc 100644 --- a/libs/wire-api-federation/src/Wire/API/Federation/API/Galley.hs +++ b/libs/wire-api-federation/src/Wire/API/Federation/API/Galley.hs @@ -137,7 +137,7 @@ data ConversationCreated conv = ConversationCreated -- | The conversation type ccCnvType :: ConvType, ccCnvAccess :: [Access], - ccCnvAccessRoles :: Set AccessRoleV2, + ccCnvAccessRoles :: Set AccessRole, -- | The conversation name, ccCnvName :: Maybe Text, -- | Members of the conversation apart from the creator diff --git a/libs/wire-api/src/Wire/API/Conversation.hs b/libs/wire-api/src/Wire/API/Conversation.hs index 283c6a0a85e..2f0b26ec0ba 100644 --- a/libs/wire-api/src/Wire/API/Conversation.hs +++ b/libs/wire-api/src/Wire/API/Conversation.hs @@ -49,7 +49,8 @@ module Wire.API.Conversation -- * Conversation properties Access (..), - AccessRoleV2 (..), + AccessRole (..), + accessRolesSchemaV2, genAccessRolesV2, AccessRoleLegacy (..), ConvType (..), @@ -71,6 +72,7 @@ module Wire.API.Conversation -- * update ConversationRename (..), ConversationAccessData (..), + conversationAccessDataSchema, ConversationReceiptModeUpdate (..), ConversationMessageTimerUpdate (..), ConversationJoin (..), @@ -96,7 +98,7 @@ module Wire.API.Conversation where import Control.Applicative -import Control.Lens (at, (?~)) +import Control.Lens ((?~)) import Data.Aeson (FromJSON (..), ToJSON (..)) import qualified Data.Aeson as A import qualified Data.ByteString.Lazy as LBS @@ -116,6 +118,7 @@ import qualified Data.Swagger.Build.Api as Doc import qualified Data.UUID as UUID import qualified Data.UUID.V5 as UUIDV5 import Imports +import Servant.API import System.Random (randomRIO) import Wire.API.Conversation.Member import Wire.API.Conversation.Protocol @@ -123,6 +126,8 @@ import Wire.API.Conversation.Role (RoleName, roleNameWireAdmin) import Wire.API.MLS.Group import Wire.API.Routes.MultiTablePaging import Wire.API.Routes.MultiVerb +import Wire.API.Routes.Version +import Wire.API.Routes.Versioned import Wire.Arbitrary -------------------------------------------------------------------------------- @@ -133,7 +138,7 @@ data ConversationMetadata = ConversationMetadata -- FUTUREWORK: Make this a qualified user ID. cnvmCreator :: UserId, cnvmAccess :: [Access], - cnvmAccessRoles :: Set AccessRoleV2, + cnvmAccessRoles :: Set AccessRole, cnvmName :: Maybe Text, -- FUTUREWORK: Think if it makes sense to make the team ID qualified due to -- federation. @@ -158,8 +163,11 @@ defConversationMetadata creator = cnvmReceiptMode = Nothing } -accessRolesSchema :: ObjectSchema SwaggerDoc (Set AccessRoleV2) -accessRolesSchema = toOutput .= accessRolesSchemaTuple `withParser` validate +accessRolesSchema :: ObjectSchema SwaggerDoc (Set AccessRole) +accessRolesSchema = field "access_role" (set schema) + +accessRolesSchemaV2 :: ObjectSchema SwaggerDoc (Set AccessRole) +accessRolesSchemaV2 = toOutput .= accessRolesSchemaTuple `withParser` validate where toOutput accessRoles = (Just $ toAccessRoleLegacy accessRoles, Just accessRoles) validate = @@ -168,8 +176,8 @@ accessRolesSchema = toOutput .= accessRolesSchemaTuple `withParser` validate (Just legacy, Nothing) -> pure $ fromAccessRoleLegacy legacy (Nothing, Nothing) -> fail "access_role|access_role_v2" -accessRolesSchemaOpt :: ObjectSchema SwaggerDoc (Maybe (Set AccessRoleV2)) -accessRolesSchemaOpt = toOutput .= accessRolesSchemaTuple `withParser` validate +accessRolesSchemaOptV2 :: ObjectSchema SwaggerDoc (Maybe (Set AccessRole)) +accessRolesSchemaOptV2 = toOutput .= accessRolesSchemaTuple `withParser` validate where toOutput accessRoles = (toAccessRoleLegacy <$> accessRoles, accessRoles) validate = @@ -178,16 +186,16 @@ accessRolesSchemaOpt = toOutput .= accessRolesSchemaTuple `withParser` validate (Just legacy, Nothing) -> pure $ Just (fromAccessRoleLegacy legacy) (Nothing, Nothing) -> pure Nothing -accessRolesSchemaTuple :: ObjectSchema SwaggerDoc (Maybe AccessRoleLegacy, Maybe (Set AccessRoleV2)) +accessRolesSchemaTuple :: ObjectSchema SwaggerDoc (Maybe AccessRoleLegacy, Maybe (Set AccessRole)) accessRolesSchemaTuple = (,) <$> fst .= optFieldWithDocModifier "access_role" (description ?~ "Deprecated, please use access_role_v2") (maybeWithDefault A.Null schema) - <*> snd .= optFieldWithDocModifier "access_role_v2" (description ?~ desc) (maybeWithDefault A.Null $ set schema) - where - desc = "This field is optional. If it is not present, the default will be `[team_member, non_team_member, service]`. Please note that an empty list is not allowed when creating a new conversation." + <*> snd .= optField "access_role_v2" (maybeWithDefault A.Null $ set schema) -conversationMetadataObjectSchema :: ObjectSchema SwaggerDoc ConversationMetadata -conversationMetadataObjectSchema = +conversationMetadataObjectSchema :: + ObjectSchema SwaggerDoc (Set AccessRole) -> + ObjectSchema SwaggerDoc ConversationMetadata +conversationMetadataObjectSchema sch = ConversationMetadata <$> cnvmType .= field "type" schema <*> cnvmCreator @@ -196,7 +204,7 @@ conversationMetadataObjectSchema = (description ?~ "The creator's user ID") schema <*> cnvmAccess .= field "access" (array schema) - <*> cnvmAccessRoles .= accessRolesSchema + <*> cnvmAccessRoles .= sch <*> cnvmName .= optField "name" (maybeWithDefault A.Null schema) <* const ("0.0" :: Text) .= optional (field "last_event" schema) <* const ("1970-01-01T00:00:00.000Z" :: Text) @@ -210,7 +218,15 @@ conversationMetadataObjectSchema = <*> cnvmReceiptMode .= optField "receipt_mode" (maybeWithDefault A.Null schema) instance ToSchema ConversationMetadata where - schema = object "ConversationMetadata" conversationMetadataObjectSchema + schema = object "ConversationMetadata" (conversationMetadataObjectSchema accessRolesSchema) + +instance ToSchema (Versioned 'V2 ConversationMetadata) where + schema = + Versioned + <$> unVersioned + .= object + "ConversationMetadata" + (conversationMetadataObjectSchema accessRolesSchemaV2) -- | Public-facing conversation type. Represents information that a -- particular user is allowed to see. @@ -238,7 +254,7 @@ cnvCreator = cnvmCreator . cnvMetadata cnvAccess :: Conversation -> [Access] cnvAccess = cnvmAccess . cnvMetadata -cnvAccessRoles :: Conversation -> Set AccessRoleV2 +cnvAccessRoles :: Conversation -> Set AccessRole cnvAccessRoles = cnvmAccessRoles . cnvMetadata cnvName :: Conversation -> Maybe Text @@ -254,17 +270,25 @@ cnvReceiptMode :: Conversation -> Maybe ReceiptMode cnvReceiptMode = cnvmReceiptMode . cnvMetadata instance ToSchema Conversation where - schema = - objectWithDocModifier - "Conversation" - (description ?~ "A conversation object as returned from the server") - $ Conversation - <$> cnvQualifiedId .= field "qualified_id" schema - <* (qUnqualified . cnvQualifiedId) - .= optional (field "id" (deprecatedSchema "qualified_id" schema)) - <*> cnvMetadata .= conversationMetadataObjectSchema - <*> cnvMembers .= field "members" schema - <*> cnvProtocol .= protocolSchema + schema = conversationSchema accessRolesSchema + +instance ToSchema (Versioned 'V2 Conversation) where + schema = Versioned <$> unVersioned .= conversationSchema accessRolesSchemaV2 + +conversationSchema :: + ObjectSchema SwaggerDoc (Set AccessRole) -> + ValueSchema NamedSwaggerDoc Conversation +conversationSchema sch = + objectWithDocModifier + "Conversation" + (description ?~ "A conversation object as returned from the server") + $ Conversation + <$> cnvQualifiedId .= field "qualified_id" schema + <* (qUnqualified . cnvQualifiedId) + .= optional (field "id" (deprecatedSchema "qualified_id" schema)) + <*> cnvMetadata .= conversationMetadataObjectSchema sch + <*> cnvMembers .= field "members" schema + <*> cnvProtocol .= protocolSchema modelConversation :: Doc.Model modelConversation = Doc.defineModel "Conversation" $ do @@ -330,6 +354,7 @@ data ConversationList a = ConversationList } deriving stock (Eq, Show, Generic) deriving (Arbitrary) via (GenericUniform (ConversationList a)) + deriving (FromJSON, ToJSON, S.ToSchema) via Schema (ConversationList a) class ConversationListItem a where convListItemName :: Proxy a -> Text @@ -340,35 +365,31 @@ instance ConversationListItem ConvId where instance ConversationListItem Conversation where convListItemName _ = "conversations" -instance ConversationListItem (Qualified ConvId) where - convListItemName _ = "qualified Conversation IDs" - -instance (ConversationListItem a, S.ToSchema a) => S.ToSchema (ConversationList a) where - declareNamedSchema _ = do - listSchema <- S.declareSchemaRef (Proxy @[a]) - pure $ - S.NamedSchema (Just "ConversationList") $ - mempty - & description ?~ "Object holding a list of " <> convListItemName (Proxy @a) - & S.properties . at "conversations" ?~ listSchema - & S.properties . at "has_more" - ?~ S.Inline - ( S.toSchema (Proxy @Bool) - & description ?~ "Indicator that the server has more conversations than returned" - ) - -instance ToJSON a => ToJSON (ConversationList a) where - toJSON (ConversationList l m) = - A.object - [ "conversations" A..= l, - "has_more" A..= m - ] - -instance FromJSON a => FromJSON (ConversationList a) where - parseJSON = A.withObject "conversation-list" $ \o -> - ConversationList - <$> o A..: "conversations" - <*> o A..: "has_more" +instance (ConversationListItem a, ToSchema a) => ToSchema (ConversationList a) where + schema = conversationListSchema schema + +instance ToSchema (Versioned 'V2 (ConversationList Conversation)) where + schema = + Versioned + <$> unVersioned + .= conversationListSchema (conversationSchema accessRolesSchemaV2) + +conversationListSchema :: + forall a. + ConversationListItem a => + ValueSchema NamedSwaggerDoc a -> + ValueSchema NamedSwaggerDoc (ConversationList a) +conversationListSchema sch = + objectWithDocModifier + "ConversationList" + (description ?~ "Object holding a list of " <> convListItemName (Proxy @a)) + $ ConversationList + <$> convList .= field "conversations" (array sch) + <*> convHasMore + .= fieldWithDocModifier + "has_more" + (description ?~ "Indicator that the server has more conversations than returned") + schema type ConversationPagingName = "ConversationIds" @@ -412,17 +433,25 @@ data ConversationsResponse = ConversationsResponse deriving stock (Eq, Show) deriving (FromJSON, ToJSON, S.ToSchema) via Schema ConversationsResponse +conversationsResponseSchema :: + ObjectSchema SwaggerDoc (Set AccessRole) -> + ValueSchema NamedSwaggerDoc ConversationsResponse +conversationsResponseSchema sch = + let notFoundDoc = description ?~ "These conversations either don't exist or are deleted." + failedDoc = description ?~ "The server failed to fetch these conversations, most likely due to network issues while contacting a remote server" + in objectWithDocModifier + "ConversationsResponse" + (description ?~ "Response object for getting metadata of a list of conversations") + $ ConversationsResponse + <$> crFound .= field "found" (array (conversationSchema sch)) + <*> crNotFound .= fieldWithDocModifier "not_found" notFoundDoc (array schema) + <*> crFailed .= fieldWithDocModifier "failed" failedDoc (array schema) + instance ToSchema ConversationsResponse where - schema = - let notFoundDoc = description ?~ "These conversations either don't exist or are deleted." - failedDoc = description ?~ "The server failed to fetch these conversations, most likely due to network issues while contacting a remote server" - in objectWithDocModifier - "ConversationsResponse" - (description ?~ "Response object for getting metadata of a list of conversations") - $ ConversationsResponse - <$> crFound .= field "found" (array schema) - <*> crNotFound .= fieldWithDocModifier "not_found" notFoundDoc (array schema) - <*> crFailed .= fieldWithDocModifier "failed" failedDoc (array schema) + schema = conversationsResponseSchema accessRolesSchema + +instance ToSchema (Versioned 'V2 ConversationsResponse) where + schema = Versioned <$> unVersioned .= conversationsResponseSchema accessRolesSchemaV2 -------------------------------------------------------------------------------- -- Conversation properties @@ -478,29 +507,29 @@ data AccessRoleLegacy deriving (Arbitrary) via (GenericUniform AccessRoleLegacy) deriving (ToJSON, FromJSON, S.ToSchema) via Schema AccessRoleLegacy -fromAccessRoleLegacy :: AccessRoleLegacy -> Set AccessRoleV2 +fromAccessRoleLegacy :: AccessRoleLegacy -> Set AccessRole fromAccessRoleLegacy = \case PrivateAccessRole -> privateAccessRole TeamAccessRole -> teamAccessRole ActivatedAccessRole -> activatedAccessRole NonActivatedAccessRole -> nonActivatedAccessRole -privateAccessRole :: Set AccessRoleV2 +privateAccessRole :: Set AccessRole privateAccessRole = Set.fromList [] -teamAccessRole :: Set AccessRoleV2 +teamAccessRole :: Set AccessRole teamAccessRole = Set.fromList [TeamMemberAccessRole] -activatedAccessRole :: Set AccessRoleV2 +activatedAccessRole :: Set AccessRole activatedAccessRole = Set.fromList [TeamMemberAccessRole, NonTeamMemberAccessRole, ServiceAccessRole] -nonActivatedAccessRole :: Set AccessRoleV2 +nonActivatedAccessRole :: Set AccessRole nonActivatedAccessRole = Set.fromList [TeamMemberAccessRole, NonTeamMemberAccessRole, GuestAccessRole, ServiceAccessRole] -defRole :: Set AccessRoleV2 +defRole :: Set AccessRole defRole = activatedAccessRole -maybeRole :: ConvType -> Maybe (Set AccessRoleV2) -> Set AccessRoleV2 +maybeRole :: ConvType -> Maybe (Set AccessRole) -> Set AccessRole maybeRole SelfConv _ = privateAccessRole maybeRole GlobalTeamConv _ = teamAccessRole maybeRole ConnectConv _ = privateAccessRole @@ -508,16 +537,16 @@ maybeRole One2OneConv _ = privateAccessRole maybeRole RegularConv Nothing = defRole maybeRole RegularConv (Just r) = r -data AccessRoleV2 +data AccessRole = TeamMemberAccessRole | NonTeamMemberAccessRole | GuestAccessRole | ServiceAccessRole deriving stock (Eq, Ord, Show, Generic, Bounded, Enum) - deriving (Arbitrary) via (GenericUniform AccessRoleV2) - deriving (ToJSON, FromJSON, S.ToSchema) via Schema AccessRoleV2 + deriving (Arbitrary) via (GenericUniform AccessRole) + deriving (ToJSON, FromJSON, S.ToSchema) via Schema AccessRole -genAccessRolesV2 :: [AccessRoleV2] -> [AccessRoleV2] -> IO (Either String (Set AccessRoleV2)) +genAccessRolesV2 :: [AccessRole] -> [AccessRole] -> IO (Either String (Set AccessRole)) genAccessRolesV2 = genEnumSet genEnumSet :: forall a. (Bounded a, Enum a, Ord a, Eq a, Show a) => [a] -> [a] -> IO (Either String (Set a)) @@ -530,17 +559,17 @@ genEnumSet with without = else do pure $ Left ("overlapping arguments: " <> show (with, without)) -toAccessRoleLegacy :: Set AccessRoleV2 -> AccessRoleLegacy +toAccessRoleLegacy :: Set AccessRole -> AccessRoleLegacy toAccessRoleLegacy accessRoles = do fromMaybe NonActivatedAccessRole $ find (allMember accessRoles . fromAccessRoleLegacy) [minBound ..] where allMember :: Ord a => Set a -> Set a -> Bool allMember rhs lhs = all (`Set.member` lhs) rhs -instance ToSchema AccessRoleV2 where +instance ToSchema AccessRole where schema = (S.schema . description ?~ desc) $ - enum @Text "AccessRoleV2" $ + enum @Text "AccessRole" $ mconcat [ element "team_member" TeamMemberAccessRole, element "non_team_member" NonTeamMemberAccessRole, @@ -550,9 +579,12 @@ instance ToSchema AccessRoleV2 where where desc = "Which users/services can join conversations.\ - \This replaces the deprecated field `access_role`\ - \and allows for a more fine grained configuration of access roles\ - \in particular a separation of guest and services access." + \ This replaces legacy access roles and allows a more fine grained\ + \ configuration of access roles, and in particular a separation of\ + \ guest and services access.\n\nThis field is optional. If it is not\ + \ present, the default will be `[team_member, non_team_member, service]`.\ + \ Please note that an empty list is not allowed when creating a new\ + \ conversation." instance ToSchema AccessRoleLegacy where schema = @@ -655,7 +687,7 @@ data NewConv = NewConv newConvQualifiedUsers :: [Qualified UserId], newConvName :: Maybe (Range 1 256 Text), newConvAccess :: Set Access, - newConvAccessRoles :: Maybe (Set AccessRoleV2), + newConvAccessRoles :: Maybe (Set AccessRole), newConvTeam :: Maybe ConvTeamInfo, newConvMessageTimer :: Maybe Milliseconds, newConvReceiptMode :: Maybe ReceiptMode, @@ -673,64 +705,74 @@ data NewConv = NewConv instance ToSchema NewConv where schema = - objectWithDocModifier - "NewConv" - (description ?~ "JSON object to create a new conversation. When using 'qualified_users' (preferred), you can omit 'users'") - $ NewConv - <$> newConvUsers - .= ( fieldWithDocModifier - "users" - (description ?~ usersDesc) - (array schema) - <|> pure [] - ) - <*> newConvQualifiedUsers - .= ( fieldWithDocModifier - "qualified_users" - (description ?~ qualifiedUsersDesc) - (array schema) - <|> pure [] - ) - <*> newConvName .= maybe_ (optField "name" schema) - <*> (Set.toList . newConvAccess) - .= (fromMaybe mempty <$> optField "access" (Set.fromList <$> array schema)) - <*> newConvAccessRoles .= accessRolesSchemaOpt - <*> newConvTeam - .= maybe_ - ( optFieldWithDocModifier - "team" - (description ?~ "Team information of this conversation") - schema - ) - <*> newConvMessageTimer - .= maybe_ - ( optFieldWithDocModifier - "message_timer" - (description ?~ "Per-conversation message timer") - schema - ) - <*> newConvReceiptMode .= maybe_ (optField "receipt_mode" schema) - <*> newConvUsersRole - .= ( fieldWithDocModifier "conversation_role" (description ?~ usersRoleDesc) schema - <|> pure roleNameWireAdmin - ) - <*> newConvProtocol .= protocolTagSchema - <*> newConvCreatorClient .= maybe_ (optField "creator_client" schema) - where - usersDesc = - "List of user IDs (excluding the requestor) to be \ - \part of this conversation (deprecated)" - qualifiedUsersDesc = - "List of qualified user IDs (excluding the requestor) \ - \to be part of this conversation" - usersRoleDesc :: Text - usersRoleDesc = - cs $ - "The conversation permissions the users \ - \added in this request should have. \ - \Optional, defaults to '" - <> show roleNameWireAdmin - <> "' if unset." + newConvSchema $ + maybe_ (optField "access_roles" (set schema)) + +instance ToSchema (Versioned 'V2 NewConv) where + schema = Versioned <$> unVersioned .= newConvSchema accessRolesSchemaOptV2 + +newConvSchema :: + ObjectSchema SwaggerDoc (Maybe (Set AccessRole)) -> + ValueSchema NamedSwaggerDoc NewConv +newConvSchema sch = + objectWithDocModifier + "NewConv" + (description ?~ "JSON object to create a new conversation. When using 'qualified_users' (preferred), you can omit 'users'") + $ NewConv + <$> newConvUsers + .= ( fieldWithDocModifier + "users" + (description ?~ usersDesc) + (array schema) + <|> pure [] + ) + <*> newConvQualifiedUsers + .= ( fieldWithDocModifier + "qualified_users" + (description ?~ qualifiedUsersDesc) + (array schema) + <|> pure [] + ) + <*> newConvName .= maybe_ (optField "name" schema) + <*> (Set.toList . newConvAccess) + .= (fromMaybe mempty <$> optField "access" (Set.fromList <$> array schema)) + <*> newConvAccessRoles .= sch + <*> newConvTeam + .= maybe_ + ( optFieldWithDocModifier + "team" + (description ?~ "Team information of this conversation") + schema + ) + <*> newConvMessageTimer + .= maybe_ + ( optFieldWithDocModifier + "message_timer" + (description ?~ "Per-conversation message timer") + schema + ) + <*> newConvReceiptMode .= maybe_ (optField "receipt_mode" schema) + <*> newConvUsersRole + .= ( fieldWithDocModifier "conversation_role" (description ?~ usersRoleDesc) schema + <|> pure roleNameWireAdmin + ) + <*> newConvProtocol .= protocolTagSchema + <*> newConvCreatorClient .= maybe_ (optField "creator_client" schema) + where + usersDesc = + "List of user IDs (excluding the requestor) to be \ + \part of this conversation (deprecated)" + qualifiedUsersDesc = + "List of qualified user IDs (excluding the requestor) \ + \to be part of this conversation" + usersRoleDesc :: Text + usersRoleDesc = + cs $ + "The conversation permissions the users \ + \added in this request should have. \ + \Optional, defaults to '" + <> show roleNameWireAdmin + <> "' if unset." newtype ConvTeamInfo = ConvTeamInfo { cnvTeamId :: TeamId @@ -845,18 +887,31 @@ modelConversationUpdateName = Doc.defineModel "ConversationUpdateName" $ do data ConversationAccessData = ConversationAccessData { cupAccess :: Set Access, - cupAccessRoles :: Set AccessRoleV2 + cupAccessRoles :: Set AccessRole } deriving stock (Eq, Show, Generic) deriving (Arbitrary) via (GenericUniform ConversationAccessData) deriving (FromJSON, ToJSON, S.ToSchema) via Schema ConversationAccessData +conversationAccessDataSchema :: Version -> ValueSchema NamedSwaggerDoc ConversationAccessData +conversationAccessDataSchema v = + object ("ConversationAccessData" <> suffix) $ + ConversationAccessData + <$> cupAccess .= field "access" (set schema) + <*> cupAccessRoles .= sch + where + suffix + | v == maxBound = "" + | otherwise = toUrlPiece v + sch = case v of + V2 -> accessRolesSchemaV2 + _ -> accessRolesSchema + instance ToSchema ConversationAccessData where - schema = - object "ConversationAccessData" $ - ConversationAccessData - <$> cupAccess .= field "access" (set schema) - <*> cupAccessRoles .= accessRolesSchema + schema = conversationAccessDataSchema V3 + +instance ToSchema (Versioned 'V2 ConversationAccessData) where + schema = Versioned <$> unVersioned .= conversationAccessDataSchema V2 modelConversationAccessData :: Doc.Model modelConversationAccessData = Doc.defineModel "ConversationAccessData" $ do diff --git a/libs/wire-api/src/Wire/API/Event/Conversation.hs b/libs/wire-api/src/Wire/API/Event/Conversation.hs index 58b50fce8e4..c94a6b0c81a 100644 --- a/libs/wire-api/src/Wire/API/Event/Conversation.hs +++ b/libs/wire-api/src/Wire/API/Event/Conversation.hs @@ -85,6 +85,7 @@ import Wire.API.Conversation.Code (ConversationCode (..)) import Wire.API.Conversation.Role import Wire.API.Conversation.Typing (TypingData (..)) import Wire.API.Routes.MultiVerb +import Wire.API.Routes.Version import Wire.API.User (QualifiedUserIdList (..)) import Wire.Arbitrary (Arbitrary (arbitrary), GenericUniform (..)) @@ -373,7 +374,13 @@ taggedEventDataSchema = MemberLeave -> tag _EdMembersLeave (unnamed schema) MemberStateUpdate -> tag _EdMemberUpdate (unnamed schema) ConvRename -> tag _EdConvRename (unnamed schema) - ConvAccessUpdate -> tag _EdConvAccessUpdate (unnamed schema) + -- FUTUREWORK: when V2 is dropped, it is fine to change this schema to + -- V3, since V3 clients are guaranteed to know how to parse V2 and V3 + -- conversation access update events. + ConvAccessUpdate -> + tag + _EdConvAccessUpdate + (unnamed (conversationAccessDataSchema V2)) ConvCodeUpdate -> tag _EdConvCodeUpdate (unnamed schema) ConvConnect -> tag _EdConnect (unnamed schema) ConvCreate -> tag _EdConversation (unnamed schema) diff --git a/libs/wire-api/src/Wire/API/Routes/MultiVerb.hs b/libs/wire-api/src/Wire/API/Routes/MultiVerb.hs index d05be1286ad..e8d79bee601 100644 --- a/libs/wire-api/src/Wire/API/Routes/MultiVerb.hs +++ b/libs/wire-api/src/Wire/API/Routes/MultiVerb.hs @@ -41,6 +41,7 @@ module Wire.API.Routes.MultiVerb ResponseType, IsResponse (..), IsSwaggerResponse (..), + simpleResponseSwagger, combineResponseSwagger, ResponseTypes, IsResponseList (..), diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Galley/Conversation.hs b/libs/wire-api/src/Wire/API/Routes/Public/Galley/Conversation.hs index 8d996a3b985..40f59559ebd 100644 --- a/libs/wire-api/src/Wire/API/Routes/Public/Galley/Conversation.hs +++ b/libs/wire-api/src/Wire/API/Routes/Public/Galley/Conversation.hs @@ -38,6 +38,7 @@ import Wire.API.Routes.Public import Wire.API.Routes.Public.Util import Wire.API.Routes.QualifiedCapture import Wire.API.Routes.Version +import Wire.API.Routes.Versioned import Wire.API.Team.Feature type ConversationResponse = ResponseForExistedCreated Conversation @@ -59,6 +60,21 @@ type ConversationVerb = ] ConversationResponse +type ConversationV2Verb = + MultiVerb + 'POST + '[JSON] + '[ WithHeaders + ConversationHeaders + Conversation + (VersionedRespond 'V2 200 "Conversation existed" Conversation), + WithHeaders + ConversationHeaders + Conversation + (VersionedRespond 'V2 201 "Conversation created" Conversation) + ] + ConversationResponse + type CreateConversationCodeVerb = MultiVerb 'POST @@ -205,6 +221,7 @@ type ConversationAPI = :<|> Named "get-conversations" ( Summary "Get all *local* conversations." + :> Until 'V3 :> Description "Will not return remote conversations.\n\n\ \Use `POST /conversations/list-ids` followed by \ @@ -232,28 +249,55 @@ type ConversationAPI = ] "size" (Range 1 500 Int32) - :> Get '[Servant.JSON] (ConversationList Conversation) + :> MultiVerb1 + 'GET + '[JSON] + ( VersionedRespond + 'V2 + 200 + "List of local conversations" + (ConversationList Conversation) + ) ) :<|> Named - "list-conversations-v1" + "list-conversations@v1" ( Summary "Get conversation metadata for a list of conversation ids" :> Until 'V2 :> ZLocalUser :> "conversations" :> "list" :> "v2" - :> ReqBody '[Servant.JSON] ListConversations - :> Post '[Servant.JSON] ConversationsResponse + :> ReqBody '[JSON] ListConversations + :> Post '[JSON] ConversationsResponse ) :<|> Named - "list-conversations" + "list-conversations@v2" ( Summary "Get conversation metadata for a list of conversation ids" :> From 'V2 + :> Until 'V3 :> ZLocalUser :> "conversations" :> "list" - :> ReqBody '[Servant.JSON] ListConversations - :> Post '[Servant.JSON] ConversationsResponse + :> ReqBody '[JSON] ListConversations + :> MultiVerb1 + 'POST + '[JSON] + ( VersionedRespond + 'V2 + 200 + "Conversation page" + ConversationsResponse + ) + ) + :<|> Named + "list-conversations" + ( Summary "Get conversation metadata for a list of conversation ids" + :> From 'V3 + :> ZLocalUser + :> "conversations" + :> "list" + :> ReqBody '[JSON] ListConversations + :> Post '[JSON] ConversationsResponse ) -- This endpoint can lead to the following events being sent: -- - ConvCreate event to members @@ -272,9 +316,27 @@ type ConversationAPI = :> QueryParam' [Required, Strict] "code" Code.Value :> Get '[Servant.JSON] ConversationCoverView ) + :<|> Named + "create-group-conversation@v2" + ( Summary "Create a new conversation" + :> Until 'V3 + :> CanThrow 'ConvAccessDenied + :> CanThrow 'MLSNonEmptyMemberList + :> CanThrow 'NotConnected + :> CanThrow 'NotATeamMember + :> CanThrow OperationDenied + :> CanThrow 'MissingLegalholdConsent + :> Description "This returns 201 when a new conversation is created, and 200 when the conversation already existed" + :> ZLocalUser + :> ZConn + :> "conversations" + :> VersionedReqBody 'V2 '[Servant.JSON] NewConv + :> ConversationV2Verb + ) :<|> Named "create-group-conversation" ( Summary "Create a new conversation" + :> From 'V3 :> CanThrow 'ConvAccessDenied :> CanThrow 'MLSNonEmptyMemberList :> CanThrow 'NotConnected @@ -288,9 +350,19 @@ type ConversationAPI = :> ReqBody '[Servant.JSON] NewConv :> ConversationVerb ) + :<|> Named + "create-self-conversation@v2" + ( Summary "Create a self-conversation" + :> Until 'V3 + :> ZLocalUser + :> "conversations" + :> "self" + :> ConversationV2Verb + ) :<|> Named "create-self-conversation" ( Summary "Create a self-conversation" + :> From 'V3 :> ZLocalUser :> "conversations" :> "self" @@ -314,9 +386,30 @@ type ConversationAPI = -- This endpoint can lead to the following events being sent: -- - ConvCreate event to members -- TODO: add note: "On 201, the conversation ID is the `Location` header" + :<|> Named + "create-one-to-one-conversation@v2" + ( Summary "Create a 1:1 conversation" + :> Until 'V3 + :> CanThrow 'ConvAccessDenied + :> CanThrow 'InvalidOperation + :> CanThrow 'NoBindingTeamMembers + :> CanThrow 'NonBindingTeam + :> CanThrow 'NotATeamMember + :> CanThrow 'NotConnected + :> CanThrow OperationDenied + :> CanThrow 'TeamNotFound + :> CanThrow 'MissingLegalholdConsent + :> ZLocalUser + :> ZConn + :> "conversations" + :> "one2one" + :> VersionedReqBody 'V2 '[JSON] NewConv + :> ConversationV2Verb + ) :<|> Named "create-one-to-one-conversation" ( Summary "Create a 1:1 conversation" + :> From 'V3 :> CanThrow 'ConvAccessDenied :> CanThrow 'InvalidOperation :> CanThrow 'NoBindingTeamMembers @@ -330,7 +423,7 @@ type ConversationAPI = :> ZConn :> "conversations" :> "one2one" - :> ReqBody '[Servant.JSON] NewConv + :> ReqBody '[JSON] NewConv :> ConversationVerb ) -- This endpoint can lead to the following events being sent: @@ -755,6 +848,7 @@ type ConversationAPI = :<|> Named "update-conversation-access-unqualified" ( Summary "Update access modes for a conversation (deprecated)" + :> Until 'V2 :> Description "Use PUT `/conversations/:domain/:cnv/access` instead." :> ZLocalUser :> ZConn @@ -767,7 +861,29 @@ type ConversationAPI = :> "conversations" :> Capture' '[Description "Conversation ID"] "cnv" ConvId :> "access" - :> ReqBody '[JSON] ConversationAccessData + :> VersionedReqBody 'V2 '[JSON] ConversationAccessData + :> MultiVerb + 'PUT + '[JSON] + (UpdateResponses "Access unchanged" "Access updated" Event) + (UpdateResult Event) + ) + :<|> Named + "update-conversation-access@v2" + ( Summary "Update access modes for a conversation" + :> Until 'V3 + :> ZLocalUser + :> ZConn + :> CanThrow ('ActionDenied 'ModifyConversationAccess) + :> CanThrow ('ActionDenied 'RemoveConversationMember) + :> CanThrow 'ConvAccessDenied + :> CanThrow 'ConvNotFound + :> CanThrow 'InvalidOperation + :> CanThrow 'InvalidTargetAccess + :> "conversations" + :> QualifiedCapture' '[Description "Conversation ID"] "cnv" ConvId + :> "access" + :> VersionedReqBody 'V2 '[JSON] ConversationAccessData :> MultiVerb 'PUT '[JSON] @@ -777,6 +893,7 @@ type ConversationAPI = :<|> Named "update-conversation-access" ( Summary "Update access modes for a conversation" + :> From 'V3 :> ZLocalUser :> ZConn :> CanThrow ('ActionDenied 'ModifyConversationAccess) diff --git a/libs/wire-api/src/Wire/API/Routes/Versioned.hs b/libs/wire-api/src/Wire/API/Routes/Versioned.hs new file mode 100644 index 00000000000..bb9dcf766ad --- /dev/null +++ b/libs/wire-api/src/Wire/API/Routes/Versioned.hs @@ -0,0 +1,113 @@ +-- This file is part of the Wire Server implementation. +-- +-- Copyright (C) 2022 Wire Swiss GmbH +-- +-- 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 . + +module Wire.API.Routes.Versioned where + +import Data.Aeson (FromJSON, ToJSON) +import Data.Metrics.Servant +import Data.Schema +import Data.Singletons +import qualified Data.Swagger as S +import GHC.TypeLits +import Imports +import Servant +import Servant.API.ContentTypes +import Servant.Swagger +import Servant.Swagger.Internal +import Wire.API.Routes.MultiVerb +import Wire.API.Routes.Version + +-------------------------------------- +-- Versioned requests + +data VersionedReqBody' v (mods :: [*]) (ct :: [*]) (a :: *) + +type VersionedReqBody v = VersionedReqBody' v '[Required, Strict] + +instance RoutesToPaths rest => RoutesToPaths (VersionedReqBody' v mods ct a :> rest) where + getRoutes = getRoutes @rest + +instance + ( AllCTUnrender cts (Versioned v a), + HasServer api context, + HasContextEntry (context .++ DefaultErrorFormatters) ErrorFormatters + ) => + HasServer (VersionedReqBody' v mods cts a :> api) context + where + type ServerT (VersionedReqBody' v mods cts a :> api) m = a -> ServerT api m + + hoistServerWithContext _p pc nt s = hoistServerWithContext p pc nt (s . unVersioned) . Versioned + where + p = Proxy :: Proxy (ReqBody cts (Versioned v a) :> api) + + route _p ctx d = route (Proxy :: Proxy (ReqBody cts (Versioned v a) :> api)) ctx (fmap (. unVersioned) d) + +instance + ( HasSwagger (ReqBody' '[Required, Strict] cts a :> api), + S.ToSchema (Versioned v a), + HasSwagger api, + AllAccept cts + ) => + HasSwagger (VersionedReqBody v cts a :> api) + where + toSwagger _ = toSwagger (Proxy @(ReqBody cts (Versioned v a) :> api)) + +-------------------------------------------------------------------------------- +-- Versioned responses + +data VersionedRespond v (s :: Nat) (desc :: Symbol) (a :: *) + +type instance ResponseType (VersionedRespond v s desc a) = a + +instance + IsResponse cs (Respond s desc (Versioned v a)) => + IsResponse cs (VersionedRespond v s desc a) + where + type ResponseStatus (VersionedRespond v s desc a) = ResponseStatus (Respond s desc a) + type ResponseBody (VersionedRespond v s desc a) = ResponseBody (Respond s desc a) + + responseRender a = responseRender @cs @(Respond s desc (Versioned v a)) a . Versioned + + responseUnrender c = fmap unVersioned . responseUnrender @cs @(Respond s desc (Versioned v a)) c + +instance + (KnownSymbol desc, S.ToSchema a) => + IsSwaggerResponse (VersionedRespond v s desc a) + where + responseSwagger = simpleResponseSwagger @a @desc + +------------------------------------------------------------------------------- +-- Versioned newtype wrapper + +-- Use this type to provide several JSON/swagger instances for a given type. +-- Use VersionedReqBody and VersionedRespond to select the instance to use in +-- Servant. +newtype Versioned (v :: Version) a = Versioned {unVersioned :: a} + deriving (Eq, Show) + +instance Functor (Versioned v) where + fmap f (Versioned a) = Versioned (f a) + +deriving via Schema (Versioned v a) instance ToSchema (Versioned v a) => FromJSON (Versioned v a) + +deriving via Schema (Versioned v a) instance ToSchema (Versioned v a) => ToJSON (Versioned v a) + +-- add version suffix to swagger schema to prevent collisions +instance (SingI v, ToSchema (Versioned v a)) => S.ToSchema (Versioned v a) where + declareNamedSchema _ = do + S.NamedSchema n s <- schemaToSwagger (Proxy @(Versioned v a)) + pure $ S.NamedSchema (fmap (<> toUrlPiece (demote @v)) n) s diff --git a/libs/wire-api/test/golden/Test/Wire/API/Golden/Generated.hs b/libs/wire-api/test/golden/Test/Wire/API/Golden/Generated.hs index 32471911e4a..b8c95a2997d 100644 --- a/libs/wire-api/test/golden/Test/Wire/API/Golden/Generated.hs +++ b/libs/wire-api/test/golden/Test/Wire/API/Golden/Generated.hs @@ -237,6 +237,8 @@ import qualified Test.Wire.API.Golden.Generated.WithStatusPatch_team import qualified Test.Wire.API.Golden.Generated.WithStatus_team import qualified Test.Wire.API.Golden.Generated.Wrapped_20_22some_5fint_22_20Int_user import Test.Wire.API.Golden.Runner +import Wire.API.Routes.Version +import Wire.API.Routes.Versioned tests :: TestTree tests = @@ -384,11 +386,21 @@ tests = testObjects [ (Test.Wire.API.Golden.Generated.ConnectionUpdate_user.testObject_ConnectionUpdate_user_1, "testObject_ConnectionUpdate_user_1.json") ], + testGroup "Golden: Conversation_user V2" $ + testObjects + [ (Versioned @'V2 Test.Wire.API.Golden.Generated.Conversation_user.testObject_Conversation_user_1, "testObject_Conversation_v2_user_1.json"), + (Versioned @'V2 Test.Wire.API.Golden.Generated.Conversation_user.testObject_Conversation_user_2, "testObject_Conversation_v2_user_2.json") + ], testGroup "Golden: Conversation_user" $ testObjects [ (Test.Wire.API.Golden.Generated.Conversation_user.testObject_Conversation_user_1, "testObject_Conversation_user_1.json"), (Test.Wire.API.Golden.Generated.Conversation_user.testObject_Conversation_user_2, "testObject_Conversation_user_2.json") ], + testGroup "Golden: NewConv_user V2" $ + testObjects + [ (Versioned @'V2 Test.Wire.API.Golden.Generated.NewConv_user.testObject_NewConv_user_1, "testObject_NewConv_v2_user_1.json"), + (Versioned @'V2 Test.Wire.API.Golden.Generated.NewConv_user.testObject_NewConv_user_3, "testObject_NewConv_v2_user_3.json") + ], testGroup "Golden: NewConv_user" $ testObjects [ (Test.Wire.API.Golden.Generated.NewConv_user.testObject_NewConv_user_1, "testObject_NewConv_user_1.json"), @@ -403,13 +415,13 @@ tests = "testObject_ConversationList_20_28Id_20_2a_20C_29_user_2.json" ) ], - testGroup "Golden: ConversationList_20Conversation_user" $ + testGroup "Golden: ConversationList_20Conversation_user V2" $ testObjects - [ ( Test.Wire.API.Golden.Generated.ConversationList_20Conversation_user.testObject_ConversationList_20Conversation_user_1, - "testObject_ConversationList_20Conversation_user_1.json" + [ ( Versioned @'V2 Test.Wire.API.Golden.Generated.ConversationList_20Conversation_user.testObject_ConversationList_20Conversation_user_1, + "testObject_ConversationList_20Conversation_v2_user_1.json" ), - ( Test.Wire.API.Golden.Generated.ConversationList_20Conversation_user.testObject_ConversationList_20Conversation_user_2, - "testObject_ConversationList_20Conversation_user_2.json" + ( Versioned @'V2 Test.Wire.API.Golden.Generated.ConversationList_20Conversation_user.testObject_ConversationList_20Conversation_user_2, + "testObject_ConversationList_20Conversation_v2_user_2.json" ) ], testGroup "Golden: Access_user" $ @@ -452,6 +464,15 @@ tests = "testObject_ConversationRename_user_1.json" ) ], + testGroup "Golden: ConversationAccessData_user V2" $ + testObjects + [ ( Versioned @'V2 Test.Wire.API.Golden.Generated.ConversationAccessData_user.testObject_ConversationAccessData_user_1, + "testObject_ConversationAccessData_v2_user_1.json" + ), + ( Versioned @'V2 Test.Wire.API.Golden.Generated.ConversationAccessData_user.testObject_ConversationAccessData_user_2, + "testObject_ConversationAccessData_v2_user_2.json" + ) + ], testGroup "Golden: ConversationAccessData_user" $ testObjects [ ( Test.Wire.API.Golden.Generated.ConversationAccessData_user.testObject_ConversationAccessData_user_1, diff --git a/libs/wire-api/test/golden/Test/Wire/API/Golden/Generated/ConversationAccessData_user.hs b/libs/wire-api/test/golden/Test/Wire/API/Golden/Generated/ConversationAccessData_user.hs index 3180a34d81e..d4f1ea554ab 100644 --- a/libs/wire-api/test/golden/Test/Wire/API/Golden/Generated/ConversationAccessData_user.hs +++ b/libs/wire-api/test/golden/Test/Wire/API/Golden/Generated/ConversationAccessData_user.hs @@ -21,10 +21,6 @@ module Test.Wire.API.Golden.Generated.ConversationAccessData_user where import qualified Data.Set as Set (fromList) import Wire.API.Conversation - ( Access (InviteAccess), - AccessRoleV2 (..), - ConversationAccessData (..), - ) testObject_ConversationAccessData_user_1 :: ConversationAccessData testObject_ConversationAccessData_user_1 = diff --git a/libs/wire-api/test/golden/Test/Wire/API/Golden/Manual.hs b/libs/wire-api/test/golden/Test/Wire/API/Golden/Manual.hs index 5f230030ccd..02ddb5d146a 100644 --- a/libs/wire-api/test/golden/Test/Wire/API/Golden/Manual.hs +++ b/libs/wire-api/test/golden/Test/Wire/API/Golden/Manual.hs @@ -38,6 +38,8 @@ import Test.Wire.API.Golden.Manual.Token import Test.Wire.API.Golden.Manual.UserClientPrekeyMap import Test.Wire.API.Golden.Manual.UserIdList import Test.Wire.API.Golden.Runner +import Wire.API.Routes.Version +import Wire.API.Routes.Versioned tests :: TestTree tests = @@ -105,6 +107,8 @@ tests = testGroup "ListConversations" $ testObjects [(testObject_ListConversations_1, "testObject_ListConversations_1.json")], + testGroup "ConversationsResponse V2" $ + testObjects [(Versioned @'V2 testObject_ConversationsResponse_1, "testObject_ConversationsResponse_v2_1.json")], testGroup "ConversationsResponse" $ testObjects [(testObject_ConversationsResponse_1, "testObject_ConversationsResponse_1.json")], testGroup "CreateScimToken" $ diff --git a/libs/wire-api/test/golden/testObject_ConversationAccessData_user_1.json b/libs/wire-api/test/golden/testObject_ConversationAccessData_user_1.json index 68a20bbafe3..b52cf68dfba 100644 --- a/libs/wire-api/test/golden/testObject_ConversationAccessData_user_1.json +++ b/libs/wire-api/test/golden/testObject_ConversationAccessData_user_1.json @@ -1,7 +1,6 @@ { "access": [], - "access_role": "non_activated", - "access_role_v2": [ + "access_role": [ "team_member", "guest", "service" diff --git a/libs/wire-api/test/golden/testObject_ConversationAccessData_user_2.json b/libs/wire-api/test/golden/testObject_ConversationAccessData_user_2.json index 74e7d6e6d2e..24639201982 100644 --- a/libs/wire-api/test/golden/testObject_ConversationAccessData_user_2.json +++ b/libs/wire-api/test/golden/testObject_ConversationAccessData_user_2.json @@ -2,8 +2,7 @@ "access": [ "invite" ], - "access_role": "non_activated", - "access_role_v2": [ + "access_role": [ "team_member", "guest" ] diff --git a/libs/wire-api/test/golden/testObject_ConversationAccessData_v2_user_1.json b/libs/wire-api/test/golden/testObject_ConversationAccessData_v2_user_1.json new file mode 100644 index 00000000000..68a20bbafe3 --- /dev/null +++ b/libs/wire-api/test/golden/testObject_ConversationAccessData_v2_user_1.json @@ -0,0 +1,9 @@ +{ + "access": [], + "access_role": "non_activated", + "access_role_v2": [ + "team_member", + "guest", + "service" + ] +} diff --git a/libs/wire-api/test/golden/testObject_ConversationAccessData_v2_user_2.json b/libs/wire-api/test/golden/testObject_ConversationAccessData_v2_user_2.json new file mode 100644 index 00000000000..74e7d6e6d2e --- /dev/null +++ b/libs/wire-api/test/golden/testObject_ConversationAccessData_v2_user_2.json @@ -0,0 +1,10 @@ +{ + "access": [ + "invite" + ], + "access_role": "non_activated", + "access_role_v2": [ + "team_member", + "guest" + ] +} diff --git a/libs/wire-api/test/golden/testObject_ConversationList_20Conversation_user_1.json b/libs/wire-api/test/golden/testObject_ConversationList_20Conversation_v2_user_1.json similarity index 100% rename from libs/wire-api/test/golden/testObject_ConversationList_20Conversation_user_1.json rename to libs/wire-api/test/golden/testObject_ConversationList_20Conversation_v2_user_1.json diff --git a/libs/wire-api/test/golden/testObject_ConversationList_20Conversation_user_2.json b/libs/wire-api/test/golden/testObject_ConversationList_20Conversation_v2_user_2.json similarity index 100% rename from libs/wire-api/test/golden/testObject_ConversationList_20Conversation_user_2.json rename to libs/wire-api/test/golden/testObject_ConversationList_20Conversation_v2_user_2.json diff --git a/libs/wire-api/test/golden/testObject_Conversation_user_1.json b/libs/wire-api/test/golden/testObject_Conversation_user_1.json index 90e837c0700..e9c08330a13 100644 --- a/libs/wire-api/test/golden/testObject_Conversation_user_1.json +++ b/libs/wire-api/test/golden/testObject_Conversation_user_1.json @@ -1,7 +1,6 @@ { "access": [], - "access_role": "private", - "access_role_v2": [], + "access_role": [], "creator": "00000001-0000-0001-0000-000200000001", "id": "00000001-0000-0000-0000-000000000000", "last_event": "0.0", diff --git a/libs/wire-api/test/golden/testObject_Conversation_user_2.json b/libs/wire-api/test/golden/testObject_Conversation_user_2.json index ffc1f3da5cd..bc75e888889 100644 --- a/libs/wire-api/test/golden/testObject_Conversation_user_2.json +++ b/libs/wire-api/test/golden/testObject_Conversation_user_2.json @@ -13,8 +13,7 @@ "private", "invite" ], - "access_role": "non_activated", - "access_role_v2": [ + "access_role": [ "team_member", "guest", "service" diff --git a/libs/wire-api/test/golden/testObject_Conversation_v2_user_1.json b/libs/wire-api/test/golden/testObject_Conversation_v2_user_1.json new file mode 100644 index 00000000000..90e837c0700 --- /dev/null +++ b/libs/wire-api/test/golden/testObject_Conversation_v2_user_1.json @@ -0,0 +1,40 @@ +{ + "access": [], + "access_role": "private", + "access_role_v2": [], + "creator": "00000001-0000-0001-0000-000200000001", + "id": "00000001-0000-0000-0000-000000000000", + "last_event": "0.0", + "last_event_time": "1970-01-01T00:00:00.000Z", + "members": { + "others": [], + "self": { + "conversation_role": "rhhdzf0j0njilixx0g0vzrp06b_5us", + "hidden": false, + "hidden_ref": "", + "id": "00000001-0000-0001-0000-000100000000", + "otr_archived": false, + "otr_archived_ref": "", + "otr_muted_ref": null, + "otr_muted_status": null, + "qualified_id": { + "domain": "golden.example.com", + "id": "00000001-0000-0001-0000-000100000000" + }, + "service": null, + "status": 0, + "status_ref": "0.0", + "status_time": "1970-01-01T00:00:00.000Z" + } + }, + "message_timer": null, + "name": " 0", + "protocol": "proteus", + "qualified_id": { + "domain": "golden.example.com", + "id": "00000001-0000-0000-0000-000000000000" + }, + "receipt_mode": -2, + "team": "00000001-0000-0001-0000-000100000002", + "type": 2 +} diff --git a/libs/wire-api/test/golden/testObject_Conversation_v2_user_2.json b/libs/wire-api/test/golden/testObject_Conversation_v2_user_2.json new file mode 100644 index 00000000000..ffc1f3da5cd --- /dev/null +++ b/libs/wire-api/test/golden/testObject_Conversation_v2_user_2.json @@ -0,0 +1,71 @@ +{ + "access": [ + "invite", + "invite", + "code", + "link", + "invite", + "private", + "link", + "code", + "code", + "link", + "private", + "invite" + ], + "access_role": "non_activated", + "access_role_v2": [ + "team_member", + "guest", + "service" + ], + "creator": "00000000-0000-0000-0000-000200000001", + "id": "00000000-0000-0000-0000-000000000002", + "last_event": "0.0", + "last_event_time": "1970-01-01T00:00:00.000Z", + "members": { + "others": [ + { + "conversation_role": "r1rg526serx51g15n99y1bw_9q0qrcwck3jxl7ocjsjqcoux7d1zbkz9nnczy92t2oyogxrx3cyh_b8yv44l61mx9uzdnv6", + "id": "00000001-0000-0001-0000-000100000001", + "qualified_id": { + "domain": "golden.example.com", + "id": "00000001-0000-0001-0000-000100000001" + }, + "service": { + "id": "00000001-0000-0000-0000-000000000000", + "provider": "00000001-0000-0000-0000-000000000001" + }, + "status": 0 + } + ], + "self": { + "conversation_role": "9b2d3thyqh4ptkwtq2n2v9qsni_ln1ca66et_z8dlhfs9oamp328knl3rj9kcj", + "hidden": true, + "hidden_ref": "", + "id": "00000000-0000-0001-0000-000100000001", + "otr_archived": false, + "otr_archived_ref": null, + "otr_muted_ref": null, + "otr_muted_status": -1, + "qualified_id": { + "domain": "golden.example.com", + "id": "00000000-0000-0001-0000-000100000001" + }, + "service": null, + "status": 0, + "status_ref": "0.0", + "status_time": "1970-01-01T00:00:00.000Z" + } + }, + "message_timer": 1319272593797015, + "name": "", + "protocol": "proteus", + "qualified_id": { + "domain": "golden.example.com", + "id": "00000000-0000-0000-0000-000000000002" + }, + "receipt_mode": null, + "team": null, + "type": 1 +} diff --git a/libs/wire-api/test/golden/testObject_ConversationsResponse_1.json b/libs/wire-api/test/golden/testObject_ConversationsResponse_1.json index 0bba3b7e155..3bba9904761 100644 --- a/libs/wire-api/test/golden/testObject_ConversationsResponse_1.json +++ b/libs/wire-api/test/golden/testObject_ConversationsResponse_1.json @@ -12,8 +12,7 @@ "found": [ { "access": [], - "access_role": "private", - "access_role_v2": [], + "access_role": [], "creator": "00000001-0000-0001-0000-000200000001", "id": "00000001-0000-0000-0000-000000000000", "last_event": "0.0", @@ -65,8 +64,7 @@ "private", "invite" ], - "access_role": "non_activated", - "access_role_v2": [ + "access_role": [ "team_member", "guest", "service" diff --git a/libs/wire-api/test/golden/testObject_ConversationsResponse_v2_1.json b/libs/wire-api/test/golden/testObject_ConversationsResponse_v2_1.json new file mode 100644 index 00000000000..0bba3b7e155 --- /dev/null +++ b/libs/wire-api/test/golden/testObject_ConversationsResponse_v2_1.json @@ -0,0 +1,124 @@ +{ + "failed": [ + { + "domain": "golden.example.com", + "id": "00000018-4444-0020-0000-000e00000002" + }, + { + "domain": "golden3.example.com", + "id": "99999999-0000-0020-0000-111111111112" + } + ], + "found": [ + { + "access": [], + "access_role": "private", + "access_role_v2": [], + "creator": "00000001-0000-0001-0000-000200000001", + "id": "00000001-0000-0000-0000-000000000000", + "last_event": "0.0", + "last_event_time": "1970-01-01T00:00:00.000Z", + "members": { + "others": [], + "self": { + "conversation_role": "rhhdzf0j0njilixx0g0vzrp06b_5us", + "hidden": false, + "hidden_ref": "", + "id": "00000001-0000-0001-0000-000100000000", + "otr_archived": false, + "otr_archived_ref": "", + "otr_muted_ref": null, + "otr_muted_status": null, + "qualified_id": { + "domain": "golden.example.com", + "id": "00000001-0000-0001-0000-000100000000" + }, + "service": null, + "status": 0, + "status_ref": "0.0", + "status_time": "1970-01-01T00:00:00.000Z" + } + }, + "message_timer": null, + "name": " 0", + "protocol": "proteus", + "qualified_id": { + "domain": "golden.example.com", + "id": "00000001-0000-0000-0000-000000000000" + }, + "receipt_mode": -2, + "team": "00000001-0000-0001-0000-000100000002", + "type": 2 + }, + { + "access": [ + "invite", + "invite", + "code", + "link", + "invite", + "private", + "link", + "code", + "code", + "link", + "private", + "invite" + ], + "access_role": "non_activated", + "access_role_v2": [ + "team_member", + "guest", + "service" + ], + "cipher_suite": 1, + "creator": "00000000-0000-0000-0000-000200000001", + "epoch": 42, + "group_id": "dGVzdF9ncm91cA==", + "id": "00000000-0000-0000-0000-000000000002", + "last_event": "0.0", + "last_event_time": "1970-01-01T00:00:00.000Z", + "members": { + "others": [], + "self": { + "conversation_role": "9b2d3thyqh4ptkwtq2n2v9qsni_ln1ca66et_z8dlhfs9oamp328knl3rj9kcj", + "hidden": true, + "hidden_ref": "", + "id": "00000000-0000-0001-0000-000100000001", + "otr_archived": false, + "otr_archived_ref": null, + "otr_muted_ref": null, + "otr_muted_status": -1, + "qualified_id": { + "domain": "golden.example.com", + "id": "00000000-0000-0001-0000-000100000001" + }, + "service": null, + "status": 0, + "status_ref": "0.0", + "status_time": "1970-01-01T00:00:00.000Z" + } + }, + "message_timer": 1319272593797015, + "name": "", + "protocol": "mls", + "qualified_id": { + "domain": "golden.example.com", + "id": "00000000-0000-0000-0000-000000000002" + }, + "receipt_mode": 2, + "team": "00000000-0000-0001-0000-000200000000", + "type": 1 + } + ], + "not_found": [ + { + "domain": "golden.example.com", + "id": "00000018-0000-0020-0000-000e00000002" + }, + { + "domain": "golden2.example.com", + "id": "00000018-0000-0020-0000-111111111112" + } + ] +} diff --git a/libs/wire-api/test/golden/testObject_Event_user_8.json b/libs/wire-api/test/golden/testObject_Event_user_8.json index 8906b271471..cfe4ffda5b6 100644 --- a/libs/wire-api/test/golden/testObject_Event_user_8.json +++ b/libs/wire-api/test/golden/testObject_Event_user_8.json @@ -10,8 +10,7 @@ "invite", "link" ], - "access_role": "non_activated", - "access_role_v2": [ + "access_role": [ "team_member", "guest", "service" diff --git a/libs/wire-api/test/golden/testObject_InvitationList_team_15.json b/libs/wire-api/test/golden/testObject_InvitationList_team_15.json index a0fc27114af..4369683fc1c 100644 --- a/libs/wire-api/test/golden/testObject_InvitationList_team_15.json +++ b/libs/wire-api/test/golden/testObject_InvitationList_team_15.json @@ -10,7 +10,7 @@ "phone": "+872574694", "role": "admin", "team": "00000000-0000-0001-0000-000100000000", - "url" :null + "url": null }, { "created_at": "1864-05-09T23:06:13.648Z", @@ -21,7 +21,7 @@ "phone": "+143031479742", "role": "partner", "team": "00000000-0000-0001-0000-000000000001", - "url" :null + "url": null }, { "created_at": "1864-05-09T10:37:03.809Z", @@ -32,7 +32,7 @@ "phone": "+236346166386230", "role": "partner", "team": "00000001-0000-0000-0000-000000000000", - "url" :null + "url": null }, { "created_at": "1864-05-09T04:46:03.504Z", @@ -43,7 +43,7 @@ "phone": "+80162248", "role": "admin", "team": "00000001-0000-0001-0000-000100000001", - "url" :null + "url": null }, { "created_at": "1864-05-09T12:53:52.047Z", @@ -54,7 +54,7 @@ "phone": null, "role": "owner", "team": "00000000-0000-0001-0000-000100000001", - "url" :null + "url": null } ] } diff --git a/libs/wire-api/test/golden/testObject_NewConv_user_1.json b/libs/wire-api/test/golden/testObject_NewConv_user_1.json index 62b6d2cd506..5428edb5f30 100644 --- a/libs/wire-api/test/golden/testObject_NewConv_user_1.json +++ b/libs/wire-api/test/golden/testObject_NewConv_user_1.json @@ -3,8 +3,7 @@ "private", "invite" ], - "access_role": "non_activated", - "access_role_v2": [ + "access_roles": [ "team_member", "guest" ], diff --git a/libs/wire-api/test/golden/testObject_NewConv_user_3.json b/libs/wire-api/test/golden/testObject_NewConv_user_3.json index 799071f5b35..b0cd7bc8098 100644 --- a/libs/wire-api/test/golden/testObject_NewConv_user_3.json +++ b/libs/wire-api/test/golden/testObject_NewConv_user_3.json @@ -4,8 +4,7 @@ "link", "code" ], - "access_role": "non_activated", - "access_role_v2": [ + "access_roles": [ "team_member", "guest" ], diff --git a/libs/wire-api/test/golden/testObject_NewConv_v2_user_1.json b/libs/wire-api/test/golden/testObject_NewConv_v2_user_1.json new file mode 100644 index 00000000000..62b6d2cd506 --- /dev/null +++ b/libs/wire-api/test/golden/testObject_NewConv_v2_user_1.json @@ -0,0 +1,24 @@ +{ + "access": [ + "private", + "invite" + ], + "access_role": "non_activated", + "access_role_v2": [ + "team_member", + "guest" + ], + "conversation_role": "8tp2gs7b6", + "message_timer": 3320987366258987, + "protocol": "proteus", + "qualified_users": [], + "receipt_mode": 1, + "team": { + "managed": false, + "teamid": "00000000-0000-0001-0000-000000000000" + }, + "users": [ + "00000001-0000-0000-0000-000000000001", + "00000000-0000-0000-0000-000000000000" + ] +} diff --git a/libs/wire-api/test/golden/testObject_NewConv_v2_user_3.json b/libs/wire-api/test/golden/testObject_NewConv_v2_user_3.json new file mode 100644 index 00000000000..799071f5b35 --- /dev/null +++ b/libs/wire-api/test/golden/testObject_NewConv_v2_user_3.json @@ -0,0 +1,17 @@ +{ + "access": [ + "invite", + "link", + "code" + ], + "access_role": "non_activated", + "access_role_v2": [ + "team_member", + "guest" + ], + "conversation_role": "y3otpiwu615lvvccxsq0315jj75jquw01flhtuf49t6mzfurvwe3_sh51f4s257e2x47zo85rif_xyiyfldpan3g4r6zr35rbwnzm0k", + "creator_client": "beef", + "protocol": "mls", + "qualified_users": [], + "users": [] +} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_1.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_1.json deleted file mode 100644 index 920ce18c589..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_1.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "disabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_10.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_10.json deleted file mode 100644 index 920ce18c589..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_10.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "disabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_11.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_11.json deleted file mode 100644 index 920ce18c589..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_11.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "disabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_12.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_12.json deleted file mode 100644 index fb16b194946..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_12.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_13.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_13.json deleted file mode 100644 index fb16b194946..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_13.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_14.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_14.json deleted file mode 100644 index fb16b194946..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_14.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_15.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_15.json deleted file mode 100644 index 920ce18c589..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_15.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "disabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_16.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_16.json deleted file mode 100644 index fb16b194946..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_16.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_17.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_17.json deleted file mode 100644 index 920ce18c589..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_17.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "disabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_18.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_18.json deleted file mode 100644 index fb16b194946..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_18.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_19.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_19.json deleted file mode 100644 index 920ce18c589..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_19.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "disabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_2.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_2.json deleted file mode 100644 index fb16b194946..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_2.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_20.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_20.json deleted file mode 100644 index 920ce18c589..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_20.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "disabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_3.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_3.json deleted file mode 100644 index fb16b194946..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_3.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_4.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_4.json deleted file mode 100644 index fb16b194946..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_4.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_5.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_5.json deleted file mode 100644 index fb16b194946..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_5.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_6.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_6.json deleted file mode 100644 index 920ce18c589..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_6.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "disabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_7.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_7.json deleted file mode 100644 index fb16b194946..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_7.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_8.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_8.json deleted file mode 100644 index 920ce18c589..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_8.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "disabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_9.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_9.json deleted file mode 100644 index fb16b194946..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusNoConfig_team_9.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_1.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_1.json deleted file mode 100644 index 78bf971c5a4..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_1.json +++ /dev/null @@ -1 +0,0 @@ -"enabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_10.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_10.json deleted file mode 100644 index a0760977f71..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_10.json +++ /dev/null @@ -1 +0,0 @@ -"disabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_11.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_11.json deleted file mode 100644 index 78bf971c5a4..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_11.json +++ /dev/null @@ -1 +0,0 @@ -"enabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_12.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_12.json deleted file mode 100644 index 78bf971c5a4..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_12.json +++ /dev/null @@ -1 +0,0 @@ -"enabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_13.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_13.json deleted file mode 100644 index 78bf971c5a4..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_13.json +++ /dev/null @@ -1 +0,0 @@ -"enabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_14.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_14.json deleted file mode 100644 index a0760977f71..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_14.json +++ /dev/null @@ -1 +0,0 @@ -"disabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_15.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_15.json deleted file mode 100644 index a0760977f71..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_15.json +++ /dev/null @@ -1 +0,0 @@ -"disabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_16.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_16.json deleted file mode 100644 index a0760977f71..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_16.json +++ /dev/null @@ -1 +0,0 @@ -"disabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_17.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_17.json deleted file mode 100644 index a0760977f71..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_17.json +++ /dev/null @@ -1 +0,0 @@ -"disabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_18.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_18.json deleted file mode 100644 index a0760977f71..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_18.json +++ /dev/null @@ -1 +0,0 @@ -"disabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_19.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_19.json deleted file mode 100644 index 78bf971c5a4..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_19.json +++ /dev/null @@ -1 +0,0 @@ -"enabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_2.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_2.json deleted file mode 100644 index a0760977f71..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_2.json +++ /dev/null @@ -1 +0,0 @@ -"disabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_20.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_20.json deleted file mode 100644 index a0760977f71..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_20.json +++ /dev/null @@ -1 +0,0 @@ -"disabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_3.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_3.json deleted file mode 100644 index 78bf971c5a4..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_3.json +++ /dev/null @@ -1 +0,0 @@ -"enabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_4.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_4.json deleted file mode 100644 index a0760977f71..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_4.json +++ /dev/null @@ -1 +0,0 @@ -"disabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_5.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_5.json deleted file mode 100644 index 78bf971c5a4..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_5.json +++ /dev/null @@ -1 +0,0 @@ -"enabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_6.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_6.json deleted file mode 100644 index a0760977f71..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_6.json +++ /dev/null @@ -1 +0,0 @@ -"disabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_7.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_7.json deleted file mode 100644 index 78bf971c5a4..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_7.json +++ /dev/null @@ -1 +0,0 @@ -"enabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_8.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_8.json deleted file mode 100644 index 78bf971c5a4..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_8.json +++ /dev/null @@ -1 +0,0 @@ -"enabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_9.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_9.json deleted file mode 100644 index a0760977f71..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusValue_team_9.json +++ /dev/null @@ -1 +0,0 @@ -"disabled" diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_1.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_1.json deleted file mode 100644 index 66a69f69b1f..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_1.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": false, - "inactivityTimeoutSecs": -98 - }, - "status": "disabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_10.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_10.json deleted file mode 100644 index 75f0b001c52..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_10.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": false, - "inactivityTimeoutSecs": 120 - }, - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_11.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_11.json deleted file mode 100644 index eafc7e40804..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_11.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": true, - "inactivityTimeoutSecs": 62 - }, - "status": "disabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_12.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_12.json deleted file mode 100644 index 43f961c2500..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_12.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": true, - "inactivityTimeoutSecs": -50 - }, - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_13.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_13.json deleted file mode 100644 index 139bac441da..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_13.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": false, - "inactivityTimeoutSecs": -99 - }, - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_14.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_14.json deleted file mode 100644 index e8271d3d4b5..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_14.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": false, - "inactivityTimeoutSecs": -96 - }, - "status": "disabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_15.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_15.json deleted file mode 100644 index 954360479ff..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_15.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": false, - "inactivityTimeoutSecs": -12 - }, - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_16.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_16.json deleted file mode 100644 index 9aa6c4cf472..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_16.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": true, - "inactivityTimeoutSecs": -60 - }, - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_17.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_17.json deleted file mode 100644 index e8b6267e67b..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_17.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": true, - "inactivityTimeoutSecs": 100 - }, - "status": "disabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_18.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_18.json deleted file mode 100644 index 6e2a810f3fd..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_18.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": true, - "inactivityTimeoutSecs": 74 - }, - "status": "disabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_19.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_19.json deleted file mode 100644 index 06a02b31411..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_19.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": false, - "inactivityTimeoutSecs": -125 - }, - "status": "disabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_2.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_2.json deleted file mode 100644 index e566224c5f3..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_2.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": false, - "inactivityTimeoutSecs": 14 - }, - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_20.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_20.json deleted file mode 100644 index e65c5f047ac..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_20.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": true, - "inactivityTimeoutSecs": 69 - }, - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_3.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_3.json deleted file mode 100644 index 19451686892..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_3.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": true, - "inactivityTimeoutSecs": 92 - }, - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_4.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_4.json deleted file mode 100644 index 5d98e6f2af7..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_4.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": false, - "inactivityTimeoutSecs": 45 - }, - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_5.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_5.json deleted file mode 100644 index 7469262bb92..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_5.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": true, - "inactivityTimeoutSecs": 119 - }, - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_6.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_6.json deleted file mode 100644 index 1f5e32f39bc..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_6.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": false, - "inactivityTimeoutSecs": -50 - }, - "status": "disabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_7.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_7.json deleted file mode 100644 index 9c0cdda20d8..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_7.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": false, - "inactivityTimeoutSecs": -50 - }, - "status": "enabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_8.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_8.json deleted file mode 100644 index 18831a5159c..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_8.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": true, - "inactivityTimeoutSecs": -76 - }, - "status": "disabled" -} diff --git a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_9.json b/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_9.json deleted file mode 100644 index 705400444f1..00000000000 --- a/libs/wire-api/test/golden/testObject_TeamFeatureStatusWithConfig_20TeamFeatureAppLockConfig_team_9.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "config": { - "enforceAppLock": false, - "inactivityTimeoutSecs": 96 - }, - "status": "disabled" -} diff --git a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_1.json b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_1.json index b1d23c68d9c..7622889a460 100644 --- a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_1.json +++ b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_1.json @@ -5,5 +5,5 @@ }, "lockStatus": "unlocked", "status": "enabled", - "ttl" : "unlimited" + "ttl": "unlimited" } diff --git a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_10.json b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_10.json index d9d048dbac5..cacda1ee8de 100644 --- a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_10.json +++ b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_10.json @@ -2,5 +2,5 @@ "config": {}, "lockStatus": "locked", "status": "disabled", - "ttl" : "unlimited" + "ttl": "unlimited" } diff --git a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_11.json b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_11.json index 36188e6b66e..d527b82217b 100644 --- a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_11.json +++ b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_11.json @@ -2,5 +2,5 @@ "config": {}, "lockStatus": "locked", "status": "enabled", - "ttl" : "unlimited" + "ttl": "unlimited" } diff --git a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_12.json b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_12.json index 22daeff858a..22c2f0fd837 100644 --- a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_12.json +++ b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_12.json @@ -1,5 +1,5 @@ { "config": {}, "status": "disabled", - "ttl" : "unlimited" + "ttl": "unlimited" } diff --git a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_13.json b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_13.json index 36188e6b66e..d527b82217b 100644 --- a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_13.json +++ b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_13.json @@ -2,5 +2,5 @@ "config": {}, "lockStatus": "locked", "status": "enabled", - "ttl" : "unlimited" + "ttl": "unlimited" } diff --git a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_14.json b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_14.json index e00849d588a..d9c772e591c 100644 --- a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_14.json +++ b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_14.json @@ -1,5 +1,5 @@ { "config": {}, "lockStatus": "unlocked", - "ttl" : "unlimited" + "ttl": "unlimited" } diff --git a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_15.json b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_15.json index 7ba8af60d9d..ad60a9e6a83 100644 --- a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_15.json +++ b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_15.json @@ -2,5 +2,5 @@ "config": {}, "lockStatus": "unlocked", "status": "enabled", - "ttl" : "unlimited" + "ttl": "unlimited" } diff --git a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_16.json b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_16.json index 50886b60c5c..7d1121ed548 100644 --- a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_16.json +++ b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_16.json @@ -2,5 +2,5 @@ "config": {}, "lockStatus": "unlocked", "status": "disabled", - "ttl" : "unlimited" + "ttl": "unlimited" } diff --git a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_18.json b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_18.json index a8a076301b0..6fc75ed3ba5 100644 --- a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_18.json +++ b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_18.json @@ -1,4 +1,4 @@ { "status": "enabled", - "ttl" : "unlimited" + "ttl": "unlimited" } diff --git a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_19.json b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_19.json index 8854a8126fc..5eab3bdf441 100644 --- a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_19.json +++ b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_19.json @@ -1,4 +1,4 @@ { "lockStatus": "unlocked", - "ttl" : "unlimited" + "ttl": "unlimited" } diff --git a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_2.json b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_2.json index cb681e75db4..65d8c450d0a 100644 --- a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_2.json +++ b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_2.json @@ -3,5 +3,5 @@ "enforceAppLock": true, "inactivityTimeoutSecs": 0 }, - "ttl" : "unlimited" + "ttl": "unlimited" } diff --git a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_3.json b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_3.json index dc67bb2702e..163c101b776 100644 --- a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_3.json +++ b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_3.json @@ -5,5 +5,5 @@ }, "lockStatus": "locked", "status": "enabled", - "ttl" : "unlimited" + "ttl": "unlimited" } diff --git a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_4.json b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_4.json index d6afd266bb9..2746f15a609 100644 --- a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_4.json +++ b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_4.json @@ -3,5 +3,5 @@ "enforcedTimeoutSeconds": -97 }, "status": "enabled", - "ttl" : "unlimited" + "ttl": "unlimited" } diff --git a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_5.json b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_5.json index fff5e5e5434..bf05bd63e58 100644 --- a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_5.json +++ b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_5.json @@ -4,5 +4,5 @@ }, "lockStatus": "unlocked", "status": "enabled", - "ttl" : "unlimited" + "ttl": "unlimited" } diff --git a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_6.json b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_6.json index f2a6e9404f7..2692d5afda2 100644 --- a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_6.json +++ b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_6.json @@ -3,5 +3,5 @@ "enforcedTimeoutSeconds": 77 }, "status": "enabled", - "ttl" : "unlimited" + "ttl": "unlimited" } diff --git a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_7.json b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_7.json index a60d276628d..8d21d6e0f3c 100644 --- a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_7.json +++ b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_7.json @@ -4,5 +4,5 @@ }, "lockStatus": "locked", "status": "enabled", - "ttl" : "unlimited" + "ttl": "unlimited" } diff --git a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_8.json b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_8.json index 166c99a213b..57f73b783d4 100644 --- a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_8.json +++ b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_8.json @@ -6,5 +6,5 @@ ] }, "lockStatus": "locked", - "ttl" : "unlimited" + "ttl": "unlimited" } diff --git a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_9.json b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_9.json index 0e9130e9666..19403614729 100644 --- a/libs/wire-api/test/golden/testObject_WithStatusPatch_team_9.json +++ b/libs/wire-api/test/golden/testObject_WithStatusPatch_team_9.json @@ -6,5 +6,5 @@ }, "lockStatus": "unlocked", "status": "enabled", - "ttl" : "unlimited" + "ttl": "unlimited" } diff --git a/libs/wire-api/test/golden/testObject_WithStatus_team_11.json b/libs/wire-api/test/golden/testObject_WithStatus_team_11.json index bae7bb42e58..1bd84a5bae0 100644 --- a/libs/wire-api/test/golden/testObject_WithStatus_team_11.json +++ b/libs/wire-api/test/golden/testObject_WithStatus_team_11.json @@ -1,5 +1,5 @@ { "lockStatus": "locked", "status": "enabled", - "ttl" : "unlimited" + "ttl": "unlimited" } diff --git a/libs/wire-api/test/unit/Test/Wire/API/Roundtrip/Aeson.hs b/libs/wire-api/test/unit/Test/Wire/API/Roundtrip/Aeson.hs index 27cd79e958d..fbe3550fa37 100644 --- a/libs/wire-api/test/unit/Test/Wire/API/Roundtrip/Aeson.hs +++ b/libs/wire-api/test/unit/Test/Wire/API/Roundtrip/Aeson.hs @@ -99,7 +99,7 @@ tests = testRoundTrip @(Conversation.ConversationList Conversation.Conversation), testRoundTrip @Conversation.Access, testRoundTrip @Conversation.AccessRoleLegacy, - testRoundTrip @Conversation.AccessRoleV2, + testRoundTrip @Conversation.AccessRole, testRoundTrip @Conversation.ConvType, testRoundTrip @Conversation.ReceiptMode, testRoundTrip @Conversation.ConvTeamInfo, diff --git a/libs/wire-api/wire-api.cabal b/libs/wire-api/wire-api.cabal index 758b9659e3d..bf841e4d756 100644 --- a/libs/wire-api/wire-api.cabal +++ b/libs/wire-api/wire-api.cabal @@ -108,6 +108,7 @@ library Wire.API.Routes.QualifiedCapture Wire.API.Routes.Version Wire.API.Routes.Version.Wai + Wire.API.Routes.Versioned Wire.API.Routes.WebSocket Wire.API.ServantProto Wire.API.Swagger diff --git a/services/brig/test/integration/API/Provider.hs b/services/brig/test/integration/API/Provider.hs index 727560b07db..91f9e7388a0 100644 --- a/services/brig/test/integration/API/Provider.hs +++ b/services/brig/test/integration/API/Provider.hs @@ -672,17 +672,17 @@ testBotTeamOnlyConv config db brig galley cannon = withTestService config db bri qcid = Qualified cid localDomain -- Make the conversation team-only and check that the bot can't be added -- to the conversation - setAccessRole uid1 cid (Set.fromList [TeamMemberAccessRole]) + setAccessRole uid1 qcid (Set.fromList [TeamMemberAccessRole]) addBot brig uid1 pid sid cid !!! do const 403 === statusCode const (Just "invalid-conversation") === fmap Error.label . responseJsonMaybe -- Make the conversation allowed for guests and add the bot successfully - setAccessRole uid1 cid (Set.fromList [TeamMemberAccessRole, NonTeamMemberAccessRole, GuestAccessRole, ServiceAccessRole]) + setAccessRole uid1 qcid (Set.fromList [TeamMemberAccessRole, NonTeamMemberAccessRole, GuestAccessRole, ServiceAccessRole]) bid <- addBotConv localDomain brig cannon uid1 uid2 cid pid sid buf let lbuid = qualifyAs luid1 . botUserId $ bid -- Make the conversation team-only again and check that the bot has been removed WS.bracketR cannon uid1 $ \ws -> do - setAccessRole uid1 cid (Set.fromList [TeamMemberAccessRole]) + setAccessRole uid1 qcid (Set.fromList [TeamMemberAccessRole]) _ <- waitFor (5 # Second) not (isMember galley lbuid cid) getBotConv galley bid cid !!! const 404 === statusCode @@ -694,8 +694,8 @@ testBotTeamOnlyConv config db brig galley cannon = withTestService config db bri svcAssertMemberLeave buf (qUntagged lbuid) [qUntagged lbuid] qcid wsAssertMemberLeave ws qcid (qUntagged lbuid) [qUntagged lbuid] where - setAccessRole uid cid role = - updateConversationAccess galley uid cid [InviteAccess] role + setAccessRole uid qcid role = + updateConversationAccess galley uid qcid [InviteAccess] role !!! const 200 === statusCode testMessageBotTeam :: Config -> DB.ClientState -> Brig -> Galley -> Cannon -> Http () @@ -1363,7 +1363,7 @@ createConv :: createConv = createConvWithAccessRoles Nothing createConvWithAccessRoles :: - Maybe (Set AccessRoleV2) -> + Maybe (Set AccessRole) -> Galley -> UserId -> [UserId] -> @@ -1443,14 +1443,19 @@ getBotConv galley bid cid = updateConversationAccess :: Galley -> UserId -> - ConvId -> + Qualified ConvId -> [Access] -> - Set AccessRoleV2 -> + Set AccessRole -> Http ResponseLBS -updateConversationAccess galley uid cid access role = +updateConversationAccess galley uid qcid access role = put $ galley - . paths ["conversations", toByteString' cid, "access"] + . paths + [ "conversations", + toByteString' (qDomain qcid), + toByteString' (qUnqualified qcid), + "access" + ] . header "Z-Type" "access" . header "Z-User" (toByteString' uid) . header "Z-Connection" "conn" diff --git a/services/brig/test/integration/API/User/Account.hs b/services/brig/test/integration/API/User/Account.hs index 11638887a91..2de33cc489c 100644 --- a/services/brig/test/integration/API/User/Account.hs +++ b/services/brig/test/integration/API/User/Account.hs @@ -38,7 +38,7 @@ import Control.Arrow ((&&&)) import Control.Exception (throw) import Control.Lens (ix, preview, (^.), (^?)) import Control.Monad.Catch -import Data.Aeson +import Data.Aeson hiding (json) import qualified Data.Aeson as Aeson import Data.Aeson.Lens import qualified Data.Aeson.Lens as AesonL @@ -52,8 +52,9 @@ import Data.Json.Util (fromUTCTimeMillis) import Data.List1 (singleton) import qualified Data.List1 as List1 import Data.Misc (PlainTextPassword (..)) +import Data.Proxy import Data.Qualified -import Data.Range (Range (fromRange)) +import Data.Range import qualified Data.Set as Set import Data.String.Conversions (cs) import qualified Data.Text as T @@ -63,8 +64,6 @@ import Data.Time (UTCTime, getCurrentTime) import Data.Time.Clock (diffUTCTime) import qualified Data.UUID as UUID import qualified Data.UUID.V4 as UUID -import Data.Vector (Vector) -import qualified Data.Vector as Vec import Federator.MockServer (FederatedRequest (..), MockException (..)) import Imports hiding (head) import qualified Imports @@ -85,10 +84,12 @@ import Web.Cookie (parseSetCookie) import Wire.API.Asset hiding (Asset) import qualified Wire.API.Asset as Asset import Wire.API.Connection +import Wire.API.Conversation import Wire.API.Federation.API.Brig (UserDeletedConnectionsNotification (..)) import qualified Wire.API.Federation.API.Brig as FedBrig import Wire.API.Federation.API.Common (EmptyResponse (EmptyResponse)) import Wire.API.Internal.Notification +import Wire.API.Routes.MultiTablePaging import Wire.API.Team.Feature (ExposeInvitationURLsToTeamAdminConfig (..), FeatureStatus (..), FeatureTTL' (..), LockStatus (LockStatusLocked), withStatus) import Wire.API.Team.Invitation (Invitation (inInvitation)) import Wire.API.Team.Permission hiding (self) @@ -303,17 +304,39 @@ testCreateUserWithPreverified opts brig aws = do testCreateUser :: Brig -> Galley -> Http () -- TODO: this has nothing to do with /register. what's going on here? testCreateUser brig galley = do uid <- userId <$> randomUser brig - get (galley . path "conversations" . zAuthAccess uid "conn") !!! do - const 200 === statusCode - -- check number of conversations: - const (Just 1) === \r -> do - b <- responseBody r - c <- b ^? key "conversations" - Vec.length <$> (maybeFromJSON c :: Maybe (Vector Value)) - -- check conversation type: - const (Just (1 :: Integer)) === \r -> do - b <- responseBody r - b ^? key "conversations" . nth 0 . key "type" >>= maybeFromJSON + assertOnlySelfConversations galley uid + +assertOnlySelfConversations :: Galley -> UserId -> Http () +assertOnlySelfConversations galley uid = do + page :: ConvIdsPage <- + responseJsonError + =<< post + ( galley + . paths ["conversations", "list-ids"] + . json + ( GetPaginatedConversationIds Nothing (toRange (Proxy @100)) :: + GetPaginatedConversationIds + ) + . zAuthAccess uid "conn" + ) + + liftIO $ cnvType conv @?= SelfConv -- The testCreateUserEmptyName test conforms to the following testing standards: -- @SF.Provisioning @TSFI.RESTfulAPI @S2 @@ -358,20 +381,10 @@ testCreateUserAnon brig galley = do -- Every registered user gets a cookie. let zuid = parseSetCookie <$> getHeader "Set-Cookie" rs liftIO $ assertBool "Missing zuid cookie" (isJust zuid) - -- Every registered user gets a self conversation. + -- Every registered user gets two self conversations. let Just uid = userId <$> responseJsonMaybe rs Just quid = userQualifiedId <$> responseJsonMaybe rs - get (galley . path "conversations" . zAuthAccess uid "conn") !!! do - const 200 === statusCode - -- check number of conversations: - const (Just 1) === \r -> do - b <- responseBody r - c <- b ^? key "conversations" - Vec.length <$> (maybeFromJSON c :: Maybe (Vector Value)) - -- check conversation type: - const (Just (1 :: Integer)) === \r -> do - b <- responseBody r - b ^? key "conversations" . nth 0 . key "type" >>= maybeFromJSON + assertOnlySelfConversations galley uid -- should not appear in search suid <- userId <$> randomUser brig Search.refreshIndex brig diff --git a/services/galley/src/Galley/API/Create.hs b/services/galley/src/Galley/API/Create.hs index 0df2dbe3530..d6a1e736f6f 100644 --- a/services/galley/src/Galley/API/Create.hs +++ b/services/galley/src/Galley/API/Create.hs @@ -583,7 +583,7 @@ toUUIDs a b = do b' <- U.fromUUID (toUUID b) & note InvalidUUID4 pure (a', b') -accessRoles :: NewConv -> Set AccessRoleV2 +accessRoles :: NewConv -> Set AccessRole accessRoles b = fromMaybe Data.defRole (newConvAccessRoles b) access :: NewConv -> [Access] diff --git a/services/galley/src/Galley/API/Public/Conversation.hs b/services/galley/src/Galley/API/Public/Conversation.hs index ec8d06bbedd..26bfb21a32c 100644 --- a/services/galley/src/Galley/API/Public/Conversation.hs +++ b/services/galley/src/Galley/API/Public/Conversation.hs @@ -39,12 +39,16 @@ conversationAPI = <@> mkNamedAPI @"list-conversation-ids-v2" (conversationIdsPageFromV2 DoNotListGlobalSelf) <@> mkNamedAPI @"list-conversation-ids" conversationIdsPageFrom <@> mkNamedAPI @"get-conversations" getConversations - <@> mkNamedAPI @"list-conversations-v1" listConversations + <@> mkNamedAPI @"list-conversations@v1" listConversations + <@> mkNamedAPI @"list-conversations@v2" listConversations <@> mkNamedAPI @"list-conversations" listConversations <@> mkNamedAPI @"get-conversation-by-reusable-code" (getConversationByReusableCode @Cassandra) + <@> mkNamedAPI @"create-group-conversation@v2" createGroupConversation <@> mkNamedAPI @"create-group-conversation" createGroupConversation + <@> mkNamedAPI @"create-self-conversation@v2" createProteusSelfConversation <@> mkNamedAPI @"create-self-conversation" createProteusSelfConversation <@> mkNamedAPI @"get-mls-self-conversation" getMLSSelfConversationWithError + <@> mkNamedAPI @"create-one-to-one-conversation@v2" createOne2OneConversation <@> mkNamedAPI @"create-one-to-one-conversation" createOne2OneConversation <@> mkNamedAPI @"add-members-to-conversation-unqualified" addMembersUnqualified <@> mkNamedAPI @"add-members-to-conversation-unqualified2" addMembersUnqualifiedV2 @@ -69,6 +73,7 @@ conversationAPI = <@> mkNamedAPI @"update-conversation-receipt-mode-unqualified" updateConversationReceiptModeUnqualified <@> mkNamedAPI @"update-conversation-receipt-mode" updateConversationReceiptMode <@> mkNamedAPI @"update-conversation-access-unqualified" updateConversationAccessUnqualified + <@> mkNamedAPI @"update-conversation-access@v2" updateConversationAccess <@> mkNamedAPI @"update-conversation-access" updateConversationAccess <@> mkNamedAPI @"get-conversation-self-unqualified" getLocalSelf <@> mkNamedAPI @"update-conversation-self-unqualified" updateUnqualifiedSelfMember diff --git a/services/galley/src/Galley/API/Util.hs b/services/galley/src/Galley/API/Util.hs index 4234d409e54..fc985ef1062 100644 --- a/services/galley/src/Galley/API/Util.hs +++ b/services/galley/src/Galley/API/Util.hs @@ -89,7 +89,7 @@ type JSON = Media "application" "json" ensureAccessRole :: Members '[BrigAccess, ErrorS 'NotATeamMember, ErrorS 'ConvAccessDenied] r => - Set Public.AccessRoleV2 -> + Set Public.AccessRole -> [(UserId, Maybe TeamMember)] -> Sem r () ensureAccessRole roles users = do diff --git a/services/galley/src/Galley/Cassandra/Conversation.hs b/services/galley/src/Galley/Cassandra/Conversation.hs index 6711a92c18f..10a87ff2c89 100644 --- a/services/galley/src/Galley/Cassandra/Conversation.hs +++ b/services/galley/src/Galley/Cassandra/Conversation.hs @@ -404,7 +404,7 @@ toConv :: ConvId -> [LocalMember] -> [RemoteMember] -> - Maybe (ConvType, Maybe UserId, Maybe (Cql.Set Access), Maybe AccessRoleLegacy, Maybe (Cql.Set AccessRoleV2), Maybe Text, Maybe TeamId, Maybe Bool, Maybe Milliseconds, Maybe ReceiptMode, Maybe ProtocolTag, Maybe GroupId, Maybe Epoch, Maybe CipherSuiteTag) -> + Maybe (ConvType, Maybe UserId, Maybe (Cql.Set Access), Maybe AccessRoleLegacy, Maybe (Cql.Set AccessRole), Maybe Text, Maybe TeamId, Maybe Bool, Maybe Milliseconds, Maybe ReceiptMode, Maybe ProtocolTag, Maybe GroupId, Maybe Epoch, Maybe CipherSuiteTag) -> Maybe Conversation toConv cid ms remoteMems mconv = do (cty, muid, acc, role, roleV2, nme, ti, del, timer, rm, ptag, mgid, mep, mcs) <- mconv diff --git a/services/galley/src/Galley/Cassandra/Instances.hs b/services/galley/src/Galley/Cassandra/Instances.hs index e9e97645610..e0ceb402552 100644 --- a/services/galley/src/Galley/Cassandra/Instances.hs +++ b/services/galley/src/Galley/Cassandra/Instances.hs @@ -101,7 +101,7 @@ instance Cql AccessRoleLegacy where n -> Left $ "Unexpected AccessRole value: " ++ show n fromCql _ = Left "AccessRole value: int expected" -instance Cql AccessRoleV2 where +instance Cql AccessRole where ctype = Tagged IntColumn toCql = \case diff --git a/services/galley/src/Galley/Cassandra/Queries.hs b/services/galley/src/Galley/Cassandra/Queries.hs index 085f0366749..0be8fc57b42 100644 --- a/services/galley/src/Galley/Cassandra/Queries.hs +++ b/services/galley/src/Galley/Cassandra/Queries.hs @@ -206,7 +206,7 @@ selectConv :: Maybe UserId, Maybe (C.Set Access), Maybe AccessRoleLegacy, - Maybe (C.Set AccessRoleV2), + Maybe (C.Set AccessRole), Maybe Text, Maybe TeamId, Maybe Bool, @@ -239,7 +239,7 @@ selectReceiptMode = "select receipt_mode from conversation where conv = ?" isConvDeleted :: PrepQuery R (Identity ConvId) (Identity (Maybe Bool)) isConvDeleted = "select deleted from conversation where conv = ?" -insertConv :: PrepQuery W (ConvId, ConvType, UserId, C.Set Access, C.Set AccessRoleV2, Maybe Text, Maybe TeamId, Maybe Milliseconds, Maybe ReceiptMode, ProtocolTag, Maybe GroupId, Maybe Epoch, Maybe CipherSuiteTag) () +insertConv :: PrepQuery W (ConvId, ConvType, UserId, C.Set Access, C.Set AccessRole, Maybe Text, Maybe TeamId, Maybe Milliseconds, Maybe ReceiptMode, ProtocolTag, Maybe GroupId, Maybe Epoch, Maybe CipherSuiteTag) () insertConv = "insert into conversation (conv, type, creator, access, access_roles_v2, name, team, message_timer, receipt_mode, protocol, group_id, epoch, cipher_suite) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" insertMLSSelfConv :: @@ -249,7 +249,7 @@ insertMLSSelfConv :: ConvType, UserId, C.Set Access, - C.Set AccessRoleV2, + C.Set AccessRole, Maybe Text, Maybe TeamId, Maybe Milliseconds, @@ -273,7 +273,7 @@ insertGlobalTeamConv = "insert into conversation (conv, type, access, name, team setGlobalTeamConvCreator :: PrepQuery W (UserId, ConvId) () setGlobalTeamConvCreator = "update conversation set creator = ? where conv = ?" -updateConvAccess :: PrepQuery W (C.Set Access, C.Set AccessRoleV2, ConvId) () +updateConvAccess :: PrepQuery W (C.Set Access, C.Set AccessRole, ConvId) () updateConvAccess = "update conversation set access = ?, access_roles_v2 = ? where conv = ?" updateConvReceiptMode :: PrepQuery W (ReceiptMode, ConvId) () diff --git a/services/galley/src/Galley/Data/Conversation.hs b/services/galley/src/Galley/Data/Conversation.hs index 3f83ecc9da5..378262560fe 100644 --- a/services/galley/src/Galley/Data/Conversation.hs +++ b/services/galley/src/Galley/Data/Conversation.hs @@ -81,7 +81,7 @@ convTeam = cnvmTeam . convMetadata convAccess :: Conversation -> [Access] convAccess = cnvmAccess . convMetadata -convAccessRoles :: Conversation -> Set AccessRoleV2 +convAccessRoles :: Conversation -> Set AccessRole convAccessRoles = cnvmAccessRoles . convMetadata convAccessData :: Conversation -> ConversationAccessData @@ -102,8 +102,8 @@ convSetName n c = c {convMetadata = (convMetadata c) {cnvmName = n}} defRegularConvAccess :: [Access] defRegularConvAccess = [InviteAccess] -parseAccessRoles :: Maybe AccessRoleLegacy -> Maybe (Set AccessRoleV2) -> Maybe (Set AccessRoleV2) -parseAccessRoles mbLegacy mbV2 = mbV2 <|> fromAccessRoleLegacy <$> mbLegacy +parseAccessRoles :: Maybe AccessRoleLegacy -> Maybe (Set AccessRole) -> Maybe (Set AccessRole) +parseAccessRoles mbLegacy mbAccess = mbAccess <|> fromAccessRoleLegacy <$> mbLegacy convMessageTimer :: Conversation -> Maybe Milliseconds convMessageTimer = cnvmMessageTimer . convMetadata diff --git a/services/galley/test/integration/API.hs b/services/galley/test/integration/API.hs index 785c099b9ac..4bfbc963efb 100644 --- a/services/galley/test/integration/API.hs +++ b/services/galley/test/integration/API.hs @@ -129,13 +129,14 @@ tests s = test s "create conversation with remote users" postConvWithRemoteUsersOk, test s "get empty conversations" getConvsOk, test s "get conversations by ids" getConvsOk2, - test s "fail to get >500 conversations" getConvsFailMaxSize, - test s "get conversation ids" getConvIdsOk, - test s "get conversation ids v2" listConvIdsOk, - test s "paginate through conversation ids" paginateConvIds, + test s "fail to get >500 conversations with v2 API" getConvsFailMaxSizeV2, + test s "get conversation ids with v2 API" testGetConvIdsV2, + test s "list conversation ids" testListConvIds, + test s "paginate through conversation ids with v2 API" paginateConvIds, test s "paginate through /conversations/list-ids" paginateConvListIds, test s "paginate through /conversations/list-ids - page ending at locals and remote domain" paginateConvListIdsPageEndingAtLocalsAndDomain, test s "fail to get >1000 conversation ids" getConvIdsFailMaxSize, + test s "fail to get >1000 conversation ids with v2 API" getConvIdsFailMaxSizeV2, 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, @@ -1382,13 +1383,13 @@ postJoinCodeConvOk = do -- changing access to non-activated should give eve access Right accessRolesWithGuests <- liftIO $ genAccessRolesV2 [TeamMemberAccessRole, NonTeamMemberAccessRole, GuestAccessRole] [] let nonActivatedAccess = ConversationAccessData (Set.singleton CodeAccess) accessRolesWithGuests - putAccessUpdate alice conv nonActivatedAccess !!! const 200 === statusCode + putAccessUpdate alice qconv nonActivatedAccess !!! const 200 === statusCode postJoinCodeConv eve payload !!! const 200 === statusCode -- guest cannot create invite link postConvCode eve conv !!! const 403 === statusCode -- after removing CodeAccess, no further people can join let noCodeAccess = ConversationAccessData (Set.singleton InviteAccess) accessRoles - putAccessUpdate alice conv noCodeAccess !!! const 200 === statusCode + putAccessUpdate alice qconv noCodeAccess !!! const 200 === statusCode postJoinCodeConv dave payload !!! const 404 === statusCode -- @END @@ -1406,16 +1407,16 @@ postConvertCodeConv = do getConvCode alice conv !!! const 403 === statusCode -- cannot change to (Set.fromList [TeamMemberAccessRole]) as not a team conversation let teamAccess = ConversationAccessData (Set.singleton InviteAccess) (Set.fromList [TeamMemberAccessRole]) - putAccessUpdate alice conv teamAccess !!! const 403 === statusCode + putAccessUpdate alice qconv teamAccess !!! const 403 === statusCode -- change access WS.bracketR c alice $ \wsA -> do let nonActivatedAccess = ConversationAccessData (Set.fromList [InviteAccess, CodeAccess]) (Set.fromList [TeamMemberAccessRole, NonTeamMemberAccessRole, GuestAccessRole, ServiceAccessRole]) - putAccessUpdate alice conv nonActivatedAccess !!! const 200 === statusCode + putAccessUpdate alice qconv nonActivatedAccess !!! const 200 === statusCode -- test no-op - putAccessUpdate alice conv nonActivatedAccess !!! const 204 === statusCode + putAccessUpdate alice qconv nonActivatedAccess !!! const 204 === statusCode void . liftIO $ WS.assertMatchN (5 # Second) [wsA] $ wsAssertConvAccessUpdate qconv qalice nonActivatedAccess @@ -1436,7 +1437,7 @@ postConvertCodeConv = do ConversationAccessData (Set.singleton InviteAccess) (Set.fromList [TeamMemberAccessRole, NonTeamMemberAccessRole, GuestAccessRole, ServiceAccessRole]) - putAccessUpdate alice conv noCodeAccess !!! const 200 === statusCode + putAccessUpdate alice qconv noCodeAccess !!! const 200 === statusCode getConvCode alice conv !!! const 403 === statusCode postConvertTeamConv :: TestM () @@ -1477,7 +1478,7 @@ postConvertTeamConv = do ConversationAccessData (Set.fromList [InviteAccess, CodeAccess]) (Set.fromList [TeamMemberAccessRole]) - putAccessUpdate alice conv teamAccess !!! const 200 === statusCode + putAccessUpdate alice qconv teamAccess !!! const 200 === statusCode void . liftIO $ WS.assertMatchN (5 # Second) [wsA, wsB, wsE, wsM] $ wsAssertConvAccessUpdate qconv qalice teamAccess @@ -1591,15 +1592,15 @@ testTeamMemberCantJoinViaGuestLinkIfAccessRoleRemoved = do -- and given alice and bob are in a team conversation and alice created a guest link let accessRoles = Set.fromList [TeamMemberAccessRole, GuestAccessRole, ServiceAccessRole] - convId <- decodeConvId <$> postTeamConv tid alice [bob] (Just "chit chat") [CodeAccess] (Just accessRoles) Nothing - cCode <- decodeConvCodeEvent <$> postConvCode alice convId + qconvId <- decodeQualifiedConvId <$> postTeamConv tid alice [bob] (Just "chit chat") [CodeAccess] (Just accessRoles) Nothing + cCode <- decodeConvCodeEvent <$> postConvCode alice (qUnqualified qconvId) -- then charlie can join via the guest link postJoinCodeConv charlie cCode !!! const 200 === statusCode -- when the guests are disabled for the conversation let accessData = ConversationAccessData (Set.singleton InviteAccess) (Set.fromList [TeamMemberAccessRole, ServiceAccessRole]) - putAccessUpdate alice convId accessData !!! const 200 === statusCode + putAccessUpdate alice qconvId accessData !!! const 200 === statusCode -- then dee cannot join via guest link postJoinCodeConv dee cCode !!! const 404 === statusCode @@ -1686,9 +1687,10 @@ postJoinConvFail = do getConvsOk :: TestM () getConvsOk = do usr <- randomUser - getConvs usr Nothing Nothing !!! do - const 200 === statusCode - const [toUUID usr] === map (toUUID . qUnqualified . cnvQualifiedId) . decodeConvList + convs <- getAllConvs usr + liftIO $ + [selfConv usr, mlsSelfConvId usr] + @?= map (qUnqualified . cnvQualifiedId) convs getConvsOk2 :: TestM () getConvsOk2 = do @@ -1696,9 +1698,13 @@ getConvsOk2 = do connectUsers alice (singleton bob) -- create & get one2one conv cnv1 <- responseJsonError =<< postO2OConv alice bob (Just "gossip1") responseJsonUnsafe rs - let c1 = convs >>= find ((== cnvQualifiedId cnv1) . cnvQualifiedId) - let c2 = convs >>= find ((== cnvQualifiedId cnv2) . cnvQualifiedId) + convs <- getAllConvs alice + let c1 = find ((== cnvQualifiedId cnv1) . cnvQualifiedId) convs + let c2 = find ((== cnvQualifiedId cnv2) . cnvQualifiedId) convs liftIO . forM_ [(cnv1, c1), (cnv2, c2)] $ \(expected, actual) -> do assertEqual "name mismatch" @@ -1728,21 +1737,28 @@ getConvsOk2 = do (Just []) ((\c -> cmOthers (cnvMembers c) \\ cmOthers (cnvMembers expected)) <$> actual) -getConvsFailMaxSize :: TestM () -getConvsFailMaxSize = do +getConvsFailMaxSizeV2 :: TestM () +getConvsFailMaxSizeV2 = do usr <- randomUser - getConvs usr Nothing (Just 501) + g <- view tsUnversionedGalley + get + ( g + . path "/v2/conversations" + . zUser usr + . zConn "conn" + . queryItem "size" (toByteString' (501 :: Int32)) + ) !!! const 400 === statusCode -getConvIdsOk :: TestM () -getConvIdsOk = do +testGetConvIdsV2 :: TestM () +testGetConvIdsV2 = do [alice, bob] <- randomUsers 2 connectUsers alice (singleton bob) void $ postO2OConv alice bob (Just "gossip") - getConvIds alice Nothing Nothing !!! do + getConvIdsV2 alice Nothing Nothing !!! do const 200 === statusCode const 2 === length . decodeConvIdList - getConvIds bob Nothing Nothing !!! do + getConvIdsV2 bob Nothing Nothing !!! do const 200 === statusCode const 2 === length . decodeConvIdList @@ -1758,7 +1774,7 @@ paginateConvIds = do foldM_ (getChunk 16 alice) Nothing [15, 14 .. 0 :: Int] where getChunk size alice start n = do - resp <- getConvIds alice start (Just size) do + r :: ConversationList ConvId <- + responseJsonError + =<< getConvIdsV2 u Nothing (Just 5) + Int32 -> Int -> UserId -> Maybe ConversationPagingState -> Int -> TestM (Maybe ConversationPagingState) getChunkedConvs size lastSize alice pagingState n = do - let paginationOpts = GetPaginatedConversationIds pagingState (unsafeRange size) - resp <- listConvIds alice paginationOpts 0 @@ -1930,23 +1951,39 @@ getConvsPagingOk :: TestM () getConvsPagingOk = do [ally, bill, carl] <- randomUsers 3 connectUsers ally (list1 bill [carl]) - replicateM_ 11 $ postConv ally [bill, carl] (Just "gossip") [] Nothing Nothing - walk ally [3, 3, 3, 3, 2] -- 11 (group) + 2 (1:1) + 1 (self) - walk bill [3, 3, 3, 3, 1] -- 11 (group) + 1 (1:1) + 1 (self) - walk carl [3, 3, 3, 3, 1] -- 11 (group) + 1 (1:1) + 1 (self) + replicateM_ 10 $ postConv ally [bill, carl] (Just "gossip") [] Nothing Nothing + + walk ally [3, 3, 3, 3, 2] -- 10 (group) + 2 (1:1) + 2 (self) + walk bill [3, 3, 3, 3, 1] -- 10 (group) + 1 (1:1) + 2 (self) + walk carl [3, 3, 3, 3, 1] -- 10 (group) + 1 (1:1) + 2 (self) where walk :: Foldable t => UserId -> t Int -> TestM () walk u = foldM_ (next u 3) Nothing - next :: UserId -> Int32 -> Maybe ConvId -> Int -> TestM (Maybe ConvId) - next u step start n = do - r1 <- getConvIds u (Right <$> start) (Just step) responseJsonUnsafe r1 - liftIO $ assertEqual "unexpected length (getConvIds)" (Just n) (length <$> ids1) - r2 <- getConvs u (Right <$> start) (Just step) responseJsonUnsafe r2 - liftIO $ assertEqual "unexpected length (getConvs)" (Just n) (length <$> ids3) - liftIO $ assertBool "getConvIds /= getConvs" (ids1 == ids3) - pure $ ids1 >>= listToMaybe . reverse + + next :: + UserId -> + Int32 -> + Maybe ConversationPagingState -> + Int -> + TestM (Maybe ConversationPagingState) + next u step state n = do + (ids1, state') <- do + r :: ConvIdsPage <- + responseJsonError + =<< getConvPage u state (Just step) + postO2OConv alice bob (Just "gossip1") - getConvs alice (Just $ Left [qUnqualified . cnvQualifiedId $ cnv1]) Nothing !!! do - const 200 === statusCode - const (Just [cnvQualifiedId cnv1]) === fmap (map cnvQualifiedId . convList) . responseJsonUnsafe + do + convs <- + responseJsonError + =<< getConvs alice [cnvQualifiedId cnv1] liftIO nextRandom GetConversationsResponse convs <- runFedClient @"get-conversations" fedGalleyClient localDomain $ diff --git a/services/galley/test/integration/API/MLS.hs b/services/galley/test/integration/API/MLS.hs index 84629a03e3f..12b78d18840 100644 --- a/services/galley/test/integration/API/MLS.hs +++ b/services/galley/test/integration/API/MLS.hs @@ -25,8 +25,6 @@ import API.Util as Util import Bilge hiding (head) import Bilge.Assert import Cassandra --- import Control.Error.Util (hush) --- import Control.Lens (view, (^.)) import Control.Lens (view, (%~), (.~)) import qualified Control.Monad.State as State import Crypto.Error @@ -76,7 +74,7 @@ import Wire.API.MLS.Serialisation import Wire.API.MLS.Welcome import Wire.API.Message import Wire.API.Routes.MultiTablePaging --- import Wire.API.Team (teamCreator) +import Wire.API.Routes.Version import Wire.API.User.Client tests :: IO TestSetup -> TestTree @@ -372,14 +370,11 @@ testAddUserWithBundle = do pure (qcnv, commit) -- check that bob can now see the conversation - convs <- - responseJsonError - =<< getConvs (qUnqualified bob) Nothing Nothing - >= assertLeaveEvent qcnv alice [bob] do - convs <- - responseJsonError - =<< getConvs (qUnqualified bob) Nothing Nothing - TestM () testSelfConversationList isBelowV3 = do let (errMsg, justOrNothing, listCnvs) = if isBelowV3 - then ("The MLS self-conversation is listed", isNothing, listConvIdsV2) - else ("The MLS self-conversation is not listed", isJust, listConvIds) + then ("The MLS self-conversation is listed", isNothing, getConvPageV2) + else ("The MLS self-conversation is not listed", isJust, getConvPage) alice <- randomUser do mMLSSelf <- findSelfConv alice listCnvs @@ -2404,29 +2390,28 @@ testSelfConversationList isBelowV3 = do -- make sure that the self-conversation is not listed below V3 even once it -- has been created. unless isBelowV3 $ do - mMLSSelf <- findSelfConv alice listConvIdsV2 + mMLSSelf <- findSelfConv alice getConvPageV2 liftIO $ assertBool errMsg (isNothing mMLSSelf) where - paginationOpts = GetPaginatedConversationIds Nothing (toRange (Proxy @100)) - isMLSSelf u conv = mlsSelfConvId u == qUnqualified conv findSelfConv u listEndpoint = do convIds :: ConvIdsPage <- responseJsonError - =<< listEndpoint u paginationOpts + =<< listEndpoint u Nothing (Just 100) ) Nothing $ guard . isMLSSelf u <$> mtpResults convIds + getConvPageV2 u s c = do + g <- view tsUnversionedGalley + getConvPageWithGalley (addPrefixAtVersion V2 . g) u s c + testSelfConversationMLSNotConfigured :: TestM () testSelfConversationMLSNotConfigured = do alice <- randomUser - let paginationOpts = GetPaginatedConversationIds Nothing (toRange (Proxy @100)) - noMLS = Opts.optSettings %~ Opts.setMlsPrivateKeyPaths .~ Nothing - runMLSTest - . liftTest - . withSettingsOverrides noMLS - $ listConvIds alice paginationOpts !!! const 200 === statusCode + let noMLS = Opts.optSettings %~ Opts.setMlsPrivateKeyPaths .~ Nothing + withSettingsOverrides noMLS $ + getConvPage alice Nothing (Just 100) !!! const 200 === statusCode testSelfConversationOtherUser :: TestM () testSelfConversationOtherUser = do @@ -2485,14 +2470,11 @@ testAddTeamUserWithBundle = do pure (qcnv, commit) -- check that bob can now see the conversation - convs <- - responseJsonError - =<< getConvs (qUnqualified bob) Nothing Nothing - viewFederationDomain let access = ConversationAccessData (Set.fromList [InviteAccess, CodeAccess]) (Set.fromList [TeamMemberAccessRole, NonTeamMemberAccessRole]) - putAccessUpdate owner cid1 access !!! const 200 === statusCode + putAccessUpdate owner qcid1 access !!! const 200 === statusCode code <- decodeConvCodeEvent <$> (postConvCode owner cid1 members) (Just "blup") Nothing Nothing Util.postMembers owner (qExtern :| [qMember]) qcid1 !!! const 200 === statusCode diff --git a/services/galley/test/integration/API/Util.hs b/services/galley/test/integration/API/Util.hs index a8d75b9c175..f37701a828b 100644 --- a/services/galley/test/integration/API/Util.hs +++ b/services/galley/test/integration/API/Util.hs @@ -596,7 +596,7 @@ createTeamConvAccess :: [UserId] -> Maybe Text -> Maybe (Set Access) -> - Maybe (Set AccessRoleV2) -> + Maybe (Set AccessRole) -> Maybe Milliseconds -> Maybe RoleName -> TestM ConvId @@ -610,7 +610,7 @@ createTeamConvAccessRaw :: [UserId] -> Maybe Text -> Maybe (Set Access) -> - Maybe (Set AccessRoleV2) -> + Maybe (Set AccessRole) -> Maybe Milliseconds -> Maybe RoleName -> TestM ResponseLBS @@ -648,7 +648,7 @@ createMLSTeamConv :: UserList UserId -> Maybe Text -> Maybe (Set Access) -> - Maybe (Set AccessRoleV2) -> + Maybe (Set AccessRole) -> Maybe Milliseconds -> Maybe RoleName -> m (Local ConvId) @@ -715,7 +715,7 @@ postConv :: [UserId] -> Maybe Text -> [Access] -> - Maybe (Set AccessRoleV2) -> + Maybe (Set AccessRole) -> Maybe Milliseconds -> TestM ResponseLBS postConv u us name a r mtimer = postConvWithRole u us name a r mtimer roleNameWireAdmin @@ -761,7 +761,7 @@ postConvWithRemoteUsers u n = setName Nothing = checked "federated gossip" setName x = x -postTeamConv :: TeamId -> UserId -> [UserId] -> Maybe Text -> [Access] -> Maybe (Set AccessRoleV2) -> Maybe Milliseconds -> TestM ResponseLBS +postTeamConv :: TeamId -> UserId -> [UserId] -> Maybe Text -> [Access] -> Maybe (Set AccessRole) -> Maybe Milliseconds -> TestM ResponseLBS postTeamConv tid u us name a r mtimer = do g <- viewGalley let conv = @@ -794,7 +794,7 @@ postConvWithRole :: [UserId] -> Maybe Text -> [Access] -> - Maybe (Set AccessRoleV2) -> + Maybe (Set AccessRole) -> Maybe Milliseconds -> RoleName -> TestM ResponseLBS @@ -810,7 +810,7 @@ postConvWithRole u members name access arole timer role = newConvUsersRole = role } -postConvWithReceipt :: UserId -> [UserId] -> Maybe Text -> [Access] -> Maybe (Set AccessRoleV2) -> Maybe Milliseconds -> ReceiptMode -> TestM ResponseLBS +postConvWithReceipt :: UserId -> [UserId] -> Maybe Text -> [Access] -> Maybe (Set AccessRole) -> Maybe Milliseconds -> ReceiptMode -> TestM ResponseLBS postConvWithReceipt u us name a r mtimer rcpt = do g <- viewGalley let conv = @@ -1053,16 +1053,39 @@ mkOtrProtoMessage sender rec reportMissing ad = & Proto.newOtrMessageData ?~ fromBase64TextLenient ad & Proto.newOtrMessageReportMissing .~ rmis -getConvs :: UserId -> Maybe (Either [ConvId] ConvId) -> Maybe Int32 -> TestM ResponseLBS -getConvs u r s = do +getConvs :: HasCallStack => UserId -> [Qualified ConvId] -> TestM ResponseLBS +getConvs u cids = do g <- viewGalley - get $ + post $ g - . path "/conversations" + . path "/conversations/list" . zUser u . zConn "conn" - . zType "access" - . convRange r s + . json (ListConversations (unsafeRange cids)) + +getAllConvs :: HasCallStack => UserId -> TestM [Conversation] +getAllConvs u = do + g <- viewGalley + cids <- do + r :: ConvIdsPage <- + responseJsonError + =<< post + ( g + . path "/conversations/list-ids" + . zUser u + . zConn "conn" + . json + ( GetPaginatedConversationIds Nothing maxBound :: + GetPaginatedConversationIds + ) + ) + @@ -1113,8 +1136,8 @@ getConvQualified u (Qualified conv domain) = do . zConn "conn" . zType "access" -getConvIds :: UserId -> Maybe (Either [ConvId] ConvId) -> Maybe Int32 -> TestM ResponseLBS -getConvIds u r s = do +getConvIdsV2 :: UserId -> Maybe (Either [ConvId] ConvId) -> Maybe Int32 -> TestM ResponseLBS +getConvIdsV2 u r s = do -- The endpoint is removed starting V3 g <- fmap (addPrefixAtVersion V2 .) (view tsUnversionedGalley) get $ @@ -1125,29 +1148,37 @@ getConvIds u r s = do . zType "access" . convRange r s -listConvIds :: UserId -> GetPaginatedConversationIds -> TestM ResponseLBS -listConvIds u paginationOpts = do +getConvPage :: UserId -> Maybe ConversationPagingState -> Maybe Int32 -> TestM ResponseLBS +getConvPage u state count = do g <- viewGalley - post $ - g - . path "/conversations/list-ids" - . zUser u - . json paginationOpts + getConvPageWithGalley g u state count -listConvIdsV2 :: UserId -> GetPaginatedConversationIds -> TestM ResponseLBS -listConvIdsV2 u paginationOpts = do - g <- fmap (addPrefixAtVersion V2 .) (view tsUnversionedGalley) +getConvPageWithGalley :: + (Request -> Request) -> + UserId -> + Maybe ConversationPagingState -> + Maybe Int32 -> + TestM ResponseLBS +getConvPageWithGalley g u state count = post $ g . path "/conversations/list-ids" . zUser u - . json paginationOpts + . zConn "conn" + -- generate JSON by hand here, so we can bypass the static range check + . json + ( object + ( map (\n -> "size" .= toJSON n) (toList count) + <> map (\s -> "paging_state" .= toJSON s) (toList state) + ) + ) -- | Does not page through conversation list listRemoteConvs :: Domain -> UserId -> TestM [Qualified ConvId] listRemoteConvs remoteDomain uid = do - let paginationOpts = GetPaginatedConversationIds Nothing (toRange (Proxy @100)) - allConvs <- fmap mtpResults . responseJsonError @_ @ConvIdsPage =<< listConvIds uid paginationOpts qDomain qcnv == remoteDomain) allConvs postQualifiedMembers :: @@ -1374,12 +1405,17 @@ postJoinCodeConv u j = do . zType "access" . json j -putAccessUpdate :: UserId -> ConvId -> ConversationAccessData -> TestM ResponseLBS -putAccessUpdate u c acc = do +putAccessUpdate :: UserId -> Qualified ConvId -> ConversationAccessData -> TestM ResponseLBS +putAccessUpdate u qc acc = do g <- viewGalley put $ g - . paths ["/conversations", toByteString' c, "access"] + . paths + [ "/conversations", + toByteString' (qDomain qc), + toByteString' (qUnqualified qc), + "access" + ] . zUser u . zConn "conn" . zType "access" @@ -1925,10 +1961,10 @@ decodeConvId = qUnqualified . decodeQualifiedConvId decodeQualifiedConvId :: HasCallStack => Response (Maybe Lazy.ByteString) -> Qualified ConvId decodeQualifiedConvId = cnvQualifiedId . responseJsonUnsafe -decodeConvList :: Response (Maybe Lazy.ByteString) -> [Conversation] +decodeConvList :: HasCallStack => Response (Maybe Lazy.ByteString) -> [Conversation] decodeConvList = convList . responseJsonUnsafeWithMsg "conversations" -decodeConvIdList :: Response (Maybe Lazy.ByteString) -> [ConvId] +decodeConvIdList :: HasCallStack => Response (Maybe Lazy.ByteString) -> [ConvId] decodeConvIdList = convList . responseJsonUnsafeWithMsg "conversation-ids" decodeQualifiedConvIdList :: Response (Maybe Lazy.ByteString) -> Either String [Qualified ConvId]