diff --git a/changelog.d/5-internal/galley-servant-split b/changelog.d/5-internal/galley-servant-split new file mode 100644 index 0000000000..450472e718 --- /dev/null +++ b/changelog.d/5-internal/galley-servant-split @@ -0,0 +1 @@ +Split galley API routes and handler definitions into several modules 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 ee690d531d..e7d86ab700 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 @@ -35,7 +35,7 @@ import Wire.API.Error.Galley import Wire.API.Federation.API.Common import Wire.API.Federation.Endpoint import Wire.API.Message -import Wire.API.Routes.Public.Galley +import Wire.API.Routes.Public.Galley.Messaging import Wire.API.Util.Aeson (CustomEncoded (..)) import Wire.Arbitrary (Arbitrary, GenericUniform (..)) diff --git a/libs/wire-api-federation/test/Test/Wire/API/Federation/Golden/MessageSendResponse.hs b/libs/wire-api-federation/test/Test/Wire/API/Federation/Golden/MessageSendResponse.hs index 21ec69477c..efbcb2d93e 100644 --- a/libs/wire-api-federation/test/Test/Wire/API/Federation/Golden/MessageSendResponse.hs +++ b/libs/wire-api-federation/test/Test/Wire/API/Federation/Golden/MessageSendResponse.hs @@ -25,7 +25,7 @@ import GHC.Exts (IsList (fromList)) import Imports import Wire.API.Federation.API.Galley (MessageSendResponse (..)) import Wire.API.Message -import Wire.API.Routes.Public.Galley +import Wire.API.Routes.Public.Galley.Messaging import Wire.API.User.Client (QualifiedUserClients (..)) missing :: QualifiedUserClients diff --git a/libs/wire-api/src/Wire/API/Conversation.hs b/libs/wire-api/src/Wire/API/Conversation.hs index f25b4f3ae0..e55df61782 100644 --- a/libs/wire-api/src/Wire/API/Conversation.hs +++ b/libs/wire-api/src/Wire/API/Conversation.hs @@ -104,9 +104,9 @@ import Data.List.Extra (disjointOrd) import Data.List.NonEmpty (NonEmpty) import Data.List1 import Data.Misc -import Data.Proxy (Proxy (Proxy)) import Data.Qualified (Qualified (qUnqualified), deprecatedSchema) import Data.Range (Range, fromRange, rangedSchema) +import Data.SOP import Data.Schema import qualified Data.Set as Set import Data.String.Conversions (cs) @@ -121,6 +121,7 @@ import Wire.API.Conversation.Protocol import Wire.API.Conversation.Role (RoleName, roleNameWireAdmin) import Wire.API.MLS.Group import Wire.API.Routes.MultiTablePaging +import Wire.API.Routes.MultiVerb import Wire.Arbitrary -------------------------------------------------------------------------------- @@ -949,3 +950,10 @@ namespaceMLSSelfConv :: UUID.UUID namespaceMLSSelfConv = -- a V5 uuid created with the nil namespace fromJust . UUID.fromString $ "3eac2a2c-3850-510b-bd08-8a98e80dd4d9" + +-------------------------------------------------------------------------------- +-- MultiVerb instances + +instance AsHeaders '[ConvId] Conversation Conversation where + toHeaders c = (I (qUnqualified (cnvQualifiedId c)) :* Nil, c) + fromHeaders = snd diff --git a/libs/wire-api/src/Wire/API/Event/Conversation.hs b/libs/wire-api/src/Wire/API/Event/Conversation.hs index f05018432d..58b50fce8e 100644 --- a/libs/wire-api/src/Wire/API/Event/Conversation.hs +++ b/libs/wire-api/src/Wire/API/Event/Conversation.hs @@ -73,6 +73,7 @@ import qualified Data.Aeson.KeyMap as KeyMap import Data.Id import Data.Json.Util import Data.Qualified +import Data.SOP import Data.Schema import qualified Data.Swagger as S import Data.Time @@ -83,6 +84,7 @@ import Wire.API.Conversation 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.User (QualifiedUserIdList (..)) import Wire.Arbitrary (Arbitrary (arbitrary), GenericUniform (..)) @@ -413,3 +415,17 @@ instance ToJSON Event where instance S.ToSchema Event where declareNamedSchema = schemaToSwagger + +-------------------------------------------------------------------------------- +-- MultiVerb instances + +instance + (ResponseType r1 ~ ConversationCode, ResponseType r2 ~ Event) => + AsUnion '[r1, r2] AddCodeResult + where + toUnion (CodeAlreadyExisted c) = Z (I c) + toUnion (CodeAdded e) = S (Z (I e)) + + fromUnion (Z (I c)) = CodeAlreadyExisted c + fromUnion (S (Z (I e))) = CodeAdded e + fromUnion (S (S x)) = case x of {} diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Galley.hs b/libs/wire-api/src/Wire/API/Routes/Public/Galley.hs index 4a8791a902..a1d786c15a 100644 --- a/libs/wire-api/src/Wire/API/Routes/Public/Galley.hs +++ b/libs/wire-api/src/Wire/API/Routes/Public/Galley.hs @@ -20,153 +20,21 @@ module Wire.API.Routes.Public.Galley where -import qualified Data.Code as Code -import Data.CommaSeparatedList -import Data.Domain (Domain) -import Data.Id (ConvId, TeamId, UserId) -import Data.Qualified (Qualified (..)) -import Data.Range import Data.SOP import qualified Data.Swagger as Swagger -import GHC.TypeLits (AppendSymbol) -import qualified Generics.SOP as GSOP -import Imports hiding (head) import Servant hiding (WithStatus) import Servant.Swagger.Internal import Servant.Swagger.Internal.Orphans () -import Wire.API.Conversation -import Wire.API.Conversation.Role -import Wire.API.CustomBackend (CustomBackend) -import Wire.API.Error -import qualified Wire.API.Error.Brig as BrigError -import Wire.API.Error.Galley -import Wire.API.Event.Conversation -import Wire.API.MLS.CommitBundle -import Wire.API.MLS.Keys -import Wire.API.MLS.Message -import Wire.API.MLS.PublicGroupState -import Wire.API.MLS.Serialisation -import Wire.API.MLS.Servant -import Wire.API.MLS.Welcome -import Wire.API.Message -import Wire.API.Routes.CSV -import Wire.API.Routes.LowLevelStream -import Wire.API.Routes.MultiVerb -import Wire.API.Routes.Named -import Wire.API.Routes.Public -import Wire.API.Routes.Public.Util -import Wire.API.Routes.QualifiedCapture -import Wire.API.Routes.Version -import Wire.API.ServantProto (Proto, RawProto) -import Wire.API.Team -import Wire.API.Team.Conversation -import Wire.API.Team.Feature -import Wire.API.Team.LegalHold -import Wire.API.Team.Member -import Wire.API.Team.Permission (Perm (..)) -import Wire.API.Team.SearchVisibility (TeamSearchVisibilityView) -import qualified Wire.API.User as User - -instance AsHeaders '[ConvId] Conversation Conversation where - toHeaders c = (I (qUnqualified (cnvQualifiedId c)) :* Nil, c) - fromHeaders = snd - -type ConversationResponse = ResponseForExistedCreated Conversation - -type ConversationHeaders = '[DescHeader "Location" "Conversation ID" ConvId] - -type ConversationVerbWithMethod (m :: StdMethod) = - MultiVerb - m - '[JSON] - '[ WithHeaders - ConversationHeaders - Conversation - (Respond 200 "Conversation existed" Conversation), - WithHeaders - ConversationHeaders - Conversation - (Respond 201 "Conversation created" Conversation) - ] - ConversationResponse - -type ConversationVerb = ConversationVerbWithMethod 'POST - -type ConversationPutVerb = ConversationVerbWithMethod 'PUT - -type CreateConversationCodeVerb = - MultiVerb - 'POST - '[JSON] - '[ Respond 200 "Conversation code already exists." ConversationCode, - Respond 201 "Conversation code created." Event - ] - AddCodeResult - -instance - (ResponseType r1 ~ ConversationCode, ResponseType r2 ~ Event) => - AsUnion '[r1, r2] AddCodeResult - where - toUnion (CodeAlreadyExisted c) = Z (I c) - toUnion (CodeAdded e) = S (Z (I e)) - - fromUnion (Z (I c)) = CodeAlreadyExisted c - fromUnion (S (Z (I e))) = CodeAdded e - fromUnion (S (S x)) = case x of {} - -type ConvUpdateResponses = UpdateResponses "Conversation unchanged" "Conversation updated" Event - -type ConvJoinResponses = UpdateResponses "Conversation unchanged" "Conversation joined" Event - -data MessageNotSent a - = MessageNotSentConversationNotFound - | MessageNotSentUnknownClient - | MessageNotSentLegalhold - | MessageNotSentClientMissing a - deriving stock (Eq, Show, Generic, Functor) - deriving - (AsUnion (MessageNotSentResponses a)) - via (GenericAsUnion (MessageNotSentResponses a) (MessageNotSent a)) - -instance GSOP.Generic (MessageNotSent a) - -type RemoveFromConversationVerb = - MultiVerb - 'DELETE - '[JSON] - '[ RespondEmpty 204 "No change", - Respond 200 "Member removed" Event - ] - (Maybe Event) - -type MessageNotSentResponses a = - '[ ErrorResponse 'ConvNotFound, - ErrorResponse 'BrigError.UnknownClient, - ErrorResponse 'BrigError.MissingLegalholdConsent, - Respond 412 "Missing clients" a - ] - -type PostOtrResponses a = - MessageNotSentResponses a - .++ '[Respond 201 "Message sent" a] - -type PostOtrResponse a = Either (MessageNotSent a) a - -instance - ( rs ~ (MessageNotSentResponses a .++ '[r]), - a ~ ResponseType r - ) => - AsUnion rs (PostOtrResponse a) - where - toUnion = - eitherToUnion - (toUnion @(MessageNotSentResponses a)) - (Z . I) - - fromUnion = - eitherFromUnion - (fromUnion @(MessageNotSentResponses a)) - (unI . unZ) +import Wire.API.Routes.Public.Galley.Bot +import Wire.API.Routes.Public.Galley.Conversation +import Wire.API.Routes.Public.Galley.CustomBackend +import Wire.API.Routes.Public.Galley.Feature +import Wire.API.Routes.Public.Galley.LegalHold +import Wire.API.Routes.Public.Galley.MLS +import Wire.API.Routes.Public.Galley.Messaging +import Wire.API.Routes.Public.Galley.Team +import Wire.API.Routes.Public.Galley.TeamConversation +import Wire.API.Routes.Public.Galley.TeamMember type ServantAPI = ConversationAPI @@ -180,1719 +48,5 @@ type ServantAPI = :<|> LegalHoldAPI :<|> TeamMemberAPI -type ConversationAPI = - Named - "get-unqualified-conversation" - ( Summary "Get a conversation by ID" - :> CanThrow 'ConvNotFound - :> CanThrow 'ConvAccessDenied - :> ZLocalUser - :> "conversations" - :> Capture "cnv" ConvId - :> Get '[Servant.JSON] Conversation - ) - :<|> Named - "get-unqualified-conversation-legalhold-alias" - -- This alias exists, so that it can be uniquely selected in zauth.acl - ( Summary "Get a conversation by ID (Legalhold alias)" - :> Until 'V2 - :> CanThrow 'ConvNotFound - :> CanThrow 'ConvAccessDenied - :> ZLocalUser - :> "legalhold" - :> "conversations" - :> Capture "cnv" ConvId - :> Get '[Servant.JSON] Conversation - ) - :<|> Named - "get-conversation" - ( Summary "Get a conversation by ID" - :> CanThrow 'ConvNotFound - :> CanThrow 'ConvAccessDenied - :> ZLocalUser - :> "conversations" - :> QualifiedCapture "cnv" ConvId - :> Get '[Servant.JSON] Conversation - ) - :<|> Named - "get-conversation-roles" - ( Summary "Get existing roles available for the given conversation" - :> CanThrow 'ConvNotFound - :> CanThrow 'ConvAccessDenied - :> ZLocalUser - :> "conversations" - :> Capture "cnv" ConvId - :> "roles" - :> Get '[Servant.JSON] ConversationRolesList - ) - :<|> Named - "get-group-info" - ( Summary "Get MLS group information" - :> CanThrow 'ConvNotFound - :> CanThrow 'MLSMissingGroupInfo - :> ZLocalUser - :> "conversations" - :> QualifiedCapture "cnv" ConvId - :> "groupinfo" - :> MultiVerb1 - 'GET - '[MLS] - ( Respond - 200 - "The group information" - OpaquePublicGroupState - ) - ) - :<|> Named - "list-conversation-ids-unqualified" - ( Summary "[deprecated] Get all local conversation IDs." - -- FUTUREWORK: add bounds to swagger schema for Range - :> ZLocalUser - :> "conversations" - :> "ids" - :> QueryParam' - [ Optional, - Strict, - Description "Conversation ID to start from (exclusive)" - ] - "start" - ConvId - :> QueryParam' - [ Optional, - Strict, - Description "Maximum number of IDs to return" - ] - "size" - (Range 1 1000 Int32) - :> Get '[Servant.JSON] (ConversationList ConvId) - ) - :<|> Named - "list-conversation-ids" - ( Summary "Get all conversation IDs." - :> Description PaginationDocs - :> ZLocalUser - :> "conversations" - :> "list-ids" - :> ReqBody '[Servant.JSON] GetPaginatedConversationIds - :> Post '[Servant.JSON] ConvIdsPage - ) - :<|> Named - "get-conversations" - ( Summary "Get all *local* conversations." - :> Description - "Will not return remote conversations.\n\n\ - \Use `POST /conversations/list-ids` followed by \ - \`POST /conversations/list` instead." - :> ZLocalUser - :> "conversations" - :> QueryParam' - [ Optional, - Strict, - Description "Mutually exclusive with 'start' (at most 32 IDs per request)" - ] - "ids" - (Range 1 32 (CommaSeparatedList ConvId)) - :> QueryParam' - [ Optional, - Strict, - Description "Conversation ID to start from (exclusive)" - ] - "start" - ConvId - :> QueryParam' - [ Optional, - Strict, - Description "Maximum number of conversations to return" - ] - "size" - (Range 1 500 Int32) - :> Get '[Servant.JSON] (ConversationList Conversation) - ) - :<|> Named - "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 - ) - :<|> Named - "list-conversations" - ( Summary "Get conversation metadata for a list of conversation ids" - :> From 'V2 - :> ZLocalUser - :> "conversations" - :> "list" - :> ReqBody '[Servant.JSON] ListConversations - :> Post '[Servant.JSON] ConversationsResponse - ) - -- This endpoint can lead to the following events being sent: - -- - ConvCreate event to members - :<|> Named - "get-conversation-by-reusable-code" - ( Summary "Get limited conversation information by key/code pair" - :> CanThrow 'CodeNotFound - :> CanThrow 'ConvNotFound - :> CanThrow 'ConvAccessDenied - :> CanThrow 'GuestLinksDisabled - :> CanThrow 'NotATeamMember - :> ZLocalUser - :> "conversations" - :> "join" - :> QueryParam' [Required, Strict] "key" Code.Key - :> QueryParam' [Required, Strict] "code" Code.Value - :> Get '[Servant.JSON] ConversationCoverView - ) - :<|> Named - "create-group-conversation" - ( Summary "Create a new conversation" - :> 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" - :> ReqBody '[Servant.JSON] NewConv - :> ConversationVerb - ) - :<|> Named - "create-self-conversation" - ( Summary "Create a self-conversation" - :> ZLocalUser - :> "conversations" - :> "self" - :> ConversationVerb - ) - :<|> Named - "create-mls-self-conversation" - ( Summary "Create the user's MLS self-conversation" - :> ZLocalUser - :> "conversations" - :> "mls-self" - :> ZClient - :> ConversationPutVerb - ) - -- 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" - ( Summary "Create a 1:1 conversation" - :> CanThrow 'ConvAccessDenied - :> CanThrow 'InvalidOperation - :> CanThrow 'NoBindingTeamMembers - :> CanThrow 'NonBindingTeam - :> CanThrow 'NotATeamMember - :> CanThrow 'NotConnected - :> CanThrow OperationDenied - :> CanThrow 'TeamNotFound - :> CanThrow 'MissingLegalholdConsent - :> ZLocalUser - :> ZConn - :> "conversations" - :> "one2one" - :> ReqBody '[Servant.JSON] NewConv - :> ConversationVerb - ) - -- This endpoint can lead to the following events being sent: - -- - MemberJoin event to members - :<|> Named - "add-members-to-conversation-unqualified" - ( Summary "Add members to an existing conversation (deprecated)" - :> Until 'V2 - :> CanThrow ('ActionDenied 'AddConversationMember) - :> CanThrow ('ActionDenied 'LeaveConversation) - :> CanThrow 'ConvNotFound - :> CanThrow 'InvalidOperation - :> CanThrow 'TooManyMembers - :> CanThrow 'ConvAccessDenied - :> CanThrow 'NotATeamMember - :> CanThrow 'NotConnected - :> CanThrow 'MissingLegalholdConsent - :> ZLocalUser - :> ZConn - :> "conversations" - :> Capture "cnv" ConvId - :> "members" - :> ReqBody '[JSON] Invite - :> MultiVerb 'POST '[JSON] ConvUpdateResponses (UpdateResult Event) - ) - :<|> Named - "add-members-to-conversation-unqualified2" - ( Summary "Add qualified members to an existing conversation." - :> Until 'V2 - :> CanThrow ('ActionDenied 'AddConversationMember) - :> CanThrow ('ActionDenied 'LeaveConversation) - :> CanThrow 'ConvNotFound - :> CanThrow 'InvalidOperation - :> CanThrow 'TooManyMembers - :> CanThrow 'ConvAccessDenied - :> CanThrow 'NotATeamMember - :> CanThrow 'NotConnected - :> CanThrow 'MissingLegalholdConsent - :> ZLocalUser - :> ZConn - :> "conversations" - :> Capture "cnv" ConvId - :> "members" - :> "v2" - :> ReqBody '[Servant.JSON] InviteQualified - :> MultiVerb 'POST '[Servant.JSON] ConvUpdateResponses (UpdateResult Event) - ) - :<|> Named - "add-members-to-conversation" - ( Summary "Add qualified members to an existing conversation." - :> From 'V2 - :> CanThrow ('ActionDenied 'AddConversationMember) - :> CanThrow ('ActionDenied 'LeaveConversation) - :> CanThrow 'ConvNotFound - :> CanThrow 'InvalidOperation - :> CanThrow 'TooManyMembers - :> CanThrow 'ConvAccessDenied - :> CanThrow 'NotATeamMember - :> CanThrow 'NotConnected - :> CanThrow 'MissingLegalholdConsent - :> ZLocalUser - :> ZConn - :> "conversations" - :> QualifiedCapture "cnv" ConvId - :> "members" - :> ReqBody '[Servant.JSON] InviteQualified - :> MultiVerb 'POST '[Servant.JSON] ConvUpdateResponses (UpdateResult Event) - ) - -- This endpoint can lead to the following events being sent: - -- - MemberJoin event to members - :<|> Named - "join-conversation-by-id-unqualified" - ( Summary "Join a conversation by its ID (if link access enabled)" - :> CanThrow 'ConvAccessDenied - :> CanThrow 'ConvNotFound - :> CanThrow 'InvalidOperation - :> CanThrow 'NotATeamMember - :> CanThrow 'TooManyMembers - :> ZLocalUser - :> ZConn - :> "conversations" - :> Capture' '[Description "Conversation ID"] "cnv" ConvId - :> "join" - :> MultiVerb 'POST '[Servant.JSON] ConvJoinResponses (UpdateResult Event) - ) - -- This endpoint can lead to the following events being sent: - -- - MemberJoin event to members - :<|> Named - "join-conversation-by-code-unqualified" - ( Summary - "Join a conversation using a reusable code.\ - \If the guest links team feature is disabled, this will fail with 409 GuestLinksDisabled.\ - \Note that this is currently inconsistent (for backwards compatibility reasons) with `POST /conversations/code-check` which responds with 404 CodeNotFound if guest links are disabled." - :> CanThrow 'CodeNotFound - :> CanThrow 'ConvAccessDenied - :> CanThrow 'ConvNotFound - :> CanThrow 'GuestLinksDisabled - :> CanThrow 'InvalidOperation - :> CanThrow 'NotATeamMember - :> CanThrow 'TooManyMembers - :> ZLocalUser - :> ZConn - :> "conversations" - :> "join" - :> ReqBody '[Servant.JSON] ConversationCode - :> MultiVerb 'POST '[Servant.JSON] ConvJoinResponses (UpdateResult Event) - ) - :<|> Named - "code-check" - ( Summary - "Check validity of a conversation code.\ - \If the guest links team feature is disabled, this will fail with 404 CodeNotFound.\ - \Note that this is currently inconsistent (for backwards compatibility reasons) with `POST /conversations/join` which responds with 409 GuestLinksDisabled if guest links are disabled." - :> CanThrow 'CodeNotFound - :> CanThrow 'ConvNotFound - :> "conversations" - :> "code-check" - :> ReqBody '[Servant.JSON] ConversationCode - :> MultiVerb - 'POST - '[JSON] - '[RespondEmpty 200 "Valid"] - () - ) - -- this endpoint can lead to the following events being sent: - -- - ConvCodeUpdate event to members, if code didn't exist before - :<|> Named - "create-conversation-code-unqualified" - ( Summary "Create or recreate a conversation code" - :> CanThrow 'ConvAccessDenied - :> CanThrow 'ConvNotFound - :> CanThrow 'GuestLinksDisabled - :> ZUser - :> ZConn - :> "conversations" - :> Capture' '[Description "Conversation ID"] "cnv" ConvId - :> "code" - :> CreateConversationCodeVerb - ) - :<|> Named - "get-conversation-guest-links-status" - ( Summary "Get the status of the guest links feature for a conversation that potentially has been created by someone from another team." - :> CanThrow 'ConvAccessDenied - :> CanThrow 'ConvNotFound - :> ZUser - :> "conversations" - :> Capture' '[Description "Conversation ID"] "cnv" ConvId - :> "features" - :> FeatureSymbol GuestLinksConfig - :> Get '[Servant.JSON] (WithStatus GuestLinksConfig) - ) - -- This endpoint can lead to the following events being sent: - -- - ConvCodeDelete event to members - :<|> Named - "remove-code-unqualified" - ( Summary "Delete conversation code" - :> CanThrow 'ConvAccessDenied - :> CanThrow 'ConvNotFound - :> ZLocalUser - :> ZConn - :> "conversations" - :> Capture' '[Description "Conversation ID"] "cnv" ConvId - :> "code" - :> MultiVerb - 'DELETE - '[JSON] - '[Respond 200 "Conversation code deleted." Event] - Event - ) - :<|> Named - "get-code" - ( Summary "Get existing conversation code" - :> CanThrow 'CodeNotFound - :> CanThrow 'ConvAccessDenied - :> CanThrow 'ConvNotFound - :> CanThrow 'GuestLinksDisabled - :> ZLocalUser - :> "conversations" - :> Capture' '[Description "Conversation ID"] "cnv" ConvId - :> "code" - :> MultiVerb - 'GET - '[JSON] - '[Respond 200 "Conversation Code" ConversationCode] - ConversationCode - ) - -- This endpoint can lead to the following events being sent: - -- - Typing event to members - :<|> Named - "member-typing-unqualified" - ( Summary "Sending typing notifications" - :> CanThrow 'ConvNotFound - :> ZLocalUser - :> ZConn - :> "conversations" - :> Capture' '[Description "Conversation ID"] "cnv" ConvId - :> "typing" - :> ReqBody '[JSON] TypingData - :> MultiVerb 'POST '[JSON] '[RespondEmpty 200 "Notification sent"] () - ) - -- This endpoint can lead to the following events being sent: - -- - MemberLeave event to members - :<|> Named - "remove-member-unqualified" - ( Summary "Remove a member from a conversation (deprecated)" - :> Until 'V2 - :> ZLocalUser - :> ZConn - :> CanThrow ('ActionDenied 'RemoveConversationMember) - :> CanThrow 'ConvNotFound - :> CanThrow 'InvalidOperation - :> "conversations" - :> Capture' '[Description "Conversation ID"] "cnv" ConvId - :> "members" - :> Capture' '[Description "Target User ID"] "usr" UserId - :> RemoveFromConversationVerb - ) - -- This endpoint can lead to the following events being sent: - -- - MemberLeave event to members - :<|> Named - "remove-member" - ( Summary "Remove a member from a conversation" - :> ZLocalUser - :> ZConn - :> CanThrow ('ActionDenied 'RemoveConversationMember) - :> CanThrow 'ConvNotFound - :> CanThrow 'InvalidOperation - :> "conversations" - :> QualifiedCapture' '[Description "Conversation ID"] "cnv" ConvId - :> "members" - :> QualifiedCapture' '[Description "Target User ID"] "usr" UserId - :> RemoveFromConversationVerb - ) - -- This endpoint can lead to the following events being sent: - -- - MemberStateUpdate event to members - :<|> Named - "update-other-member-unqualified" - ( Summary "Update membership of the specified user (deprecated)" - :> Description "Use `PUT /conversations/:cnv_domain/:cnv/members/:usr_domain/:usr` instead" - :> ZLocalUser - :> ZConn - :> CanThrow 'ConvNotFound - :> CanThrow 'ConvMemberNotFound - :> CanThrow ('ActionDenied 'ModifyOtherConversationMember) - :> CanThrow 'InvalidTarget - :> CanThrow 'InvalidOperation - :> "conversations" - :> Capture' '[Description "Conversation ID"] "cnv" ConvId - :> "members" - :> Capture' '[Description "Target User ID"] "usr" UserId - :> ReqBody '[JSON] OtherMemberUpdate - :> MultiVerb - 'PUT - '[JSON] - '[RespondEmpty 200 "Membership updated"] - () - ) - :<|> Named - "update-other-member" - ( Summary "Update membership of the specified user" - :> Description "**Note**: at least one field has to be provided." - :> ZLocalUser - :> ZConn - :> CanThrow 'ConvNotFound - :> CanThrow 'ConvMemberNotFound - :> CanThrow ('ActionDenied 'ModifyOtherConversationMember) - :> CanThrow 'InvalidTarget - :> CanThrow 'InvalidOperation - :> "conversations" - :> QualifiedCapture' '[Description "Conversation ID"] "cnv" ConvId - :> "members" - :> QualifiedCapture' '[Description "Target User ID"] "usr" UserId - :> ReqBody '[JSON] OtherMemberUpdate - :> MultiVerb - 'PUT - '[JSON] - '[RespondEmpty 200 "Membership updated"] - () - ) - -- This endpoint can lead to the following events being sent: - -- - ConvRename event to members - :<|> Named - "update-conversation-name-deprecated" - ( Summary "Update conversation name (deprecated)" - :> Description "Use `/conversations/:domain/:conv/name` instead." - :> CanThrow ('ActionDenied 'ModifyConversationName) - :> CanThrow 'ConvNotFound - :> CanThrow 'InvalidOperation - :> ZLocalUser - :> ZConn - :> "conversations" - :> Capture' '[Description "Conversation ID"] "cnv" ConvId - :> ReqBody '[JSON] ConversationRename - :> MultiVerb - 'PUT - '[JSON] - (UpdateResponses "Name unchanged" "Name updated" Event) - (UpdateResult Event) - ) - :<|> Named - "update-conversation-name-unqualified" - ( Summary "Update conversation name (deprecated)" - :> Description "Use `/conversations/:domain/:conv/name` instead." - :> CanThrow ('ActionDenied 'ModifyConversationName) - :> CanThrow 'ConvNotFound - :> CanThrow 'InvalidOperation - :> ZLocalUser - :> ZConn - :> "conversations" - :> Capture' '[Description "Conversation ID"] "cnv" ConvId - :> "name" - :> ReqBody '[JSON] ConversationRename - :> MultiVerb - 'PUT - '[JSON] - (UpdateResponses "Name unchanged" "Name updated" Event) - (UpdateResult Event) - ) - :<|> Named - "update-conversation-name" - ( Summary "Update conversation name" - :> CanThrow ('ActionDenied 'ModifyConversationName) - :> CanThrow 'ConvNotFound - :> CanThrow 'InvalidOperation - :> ZLocalUser - :> ZConn - :> "conversations" - :> QualifiedCapture' '[Description "Conversation ID"] "cnv" ConvId - :> "name" - :> ReqBody '[JSON] ConversationRename - :> MultiVerb - 'PUT - '[JSON] - (UpdateResponses "Name updated" "Name unchanged" Event) - (UpdateResult Event) - ) - -- This endpoint can lead to the following events being sent: - -- - ConvMessageTimerUpdate event to members - :<|> Named - "update-conversation-message-timer-unqualified" - ( Summary "Update the message timer for a conversation (deprecated)" - :> Description "Use `/conversations/:domain/:cnv/message-timer` instead." - :> ZLocalUser - :> ZConn - :> CanThrow ('ActionDenied 'ModifyConversationMessageTimer) - :> CanThrow 'ConvAccessDenied - :> CanThrow 'ConvNotFound - :> CanThrow 'InvalidOperation - :> "conversations" - :> Capture' '[Description "Conversation ID"] "cnv" ConvId - :> "message-timer" - :> ReqBody '[JSON] ConversationMessageTimerUpdate - :> MultiVerb - 'PUT - '[JSON] - (UpdateResponses "Message timer unchanged" "Message timer updated" Event) - (UpdateResult Event) - ) - :<|> Named - "update-conversation-message-timer" - ( Summary "Update the message timer for a conversation" - :> ZLocalUser - :> ZConn - :> CanThrow ('ActionDenied 'ModifyConversationMessageTimer) - :> CanThrow 'ConvAccessDenied - :> CanThrow 'ConvNotFound - :> CanThrow 'InvalidOperation - :> "conversations" - :> QualifiedCapture' '[Description "Conversation ID"] "cnv" ConvId - :> "message-timer" - :> ReqBody '[JSON] ConversationMessageTimerUpdate - :> MultiVerb - 'PUT - '[JSON] - (UpdateResponses "Message timer unchanged" "Message timer updated" Event) - (UpdateResult Event) - ) - -- This endpoint can lead to the following events being sent: - -- - ConvReceiptModeUpdate event to members - :<|> Named - "update-conversation-receipt-mode-unqualified" - ( Summary "Update receipt mode for a conversation (deprecated)" - :> Description "Use `PUT /conversations/:domain/:cnv/receipt-mode` instead." - :> ZLocalUser - :> ZConn - :> CanThrow ('ActionDenied 'ModifyConversationReceiptMode) - :> CanThrow 'ConvAccessDenied - :> CanThrow 'ConvNotFound - :> CanThrow 'InvalidOperation - :> "conversations" - :> Capture' '[Description "Conversation ID"] "cnv" ConvId - :> "receipt-mode" - :> ReqBody '[JSON] ConversationReceiptModeUpdate - :> MultiVerb - 'PUT - '[JSON] - (UpdateResponses "Receipt mode unchanged" "Receipt mode updated" Event) - (UpdateResult Event) - ) - :<|> Named - "update-conversation-receipt-mode" - ( Summary "Update receipt mode for a conversation" - :> ZLocalUser - :> ZConn - :> CanThrow ('ActionDenied 'ModifyConversationReceiptMode) - :> CanThrow 'ConvAccessDenied - :> CanThrow 'ConvNotFound - :> CanThrow 'InvalidOperation - :> "conversations" - :> QualifiedCapture' '[Description "Conversation ID"] "cnv" ConvId - :> "receipt-mode" - :> ReqBody '[JSON] ConversationReceiptModeUpdate - :> MultiVerb - 'PUT - '[JSON] - (UpdateResponses "Receipt mode unchanged" "Receipt mode updated" Event) - (UpdateResult Event) - ) - -- This endpoint can lead to the following events being sent: - -- - MemberLeave event to members, if members get removed - -- - ConvAccessUpdate event to members - :<|> Named - "update-conversation-access-unqualified" - ( Summary "Update access modes for a conversation (deprecated)" - :> Description "Use PUT `/conversations/:domain/:cnv/access` instead." - :> ZLocalUser - :> ZConn - :> CanThrow ('ActionDenied 'ModifyConversationAccess) - :> CanThrow ('ActionDenied 'RemoveConversationMember) - :> CanThrow 'ConvAccessDenied - :> CanThrow 'ConvNotFound - :> CanThrow 'InvalidOperation - :> CanThrow 'InvalidTargetAccess - :> "conversations" - :> Capture' '[Description "Conversation ID"] "cnv" ConvId - :> "access" - :> ReqBody '[JSON] ConversationAccessData - :> MultiVerb - 'PUT - '[JSON] - (UpdateResponses "Access unchanged" "Access updated" Event) - (UpdateResult Event) - ) - :<|> Named - "update-conversation-access" - ( Summary "Update access modes for a conversation" - :> ZLocalUser - :> ZConn - :> CanThrow ('ActionDenied 'ModifyConversationAccess) - :> CanThrow ('ActionDenied 'RemoveConversationMember) - :> CanThrow 'ConvAccessDenied - :> CanThrow 'ConvNotFound - :> CanThrow 'InvalidOperation - :> CanThrow 'InvalidTargetAccess - :> "conversations" - :> QualifiedCapture' '[Description "Conversation ID"] "cnv" ConvId - :> "access" - :> ReqBody '[JSON] ConversationAccessData - :> MultiVerb - 'PUT - '[JSON] - (UpdateResponses "Access unchanged" "Access updated" Event) - (UpdateResult Event) - ) - :<|> Named - "get-conversation-self-unqualified" - ( Summary "Get self membership properties (deprecated)" - :> ZLocalUser - :> "conversations" - :> Capture' '[Description "Conversation ID"] "cnv" ConvId - :> "self" - :> Get '[JSON] (Maybe Member) - ) - :<|> Named - "update-conversation-self-unqualified" - ( Summary "Update self membership properties (deprecated)" - :> Description "Use `/conversations/:domain/:conv/self` instead." - :> CanThrow 'ConvNotFound - :> ZLocalUser - :> ZConn - :> "conversations" - :> Capture' '[Description "Conversation ID"] "cnv" ConvId - :> "self" - :> ReqBody '[JSON] MemberUpdate - :> MultiVerb - 'PUT - '[JSON] - '[RespondEmpty 200 "Update successful"] - () - ) - :<|> Named - "update-conversation-self" - ( Summary "Update self membership properties" - :> Description "**Note**: at least one field has to be provided." - :> CanThrow 'ConvNotFound - :> ZLocalUser - :> ZConn - :> "conversations" - :> QualifiedCapture' '[Description "Conversation ID"] "cnv" ConvId - :> "self" - :> ReqBody '[JSON] MemberUpdate - :> MultiVerb - 'PUT - '[JSON] - '[RespondEmpty 200 "Update successful"] - () - ) - -type TeamConversationAPI = - Named - "get-team-conversation-roles" - ( Summary "Get existing roles available for the given team" - :> CanThrow 'NotATeamMember - :> ZUser - :> "teams" - :> Capture "tid" TeamId - :> "conversations" - :> "roles" - :> Get '[Servant.JSON] ConversationRolesList - ) - :<|> Named - "get-team-conversations" - ( Summary "Get team conversations" - :> CanThrow OperationDenied - :> CanThrow 'NotATeamMember - :> ZUser - :> "teams" - :> Capture "tid" TeamId - :> "conversations" - :> Get '[Servant.JSON] TeamConversationList - ) - :<|> Named - "get-team-conversation" - ( Summary "Get one team conversation" - :> CanThrow 'ConvNotFound - :> CanThrow OperationDenied - :> CanThrow 'NotATeamMember - :> ZUser - :> "teams" - :> Capture "tid" TeamId - :> "conversations" - :> Capture "cid" ConvId - :> Get '[Servant.JSON] TeamConversation - ) - :<|> Named - "delete-team-conversation" - ( Summary "Remove a team conversation" - :> CanThrow ('ActionDenied 'DeleteConversation) - :> CanThrow 'ConvNotFound - :> CanThrow 'InvalidOperation - :> CanThrow 'NotATeamMember - :> ZLocalUser - :> ZConn - :> "teams" - :> Capture "tid" TeamId - :> "conversations" - :> Capture "cid" ConvId - :> MultiVerb 'DELETE '[JSON] '[RespondEmpty 200 "Conversation deleted"] () - ) - -type TeamAPI = - Named - "create-non-binding-team" - ( Summary "Create a new non binding team" - -- FUTUREWORK: deprecated in https://github.com/wireapp/wire-server/pull/2607 - :> ZUser - :> ZConn - :> CanThrow 'NotConnected - :> CanThrow 'UserBindingExists - :> "teams" - :> ReqBody '[Servant.JSON] NonBindingNewTeam - :> MultiVerb - 'POST - '[JSON] - '[ WithHeaders - '[DescHeader "Location" "Team ID" TeamId] - TeamId - (RespondEmpty 201 "Team ID as `Location` header value") - ] - TeamId - ) - :<|> Named - "update-team" - ( Summary "Update team properties" - :> ZUser - :> ZConn - :> CanThrow 'NotATeamMember - :> CanThrow ('MissingPermission ('Just 'SetTeamData)) - :> "teams" - :> Capture "tid" TeamId - :> ReqBody '[JSON] TeamUpdateData - :> MultiVerb - 'PUT - '[JSON] - '[RespondEmpty 200 "Team updated"] - () - ) - :<|> Named - "get-teams" - ( Summary "Get teams (deprecated); use `GET /teams/:tid`" - -- FUTUREWORK: deprecated in https://github.com/wireapp/wire-server/pull/2607 - :> ZUser - :> "teams" - :> Get '[JSON] TeamList - ) - :<|> Named - "get-team" - ( Summary "Get a team by ID" - :> ZUser - :> CanThrow 'TeamNotFound - :> "teams" - :> Capture "tid" TeamId - :> Get '[JSON] Team - ) - :<|> Named - "delete-team" - ( Summary "Delete a team" - :> ZUser - :> ZConn - :> CanThrow 'TeamNotFound - :> CanThrow ('MissingPermission ('Just 'DeleteTeam)) - :> CanThrow 'NotATeamMember - :> CanThrow OperationDenied - :> CanThrow 'DeleteQueueFull - :> CanThrow AuthenticationError - :> "teams" - :> Capture "tid" TeamId - :> ReqBody '[Servant.JSON] TeamDeleteData - :> MultiVerb 'DELETE '[JSON] '[RespondEmpty 202 "Team is scheduled for removal"] () - ) - -type MessagingAPI = - Named - "post-otr-message-unqualified" - ( Summary "Post an encrypted message to a conversation (accepts JSON or Protobuf)" - :> Description PostOtrDescriptionUnqualified - :> ZLocalUser - :> ZConn - :> "conversations" - :> Capture "cnv" ConvId - :> "otr" - :> "messages" - :> QueryParam "ignore_missing" IgnoreMissing - :> QueryParam "report_missing" ReportMissing - :> ReqBody '[JSON, Proto] NewOtrMessage - :> MultiVerb - 'POST - '[Servant.JSON] - (PostOtrResponses ClientMismatch) - (PostOtrResponse ClientMismatch) - ) - :<|> Named - "post-otr-broadcast-unqualified" - ( Summary "Broadcast an encrypted message to all team members and all contacts (accepts JSON or Protobuf)" - :> Description PostOtrDescriptionUnqualified - :> ZLocalUser - :> ZConn - :> CanThrow 'TeamNotFound - :> CanThrow 'BroadcastLimitExceeded - :> CanThrow 'NonBindingTeam - :> "broadcast" - :> "otr" - :> "messages" - :> QueryParam "ignore_missing" IgnoreMissing - :> QueryParam "report_missing" ReportMissing - :> ReqBody '[JSON, Proto] NewOtrMessage - :> MultiVerb - 'POST - '[JSON] - (PostOtrResponses ClientMismatch) - (PostOtrResponse ClientMismatch) - ) - :<|> Named - "post-proteus-message" - ( Summary "Post an encrypted message to a conversation (accepts only Protobuf)" - :> Description PostOtrDescription - :> ZLocalUser - :> ZConn - :> "conversations" - :> QualifiedCapture "cnv" ConvId - :> "proteus" - :> "messages" - :> ReqBody '[Proto] (RawProto QualifiedNewOtrMessage) - :> MultiVerb - 'POST - '[Servant.JSON] - (PostOtrResponses MessageSendingStatus) - (Either (MessageNotSent MessageSendingStatus) MessageSendingStatus) - ) - :<|> Named - "post-proteus-broadcast" - ( Summary "Post an encrypted message to all team members and all contacts (accepts only Protobuf)" - :> Description PostOtrDescription - :> ZLocalUser - :> ZConn - :> CanThrow 'TeamNotFound - :> CanThrow 'BroadcastLimitExceeded - :> CanThrow 'NonBindingTeam - :> "broadcast" - :> "proteus" - :> "messages" - :> ReqBody '[Proto] QualifiedNewOtrMessage - :> MultiVerb - 'POST - '[JSON] - (PostOtrResponses MessageSendingStatus) - (Either (MessageNotSent MessageSendingStatus) MessageSendingStatus) - ) - -type BotAPI = - Named - "post-bot-message-unqualified" - ( ZBot - :> ZConversation - :> CanThrow 'ConvNotFound - :> "bot" - :> "messages" - :> QueryParam "ignore_missing" IgnoreMissing - :> QueryParam "report_missing" ReportMissing - :> ReqBody '[JSON] NewOtrMessage - :> MultiVerb - 'POST - '[Servant.JSON] - (PostOtrResponses ClientMismatch) - (PostOtrResponse ClientMismatch) - ) - -type FeatureAPI = - FeatureStatusGet SSOConfig - :<|> FeatureStatusGet LegalholdConfig - :<|> FeatureStatusPut - '( 'ActionDenied 'RemoveConversationMember, - '( AuthenticationError, - '( 'CannotEnableLegalHoldServiceLargeTeam, - '( 'LegalHoldNotEnabled, - '( 'LegalHoldDisableUnimplemented, - '( 'LegalHoldServiceNotRegistered, - '( 'UserLegalHoldIllegalOperation, - '( 'LegalHoldCouldNotBlockConnections, '()) - ) - ) - ) - ) - ) - ) - ) - LegalholdConfig - :<|> FeatureStatusGet SearchVisibilityAvailableConfig - :<|> FeatureStatusPut '() SearchVisibilityAvailableConfig - :<|> FeatureStatusDeprecatedGet "This endpoint is potentially used by the old Android client. It is not used by iOS, team management, or webapp as of June 2022" SearchVisibilityAvailableConfig - :<|> FeatureStatusDeprecatedPut "This endpoint is potentially used by the old Android client. It is not used by iOS, team management, or webapp as of June 2022" SearchVisibilityAvailableConfig - :<|> SearchVisibilityGet - :<|> SearchVisibilitySet - :<|> FeatureStatusGet ValidateSAMLEmailsConfig - :<|> FeatureStatusDeprecatedGet "This endpoint is potentially used by the old Android client. It is not used by iOS, team management, or webapp as of June 2022" ValidateSAMLEmailsConfig - :<|> FeatureStatusGet DigitalSignaturesConfig - :<|> FeatureStatusDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is potentially used by the old Android client. It is not used by team management, or webapp as of June 2022" DigitalSignaturesConfig - :<|> FeatureStatusGet AppLockConfig - :<|> FeatureStatusPut '() AppLockConfig - :<|> FeatureStatusGet FileSharingConfig - :<|> FeatureStatusPut '() FileSharingConfig - :<|> FeatureStatusGet ClassifiedDomainsConfig - :<|> FeatureStatusGet ConferenceCallingConfig - :<|> FeatureStatusGet SelfDeletingMessagesConfig - :<|> FeatureStatusPut '() SelfDeletingMessagesConfig - :<|> FeatureStatusGet GuestLinksConfig - :<|> FeatureStatusPut '() GuestLinksConfig - :<|> FeatureStatusGet SndFactorPasswordChallengeConfig - :<|> FeatureStatusPut '() SndFactorPasswordChallengeConfig - :<|> FeatureStatusGet MLSConfig - :<|> FeatureStatusPut '() MLSConfig - :<|> FeatureStatusGet ExposeInvitationURLsToTeamAdminConfig - :<|> FeatureStatusPut '() ExposeInvitationURLsToTeamAdminConfig - :<|> FeatureStatusGet SearchVisibilityInboundConfig - :<|> FeatureStatusPut '() SearchVisibilityInboundConfig - :<|> AllFeatureConfigsUserGet - :<|> AllFeatureConfigsTeamGet - :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is not used by team management, or webapp, and is potentially used by the old Android client as of June 2022" LegalholdConfig - :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is used by team management, webapp, and potentially the old Android client as of June 2022" SSOConfig - :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is not used by team management, or webapp, and is potentially used by the old Android client as of June 2022" SearchVisibilityAvailableConfig - :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is not used by team management, or webapp, and is potentially used by the old Android client as of June 2022" ValidateSAMLEmailsConfig - :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is used by team management, webapp, and potentially the old Android client as of June 2022" DigitalSignaturesConfig - :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is used by team management, webapp, and potentially the old Android client as of June 2022" AppLockConfig - :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is used by team management, webapp, and potentially the old Android client as of June 2022" FileSharingConfig - :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is not used by team management, or webapp, and is potentially used by the old Android client as of June 2022" ClassifiedDomainsConfig - :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is not used by team management, or webapp, and is potentially used by the old Android client as of June 2022" ConferenceCallingConfig - :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is not used by team management, or webapp, and is potentially used by the old Android client as of June 2022" SelfDeletingMessagesConfig - :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is used by team management, webapp, and potentially the old Android client as of June 2022" GuestLinksConfig - :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is used by team management, webapp, and potentially the old Android client as of June 2022" SndFactorPasswordChallengeConfig - :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is used by team management, webapp, and potentially the old Android client as of June 2022" MLSConfig - -type FeatureStatusGet f = - Named - '("get", f) - (ZUser :> FeatureStatusBaseGet f) - -type FeatureStatusPut errs f = - Named - '("put", f) - (ZUser :> FeatureStatusBasePutPublic errs f) - -type FeatureStatusDeprecatedGet d f = - Named - '("get-deprecated", f) - (ZUser :> FeatureStatusBaseDeprecatedGet d f) - -type FeatureStatusDeprecatedPut d f = - Named - '("put-deprecated", f) - (ZUser :> FeatureStatusBaseDeprecatedPut d f) - -type FeatureStatusBaseGet featureConfig = - Summary (AppendSymbol "Get config for " (FeatureSymbol featureConfig)) - :> CanThrow OperationDenied - :> CanThrow 'NotATeamMember - :> CanThrow 'TeamNotFound - :> "teams" - :> Capture "tid" TeamId - :> "features" - :> FeatureSymbol featureConfig - :> Get '[Servant.JSON] (WithStatus featureConfig) - -type FeatureStatusBasePutPublic errs featureConfig = - Summary (AppendSymbol "Put config for " (FeatureSymbol featureConfig)) - :> CanThrow OperationDenied - :> CanThrow 'NotATeamMember - :> CanThrow 'TeamNotFound - :> CanThrow TeamFeatureError - :> CanThrowMany errs - :> "teams" - :> Capture "tid" TeamId - :> "features" - :> FeatureSymbol featureConfig - :> ReqBody '[Servant.JSON] (WithStatusNoLock featureConfig) - :> Put '[Servant.JSON] (WithStatus featureConfig) - --- | A type for a GET endpoint for a feature with a deprecated path -type FeatureStatusBaseDeprecatedGet desc featureConfig = - ( Summary - (AppendSymbol "[deprecated] Get config for " (FeatureSymbol featureConfig)) - :> Until 'V2 - :> Description - ( "Deprecated. Please use `GET /teams/:tid/features/" - `AppendSymbol` FeatureSymbol featureConfig - `AppendSymbol` "` instead.\n" - `AppendSymbol` desc - ) - :> CanThrow 'NotATeamMember - :> CanThrow OperationDenied - :> CanThrow 'TeamNotFound - :> "teams" - :> Capture "tid" TeamId - :> "features" - :> DeprecatedFeatureName featureConfig - :> Get '[Servant.JSON] (WithStatus featureConfig) - ) - --- | A type for a PUT endpoint for a feature with a deprecated path -type FeatureStatusBaseDeprecatedPut desc featureConfig = - Summary - (AppendSymbol "[deprecated] Get config for " (FeatureSymbol featureConfig)) - :> Until 'V2 - :> Description - ( "Deprecated. Please use `PUT /teams/:tid/features/" - `AppendSymbol` FeatureSymbol featureConfig - `AppendSymbol` "` instead.\n" - `AppendSymbol` desc - ) - :> CanThrow 'NotATeamMember - :> CanThrow OperationDenied - :> CanThrow 'TeamNotFound - :> CanThrow TeamFeatureError - :> "teams" - :> Capture "tid" TeamId - :> "features" - :> DeprecatedFeatureName featureConfig - :> ReqBody '[Servant.JSON] (WithStatusNoLock featureConfig) - :> Put '[Servant.JSON] (WithStatus featureConfig) - -type FeatureConfigDeprecatedGet desc featureConfig = - Named - '("get-config", featureConfig) - ( Summary (AppendSymbol "[deprecated] Get feature config for feature " (FeatureSymbol featureConfig)) - :> Until 'V2 - :> Description ("Deprecated. Please use `GET /feature-configs` instead.\n" `AppendSymbol` desc) - :> ZUser - :> CanThrow 'NotATeamMember - :> CanThrow OperationDenied - :> CanThrow 'TeamNotFound - :> "feature-configs" - :> FeatureSymbol featureConfig - :> Get '[Servant.JSON] (WithStatus featureConfig) - ) - -type AllFeatureConfigsUserGet = - Named - "get-all-feature-configs-for-user" - ( Summary - "Gets feature configs for a user" - :> Description - "Gets feature configs for a user. If the user is a member of a team and has the required permissions, this will return the team's feature configs.\ - \If the user is not a member of a team, this will return the personal feature configs (the server defaults)." - :> ZUser - :> CanThrow 'NotATeamMember - :> CanThrow OperationDenied - :> CanThrow 'TeamNotFound - :> "feature-configs" - :> Get '[Servant.JSON] AllFeatureConfigs - ) - -type AllFeatureConfigsTeamGet = - Named - "get-all-feature-configs-for-team" - ( Summary "Gets feature configs for a team" - :> Description "Gets feature configs for a team. User must be a member of the team and have permission to view team features." - :> CanThrow 'NotATeamMember - :> CanThrow OperationDenied - :> CanThrow 'TeamNotFound - :> ZLocalUser - :> "teams" - :> Capture "tid" TeamId - :> "features" - :> Get '[JSON] AllFeatureConfigs - ) - -type SearchVisibilityGet = - Named - "get-search-visibility" - ( Summary "Shows the value for search visibility" - :> CanThrow 'NotATeamMember - :> CanThrow OperationDenied - :> ZLocalUser - :> "teams" - :> Capture "tid" TeamId - :> "search-visibility" - :> Get '[JSON] TeamSearchVisibilityView - ) - -type SearchVisibilitySet = - Named - "set-search-visibility" - ( Summary "Sets the search visibility for the whole team" - :> CanThrow 'NotATeamMember - :> CanThrow OperationDenied - :> CanThrow 'TeamSearchVisibilityNotEnabled - :> CanThrow 'TeamNotFound - :> CanThrow TeamFeatureError - :> ZLocalUser - :> "teams" - :> Capture "tid" TeamId - :> "search-visibility" - :> ReqBody '[JSON] TeamSearchVisibilityView - :> MultiVerb 'PUT '[JSON] '[RespondEmpty 204 "Search visibility set"] () - ) - -type MLSMessagingAPI = - Named - "mls-welcome-message" - ( Summary "Post an MLS welcome message" - :> CanThrow 'MLSKeyPackageRefNotFound - :> "welcome" - :> ZConn - :> ReqBody '[MLS] (RawMLS Welcome) - :> MultiVerb1 'POST '[JSON] (RespondEmpty 201 "Welcome message sent") - ) - :<|> Named - "mls-message-v1" - ( Summary "Post an MLS message" - :> Until 'V2 - :> CanThrow 'ConvAccessDenied - :> CanThrow 'ConvMemberNotFound - :> CanThrow 'ConvNotFound - :> CanThrow 'LegalHoldNotEnabled - :> CanThrow 'MLSClientMismatch - :> CanThrow 'MLSCommitMissingReferences - :> CanThrow 'MLSKeyPackageRefNotFound - :> CanThrow 'MLSProposalNotFound - :> CanThrow 'MLSProtocolErrorTag - :> CanThrow 'MLSSelfRemovalNotAllowed - :> CanThrow 'MLSStaleMessage - :> CanThrow 'MLSUnsupportedMessage - :> CanThrow 'MLSUnsupportedProposal - :> CanThrow 'MLSClientSenderUserMismatch - :> CanThrow 'MLSGroupConversationMismatch - :> CanThrow 'MissingLegalholdConsent - :> CanThrow MLSProposalFailure - :> "messages" - :> ZConn - :> ReqBody '[MLS] (RawMLS SomeMessage) - :> MultiVerb1 'POST '[JSON] (Respond 201 "Message sent" [Event]) - ) - :<|> Named - "mls-message" - ( Summary "Post an MLS message" - :> From 'V2 - :> CanThrow 'ConvAccessDenied - :> CanThrow 'ConvMemberNotFound - :> CanThrow 'ConvNotFound - :> CanThrow 'LegalHoldNotEnabled - :> CanThrow 'MLSClientMismatch - :> CanThrow 'MLSCommitMissingReferences - :> CanThrow 'MLSKeyPackageRefNotFound - :> CanThrow 'MLSProposalNotFound - :> CanThrow 'MLSProtocolErrorTag - :> CanThrow 'MLSSelfRemovalNotAllowed - :> CanThrow 'MLSStaleMessage - :> CanThrow 'MLSUnsupportedMessage - :> CanThrow 'MLSUnsupportedProposal - :> CanThrow 'MLSClientSenderUserMismatch - :> CanThrow 'MLSGroupConversationMismatch - :> CanThrow 'MissingLegalholdConsent - :> CanThrow MLSProposalFailure - :> "messages" - :> ZConn - :> ReqBody '[MLS] (RawMLS SomeMessage) - :> MultiVerb1 'POST '[JSON] (Respond 201 "Message sent" MLSMessageSendingStatus) - ) - :<|> Named - "mls-commit-bundle" - ( Summary "Post a MLS CommitBundle" - :> From 'V3 - :> CanThrow 'ConvAccessDenied - :> CanThrow 'ConvMemberNotFound - :> CanThrow 'ConvNotFound - :> CanThrow 'LegalHoldNotEnabled - :> CanThrow 'MLSClientMismatch - :> CanThrow 'MLSCommitMissingReferences - :> CanThrow 'MLSKeyPackageRefNotFound - :> CanThrow 'MLSProposalNotFound - :> CanThrow 'MLSProtocolErrorTag - :> CanThrow 'MLSSelfRemovalNotAllowed - :> CanThrow 'MLSStaleMessage - :> CanThrow 'MLSUnsupportedMessage - :> CanThrow 'MLSUnsupportedProposal - :> CanThrow 'MLSClientSenderUserMismatch - :> CanThrow 'MLSGroupConversationMismatch - :> CanThrow 'MLSWelcomeMismatch - :> CanThrow 'MissingLegalholdConsent - :> CanThrow MLSProposalFailure - :> "commit-bundles" - :> ZConn - :> ReqBody '[CommitBundleMimeType] CommitBundle - :> MultiVerb1 'POST '[JSON] (Respond 201 "Commit accepted and forwarded" MLSMessageSendingStatus) - ) - :<|> Named - "mls-public-keys" - ( Summary "Get public keys used by the backend to sign external proposals" - :> "public-keys" - :> MultiVerb1 'GET '[JSON] (Respond 200 "Public keys" MLSPublicKeys) - ) - -type MLSAPI = LiftNamed (ZLocalUser :> "mls" :> MLSMessagingAPI) - -type CustomBackendAPI = - Named - "get-custom-backend-by-domain" - ( Summary "Shows information about custom backends related to a given email domain" - :> CanThrow 'CustomBackendNotFound - :> "custom-backend" - :> "by-domain" - :> Capture' '[Description "URL-encoded email domain"] "domain" Domain - :> Get '[JSON] CustomBackend - ) - -type LegalHoldAPI = - Named - "create-legal-hold-settings" - ( Summary "Create legal hold service settings" - :> CanThrow 'NotATeamMember - :> CanThrow OperationDenied - :> CanThrow 'LegalHoldNotEnabled - :> CanThrow 'LegalHoldServiceInvalidKey - :> CanThrow 'LegalHoldServiceBadResponse - :> ZLocalUser - :> "teams" - :> Capture "tid" TeamId - :> "legalhold" - :> "settings" - :> ReqBody '[JSON] NewLegalHoldService - :> MultiVerb1 'POST '[JSON] (Respond 201 "Legal hold service settings created" ViewLegalHoldService) - ) - :<|> Named - "get-legal-hold-settings" - ( Summary "Get legal hold service settings" - :> CanThrow 'NotATeamMember - :> CanThrow OperationDenied - :> ZLocalUser - :> "teams" - :> Capture "tid" TeamId - :> "legalhold" - :> "settings" - :> Get '[JSON] ViewLegalHoldService - ) - :<|> Named - "delete-legal-hold-settings" - ( Summary "Delete legal hold service settings" - :> CanThrow AuthenticationError - :> CanThrow OperationDenied - :> CanThrow 'NotATeamMember - :> CanThrow ('ActionDenied 'RemoveConversationMember) - :> CanThrow 'InvalidOperation - :> CanThrow 'LegalHoldNotEnabled - :> CanThrow 'LegalHoldDisableUnimplemented - :> CanThrow 'LegalHoldServiceNotRegistered - :> CanThrow 'UserLegalHoldIllegalOperation - :> CanThrow 'LegalHoldCouldNotBlockConnections - :> Description - "This endpoint can lead to the following events being sent:\n\ - \- ClientRemoved event to members with a legalhold client (via brig)\n\ - \- UserLegalHoldDisabled event to contacts of members with a legalhold client (via brig)" - :> ZLocalUser - :> "teams" - :> Capture "tid" TeamId - :> "legalhold" - :> "settings" - :> ReqBody '[JSON] RemoveLegalHoldSettingsRequest - :> MultiVerb1 'DELETE '[JSON] (RespondEmpty 204 "Legal hold service settings deleted") - ) - :<|> Named - "get-legal-hold" - ( Summary "Get legal hold status" - :> CanThrow 'TeamMemberNotFound - :> ZLocalUser - :> "teams" - :> Capture "tid" TeamId - :> "legalhold" - :> Capture "uid" UserId - :> Get '[JSON] UserLegalHoldStatusResponse - ) - :<|> Named - "consent-to-legal-hold" - ( Summary "Consent to legal hold" - :> CanThrow ('ActionDenied 'RemoveConversationMember) - :> CanThrow 'InvalidOperation - :> CanThrow 'TeamMemberNotFound - :> CanThrow 'UserLegalHoldIllegalOperation - :> CanThrow 'LegalHoldCouldNotBlockConnections - :> ZLocalUser - :> "teams" - :> Capture "tid" TeamId - :> "legalhold" - :> "consent" - :> MultiVerb 'POST '[JSON] GrantConsentResultResponseTypes GrantConsentResult - ) - :<|> Named - "request-legal-hold-device" - ( Summary "Request legal hold device" - :> CanThrow ('ActionDenied 'RemoveConversationMember) - :> CanThrow 'NotATeamMember - :> CanThrow OperationDenied - :> CanThrow 'TeamMemberNotFound - :> CanThrow 'LegalHoldNotEnabled - :> CanThrow 'UserLegalHoldAlreadyEnabled - :> CanThrow 'NoUserLegalHoldConsent - :> CanThrow 'LegalHoldServiceBadResponse - :> CanThrow 'LegalHoldServiceNotRegistered - :> CanThrow 'LegalHoldCouldNotBlockConnections - :> CanThrow 'UserLegalHoldIllegalOperation - :> Description - "This endpoint can lead to the following events being sent:\n\ - \- LegalHoldClientRequested event to contacts of the user the device is requested for, if they didn't already have a legalhold client (via brig)" - :> ZLocalUser - :> "teams" - :> Capture "tid" TeamId - :> "legalhold" - :> Capture "uid" UserId - :> MultiVerb - 'POST - '[JSON] - RequestDeviceResultResponseType - RequestDeviceResult - ) - :<|> Named - "disable-legal-hold-for-user" - ( Summary "Disable legal hold for user" - :> CanThrow AuthenticationError - :> CanThrow ('ActionDenied 'RemoveConversationMember) - :> CanThrow 'NotATeamMember - :> CanThrow OperationDenied - :> CanThrow 'LegalHoldServiceNotRegistered - :> CanThrow 'UserLegalHoldIllegalOperation - :> CanThrow 'LegalHoldCouldNotBlockConnections - :> Description - "This endpoint can lead to the following events being sent:\n\ - \- ClientRemoved event to the user owning the client (via brig)\n\ - \- UserLegalHoldDisabled event to contacts of the user owning the client (via brig)" - :> ZLocalUser - :> "teams" - :> Capture "tid" TeamId - :> "legalhold" - :> Capture "uid" UserId - :> ReqBody '[JSON] DisableLegalHoldForUserRequest - :> MultiVerb - 'DELETE - '[JSON] - DisableLegalHoldForUserResponseType - DisableLegalHoldForUserResponse - ) - :<|> Named - "approve-legal-hold-device" - ( Summary "Approve legal hold device" - :> CanThrow AuthenticationError - :> CanThrow 'AccessDenied - :> CanThrow ('ActionDenied 'RemoveConversationMember) - :> CanThrow 'NotATeamMember - :> CanThrow 'LegalHoldNotEnabled - :> CanThrow 'UserLegalHoldNotPending - :> CanThrow 'NoLegalHoldDeviceAllocated - :> CanThrow 'LegalHoldServiceNotRegistered - :> CanThrow 'UserLegalHoldAlreadyEnabled - :> CanThrow 'UserLegalHoldIllegalOperation - :> CanThrow 'LegalHoldCouldNotBlockConnections - :> Description - "This endpoint can lead to the following events being sent:\n\ - \- ClientAdded event to the user owning the client (via brig)\n\ - \- UserLegalHoldEnabled event to contacts of the user owning the client (via brig)\n\ - \- ClientRemoved event to the user, if removing old client due to max number (via brig)" - :> ZLocalUser - :> ZConn - :> "teams" - :> Capture "tid" TeamId - :> "legalhold" - :> Capture "uid" UserId - :> "approve" - :> ReqBody '[JSON] ApproveLegalHoldForUserRequest - :> MultiVerb1 'PUT '[JSON] (RespondEmpty 200 "Legal hold approved") - ) - -type RequestDeviceResultResponseType = - '[ RespondEmpty 201 "Request device successful", - RespondEmpty 204 "Request device already pending" - ] - -data RequestDeviceResult - = RequestDeviceSuccess - | RequestDeviceAlreadyPending - deriving (Generic) - deriving (AsUnion RequestDeviceResultResponseType) via GenericAsUnion RequestDeviceResultResponseType RequestDeviceResult - -instance GSOP.Generic RequestDeviceResult - -type DisableLegalHoldForUserResponseType = - '[ RespondEmpty 200 "Disable legal hold successful", - RespondEmpty 204 "Legal hold was not enabled" - ] - -data DisableLegalHoldForUserResponse - = DisableLegalHoldSuccess - | DisableLegalHoldWasNotEnabled - deriving (Generic) - deriving (AsUnion DisableLegalHoldForUserResponseType) via GenericAsUnion DisableLegalHoldForUserResponseType DisableLegalHoldForUserResponse - -instance GSOP.Generic DisableLegalHoldForUserResponse - -type GrantConsentResultResponseTypes = - '[ RespondEmpty 201 "Grant consent successful", - RespondEmpty 204 "Consent already granted" - ] - -data GrantConsentResult - = GrantConsentSuccess - | GrantConsentAlreadyGranted - deriving (Generic) - deriving (AsUnion GrantConsentResultResponseTypes) via GenericAsUnion GrantConsentResultResponseTypes GrantConsentResult - -instance GSOP.Generic GrantConsentResult - -type TeamMemberAPI = - Named - "get-team-members" - ( Summary "Get team members" - :> CanThrow 'NotATeamMember - :> ZLocalUser - :> "teams" - :> Capture "tid" TeamId - :> "members" - :> QueryParam' - [ Optional, - Strict, - Description "Maximum results to be returned" - ] - "maxResults" - (Range 1 HardTruncationLimit Int32) - :> QueryParam' - [ Optional, - Strict, - Description - "Optional, when not specified, the first page will be returned.\ - \Every returned page contains a `pagingState`, this should be supplied to retrieve the next page." - ] - "pagingState" - TeamMembersPagingState - :> Get '[JSON] TeamMembersPage - ) - :<|> Named - "get-team-member" - ( Summary "Get single team member" - :> CanThrow 'NotATeamMember - :> CanThrow 'TeamMemberNotFound - :> ZLocalUser - :> "teams" - :> Capture "tid" TeamId - :> "members" - :> Capture "uid" UserId - :> Get '[JSON] TeamMemberOptPerms - ) - :<|> Named - "get-team-members-by-ids" - ( Summary "Get team members by user id list" - :> Description "The `has_more` field in the response body is always `false`." - :> CanThrow 'NotATeamMember - :> CanThrow 'BulkGetMemberLimitExceeded - :> ZLocalUser - :> "teams" - :> Capture "tid" TeamId - :> "get-members-by-ids-using-post" - :> QueryParam' - [ Optional, - Strict, - Description "Maximum results to be returned" - ] - "maxResults" - (Range 1 HardTruncationLimit Int32) - :> ReqBody '[JSON] User.UserIdList - :> Post '[JSON] TeamMemberListOptPerms - ) - :<|> Named - "add-team-member" - ( Summary "Add a new team member" - -- FUTUREWORK: deprecated in https://github.com/wireapp/wire-server/pull/2607 - :> CanThrow 'InvalidPermissions - :> CanThrow 'NoAddToBinding - :> CanThrow 'NotATeamMember - :> CanThrow 'NotConnected - :> CanThrow OperationDenied - :> CanThrow 'TeamNotFound - :> CanThrow 'TooManyTeamMembers - :> CanThrow 'UserBindingExists - :> CanThrow 'TooManyTeamMembersOnTeamWithLegalhold - :> ZLocalUser - :> ZConn - :> "teams" - :> Capture "tid" TeamId - :> "members" - :> ReqBody '[JSON] NewTeamMember - :> MultiVerb1 - 'POST - '[JSON] - (RespondEmpty 200 "") - ) - :<|> Named - "delete-team-member" - ( Summary "Remove an existing team member" - :> CanThrow AuthenticationError - :> CanThrow 'AccessDenied - :> CanThrow 'TeamMemberNotFound - :> CanThrow 'TeamNotFound - :> CanThrow 'NotATeamMember - :> CanThrow OperationDenied - :> ZLocalUser - :> ZConn - :> "teams" - :> Capture "tid" TeamId - :> "members" - :> Capture "uid" UserId - :> ReqBody '[JSON] TeamMemberDeleteData - :> MultiVerb - 'DELETE - '[JSON] - TeamMemberDeleteResultResponseType - TeamMemberDeleteResult - ) - :<|> Named - "delete-non-binding-team-member" - ( Summary "Remove an existing team member" - -- FUTUREWORK: deprecated in https://github.com/wireapp/wire-server/pull/2607 - :> CanThrow AuthenticationError - :> CanThrow 'AccessDenied - :> CanThrow 'TeamMemberNotFound - :> CanThrow 'TeamNotFound - :> CanThrow 'NotATeamMember - :> CanThrow OperationDenied - :> ZLocalUser - :> ZConn - :> "teams" - :> Capture "tid" TeamId - :> "members" - :> Capture "uid" UserId - :> MultiVerb - 'DELETE - '[JSON] - TeamMemberDeleteResultResponseType - TeamMemberDeleteResult - ) - :<|> Named - "update-team-member" - ( Summary "Update an existing team member" - :> CanThrow 'AccessDenied - :> CanThrow 'InvalidPermissions - :> CanThrow 'TeamNotFound - :> CanThrow 'TeamMemberNotFound - :> CanThrow 'NotATeamMember - :> CanThrow OperationDenied - :> ZLocalUser - :> ZConn - :> "teams" - :> Capture "tid" TeamId - :> "members" - :> ReqBody '[JSON] NewTeamMember - :> MultiVerb1 - 'PUT - '[JSON] - (RespondEmpty 200 "") - ) - :<|> Named - "get-team-members-csv" - ( Summary "Get all members of the team as a CSV file" - :> CanThrow 'AccessDenied - :> Description - "The endpoint returns data in chunked transfer encoding.\ - \ Internal server errors might result in a failed transfer\ - \ instead of a 500 response." - :> ZLocalUser - :> "teams" - :> Capture "tid" TeamId - :> "members" - :> "csv" - :> LowLevelStream - 'GET - 200 - '[ '( "Content-Disposition", - "attachment; filename=\"wire_team_members.csv\"" - ) - ] - "CSV of team members" - CSV - ) - -type TeamMemberDeleteResultResponseType = - '[ RespondEmpty 202 "Team member scheduled for deletion", - RespondEmpty 200 "" - ] - -data TeamMemberDeleteResult - = TeamMemberDeleteAccepted - | TeamMemberDeleteCompleted - deriving (Generic) - deriving (AsUnion TeamMemberDeleteResultResponseType) via GenericAsUnion TeamMemberDeleteResultResponseType TeamMemberDeleteResult - -instance GSOP.Generic TeamMemberDeleteResult - --- This is a work-around for the fact that we sometimes want to send larger lists of user ids --- in the filter query than fits the url length limit. For details, see --- https://github.com/zinfra/backend-issues/issues/1248 -type PostOtrDescriptionUnqualified = - "This endpoint ensures that the list of clients is correct and only sends the message if the list is correct.\n\ - \To override this, the endpoint accepts two query params:\n\ - \- `ignore_missing`: Can be 'true' 'false' or a comma separated list of user IDs.\n\ - \ - When 'true' all missing clients are ignored.\n\ - \ - When 'false' all missing clients are reported.\n\ - \ - When comma separated list of user-ids, only clients for listed users are ignored.\n\ - \- `report_missing`: Can be 'true' 'false' or a comma separated list of user IDs.\n\ - \ - When 'true' all missing clients are reported.\n\ - \ - When 'false' all missing clients are ignored.\n\ - \ - When comma separated list of user-ids, only clients for listed users are reported.\n\ - \\n\ - \Apart from these, the request body also accepts `report_missing` which can only be a list of user ids and behaves the same way as the query parameter.\n\ - \\n\ - \All three of these should be considered mutually exclusive. The server however does not error if more than one is specified, it reads them in this order of precedence:\n\ - \- `report_missing` in the request body has highest precedence.\n\ - \- `ignore_missing` in the query param is the next.\n\ - \- `report_missing` in the query param has the lowest precedence.\n\ - \\n\ - \This endpoint can lead to OtrMessageAdd event being sent to the recipients.\n\ - \\n\ - \**NOTE:** The protobuf definitions of the request body can be found at https://github.com/wireapp/generic-message-proto/blob/master/proto/otr.proto." - -type PostOtrDescription = - "This endpoint ensures that the list of clients is correct and only sends the message if the list is correct.\n\ - \To override this, the endpoint accepts `client_mismatch_strategy` in the body. It can have these values:\n\ - \- `report_all`: When set, the message is not sent if any clients are missing. The missing clients are reported in the response.\n\ - \- `ignore_all`: When set, no checks about missing clients are carried out.\n\ - \- `report_only`: Takes a list of qualified UserIDs. If any clients of the listed users are missing, the message is not sent. The missing clients are reported in the response.\n\ - \- `ignore_only`: Takes a list of qualified UserIDs. If any clients of the non-listed users are missing, the message is not sent. The missing clients are reported in the response.\n\ - \\n\ - \The sending of messages in a federated conversation could theoretically fail partially. \ - \To make this case unlikely, the backend first gets a list of clients from all the involved backends and then tries to send a message. \ - \So, if any backend is down, the message is not propagated to anyone. \ - \But the actual message fan out to multiple backends could still fail partially. This type of failure is reported as a 201, \ - \the clients for which the message sending failed are part of the response body.\n\ - \\n\ - \This endpoint can lead to OtrMessageAdd event being sent to the recipients.\n\ - \\n\ - \**NOTE:** The protobuf definitions of the request body can be found at https://github.com/wireapp/generic-message-proto/blob/master/proto/otr.proto." - swaggerDoc :: Swagger.Swagger swaggerDoc = toSwagger (Proxy @ServantAPI) diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Galley/Bot.hs b/libs/wire-api/src/Wire/API/Routes/Public/Galley/Bot.hs new file mode 100644 index 0000000000..fddc356beb --- /dev/null +++ b/libs/wire-api/src/Wire/API/Routes/Public/Galley/Bot.hs @@ -0,0 +1,46 @@ +-- 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.Public.Galley.Bot where + +import Servant hiding (WithStatus) +import Servant.Swagger.Internal.Orphans () +import Wire.API.Error +import Wire.API.Error.Galley +import Wire.API.Message +import Wire.API.Routes.MultiVerb +import Wire.API.Routes.Named +import Wire.API.Routes.Public +import Wire.API.Routes.Public.Galley.Messaging + +type BotAPI = + Named + "post-bot-message-unqualified" + ( ZBot + :> ZConversation + :> CanThrow 'ConvNotFound + :> "bot" + :> "messages" + :> QueryParam "ignore_missing" IgnoreMissing + :> QueryParam "report_missing" ReportMissing + :> ReqBody '[JSON] NewOtrMessage + :> MultiVerb + 'POST + '[Servant.JSON] + (PostOtrResponses ClientMismatch) + (PostOtrResponse ClientMismatch) + ) 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 new file mode 100644 index 0000000000..9cb3caaf7d --- /dev/null +++ b/libs/wire-api/src/Wire/API/Routes/Public/Galley/Conversation.hs @@ -0,0 +1,812 @@ +-- 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.Public.Galley.Conversation where + +import qualified Data.Code as Code +import Data.CommaSeparatedList +import Data.Id +import Data.Range +import Imports hiding (head) +import Servant hiding (WithStatus) +import Servant.Swagger.Internal.Orphans () +import Wire.API.Conversation +import Wire.API.Conversation.Role +import Wire.API.Error +import Wire.API.Error.Galley +import Wire.API.Event.Conversation +import Wire.API.MLS.PublicGroupState +import Wire.API.MLS.Servant +import Wire.API.Routes.MultiVerb +import Wire.API.Routes.Named +import Wire.API.Routes.Public +import Wire.API.Routes.Public.Util +import Wire.API.Routes.QualifiedCapture +import Wire.API.Routes.Version +import Wire.API.Team.Feature + +type ConversationResponse = ResponseForExistedCreated Conversation + +type ConversationHeaders = '[DescHeader "Location" "Conversation ID" ConvId] + +type ConversationVerbWithMethod (m :: StdMethod) = + MultiVerb + m + '[JSON] + '[ WithHeaders + ConversationHeaders + Conversation + (Respond 200 "Conversation existed" Conversation), + WithHeaders + ConversationHeaders + Conversation + (Respond 201 "Conversation created" Conversation) + ] + ConversationResponse + +type ConversationVerb = ConversationVerbWithMethod 'POST + +type ConversationPutVerb = ConversationVerbWithMethod 'PUT + +type CreateConversationCodeVerb = + MultiVerb + 'POST + '[JSON] + '[ Respond 200 "Conversation code already exists." ConversationCode, + Respond 201 "Conversation code created." Event + ] + AddCodeResult + +type ConvUpdateResponses = UpdateResponses "Conversation unchanged" "Conversation updated" Event + +type ConvJoinResponses = UpdateResponses "Conversation unchanged" "Conversation joined" Event + +type RemoveFromConversationVerb = + MultiVerb + 'DELETE + '[JSON] + '[ RespondEmpty 204 "No change", + Respond 200 "Member removed" Event + ] + (Maybe Event) + +type ConversationAPI = + Named + "get-unqualified-conversation" + ( Summary "Get a conversation by ID" + :> CanThrow 'ConvNotFound + :> CanThrow 'ConvAccessDenied + :> ZLocalUser + :> "conversations" + :> Capture "cnv" ConvId + :> Get '[Servant.JSON] Conversation + ) + :<|> Named + "get-unqualified-conversation-legalhold-alias" + -- This alias exists, so that it can be uniquely selected in zauth.acl + ( Summary "Get a conversation by ID (Legalhold alias)" + :> Until 'V2 + :> CanThrow 'ConvNotFound + :> CanThrow 'ConvAccessDenied + :> ZLocalUser + :> "legalhold" + :> "conversations" + :> Capture "cnv" ConvId + :> Get '[Servant.JSON] Conversation + ) + :<|> Named + "get-conversation" + ( Summary "Get a conversation by ID" + :> CanThrow 'ConvNotFound + :> CanThrow 'ConvAccessDenied + :> ZLocalUser + :> "conversations" + :> QualifiedCapture "cnv" ConvId + :> Get '[Servant.JSON] Conversation + ) + :<|> Named + "get-conversation-roles" + ( Summary "Get existing roles available for the given conversation" + :> CanThrow 'ConvNotFound + :> CanThrow 'ConvAccessDenied + :> ZLocalUser + :> "conversations" + :> Capture "cnv" ConvId + :> "roles" + :> Get '[Servant.JSON] ConversationRolesList + ) + :<|> Named + "get-group-info" + ( Summary "Get MLS group information" + :> CanThrow 'ConvNotFound + :> CanThrow 'MLSMissingGroupInfo + :> ZLocalUser + :> "conversations" + :> QualifiedCapture "cnv" ConvId + :> "groupinfo" + :> MultiVerb1 + 'GET + '[MLS] + ( Respond + 200 + "The group information" + OpaquePublicGroupState + ) + ) + :<|> Named + "list-conversation-ids-unqualified" + ( Summary "[deprecated] Get all local conversation IDs." + -- FUTUREWORK: add bounds to swagger schema for Range + :> ZLocalUser + :> "conversations" + :> "ids" + :> QueryParam' + [ Optional, + Strict, + Description "Conversation ID to start from (exclusive)" + ] + "start" + ConvId + :> QueryParam' + [ Optional, + Strict, + Description "Maximum number of IDs to return" + ] + "size" + (Range 1 1000 Int32) + :> Get '[Servant.JSON] (ConversationList ConvId) + ) + :<|> Named + "list-conversation-ids" + ( Summary "Get all conversation IDs." + :> Description PaginationDocs + :> ZLocalUser + :> "conversations" + :> "list-ids" + :> ReqBody '[Servant.JSON] GetPaginatedConversationIds + :> Post '[Servant.JSON] ConvIdsPage + ) + :<|> Named + "get-conversations" + ( Summary "Get all *local* conversations." + :> Description + "Will not return remote conversations.\n\n\ + \Use `POST /conversations/list-ids` followed by \ + \`POST /conversations/list` instead." + :> ZLocalUser + :> "conversations" + :> QueryParam' + [ Optional, + Strict, + Description "Mutually exclusive with 'start' (at most 32 IDs per request)" + ] + "ids" + (Range 1 32 (CommaSeparatedList ConvId)) + :> QueryParam' + [ Optional, + Strict, + Description "Conversation ID to start from (exclusive)" + ] + "start" + ConvId + :> QueryParam' + [ Optional, + Strict, + Description "Maximum number of conversations to return" + ] + "size" + (Range 1 500 Int32) + :> Get '[Servant.JSON] (ConversationList Conversation) + ) + :<|> Named + "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 + ) + :<|> Named + "list-conversations" + ( Summary "Get conversation metadata for a list of conversation ids" + :> From 'V2 + :> ZLocalUser + :> "conversations" + :> "list" + :> ReqBody '[Servant.JSON] ListConversations + :> Post '[Servant.JSON] ConversationsResponse + ) + -- This endpoint can lead to the following events being sent: + -- - ConvCreate event to members + :<|> Named + "get-conversation-by-reusable-code" + ( Summary "Get limited conversation information by key/code pair" + :> CanThrow 'CodeNotFound + :> CanThrow 'ConvNotFound + :> CanThrow 'ConvAccessDenied + :> CanThrow 'GuestLinksDisabled + :> CanThrow 'NotATeamMember + :> ZLocalUser + :> "conversations" + :> "join" + :> QueryParam' [Required, Strict] "key" Code.Key + :> QueryParam' [Required, Strict] "code" Code.Value + :> Get '[Servant.JSON] ConversationCoverView + ) + :<|> Named + "create-group-conversation" + ( Summary "Create a new conversation" + :> 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" + :> ReqBody '[Servant.JSON] NewConv + :> ConversationVerb + ) + :<|> Named + "create-self-conversation" + ( Summary "Create a self-conversation" + :> ZLocalUser + :> "conversations" + :> "self" + :> ConversationVerb + ) + :<|> Named + "create-mls-self-conversation" + ( Summary "Create the user's MLS self-conversation" + :> ZLocalUser + :> "conversations" + :> "mls-self" + :> ZClient + :> ConversationPutVerb + ) + -- 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" + ( Summary "Create a 1:1 conversation" + :> CanThrow 'ConvAccessDenied + :> CanThrow 'InvalidOperation + :> CanThrow 'NoBindingTeamMembers + :> CanThrow 'NonBindingTeam + :> CanThrow 'NotATeamMember + :> CanThrow 'NotConnected + :> CanThrow OperationDenied + :> CanThrow 'TeamNotFound + :> CanThrow 'MissingLegalholdConsent + :> ZLocalUser + :> ZConn + :> "conversations" + :> "one2one" + :> ReqBody '[Servant.JSON] NewConv + :> ConversationVerb + ) + -- This endpoint can lead to the following events being sent: + -- - MemberJoin event to members + :<|> Named + "add-members-to-conversation-unqualified" + ( Summary "Add members to an existing conversation (deprecated)" + :> Until 'V2 + :> CanThrow ('ActionDenied 'AddConversationMember) + :> CanThrow ('ActionDenied 'LeaveConversation) + :> CanThrow 'ConvNotFound + :> CanThrow 'InvalidOperation + :> CanThrow 'TooManyMembers + :> CanThrow 'ConvAccessDenied + :> CanThrow 'NotATeamMember + :> CanThrow 'NotConnected + :> CanThrow 'MissingLegalholdConsent + :> ZLocalUser + :> ZConn + :> "conversations" + :> Capture "cnv" ConvId + :> "members" + :> ReqBody '[JSON] Invite + :> MultiVerb 'POST '[JSON] ConvUpdateResponses (UpdateResult Event) + ) + :<|> Named + "add-members-to-conversation-unqualified2" + ( Summary "Add qualified members to an existing conversation." + :> Until 'V2 + :> CanThrow ('ActionDenied 'AddConversationMember) + :> CanThrow ('ActionDenied 'LeaveConversation) + :> CanThrow 'ConvNotFound + :> CanThrow 'InvalidOperation + :> CanThrow 'TooManyMembers + :> CanThrow 'ConvAccessDenied + :> CanThrow 'NotATeamMember + :> CanThrow 'NotConnected + :> CanThrow 'MissingLegalholdConsent + :> ZLocalUser + :> ZConn + :> "conversations" + :> Capture "cnv" ConvId + :> "members" + :> "v2" + :> ReqBody '[Servant.JSON] InviteQualified + :> MultiVerb 'POST '[Servant.JSON] ConvUpdateResponses (UpdateResult Event) + ) + :<|> Named + "add-members-to-conversation" + ( Summary "Add qualified members to an existing conversation." + :> From 'V2 + :> CanThrow ('ActionDenied 'AddConversationMember) + :> CanThrow ('ActionDenied 'LeaveConversation) + :> CanThrow 'ConvNotFound + :> CanThrow 'InvalidOperation + :> CanThrow 'TooManyMembers + :> CanThrow 'ConvAccessDenied + :> CanThrow 'NotATeamMember + :> CanThrow 'NotConnected + :> CanThrow 'MissingLegalholdConsent + :> ZLocalUser + :> ZConn + :> "conversations" + :> QualifiedCapture "cnv" ConvId + :> "members" + :> ReqBody '[Servant.JSON] InviteQualified + :> MultiVerb 'POST '[Servant.JSON] ConvUpdateResponses (UpdateResult Event) + ) + -- This endpoint can lead to the following events being sent: + -- - MemberJoin event to members + :<|> Named + "join-conversation-by-id-unqualified" + ( Summary "Join a conversation by its ID (if link access enabled)" + :> CanThrow 'ConvAccessDenied + :> CanThrow 'ConvNotFound + :> CanThrow 'InvalidOperation + :> CanThrow 'NotATeamMember + :> CanThrow 'TooManyMembers + :> ZLocalUser + :> ZConn + :> "conversations" + :> Capture' '[Description "Conversation ID"] "cnv" ConvId + :> "join" + :> MultiVerb 'POST '[Servant.JSON] ConvJoinResponses (UpdateResult Event) + ) + -- This endpoint can lead to the following events being sent: + -- - MemberJoin event to members + :<|> Named + "join-conversation-by-code-unqualified" + ( Summary + "Join a conversation using a reusable code.\ + \If the guest links team feature is disabled, this will fail with 409 GuestLinksDisabled.\ + \Note that this is currently inconsistent (for backwards compatibility reasons) with `POST /conversations/code-check` which responds with 404 CodeNotFound if guest links are disabled." + :> CanThrow 'CodeNotFound + :> CanThrow 'ConvAccessDenied + :> CanThrow 'ConvNotFound + :> CanThrow 'GuestLinksDisabled + :> CanThrow 'InvalidOperation + :> CanThrow 'NotATeamMember + :> CanThrow 'TooManyMembers + :> ZLocalUser + :> ZConn + :> "conversations" + :> "join" + :> ReqBody '[Servant.JSON] ConversationCode + :> MultiVerb 'POST '[Servant.JSON] ConvJoinResponses (UpdateResult Event) + ) + :<|> Named + "code-check" + ( Summary + "Check validity of a conversation code.\ + \If the guest links team feature is disabled, this will fail with 404 CodeNotFound.\ + \Note that this is currently inconsistent (for backwards compatibility reasons) with `POST /conversations/join` which responds with 409 GuestLinksDisabled if guest links are disabled." + :> CanThrow 'CodeNotFound + :> CanThrow 'ConvNotFound + :> "conversations" + :> "code-check" + :> ReqBody '[Servant.JSON] ConversationCode + :> MultiVerb + 'POST + '[JSON] + '[RespondEmpty 200 "Valid"] + () + ) + -- this endpoint can lead to the following events being sent: + -- - ConvCodeUpdate event to members, if code didn't exist before + :<|> Named + "create-conversation-code-unqualified" + ( Summary "Create or recreate a conversation code" + :> CanThrow 'ConvAccessDenied + :> CanThrow 'ConvNotFound + :> CanThrow 'GuestLinksDisabled + :> ZUser + :> ZConn + :> "conversations" + :> Capture' '[Description "Conversation ID"] "cnv" ConvId + :> "code" + :> CreateConversationCodeVerb + ) + :<|> Named + "get-conversation-guest-links-status" + ( Summary "Get the status of the guest links feature for a conversation that potentially has been created by someone from another team." + :> CanThrow 'ConvAccessDenied + :> CanThrow 'ConvNotFound + :> ZUser + :> "conversations" + :> Capture' '[Description "Conversation ID"] "cnv" ConvId + :> "features" + :> FeatureSymbol GuestLinksConfig + :> Get '[Servant.JSON] (WithStatus GuestLinksConfig) + ) + -- This endpoint can lead to the following events being sent: + -- - ConvCodeDelete event to members + :<|> Named + "remove-code-unqualified" + ( Summary "Delete conversation code" + :> CanThrow 'ConvAccessDenied + :> CanThrow 'ConvNotFound + :> ZLocalUser + :> ZConn + :> "conversations" + :> Capture' '[Description "Conversation ID"] "cnv" ConvId + :> "code" + :> MultiVerb + 'DELETE + '[JSON] + '[Respond 200 "Conversation code deleted." Event] + Event + ) + :<|> Named + "get-code" + ( Summary "Get existing conversation code" + :> CanThrow 'CodeNotFound + :> CanThrow 'ConvAccessDenied + :> CanThrow 'ConvNotFound + :> CanThrow 'GuestLinksDisabled + :> ZLocalUser + :> "conversations" + :> Capture' '[Description "Conversation ID"] "cnv" ConvId + :> "code" + :> MultiVerb + 'GET + '[JSON] + '[Respond 200 "Conversation Code" ConversationCode] + ConversationCode + ) + -- This endpoint can lead to the following events being sent: + -- - Typing event to members + :<|> Named + "member-typing-unqualified" + ( Summary "Sending typing notifications" + :> CanThrow 'ConvNotFound + :> ZLocalUser + :> ZConn + :> "conversations" + :> Capture' '[Description "Conversation ID"] "cnv" ConvId + :> "typing" + :> ReqBody '[JSON] TypingData + :> MultiVerb 'POST '[JSON] '[RespondEmpty 200 "Notification sent"] () + ) + -- This endpoint can lead to the following events being sent: + -- - MemberLeave event to members + :<|> Named + "remove-member-unqualified" + ( Summary "Remove a member from a conversation (deprecated)" + :> Until 'V2 + :> ZLocalUser + :> ZConn + :> CanThrow ('ActionDenied 'RemoveConversationMember) + :> CanThrow 'ConvNotFound + :> CanThrow 'InvalidOperation + :> "conversations" + :> Capture' '[Description "Conversation ID"] "cnv" ConvId + :> "members" + :> Capture' '[Description "Target User ID"] "usr" UserId + :> RemoveFromConversationVerb + ) + -- This endpoint can lead to the following events being sent: + -- - MemberLeave event to members + :<|> Named + "remove-member" + ( Summary "Remove a member from a conversation" + :> ZLocalUser + :> ZConn + :> CanThrow ('ActionDenied 'RemoveConversationMember) + :> CanThrow 'ConvNotFound + :> CanThrow 'InvalidOperation + :> "conversations" + :> QualifiedCapture' '[Description "Conversation ID"] "cnv" ConvId + :> "members" + :> QualifiedCapture' '[Description "Target User ID"] "usr" UserId + :> RemoveFromConversationVerb + ) + -- This endpoint can lead to the following events being sent: + -- - MemberStateUpdate event to members + :<|> Named + "update-other-member-unqualified" + ( Summary "Update membership of the specified user (deprecated)" + :> Description "Use `PUT /conversations/:cnv_domain/:cnv/members/:usr_domain/:usr` instead" + :> ZLocalUser + :> ZConn + :> CanThrow 'ConvNotFound + :> CanThrow 'ConvMemberNotFound + :> CanThrow ('ActionDenied 'ModifyOtherConversationMember) + :> CanThrow 'InvalidTarget + :> CanThrow 'InvalidOperation + :> "conversations" + :> Capture' '[Description "Conversation ID"] "cnv" ConvId + :> "members" + :> Capture' '[Description "Target User ID"] "usr" UserId + :> ReqBody '[JSON] OtherMemberUpdate + :> MultiVerb + 'PUT + '[JSON] + '[RespondEmpty 200 "Membership updated"] + () + ) + :<|> Named + "update-other-member" + ( Summary "Update membership of the specified user" + :> Description "**Note**: at least one field has to be provided." + :> ZLocalUser + :> ZConn + :> CanThrow 'ConvNotFound + :> CanThrow 'ConvMemberNotFound + :> CanThrow ('ActionDenied 'ModifyOtherConversationMember) + :> CanThrow 'InvalidTarget + :> CanThrow 'InvalidOperation + :> "conversations" + :> QualifiedCapture' '[Description "Conversation ID"] "cnv" ConvId + :> "members" + :> QualifiedCapture' '[Description "Target User ID"] "usr" UserId + :> ReqBody '[JSON] OtherMemberUpdate + :> MultiVerb + 'PUT + '[JSON] + '[RespondEmpty 200 "Membership updated"] + () + ) + -- This endpoint can lead to the following events being sent: + -- - ConvRename event to members + :<|> Named + "update-conversation-name-deprecated" + ( Summary "Update conversation name (deprecated)" + :> Description "Use `/conversations/:domain/:conv/name` instead." + :> CanThrow ('ActionDenied 'ModifyConversationName) + :> CanThrow 'ConvNotFound + :> CanThrow 'InvalidOperation + :> ZLocalUser + :> ZConn + :> "conversations" + :> Capture' '[Description "Conversation ID"] "cnv" ConvId + :> ReqBody '[JSON] ConversationRename + :> MultiVerb + 'PUT + '[JSON] + (UpdateResponses "Name unchanged" "Name updated" Event) + (UpdateResult Event) + ) + :<|> Named + "update-conversation-name-unqualified" + ( Summary "Update conversation name (deprecated)" + :> Description "Use `/conversations/:domain/:conv/name` instead." + :> CanThrow ('ActionDenied 'ModifyConversationName) + :> CanThrow 'ConvNotFound + :> CanThrow 'InvalidOperation + :> ZLocalUser + :> ZConn + :> "conversations" + :> Capture' '[Description "Conversation ID"] "cnv" ConvId + :> "name" + :> ReqBody '[JSON] ConversationRename + :> MultiVerb + 'PUT + '[JSON] + (UpdateResponses "Name unchanged" "Name updated" Event) + (UpdateResult Event) + ) + :<|> Named + "update-conversation-name" + ( Summary "Update conversation name" + :> CanThrow ('ActionDenied 'ModifyConversationName) + :> CanThrow 'ConvNotFound + :> CanThrow 'InvalidOperation + :> ZLocalUser + :> ZConn + :> "conversations" + :> QualifiedCapture' '[Description "Conversation ID"] "cnv" ConvId + :> "name" + :> ReqBody '[JSON] ConversationRename + :> MultiVerb + 'PUT + '[JSON] + (UpdateResponses "Name updated" "Name unchanged" Event) + (UpdateResult Event) + ) + -- This endpoint can lead to the following events being sent: + -- - ConvMessageTimerUpdate event to members + :<|> Named + "update-conversation-message-timer-unqualified" + ( Summary "Update the message timer for a conversation (deprecated)" + :> Description "Use `/conversations/:domain/:cnv/message-timer` instead." + :> ZLocalUser + :> ZConn + :> CanThrow ('ActionDenied 'ModifyConversationMessageTimer) + :> CanThrow 'ConvAccessDenied + :> CanThrow 'ConvNotFound + :> CanThrow 'InvalidOperation + :> "conversations" + :> Capture' '[Description "Conversation ID"] "cnv" ConvId + :> "message-timer" + :> ReqBody '[JSON] ConversationMessageTimerUpdate + :> MultiVerb + 'PUT + '[JSON] + (UpdateResponses "Message timer unchanged" "Message timer updated" Event) + (UpdateResult Event) + ) + :<|> Named + "update-conversation-message-timer" + ( Summary "Update the message timer for a conversation" + :> ZLocalUser + :> ZConn + :> CanThrow ('ActionDenied 'ModifyConversationMessageTimer) + :> CanThrow 'ConvAccessDenied + :> CanThrow 'ConvNotFound + :> CanThrow 'InvalidOperation + :> "conversations" + :> QualifiedCapture' '[Description "Conversation ID"] "cnv" ConvId + :> "message-timer" + :> ReqBody '[JSON] ConversationMessageTimerUpdate + :> MultiVerb + 'PUT + '[JSON] + (UpdateResponses "Message timer unchanged" "Message timer updated" Event) + (UpdateResult Event) + ) + -- This endpoint can lead to the following events being sent: + -- - ConvReceiptModeUpdate event to members + :<|> Named + "update-conversation-receipt-mode-unqualified" + ( Summary "Update receipt mode for a conversation (deprecated)" + :> Description "Use `PUT /conversations/:domain/:cnv/receipt-mode` instead." + :> ZLocalUser + :> ZConn + :> CanThrow ('ActionDenied 'ModifyConversationReceiptMode) + :> CanThrow 'ConvAccessDenied + :> CanThrow 'ConvNotFound + :> CanThrow 'InvalidOperation + :> "conversations" + :> Capture' '[Description "Conversation ID"] "cnv" ConvId + :> "receipt-mode" + :> ReqBody '[JSON] ConversationReceiptModeUpdate + :> MultiVerb + 'PUT + '[JSON] + (UpdateResponses "Receipt mode unchanged" "Receipt mode updated" Event) + (UpdateResult Event) + ) + :<|> Named + "update-conversation-receipt-mode" + ( Summary "Update receipt mode for a conversation" + :> ZLocalUser + :> ZConn + :> CanThrow ('ActionDenied 'ModifyConversationReceiptMode) + :> CanThrow 'ConvAccessDenied + :> CanThrow 'ConvNotFound + :> CanThrow 'InvalidOperation + :> "conversations" + :> QualifiedCapture' '[Description "Conversation ID"] "cnv" ConvId + :> "receipt-mode" + :> ReqBody '[JSON] ConversationReceiptModeUpdate + :> MultiVerb + 'PUT + '[JSON] + (UpdateResponses "Receipt mode unchanged" "Receipt mode updated" Event) + (UpdateResult Event) + ) + -- This endpoint can lead to the following events being sent: + -- - MemberLeave event to members, if members get removed + -- - ConvAccessUpdate event to members + :<|> Named + "update-conversation-access-unqualified" + ( Summary "Update access modes for a conversation (deprecated)" + :> Description "Use PUT `/conversations/:domain/:cnv/access` instead." + :> ZLocalUser + :> ZConn + :> CanThrow ('ActionDenied 'ModifyConversationAccess) + :> CanThrow ('ActionDenied 'RemoveConversationMember) + :> CanThrow 'ConvAccessDenied + :> CanThrow 'ConvNotFound + :> CanThrow 'InvalidOperation + :> CanThrow 'InvalidTargetAccess + :> "conversations" + :> Capture' '[Description "Conversation ID"] "cnv" ConvId + :> "access" + :> ReqBody '[JSON] ConversationAccessData + :> MultiVerb + 'PUT + '[JSON] + (UpdateResponses "Access unchanged" "Access updated" Event) + (UpdateResult Event) + ) + :<|> Named + "update-conversation-access" + ( Summary "Update access modes for a conversation" + :> ZLocalUser + :> ZConn + :> CanThrow ('ActionDenied 'ModifyConversationAccess) + :> CanThrow ('ActionDenied 'RemoveConversationMember) + :> CanThrow 'ConvAccessDenied + :> CanThrow 'ConvNotFound + :> CanThrow 'InvalidOperation + :> CanThrow 'InvalidTargetAccess + :> "conversations" + :> QualifiedCapture' '[Description "Conversation ID"] "cnv" ConvId + :> "access" + :> ReqBody '[JSON] ConversationAccessData + :> MultiVerb + 'PUT + '[JSON] + (UpdateResponses "Access unchanged" "Access updated" Event) + (UpdateResult Event) + ) + :<|> Named + "get-conversation-self-unqualified" + ( Summary "Get self membership properties (deprecated)" + :> ZLocalUser + :> "conversations" + :> Capture' '[Description "Conversation ID"] "cnv" ConvId + :> "self" + :> Get '[JSON] (Maybe Member) + ) + :<|> Named + "update-conversation-self-unqualified" + ( Summary "Update self membership properties (deprecated)" + :> Description "Use `/conversations/:domain/:conv/self` instead." + :> CanThrow 'ConvNotFound + :> ZLocalUser + :> ZConn + :> "conversations" + :> Capture' '[Description "Conversation ID"] "cnv" ConvId + :> "self" + :> ReqBody '[JSON] MemberUpdate + :> MultiVerb + 'PUT + '[JSON] + '[RespondEmpty 200 "Update successful"] + () + ) + :<|> Named + "update-conversation-self" + ( Summary "Update self membership properties" + :> Description "**Note**: at least one field has to be provided." + :> CanThrow 'ConvNotFound + :> ZLocalUser + :> ZConn + :> "conversations" + :> QualifiedCapture' '[Description "Conversation ID"] "cnv" ConvId + :> "self" + :> ReqBody '[JSON] MemberUpdate + :> MultiVerb + 'PUT + '[JSON] + '[RespondEmpty 200 "Update successful"] + () + ) diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Galley/CustomBackend.hs b/libs/wire-api/src/Wire/API/Routes/Public/Galley/CustomBackend.hs new file mode 100644 index 0000000000..079858baa0 --- /dev/null +++ b/libs/wire-api/src/Wire/API/Routes/Public/Galley/CustomBackend.hs @@ -0,0 +1,37 @@ +-- 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.Public.Galley.CustomBackend where + +import Data.Domain +import Servant hiding (WithStatus) +import Servant.Swagger.Internal.Orphans () +import Wire.API.CustomBackend +import Wire.API.Error +import Wire.API.Error.Galley +import Wire.API.Routes.Named + +type CustomBackendAPI = + Named + "get-custom-backend-by-domain" + ( Summary "Shows information about custom backends related to a given email domain" + :> CanThrow 'CustomBackendNotFound + :> "custom-backend" + :> "by-domain" + :> Capture' '[Description "URL-encoded email domain"] "domain" Domain + :> Get '[JSON] CustomBackend + ) diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Galley/Feature.hs b/libs/wire-api/src/Wire/API/Routes/Public/Galley/Feature.hs new file mode 100644 index 0000000000..f52fd7b183 --- /dev/null +++ b/libs/wire-api/src/Wire/API/Routes/Public/Galley/Feature.hs @@ -0,0 +1,260 @@ +-- 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.Public.Galley.Feature where + +import Data.Id +import GHC.TypeLits +import Servant hiding (WithStatus) +import Servant.Swagger.Internal.Orphans () +import Wire.API.Conversation.Role +import Wire.API.Error +import Wire.API.Error.Galley +import Wire.API.Routes.MultiVerb +import Wire.API.Routes.Named +import Wire.API.Routes.Public +import Wire.API.Routes.Version +import Wire.API.Team.Feature +import Wire.API.Team.SearchVisibility (TeamSearchVisibilityView) + +type FeatureAPI = + FeatureStatusGet SSOConfig + :<|> FeatureStatusGet LegalholdConfig + :<|> FeatureStatusPut + '( 'ActionDenied 'RemoveConversationMember, + '( AuthenticationError, + '( 'CannotEnableLegalHoldServiceLargeTeam, + '( 'LegalHoldNotEnabled, + '( 'LegalHoldDisableUnimplemented, + '( 'LegalHoldServiceNotRegistered, + '( 'UserLegalHoldIllegalOperation, + '( 'LegalHoldCouldNotBlockConnections, '()) + ) + ) + ) + ) + ) + ) + ) + LegalholdConfig + :<|> FeatureStatusGet SearchVisibilityAvailableConfig + :<|> FeatureStatusPut '() SearchVisibilityAvailableConfig + :<|> FeatureStatusDeprecatedGet "This endpoint is potentially used by the old Android client. It is not used by iOS, team management, or webapp as of June 2022" SearchVisibilityAvailableConfig + :<|> FeatureStatusDeprecatedPut "This endpoint is potentially used by the old Android client. It is not used by iOS, team management, or webapp as of June 2022" SearchVisibilityAvailableConfig + :<|> SearchVisibilityGet + :<|> SearchVisibilitySet + :<|> FeatureStatusGet ValidateSAMLEmailsConfig + :<|> FeatureStatusDeprecatedGet "This endpoint is potentially used by the old Android client. It is not used by iOS, team management, or webapp as of June 2022" ValidateSAMLEmailsConfig + :<|> FeatureStatusGet DigitalSignaturesConfig + :<|> FeatureStatusDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is potentially used by the old Android client. It is not used by team management, or webapp as of June 2022" DigitalSignaturesConfig + :<|> FeatureStatusGet AppLockConfig + :<|> FeatureStatusPut '() AppLockConfig + :<|> FeatureStatusGet FileSharingConfig + :<|> FeatureStatusPut '() FileSharingConfig + :<|> FeatureStatusGet ClassifiedDomainsConfig + :<|> FeatureStatusGet ConferenceCallingConfig + :<|> FeatureStatusGet SelfDeletingMessagesConfig + :<|> FeatureStatusPut '() SelfDeletingMessagesConfig + :<|> FeatureStatusGet GuestLinksConfig + :<|> FeatureStatusPut '() GuestLinksConfig + :<|> FeatureStatusGet SndFactorPasswordChallengeConfig + :<|> FeatureStatusPut '() SndFactorPasswordChallengeConfig + :<|> FeatureStatusGet MLSConfig + :<|> FeatureStatusPut '() MLSConfig + :<|> FeatureStatusGet ExposeInvitationURLsToTeamAdminConfig + :<|> FeatureStatusPut '() ExposeInvitationURLsToTeamAdminConfig + :<|> FeatureStatusGet SearchVisibilityInboundConfig + :<|> FeatureStatusPut '() SearchVisibilityInboundConfig + :<|> AllFeatureConfigsUserGet + :<|> AllFeatureConfigsTeamGet + :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is not used by team management, or webapp, and is potentially used by the old Android client as of June 2022" LegalholdConfig + :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is used by team management, webapp, and potentially the old Android client as of June 2022" SSOConfig + :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is not used by team management, or webapp, and is potentially used by the old Android client as of June 2022" SearchVisibilityAvailableConfig + :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is not used by team management, or webapp, and is potentially used by the old Android client as of June 2022" ValidateSAMLEmailsConfig + :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is used by team management, webapp, and potentially the old Android client as of June 2022" DigitalSignaturesConfig + :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is used by team management, webapp, and potentially the old Android client as of June 2022" AppLockConfig + :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is used by team management, webapp, and potentially the old Android client as of June 2022" FileSharingConfig + :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is not used by team management, or webapp, and is potentially used by the old Android client as of June 2022" ClassifiedDomainsConfig + :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is not used by team management, or webapp, and is potentially used by the old Android client as of June 2022" ConferenceCallingConfig + :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is not used by team management, or webapp, and is potentially used by the old Android client as of June 2022" SelfDeletingMessagesConfig + :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is used by team management, webapp, and potentially the old Android client as of June 2022" GuestLinksConfig + :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is used by team management, webapp, and potentially the old Android client as of June 2022" SndFactorPasswordChallengeConfig + :<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is used by team management, webapp, and potentially the old Android client as of June 2022" MLSConfig + +type FeatureStatusGet f = + Named + '("get", f) + (ZUser :> FeatureStatusBaseGet f) + +type FeatureStatusPut errs f = + Named + '("put", f) + (ZUser :> FeatureStatusBasePutPublic errs f) + +type FeatureStatusDeprecatedGet d f = + Named + '("get-deprecated", f) + (ZUser :> FeatureStatusBaseDeprecatedGet d f) + +type FeatureStatusDeprecatedPut d f = + Named + '("put-deprecated", f) + (ZUser :> FeatureStatusBaseDeprecatedPut d f) + +type FeatureStatusBaseGet featureConfig = + Summary (AppendSymbol "Get config for " (FeatureSymbol featureConfig)) + :> CanThrow OperationDenied + :> CanThrow 'NotATeamMember + :> CanThrow 'TeamNotFound + :> "teams" + :> Capture "tid" TeamId + :> "features" + :> FeatureSymbol featureConfig + :> Get '[Servant.JSON] (WithStatus featureConfig) + +type FeatureStatusBasePutPublic errs featureConfig = + Summary (AppendSymbol "Put config for " (FeatureSymbol featureConfig)) + :> CanThrow OperationDenied + :> CanThrow 'NotATeamMember + :> CanThrow 'TeamNotFound + :> CanThrow TeamFeatureError + :> CanThrowMany errs + :> "teams" + :> Capture "tid" TeamId + :> "features" + :> FeatureSymbol featureConfig + :> ReqBody '[Servant.JSON] (WithStatusNoLock featureConfig) + :> Put '[Servant.JSON] (WithStatus featureConfig) + +-- | A type for a GET endpoint for a feature with a deprecated path +type FeatureStatusBaseDeprecatedGet desc featureConfig = + ( Summary + (AppendSymbol "[deprecated] Get config for " (FeatureSymbol featureConfig)) + :> Until 'V2 + :> Description + ( "Deprecated. Please use `GET /teams/:tid/features/" + `AppendSymbol` FeatureSymbol featureConfig + `AppendSymbol` "` instead.\n" + `AppendSymbol` desc + ) + :> CanThrow 'NotATeamMember + :> CanThrow OperationDenied + :> CanThrow 'TeamNotFound + :> "teams" + :> Capture "tid" TeamId + :> "features" + :> DeprecatedFeatureName featureConfig + :> Get '[Servant.JSON] (WithStatus featureConfig) + ) + +-- | A type for a PUT endpoint for a feature with a deprecated path +type FeatureStatusBaseDeprecatedPut desc featureConfig = + Summary + (AppendSymbol "[deprecated] Get config for " (FeatureSymbol featureConfig)) + :> Until 'V2 + :> Description + ( "Deprecated. Please use `PUT /teams/:tid/features/" + `AppendSymbol` FeatureSymbol featureConfig + `AppendSymbol` "` instead.\n" + `AppendSymbol` desc + ) + :> CanThrow 'NotATeamMember + :> CanThrow OperationDenied + :> CanThrow 'TeamNotFound + :> CanThrow TeamFeatureError + :> "teams" + :> Capture "tid" TeamId + :> "features" + :> DeprecatedFeatureName featureConfig + :> ReqBody '[Servant.JSON] (WithStatusNoLock featureConfig) + :> Put '[Servant.JSON] (WithStatus featureConfig) + +type FeatureConfigDeprecatedGet desc featureConfig = + Named + '("get-config", featureConfig) + ( Summary (AppendSymbol "[deprecated] Get feature config for feature " (FeatureSymbol featureConfig)) + :> Until 'V2 + :> Description ("Deprecated. Please use `GET /feature-configs` instead.\n" `AppendSymbol` desc) + :> ZUser + :> CanThrow 'NotATeamMember + :> CanThrow OperationDenied + :> CanThrow 'TeamNotFound + :> "feature-configs" + :> FeatureSymbol featureConfig + :> Get '[Servant.JSON] (WithStatus featureConfig) + ) + +type AllFeatureConfigsUserGet = + Named + "get-all-feature-configs-for-user" + ( Summary + "Gets feature configs for a user" + :> Description + "Gets feature configs for a user. If the user is a member of a team and has the required permissions, this will return the team's feature configs.\ + \If the user is not a member of a team, this will return the personal feature configs (the server defaults)." + :> ZUser + :> CanThrow 'NotATeamMember + :> CanThrow OperationDenied + :> CanThrow 'TeamNotFound + :> "feature-configs" + :> Get '[Servant.JSON] AllFeatureConfigs + ) + +type AllFeatureConfigsTeamGet = + Named + "get-all-feature-configs-for-team" + ( Summary "Gets feature configs for a team" + :> Description "Gets feature configs for a team. User must be a member of the team and have permission to view team features." + :> CanThrow 'NotATeamMember + :> CanThrow OperationDenied + :> CanThrow 'TeamNotFound + :> ZLocalUser + :> "teams" + :> Capture "tid" TeamId + :> "features" + :> Get '[JSON] AllFeatureConfigs + ) + +type SearchVisibilityGet = + Named + "get-search-visibility" + ( Summary "Shows the value for search visibility" + :> CanThrow 'NotATeamMember + :> CanThrow OperationDenied + :> ZLocalUser + :> "teams" + :> Capture "tid" TeamId + :> "search-visibility" + :> Get '[JSON] TeamSearchVisibilityView + ) + +type SearchVisibilitySet = + Named + "set-search-visibility" + ( Summary "Sets the search visibility for the whole team" + :> CanThrow 'NotATeamMember + :> CanThrow OperationDenied + :> CanThrow 'TeamSearchVisibilityNotEnabled + :> CanThrow 'TeamNotFound + :> CanThrow TeamFeatureError + :> ZLocalUser + :> "teams" + :> Capture "tid" TeamId + :> "search-visibility" + :> ReqBody '[JSON] TeamSearchVisibilityView + :> MultiVerb 'PUT '[JSON] '[RespondEmpty 204 "Search visibility set"] () + ) diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Galley/LegalHold.hs b/libs/wire-api/src/Wire/API/Routes/Public/Galley/LegalHold.hs new file mode 100644 index 0000000000..0c1ae5b2f1 --- /dev/null +++ b/libs/wire-api/src/Wire/API/Routes/Public/Galley/LegalHold.hs @@ -0,0 +1,234 @@ +-- 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.Public.Galley.LegalHold where + +import Data.Id +import GHC.Generics +import qualified Generics.SOP as GSOP +import Servant hiding (WithStatus) +import Servant.Swagger.Internal.Orphans () +import Wire.API.Conversation.Role +import Wire.API.Error +import Wire.API.Error.Galley +import Wire.API.Routes.MultiVerb +import Wire.API.Routes.Named +import Wire.API.Routes.Public +import Wire.API.Team.LegalHold + +type LegalHoldAPI = + Named + "create-legal-hold-settings" + ( Summary "Create legal hold service settings" + :> CanThrow 'NotATeamMember + :> CanThrow OperationDenied + :> CanThrow 'LegalHoldNotEnabled + :> CanThrow 'LegalHoldServiceInvalidKey + :> CanThrow 'LegalHoldServiceBadResponse + :> ZLocalUser + :> "teams" + :> Capture "tid" TeamId + :> "legalhold" + :> "settings" + :> ReqBody '[JSON] NewLegalHoldService + :> MultiVerb1 'POST '[JSON] (Respond 201 "Legal hold service settings created" ViewLegalHoldService) + ) + :<|> Named + "get-legal-hold-settings" + ( Summary "Get legal hold service settings" + :> CanThrow 'NotATeamMember + :> CanThrow OperationDenied + :> ZLocalUser + :> "teams" + :> Capture "tid" TeamId + :> "legalhold" + :> "settings" + :> Get '[JSON] ViewLegalHoldService + ) + :<|> Named + "delete-legal-hold-settings" + ( Summary "Delete legal hold service settings" + :> CanThrow AuthenticationError + :> CanThrow OperationDenied + :> CanThrow 'NotATeamMember + :> CanThrow ('ActionDenied 'RemoveConversationMember) + :> CanThrow 'InvalidOperation + :> CanThrow 'LegalHoldNotEnabled + :> CanThrow 'LegalHoldDisableUnimplemented + :> CanThrow 'LegalHoldServiceNotRegistered + :> CanThrow 'UserLegalHoldIllegalOperation + :> CanThrow 'LegalHoldCouldNotBlockConnections + :> Description + "This endpoint can lead to the following events being sent:\n\ + \- ClientRemoved event to members with a legalhold client (via brig)\n\ + \- UserLegalHoldDisabled event to contacts of members with a legalhold client (via brig)" + :> ZLocalUser + :> "teams" + :> Capture "tid" TeamId + :> "legalhold" + :> "settings" + :> ReqBody '[JSON] RemoveLegalHoldSettingsRequest + :> MultiVerb1 'DELETE '[JSON] (RespondEmpty 204 "Legal hold service settings deleted") + ) + :<|> Named + "get-legal-hold" + ( Summary "Get legal hold status" + :> CanThrow 'TeamMemberNotFound + :> ZLocalUser + :> "teams" + :> Capture "tid" TeamId + :> "legalhold" + :> Capture "uid" UserId + :> Get '[JSON] UserLegalHoldStatusResponse + ) + :<|> Named + "consent-to-legal-hold" + ( Summary "Consent to legal hold" + :> CanThrow ('ActionDenied 'RemoveConversationMember) + :> CanThrow 'InvalidOperation + :> CanThrow 'TeamMemberNotFound + :> CanThrow 'UserLegalHoldIllegalOperation + :> CanThrow 'LegalHoldCouldNotBlockConnections + :> ZLocalUser + :> "teams" + :> Capture "tid" TeamId + :> "legalhold" + :> "consent" + :> MultiVerb 'POST '[JSON] GrantConsentResultResponseTypes GrantConsentResult + ) + :<|> Named + "request-legal-hold-device" + ( Summary "Request legal hold device" + :> CanThrow ('ActionDenied 'RemoveConversationMember) + :> CanThrow 'NotATeamMember + :> CanThrow OperationDenied + :> CanThrow 'TeamMemberNotFound + :> CanThrow 'LegalHoldNotEnabled + :> CanThrow 'UserLegalHoldAlreadyEnabled + :> CanThrow 'NoUserLegalHoldConsent + :> CanThrow 'LegalHoldServiceBadResponse + :> CanThrow 'LegalHoldServiceNotRegistered + :> CanThrow 'LegalHoldCouldNotBlockConnections + :> CanThrow 'UserLegalHoldIllegalOperation + :> Description + "This endpoint can lead to the following events being sent:\n\ + \- LegalHoldClientRequested event to contacts of the user the device is requested for, if they didn't already have a legalhold client (via brig)" + :> ZLocalUser + :> "teams" + :> Capture "tid" TeamId + :> "legalhold" + :> Capture "uid" UserId + :> MultiVerb + 'POST + '[JSON] + RequestDeviceResultResponseType + RequestDeviceResult + ) + :<|> Named + "disable-legal-hold-for-user" + ( Summary "Disable legal hold for user" + :> CanThrow AuthenticationError + :> CanThrow ('ActionDenied 'RemoveConversationMember) + :> CanThrow 'NotATeamMember + :> CanThrow OperationDenied + :> CanThrow 'LegalHoldServiceNotRegistered + :> CanThrow 'UserLegalHoldIllegalOperation + :> CanThrow 'LegalHoldCouldNotBlockConnections + :> Description + "This endpoint can lead to the following events being sent:\n\ + \- ClientRemoved event to the user owning the client (via brig)\n\ + \- UserLegalHoldDisabled event to contacts of the user owning the client (via brig)" + :> ZLocalUser + :> "teams" + :> Capture "tid" TeamId + :> "legalhold" + :> Capture "uid" UserId + :> ReqBody '[JSON] DisableLegalHoldForUserRequest + :> MultiVerb + 'DELETE + '[JSON] + DisableLegalHoldForUserResponseType + DisableLegalHoldForUserResponse + ) + :<|> Named + "approve-legal-hold-device" + ( Summary "Approve legal hold device" + :> CanThrow AuthenticationError + :> CanThrow 'AccessDenied + :> CanThrow ('ActionDenied 'RemoveConversationMember) + :> CanThrow 'NotATeamMember + :> CanThrow 'LegalHoldNotEnabled + :> CanThrow 'UserLegalHoldNotPending + :> CanThrow 'NoLegalHoldDeviceAllocated + :> CanThrow 'LegalHoldServiceNotRegistered + :> CanThrow 'UserLegalHoldAlreadyEnabled + :> CanThrow 'UserLegalHoldIllegalOperation + :> CanThrow 'LegalHoldCouldNotBlockConnections + :> Description + "This endpoint can lead to the following events being sent:\n\ + \- ClientAdded event to the user owning the client (via brig)\n\ + \- UserLegalHoldEnabled event to contacts of the user owning the client (via brig)\n\ + \- ClientRemoved event to the user, if removing old client due to max number (via brig)" + :> ZLocalUser + :> ZConn + :> "teams" + :> Capture "tid" TeamId + :> "legalhold" + :> Capture "uid" UserId + :> "approve" + :> ReqBody '[JSON] ApproveLegalHoldForUserRequest + :> MultiVerb1 'PUT '[JSON] (RespondEmpty 200 "Legal hold approved") + ) + +type RequestDeviceResultResponseType = + '[ RespondEmpty 201 "Request device successful", + RespondEmpty 204 "Request device already pending" + ] + +data RequestDeviceResult + = RequestDeviceSuccess + | RequestDeviceAlreadyPending + deriving (Generic) + deriving (AsUnion RequestDeviceResultResponseType) via GenericAsUnion RequestDeviceResultResponseType RequestDeviceResult + +instance GSOP.Generic RequestDeviceResult + +type DisableLegalHoldForUserResponseType = + '[ RespondEmpty 200 "Disable legal hold successful", + RespondEmpty 204 "Legal hold was not enabled" + ] + +data DisableLegalHoldForUserResponse + = DisableLegalHoldSuccess + | DisableLegalHoldWasNotEnabled + deriving (Generic) + deriving (AsUnion DisableLegalHoldForUserResponseType) via GenericAsUnion DisableLegalHoldForUserResponseType DisableLegalHoldForUserResponse + +instance GSOP.Generic DisableLegalHoldForUserResponse + +type GrantConsentResultResponseTypes = + '[ RespondEmpty 201 "Grant consent successful", + RespondEmpty 204 "Consent already granted" + ] + +data GrantConsentResult + = GrantConsentSuccess + | GrantConsentAlreadyGranted + deriving (Generic) + deriving (AsUnion GrantConsentResultResponseTypes) via GenericAsUnion GrantConsentResultResponseTypes GrantConsentResult + +instance GSOP.Generic GrantConsentResult diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Galley/MLS.hs b/libs/wire-api/src/Wire/API/Routes/Public/Galley/MLS.hs new file mode 100644 index 0000000000..5a2c51997e --- /dev/null +++ b/libs/wire-api/src/Wire/API/Routes/Public/Galley/MLS.hs @@ -0,0 +1,132 @@ +-- 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.Public.Galley.MLS where + +import Servant hiding (WithStatus) +import Servant.Swagger.Internal.Orphans () +import Wire.API.Error +import Wire.API.Error.Galley +import Wire.API.Event.Conversation +import Wire.API.MLS.CommitBundle +import Wire.API.MLS.Keys +import Wire.API.MLS.Message +import Wire.API.MLS.Serialisation +import Wire.API.MLS.Servant +import Wire.API.MLS.Welcome +import Wire.API.Routes.MultiVerb +import Wire.API.Routes.Named +import Wire.API.Routes.Public +import Wire.API.Routes.Version + +type MLSMessagingAPI = + Named + "mls-welcome-message" + ( Summary "Post an MLS welcome message" + :> CanThrow 'MLSKeyPackageRefNotFound + :> "welcome" + :> ZConn + :> ReqBody '[MLS] (RawMLS Welcome) + :> MultiVerb1 'POST '[JSON] (RespondEmpty 201 "Welcome message sent") + ) + :<|> Named + "mls-message-v1" + ( Summary "Post an MLS message" + :> Until 'V2 + :> CanThrow 'ConvAccessDenied + :> CanThrow 'ConvMemberNotFound + :> CanThrow 'ConvNotFound + :> CanThrow 'LegalHoldNotEnabled + :> CanThrow 'MLSClientMismatch + :> CanThrow 'MLSCommitMissingReferences + :> CanThrow 'MLSKeyPackageRefNotFound + :> CanThrow 'MLSProposalNotFound + :> CanThrow 'MLSProtocolErrorTag + :> CanThrow 'MLSSelfRemovalNotAllowed + :> CanThrow 'MLSStaleMessage + :> CanThrow 'MLSUnsupportedMessage + :> CanThrow 'MLSUnsupportedProposal + :> CanThrow 'MLSClientSenderUserMismatch + :> CanThrow 'MLSGroupConversationMismatch + :> CanThrow 'MissingLegalholdConsent + :> CanThrow MLSProposalFailure + :> "messages" + :> ZConn + :> ReqBody '[MLS] (RawMLS SomeMessage) + :> MultiVerb1 'POST '[JSON] (Respond 201 "Message sent" [Event]) + ) + :<|> Named + "mls-message" + ( Summary "Post an MLS message" + :> From 'V2 + :> CanThrow 'ConvAccessDenied + :> CanThrow 'ConvMemberNotFound + :> CanThrow 'ConvNotFound + :> CanThrow 'LegalHoldNotEnabled + :> CanThrow 'MLSClientMismatch + :> CanThrow 'MLSCommitMissingReferences + :> CanThrow 'MLSKeyPackageRefNotFound + :> CanThrow 'MLSProposalNotFound + :> CanThrow 'MLSProtocolErrorTag + :> CanThrow 'MLSSelfRemovalNotAllowed + :> CanThrow 'MLSStaleMessage + :> CanThrow 'MLSUnsupportedMessage + :> CanThrow 'MLSUnsupportedProposal + :> CanThrow 'MLSClientSenderUserMismatch + :> CanThrow 'MLSGroupConversationMismatch + :> CanThrow 'MissingLegalholdConsent + :> CanThrow MLSProposalFailure + :> "messages" + :> ZConn + :> ReqBody '[MLS] (RawMLS SomeMessage) + :> MultiVerb1 'POST '[JSON] (Respond 201 "Message sent" MLSMessageSendingStatus) + ) + :<|> Named + "mls-commit-bundle" + ( Summary "Post a MLS CommitBundle" + :> From 'V3 + :> CanThrow 'ConvAccessDenied + :> CanThrow 'ConvMemberNotFound + :> CanThrow 'ConvNotFound + :> CanThrow 'LegalHoldNotEnabled + :> CanThrow 'MLSClientMismatch + :> CanThrow 'MLSCommitMissingReferences + :> CanThrow 'MLSKeyPackageRefNotFound + :> CanThrow 'MLSProposalNotFound + :> CanThrow 'MLSProtocolErrorTag + :> CanThrow 'MLSSelfRemovalNotAllowed + :> CanThrow 'MLSStaleMessage + :> CanThrow 'MLSUnsupportedMessage + :> CanThrow 'MLSUnsupportedProposal + :> CanThrow 'MLSClientSenderUserMismatch + :> CanThrow 'MLSGroupConversationMismatch + :> CanThrow 'MLSWelcomeMismatch + :> CanThrow 'MissingLegalholdConsent + :> CanThrow MLSProposalFailure + :> "commit-bundles" + :> ZConn + :> ReqBody '[CommitBundleMimeType] CommitBundle + :> MultiVerb1 'POST '[JSON] (Respond 201 "Commit accepted and forwarded" MLSMessageSendingStatus) + ) + :<|> Named + "mls-public-keys" + ( Summary "Get public keys used by the backend to sign external proposals" + :> "public-keys" + :> MultiVerb1 'GET '[JSON] (Respond 200 "Public keys" MLSPublicKeys) + ) + +type MLSAPI = LiftNamed (ZLocalUser :> "mls" :> MLSMessagingAPI) diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Galley/Messaging.hs b/libs/wire-api/src/Wire/API/Routes/Public/Galley/Messaging.hs new file mode 100644 index 0000000000..1e982f96e6 --- /dev/null +++ b/libs/wire-api/src/Wire/API/Routes/Public/Galley/Messaging.hs @@ -0,0 +1,197 @@ +-- 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.Public.Galley.Messaging where + +import Data.Id +import Data.SOP +import qualified Generics.SOP as GSOP +import Imports +import Servant hiding (WithStatus) +import Servant.Swagger.Internal.Orphans () +import Wire.API.Error +import qualified Wire.API.Error.Brig as BrigError +import Wire.API.Error.Galley +import Wire.API.Message +import Wire.API.Routes.MultiVerb +import Wire.API.Routes.Named +import Wire.API.Routes.Public +import Wire.API.Routes.QualifiedCapture +import Wire.API.ServantProto + +type MessagingAPI = + Named + "post-otr-message-unqualified" + ( Summary "Post an encrypted message to a conversation (accepts JSON or Protobuf)" + :> Description PostOtrDescriptionUnqualified + :> ZLocalUser + :> ZConn + :> "conversations" + :> Capture "cnv" ConvId + :> "otr" + :> "messages" + :> QueryParam "ignore_missing" IgnoreMissing + :> QueryParam "report_missing" ReportMissing + :> ReqBody '[JSON, Proto] NewOtrMessage + :> MultiVerb + 'POST + '[Servant.JSON] + (PostOtrResponses ClientMismatch) + (PostOtrResponse ClientMismatch) + ) + :<|> Named + "post-otr-broadcast-unqualified" + ( Summary "Broadcast an encrypted message to all team members and all contacts (accepts JSON or Protobuf)" + :> Description PostOtrDescriptionUnqualified + :> ZLocalUser + :> ZConn + :> CanThrow 'TeamNotFound + :> CanThrow 'BroadcastLimitExceeded + :> CanThrow 'NonBindingTeam + :> "broadcast" + :> "otr" + :> "messages" + :> QueryParam "ignore_missing" IgnoreMissing + :> QueryParam "report_missing" ReportMissing + :> ReqBody '[JSON, Proto] NewOtrMessage + :> MultiVerb + 'POST + '[JSON] + (PostOtrResponses ClientMismatch) + (PostOtrResponse ClientMismatch) + ) + :<|> Named + "post-proteus-message" + ( Summary "Post an encrypted message to a conversation (accepts only Protobuf)" + :> Description PostOtrDescription + :> ZLocalUser + :> ZConn + :> "conversations" + :> QualifiedCapture "cnv" ConvId + :> "proteus" + :> "messages" + :> ReqBody '[Proto] (RawProto QualifiedNewOtrMessage) + :> MultiVerb + 'POST + '[Servant.JSON] + (PostOtrResponses MessageSendingStatus) + (Either (MessageNotSent MessageSendingStatus) MessageSendingStatus) + ) + :<|> Named + "post-proteus-broadcast" + ( Summary "Post an encrypted message to all team members and all contacts (accepts only Protobuf)" + :> Description PostOtrDescription + :> ZLocalUser + :> ZConn + :> CanThrow 'TeamNotFound + :> CanThrow 'BroadcastLimitExceeded + :> CanThrow 'NonBindingTeam + :> "broadcast" + :> "proteus" + :> "messages" + :> ReqBody '[Proto] QualifiedNewOtrMessage + :> MultiVerb + 'POST + '[JSON] + (PostOtrResponses MessageSendingStatus) + (Either (MessageNotSent MessageSendingStatus) MessageSendingStatus) + ) + +data MessageNotSent a + = MessageNotSentConversationNotFound + | MessageNotSentUnknownClient + | MessageNotSentLegalhold + | MessageNotSentClientMissing a + deriving stock (Eq, Show, Generic, Functor) + deriving + (AsUnion (MessageNotSentResponses a)) + via (GenericAsUnion (MessageNotSentResponses a) (MessageNotSent a)) + +instance GSOP.Generic (MessageNotSent a) + +type MessageNotSentResponses a = + '[ ErrorResponse 'ConvNotFound, + ErrorResponse 'BrigError.UnknownClient, + ErrorResponse 'BrigError.MissingLegalholdConsent, + Respond 412 "Missing clients" a + ] + +type PostOtrResponses a = + MessageNotSentResponses a + .++ '[Respond 201 "Message sent" a] + +type PostOtrResponse a = Either (MessageNotSent a) a + +instance + ( rs ~ (MessageNotSentResponses a .++ '[r]), + a ~ ResponseType r + ) => + AsUnion rs (PostOtrResponse a) + where + toUnion = + eitherToUnion + (toUnion @(MessageNotSentResponses a)) + (Z . I) + + fromUnion = + eitherFromUnion + (fromUnion @(MessageNotSentResponses a)) + (unI . unZ) + +-- This is a work-around for the fact that we sometimes want to send larger lists of user ids +-- in the filter query than fits the url length limit. For details, see +-- https://github.com/zinfra/backend-issues/issues/1248 +type PostOtrDescriptionUnqualified = + "This endpoint ensures that the list of clients is correct and only sends the message if the list is correct.\n\ + \To override this, the endpoint accepts two query params:\n\ + \- `ignore_missing`: Can be 'true' 'false' or a comma separated list of user IDs.\n\ + \ - When 'true' all missing clients are ignored.\n\ + \ - When 'false' all missing clients are reported.\n\ + \ - When comma separated list of user-ids, only clients for listed users are ignored.\n\ + \- `report_missing`: Can be 'true' 'false' or a comma separated list of user IDs.\n\ + \ - When 'true' all missing clients are reported.\n\ + \ - When 'false' all missing clients are ignored.\n\ + \ - When comma separated list of user-ids, only clients for listed users are reported.\n\ + \\n\ + \Apart from these, the request body also accepts `report_missing` which can only be a list of user ids and behaves the same way as the query parameter.\n\ + \\n\ + \All three of these should be considered mutually exclusive. The server however does not error if more than one is specified, it reads them in this order of precedence:\n\ + \- `report_missing` in the request body has highest precedence.\n\ + \- `ignore_missing` in the query param is the next.\n\ + \- `report_missing` in the query param has the lowest precedence.\n\ + \\n\ + \This endpoint can lead to OtrMessageAdd event being sent to the recipients.\n\ + \\n\ + \**NOTE:** The protobuf definitions of the request body can be found at https://github.com/wireapp/generic-message-proto/blob/master/proto/otr.proto." + +type PostOtrDescription = + "This endpoint ensures that the list of clients is correct and only sends the message if the list is correct.\n\ + \To override this, the endpoint accepts `client_mismatch_strategy` in the body. It can have these values:\n\ + \- `report_all`: When set, the message is not sent if any clients are missing. The missing clients are reported in the response.\n\ + \- `ignore_all`: When set, no checks about missing clients are carried out.\n\ + \- `report_only`: Takes a list of qualified UserIDs. If any clients of the listed users are missing, the message is not sent. The missing clients are reported in the response.\n\ + \- `ignore_only`: Takes a list of qualified UserIDs. If any clients of the non-listed users are missing, the message is not sent. The missing clients are reported in the response.\n\ + \\n\ + \The sending of messages in a federated conversation could theoretically fail partially. \ + \To make this case unlikely, the backend first gets a list of clients from all the involved backends and then tries to send a message. \ + \So, if any backend is down, the message is not propagated to anyone. \ + \But the actual message fan out to multiple backends could still fail partially. This type of failure is reported as a 201, \ + \the clients for which the message sending failed are part of the response body.\n\ + \\n\ + \This endpoint can lead to OtrMessageAdd event being sent to the recipients.\n\ + \\n\ + \**NOTE:** The protobuf definitions of the request body can be found at https://github.com/wireapp/generic-message-proto/blob/master/proto/otr.proto." diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Galley/Team.hs b/libs/wire-api/src/Wire/API/Routes/Public/Galley/Team.hs new file mode 100644 index 0000000000..0a81f55c27 --- /dev/null +++ b/libs/wire-api/src/Wire/API/Routes/Public/Galley/Team.hs @@ -0,0 +1,101 @@ +-- 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.Public.Galley.Team where + +import Data.Id +import Imports +import Servant hiding (WithStatus) +import Servant.Swagger.Internal.Orphans () +import Wire.API.Error +import Wire.API.Error.Galley +import Wire.API.Routes.MultiVerb +import Wire.API.Routes.Named +import Wire.API.Routes.Public +import Wire.API.Team +import Wire.API.Team.Permission + +type TeamAPI = + Named + "create-non-binding-team" + ( Summary "Create a new non binding team" + -- FUTUREWORK: deprecated in https://github.com/wireapp/wire-server/pull/2607 + :> ZUser + :> ZConn + :> CanThrow 'NotConnected + :> CanThrow 'UserBindingExists + :> "teams" + :> ReqBody '[Servant.JSON] NonBindingNewTeam + :> MultiVerb + 'POST + '[JSON] + '[ WithHeaders + '[DescHeader "Location" "Team ID" TeamId] + TeamId + (RespondEmpty 201 "Team ID as `Location` header value") + ] + TeamId + ) + :<|> Named + "update-team" + ( Summary "Update team properties" + :> ZUser + :> ZConn + :> CanThrow 'NotATeamMember + :> CanThrow ('MissingPermission ('Just 'SetTeamData)) + :> "teams" + :> Capture "tid" TeamId + :> ReqBody '[JSON] TeamUpdateData + :> MultiVerb + 'PUT + '[JSON] + '[RespondEmpty 200 "Team updated"] + () + ) + :<|> Named + "get-teams" + ( Summary "Get teams (deprecated); use `GET /teams/:tid`" + -- FUTUREWORK: deprecated in https://github.com/wireapp/wire-server/pull/2607 + :> ZUser + :> "teams" + :> Get '[JSON] TeamList + ) + :<|> Named + "get-team" + ( Summary "Get a team by ID" + :> ZUser + :> CanThrow 'TeamNotFound + :> "teams" + :> Capture "tid" TeamId + :> Get '[JSON] Team + ) + :<|> Named + "delete-team" + ( Summary "Delete a team" + :> ZUser + :> ZConn + :> CanThrow 'TeamNotFound + :> CanThrow ('MissingPermission ('Just 'DeleteTeam)) + :> CanThrow 'NotATeamMember + :> CanThrow OperationDenied + :> CanThrow 'DeleteQueueFull + :> CanThrow AuthenticationError + :> "teams" + :> Capture "tid" TeamId + :> ReqBody '[Servant.JSON] TeamDeleteData + :> MultiVerb 'DELETE '[JSON] '[RespondEmpty 202 "Team is scheduled for removal"] () + ) diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Galley/TeamConversation.hs b/libs/wire-api/src/Wire/API/Routes/Public/Galley/TeamConversation.hs new file mode 100644 index 0000000000..ce00269f8a --- /dev/null +++ b/libs/wire-api/src/Wire/API/Routes/Public/Galley/TeamConversation.hs @@ -0,0 +1,81 @@ +-- 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.Public.Galley.TeamConversation where + +import Data.Id +import Servant hiding (WithStatus) +import Servant.Swagger.Internal.Orphans () +import Wire.API.Conversation.Role +import Wire.API.Error +import Wire.API.Error.Galley +import Wire.API.Routes.MultiVerb +import Wire.API.Routes.Named +import Wire.API.Routes.Public +import Wire.API.Team.Conversation + +type TeamConversationAPI = + Named + "get-team-conversation-roles" + ( Summary "Get existing roles available for the given team" + :> CanThrow 'NotATeamMember + :> ZUser + :> "teams" + :> Capture "tid" TeamId + :> "conversations" + :> "roles" + :> Get '[Servant.JSON] ConversationRolesList + ) + :<|> Named + "get-team-conversations" + ( Summary "Get team conversations" + :> CanThrow OperationDenied + :> CanThrow 'NotATeamMember + :> ZUser + :> "teams" + :> Capture "tid" TeamId + :> "conversations" + :> Get '[Servant.JSON] TeamConversationList + ) + :<|> Named + "get-team-conversation" + ( Summary "Get one team conversation" + :> CanThrow 'ConvNotFound + :> CanThrow OperationDenied + :> CanThrow 'NotATeamMember + :> ZUser + :> "teams" + :> Capture "tid" TeamId + :> "conversations" + :> Capture "cid" ConvId + :> Get '[Servant.JSON] TeamConversation + ) + :<|> Named + "delete-team-conversation" + ( Summary "Remove a team conversation" + :> CanThrow ('ActionDenied 'DeleteConversation) + :> CanThrow 'ConvNotFound + :> CanThrow 'InvalidOperation + :> CanThrow 'NotATeamMember + :> ZLocalUser + :> ZConn + :> "teams" + :> Capture "tid" TeamId + :> "conversations" + :> Capture "cid" ConvId + :> MultiVerb 'DELETE '[JSON] '[RespondEmpty 200 "Conversation deleted"] () + ) diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Galley/TeamMember.hs b/libs/wire-api/src/Wire/API/Routes/Public/Galley/TeamMember.hs new file mode 100644 index 0000000000..7f9e99dcaa --- /dev/null +++ b/libs/wire-api/src/Wire/API/Routes/Public/Galley/TeamMember.hs @@ -0,0 +1,219 @@ +-- 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.Public.Galley.TeamMember where + +import Data.Id +import Data.Int +import Data.Range +import GHC.Generics +import qualified Generics.SOP as GSOP +import Servant hiding (WithStatus) +import Servant.Swagger.Internal.Orphans () +import Wire.API.Error +import Wire.API.Error.Galley +import Wire.API.Routes.CSV +import Wire.API.Routes.LowLevelStream +import Wire.API.Routes.MultiVerb +import Wire.API.Routes.Named +import Wire.API.Routes.Public +import Wire.API.Team.Member +import qualified Wire.API.User as User + +type TeamMemberAPI = + Named + "get-team-members" + ( Summary "Get team members" + :> CanThrow 'NotATeamMember + :> ZLocalUser + :> "teams" + :> Capture "tid" TeamId + :> "members" + :> QueryParam' + [ Optional, + Strict, + Description "Maximum results to be returned" + ] + "maxResults" + (Range 1 HardTruncationLimit Int32) + :> QueryParam' + [ Optional, + Strict, + Description + "Optional, when not specified, the first page will be returned.\ + \Every returned page contains a `pagingState`, this should be supplied to retrieve the next page." + ] + "pagingState" + TeamMembersPagingState + :> Get '[JSON] TeamMembersPage + ) + :<|> Named + "get-team-member" + ( Summary "Get single team member" + :> CanThrow 'NotATeamMember + :> CanThrow 'TeamMemberNotFound + :> ZLocalUser + :> "teams" + :> Capture "tid" TeamId + :> "members" + :> Capture "uid" UserId + :> Get '[JSON] TeamMemberOptPerms + ) + :<|> Named + "get-team-members-by-ids" + ( Summary "Get team members by user id list" + :> Description "The `has_more` field in the response body is always `false`." + :> CanThrow 'NotATeamMember + :> CanThrow 'BulkGetMemberLimitExceeded + :> ZLocalUser + :> "teams" + :> Capture "tid" TeamId + :> "get-members-by-ids-using-post" + :> QueryParam' + [ Optional, + Strict, + Description "Maximum results to be returned" + ] + "maxResults" + (Range 1 HardTruncationLimit Int32) + :> ReqBody '[JSON] User.UserIdList + :> Post '[JSON] TeamMemberListOptPerms + ) + :<|> Named + "add-team-member" + ( Summary "Add a new team member" + -- FUTUREWORK: deprecated in https://github.com/wireapp/wire-server/pull/2607 + :> CanThrow 'InvalidPermissions + :> CanThrow 'NoAddToBinding + :> CanThrow 'NotATeamMember + :> CanThrow 'NotConnected + :> CanThrow OperationDenied + :> CanThrow 'TeamNotFound + :> CanThrow 'TooManyTeamMembers + :> CanThrow 'UserBindingExists + :> CanThrow 'TooManyTeamMembersOnTeamWithLegalhold + :> ZLocalUser + :> ZConn + :> "teams" + :> Capture "tid" TeamId + :> "members" + :> ReqBody '[JSON] NewTeamMember + :> MultiVerb1 + 'POST + '[JSON] + (RespondEmpty 200 "") + ) + :<|> Named + "delete-team-member" + ( Summary "Remove an existing team member" + :> CanThrow AuthenticationError + :> CanThrow 'AccessDenied + :> CanThrow 'TeamMemberNotFound + :> CanThrow 'TeamNotFound + :> CanThrow 'NotATeamMember + :> CanThrow OperationDenied + :> ZLocalUser + :> ZConn + :> "teams" + :> Capture "tid" TeamId + :> "members" + :> Capture "uid" UserId + :> ReqBody '[JSON] TeamMemberDeleteData + :> MultiVerb + 'DELETE + '[JSON] + TeamMemberDeleteResultResponseType + TeamMemberDeleteResult + ) + :<|> Named + "delete-non-binding-team-member" + ( Summary "Remove an existing team member" + -- FUTUREWORK: deprecated in https://github.com/wireapp/wire-server/pull/2607 + :> CanThrow AuthenticationError + :> CanThrow 'AccessDenied + :> CanThrow 'TeamMemberNotFound + :> CanThrow 'TeamNotFound + :> CanThrow 'NotATeamMember + :> CanThrow OperationDenied + :> ZLocalUser + :> ZConn + :> "teams" + :> Capture "tid" TeamId + :> "members" + :> Capture "uid" UserId + :> MultiVerb + 'DELETE + '[JSON] + TeamMemberDeleteResultResponseType + TeamMemberDeleteResult + ) + :<|> Named + "update-team-member" + ( Summary "Update an existing team member" + :> CanThrow 'AccessDenied + :> CanThrow 'InvalidPermissions + :> CanThrow 'TeamNotFound + :> CanThrow 'TeamMemberNotFound + :> CanThrow 'NotATeamMember + :> CanThrow OperationDenied + :> ZLocalUser + :> ZConn + :> "teams" + :> Capture "tid" TeamId + :> "members" + :> ReqBody '[JSON] NewTeamMember + :> MultiVerb1 + 'PUT + '[JSON] + (RespondEmpty 200 "") + ) + :<|> Named + "get-team-members-csv" + ( Summary "Get all members of the team as a CSV file" + :> CanThrow 'AccessDenied + :> Description + "The endpoint returns data in chunked transfer encoding.\ + \ Internal server errors might result in a failed transfer\ + \ instead of a 500 response." + :> ZLocalUser + :> "teams" + :> Capture "tid" TeamId + :> "members" + :> "csv" + :> LowLevelStream + 'GET + 200 + '[ '( "Content-Disposition", + "attachment; filename=\"wire_team_members.csv\"" + ) + ] + "CSV of team members" + CSV + ) + +type TeamMemberDeleteResultResponseType = + '[ RespondEmpty 202 "Team member scheduled for deletion", + RespondEmpty 200 "" + ] + +data TeamMemberDeleteResult + = TeamMemberDeleteAccepted + | TeamMemberDeleteCompleted + deriving (Generic) + deriving (AsUnion TeamMemberDeleteResultResponseType) via GenericAsUnion TeamMemberDeleteResultResponseType TeamMemberDeleteResult + +instance GSOP.Generic TeamMemberDeleteResult diff --git a/libs/wire-api/wire-api.cabal b/libs/wire-api/wire-api.cabal index 0cef6f4c10..866f26746c 100644 --- a/libs/wire-api/wire-api.cabal +++ b/libs/wire-api/wire-api.cabal @@ -91,6 +91,16 @@ library Wire.API.Routes.Public.Cannon Wire.API.Routes.Public.Cargohold Wire.API.Routes.Public.Galley + Wire.API.Routes.Public.Galley.Bot + Wire.API.Routes.Public.Galley.Conversation + Wire.API.Routes.Public.Galley.CustomBackend + Wire.API.Routes.Public.Galley.Feature + Wire.API.Routes.Public.Galley.LegalHold + Wire.API.Routes.Public.Galley.Messaging + Wire.API.Routes.Public.Galley.MLS + Wire.API.Routes.Public.Galley.Team + Wire.API.Routes.Public.Galley.TeamConversation + Wire.API.Routes.Public.Galley.TeamMember Wire.API.Routes.Public.Gundeck Wire.API.Routes.Public.Spar Wire.API.Routes.Public.Util diff --git a/services/galley/galley.cabal b/services/galley/galley.cabal index 6e3529e497..448a2f9dce 100644 --- a/services/galley/galley.cabal +++ b/services/galley/galley.cabal @@ -42,7 +42,17 @@ library Galley.API.MLS.Welcome Galley.API.One2One Galley.API.Public + Galley.API.Public.Bot + Galley.API.Public.Conversation + Galley.API.Public.CustomBackend + Galley.API.Public.Feature + Galley.API.Public.LegalHold + Galley.API.Public.Messaging + Galley.API.Public.MLS Galley.API.Public.Servant + Galley.API.Public.Team + Galley.API.Public.TeamConversation + Galley.API.Public.TeamMember Galley.API.Push Galley.API.Query Galley.API.Teams diff --git a/services/galley/src/Galley/API/Create.hs b/services/galley/src/Galley/API/Create.hs index edaee398a7..ed93dca566 100644 --- a/services/galley/src/Galley/API/Create.hs +++ b/services/galley/src/Galley/API/Create.hs @@ -72,7 +72,7 @@ import Wire.API.Error import Wire.API.Error.Galley import Wire.API.Event.Conversation import Wire.API.Federation.Error -import Wire.API.Routes.Public.Galley (ConversationResponse) +import Wire.API.Routes.Public.Galley.Conversation import Wire.API.Routes.Public.Util import Wire.API.Team import Wire.API.Team.LegalHold (LegalholdProtectee (LegalholdPlusFederationNotImplemented)) diff --git a/services/galley/src/Galley/API/Internal.hs b/services/galley/src/Galley/API/Internal.hs index f57d698186..b2e55a7bce 100644 --- a/services/galley/src/Galley/API/Internal.hs +++ b/services/galley/src/Galley/API/Internal.hs @@ -103,7 +103,8 @@ import Wire.API.Routes.MultiTablePaging (mtpHasMore, mtpPagingState, mtpResults) import Wire.API.Routes.MultiVerb import Wire.API.Routes.Named import Wire.API.Routes.Public -import Wire.API.Routes.Public.Galley +import Wire.API.Routes.Public.Galley.Conversation +import Wire.API.Routes.Public.Galley.Feature import Wire.API.Team import Wire.API.Team.Feature import Wire.API.Team.Member diff --git a/services/galley/src/Galley/API/LegalHold.hs b/services/galley/src/Galley/API/LegalHold.hs index 71288e7af5..151bc14655 100644 --- a/services/galley/src/Galley/API/LegalHold.hs +++ b/services/galley/src/Galley/API/LegalHold.hs @@ -74,7 +74,7 @@ import Wire.API.Error import Wire.API.Error.Galley import Wire.API.Provider.Service import Wire.API.Routes.Internal.Brig.Connection -import Wire.API.Routes.Public.Galley (DisableLegalHoldForUserResponse (..), GrantConsentResult (..), RequestDeviceResult (..)) +import Wire.API.Routes.Public.Galley.LegalHold import qualified Wire.API.Team.Feature as Public import Wire.API.Team.LegalHold import qualified Wire.API.Team.LegalHold as Public diff --git a/services/galley/src/Galley/API/Message.hs b/services/galley/src/Galley/API/Message.hs index 199129610a..a16128fa37 100644 --- a/services/galley/src/Galley/API/Message.hs +++ b/services/galley/src/Galley/API/Message.hs @@ -79,7 +79,7 @@ import Wire.API.Federation.API.Brig import Wire.API.Federation.API.Galley import Wire.API.Federation.Error import Wire.API.Message -import Wire.API.Routes.Public.Galley +import Wire.API.Routes.Public.Galley.Messaging import Wire.API.Team.LegalHold import Wire.API.Team.Member import Wire.API.User.Client diff --git a/services/galley/src/Galley/API/Public/Bot.hs b/services/galley/src/Galley/API/Public/Bot.hs new file mode 100644 index 0000000000..8c75ddbdee --- /dev/null +++ b/services/galley/src/Galley/API/Public/Bot.hs @@ -0,0 +1,26 @@ +-- 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 Galley.API.Public.Bot where + +import Galley.API.Update +import Galley.App +import Wire.API.Routes.API +import Wire.API.Routes.Public.Galley.Bot + +botAPI :: API BotAPI GalleyEffects +botAPI = mkNamedAPI @"post-bot-message-unqualified" postBotMessageUnqualified diff --git a/services/galley/src/Galley/API/Public/Conversation.hs b/services/galley/src/Galley/API/Public/Conversation.hs new file mode 100644 index 0000000000..6bff31d00d --- /dev/null +++ b/services/galley/src/Galley/API/Public/Conversation.hs @@ -0,0 +1,72 @@ +-- 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 Galley.API.Public.Conversation where + +import Galley.API.Create +import Galley.API.MLS.GroupInfo +import Galley.API.Query +import Galley.API.Update +import Galley.App +import Galley.Cassandra.TeamFeatures +import Wire.API.Routes.API +import Wire.API.Routes.Public.Galley.Conversation + +conversationAPI :: API ConversationAPI GalleyEffects +conversationAPI = + mkNamedAPI @"get-unqualified-conversation" getUnqualifiedConversation + <@> mkNamedAPI @"get-unqualified-conversation-legalhold-alias" getUnqualifiedConversation + <@> mkNamedAPI @"get-conversation" getConversation + <@> mkNamedAPI @"get-conversation-roles" getConversationRoles + <@> mkNamedAPI @"get-group-info" getGroupInfo + <@> mkNamedAPI @"list-conversation-ids-unqualified" conversationIdsPageFromUnqualified + <@> mkNamedAPI @"list-conversation-ids" conversationIdsPageFrom + <@> mkNamedAPI @"get-conversations" getConversations + <@> mkNamedAPI @"list-conversations-v1" listConversations + <@> mkNamedAPI @"list-conversations" listConversations + <@> mkNamedAPI @"get-conversation-by-reusable-code" (getConversationByReusableCode @Cassandra) + <@> mkNamedAPI @"create-group-conversation" createGroupConversation + <@> mkNamedAPI @"create-self-conversation" createProteusSelfConversation + <@> mkNamedAPI @"create-mls-self-conversation" createMLSSelfConversation + <@> mkNamedAPI @"create-one-to-one-conversation" createOne2OneConversation + <@> mkNamedAPI @"add-members-to-conversation-unqualified" addMembersUnqualified + <@> mkNamedAPI @"add-members-to-conversation-unqualified2" addMembersUnqualifiedV2 + <@> mkNamedAPI @"add-members-to-conversation" addMembers + <@> mkNamedAPI @"join-conversation-by-id-unqualified" (joinConversationById @Cassandra) + <@> mkNamedAPI @"join-conversation-by-code-unqualified" (joinConversationByReusableCode @Cassandra) + <@> mkNamedAPI @"code-check" (checkReusableCode @Cassandra) + <@> mkNamedAPI @"create-conversation-code-unqualified" (addCodeUnqualified @Cassandra) + <@> mkNamedAPI @"get-conversation-guest-links-status" (getConversationGuestLinksStatus @Cassandra) + <@> mkNamedAPI @"remove-code-unqualified" rmCodeUnqualified + <@> mkNamedAPI @"get-code" (getCode @Cassandra) + <@> mkNamedAPI @"member-typing-unqualified" isTypingUnqualified + <@> mkNamedAPI @"remove-member-unqualified" removeMemberUnqualified + <@> mkNamedAPI @"remove-member" removeMemberQualified + <@> mkNamedAPI @"update-other-member-unqualified" updateOtherMemberUnqualified + <@> mkNamedAPI @"update-other-member" updateOtherMember + <@> mkNamedAPI @"update-conversation-name-deprecated" updateUnqualifiedConversationName + <@> mkNamedAPI @"update-conversation-name-unqualified" updateUnqualifiedConversationName + <@> mkNamedAPI @"update-conversation-name" updateConversationName + <@> mkNamedAPI @"update-conversation-message-timer-unqualified" updateConversationMessageTimerUnqualified + <@> mkNamedAPI @"update-conversation-message-timer" updateConversationMessageTimer + <@> mkNamedAPI @"update-conversation-receipt-mode-unqualified" updateConversationReceiptModeUnqualified + <@> mkNamedAPI @"update-conversation-receipt-mode" updateConversationReceiptMode + <@> mkNamedAPI @"update-conversation-access-unqualified" updateConversationAccessUnqualified + <@> mkNamedAPI @"update-conversation-access" updateConversationAccess + <@> mkNamedAPI @"get-conversation-self-unqualified" getLocalSelf + <@> mkNamedAPI @"update-conversation-self-unqualified" updateUnqualifiedSelfMember + <@> mkNamedAPI @"update-conversation-self" updateSelfMember diff --git a/services/galley/src/Galley/API/Public/CustomBackend.hs b/services/galley/src/Galley/API/Public/CustomBackend.hs new file mode 100644 index 0000000000..23b79abedf --- /dev/null +++ b/services/galley/src/Galley/API/Public/CustomBackend.hs @@ -0,0 +1,26 @@ +-- 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 Galley.API.Public.CustomBackend where + +import Galley.API.CustomBackend +import Galley.App +import Wire.API.Routes.API +import Wire.API.Routes.Public.Galley.CustomBackend + +customBackendAPI :: API CustomBackendAPI GalleyEffects +customBackendAPI = mkNamedAPI @"get-custom-backend-by-domain" getCustomBackendByDomain diff --git a/services/galley/src/Galley/API/Public/Feature.hs b/services/galley/src/Galley/API/Public/Feature.hs new file mode 100644 index 0000000000..2d4f06ea85 --- /dev/null +++ b/services/galley/src/Galley/API/Public/Feature.hs @@ -0,0 +1,76 @@ +-- 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 Galley.API.Public.Feature where + +import Galley.API.Teams +import Galley.API.Teams.Features +import Galley.App +import Galley.Cassandra.TeamFeatures +import Imports +import Wire.API.Routes.API +import Wire.API.Routes.Public.Galley.Feature +import Wire.API.Team.Feature + +featureAPI :: API FeatureAPI GalleyEffects +featureAPI = + mkNamedAPI @'("get", SSOConfig) (getFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("get", LegalholdConfig) (getFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("put", LegalholdConfig) (setFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("get", SearchVisibilityAvailableConfig) (getFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("put", SearchVisibilityAvailableConfig) (setFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("get-deprecated", SearchVisibilityAvailableConfig) (getFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("put-deprecated", SearchVisibilityAvailableConfig) (setFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @"get-search-visibility" getSearchVisibility + <@> mkNamedAPI @"set-search-visibility" (setSearchVisibility @Cassandra (featureEnabledForTeam @Cassandra @SearchVisibilityAvailableConfig)) + <@> mkNamedAPI @'("get", ValidateSAMLEmailsConfig) (getFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("get-deprecated", ValidateSAMLEmailsConfig) (getFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("get", DigitalSignaturesConfig) (getFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("get-deprecated", DigitalSignaturesConfig) (getFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("get", AppLockConfig) (getFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("put", AppLockConfig) (setFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("get", FileSharingConfig) (getFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("put", FileSharingConfig) (setFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("get", ClassifiedDomainsConfig) (getFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("get", ConferenceCallingConfig) (getFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("get", SelfDeletingMessagesConfig) (getFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("put", SelfDeletingMessagesConfig) (setFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("get", GuestLinksConfig) (getFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("put", GuestLinksConfig) (setFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("get", SndFactorPasswordChallengeConfig) (getFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("put", SndFactorPasswordChallengeConfig) (setFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("get", MLSConfig) (getFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("put", MLSConfig) (setFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("get", ExposeInvitationURLsToTeamAdminConfig) (getFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("put", ExposeInvitationURLsToTeamAdminConfig) (setFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("get", SearchVisibilityInboundConfig) (getFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @'("put", SearchVisibilityInboundConfig) (setFeatureStatus @Cassandra . DoAuth) + <@> mkNamedAPI @"get-all-feature-configs-for-user" (getAllFeatureConfigsForUser @Cassandra) + <@> mkNamedAPI @"get-all-feature-configs-for-team" (getAllFeatureConfigsForTeam @Cassandra) + <@> mkNamedAPI @'("get-config", LegalholdConfig) (getFeatureStatusForUser @Cassandra) + <@> mkNamedAPI @'("get-config", SSOConfig) (getFeatureStatusForUser @Cassandra) + <@> mkNamedAPI @'("get-config", SearchVisibilityAvailableConfig) (getFeatureStatusForUser @Cassandra) + <@> mkNamedAPI @'("get-config", ValidateSAMLEmailsConfig) (getFeatureStatusForUser @Cassandra) + <@> mkNamedAPI @'("get-config", DigitalSignaturesConfig) (getFeatureStatusForUser @Cassandra) + <@> mkNamedAPI @'("get-config", AppLockConfig) (getFeatureStatusForUser @Cassandra) + <@> mkNamedAPI @'("get-config", FileSharingConfig) (getFeatureStatusForUser @Cassandra) + <@> mkNamedAPI @'("get-config", ClassifiedDomainsConfig) (getFeatureStatusForUser @Cassandra) + <@> mkNamedAPI @'("get-config", ConferenceCallingConfig) (getFeatureStatusForUser @Cassandra) + <@> mkNamedAPI @'("get-config", SelfDeletingMessagesConfig) (getFeatureStatusForUser @Cassandra) + <@> mkNamedAPI @'("get-config", GuestLinksConfig) (getFeatureStatusForUser @Cassandra) + <@> mkNamedAPI @'("get-config", SndFactorPasswordChallengeConfig) (getFeatureStatusForUser @Cassandra) + <@> mkNamedAPI @'("get-config", MLSConfig) (getFeatureStatusForUser @Cassandra) diff --git a/services/galley/src/Galley/API/Public/LegalHold.hs b/services/galley/src/Galley/API/Public/LegalHold.hs new file mode 100644 index 0000000000..21d658d217 --- /dev/null +++ b/services/galley/src/Galley/API/Public/LegalHold.hs @@ -0,0 +1,35 @@ +-- 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 Galley.API.Public.LegalHold where + +import Galley.API.LegalHold +import Galley.App +import Galley.Cassandra.TeamFeatures +import Wire.API.Routes.API +import Wire.API.Routes.Public.Galley.LegalHold + +legalHoldAPI :: API LegalHoldAPI GalleyEffects +legalHoldAPI = + mkNamedAPI @"create-legal-hold-settings" (createSettings @Cassandra) + <@> mkNamedAPI @"get-legal-hold-settings" (getSettings @Cassandra) + <@> mkNamedAPI @"delete-legal-hold-settings" (removeSettingsInternalPaging @Cassandra) + <@> mkNamedAPI @"get-legal-hold" getUserStatus + <@> mkNamedAPI @"consent-to-legal-hold" grantConsent + <@> mkNamedAPI @"request-legal-hold-device" (requestDevice @Cassandra) + <@> mkNamedAPI @"disable-legal-hold-for-user" disableForUser + <@> mkNamedAPI @"approve-legal-hold-device" (approveDevice @Cassandra) diff --git a/services/galley/src/Galley/API/Public/MLS.hs b/services/galley/src/Galley/API/Public/MLS.hs new file mode 100644 index 0000000000..93bd240b77 --- /dev/null +++ b/services/galley/src/Galley/API/Public/MLS.hs @@ -0,0 +1,31 @@ +-- 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 Galley.API.Public.MLS where + +import Galley.API.MLS +import Galley.App +import Wire.API.Routes.API +import Wire.API.Routes.Public.Galley.MLS + +mlsAPI :: API MLSAPI GalleyEffects +mlsAPI = + mkNamedAPI @"mls-welcome-message" postMLSWelcomeFromLocalUser + <@> mkNamedAPI @"mls-message-v1" postMLSMessageFromLocalUserV1 + <@> mkNamedAPI @"mls-message" postMLSMessageFromLocalUser + <@> mkNamedAPI @"mls-commit-bundle" postMLSCommitBundleFromLocalUser + <@> mkNamedAPI @"mls-public-keys" getMLSPublicKeys diff --git a/services/galley/src/Galley/API/Public/Messaging.hs b/services/galley/src/Galley/API/Public/Messaging.hs new file mode 100644 index 0000000000..806484ae90 --- /dev/null +++ b/services/galley/src/Galley/API/Public/Messaging.hs @@ -0,0 +1,30 @@ +-- 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 Galley.API.Public.Messaging where + +import Galley.API.Update +import Galley.App +import Wire.API.Routes.API +import Wire.API.Routes.Public.Galley.Messaging + +messagingAPI :: API MessagingAPI GalleyEffects +messagingAPI = + mkNamedAPI @"post-otr-message-unqualified" postOtrMessageUnqualified + <@> mkNamedAPI @"post-otr-broadcast-unqualified" postOtrBroadcastUnqualified + <@> mkNamedAPI @"post-proteus-message" postProteusMessage + <@> mkNamedAPI @"post-proteus-broadcast" postProteusBroadcast diff --git a/services/galley/src/Galley/API/Public/Servant.hs b/services/galley/src/Galley/API/Public/Servant.hs index ef8640cbcc..e7eae6adde 100644 --- a/services/galley/src/Galley/API/Public/Servant.hs +++ b/services/galley/src/Galley/API/Public/Servant.hs @@ -17,181 +17,29 @@ module Galley.API.Public.Servant (mkNamedAPI, servantSitemap) where -import Galley.API.Create -import Galley.API.CustomBackend -import Galley.API.LegalHold -import Galley.API.MLS -import Galley.API.MLS.GroupInfo -import Galley.API.Query -import Galley.API.Teams -import Galley.API.Teams.Features -import Galley.API.Update +import Galley.API.Public.Bot +import Galley.API.Public.Conversation +import Galley.API.Public.CustomBackend +import Galley.API.Public.Feature +import Galley.API.Public.LegalHold +import Galley.API.Public.MLS +import Galley.API.Public.Messaging +import Galley.API.Public.Team +import Galley.API.Public.TeamConversation +import Galley.API.Public.TeamMember import Galley.App -import Galley.Cassandra.TeamFeatures -import Imports import Wire.API.Routes.API import Wire.API.Routes.Public.Galley -import Wire.API.Team.Feature servantSitemap :: API ServantAPI GalleyEffects servantSitemap = - conversations - <@> teamConversations - <@> messaging - <@> bot - <@> team - <@> features - <@> mls - <@> customBackend - <@> legalHold - <@> teamMember - where - conversations = - mkNamedAPI @"get-unqualified-conversation" getUnqualifiedConversation - <@> mkNamedAPI @"get-unqualified-conversation-legalhold-alias" getUnqualifiedConversation - <@> mkNamedAPI @"get-conversation" getConversation - <@> mkNamedAPI @"get-conversation-roles" getConversationRoles - <@> mkNamedAPI @"get-group-info" getGroupInfo - <@> mkNamedAPI @"list-conversation-ids-unqualified" conversationIdsPageFromUnqualified - <@> mkNamedAPI @"list-conversation-ids" conversationIdsPageFrom - <@> mkNamedAPI @"get-conversations" getConversations - <@> mkNamedAPI @"list-conversations-v1" listConversations - <@> mkNamedAPI @"list-conversations" listConversations - <@> mkNamedAPI @"get-conversation-by-reusable-code" (getConversationByReusableCode @Cassandra) - <@> mkNamedAPI @"create-group-conversation" createGroupConversation - <@> mkNamedAPI @"create-self-conversation" createProteusSelfConversation - <@> mkNamedAPI @"create-mls-self-conversation" createMLSSelfConversation - <@> mkNamedAPI @"create-one-to-one-conversation" createOne2OneConversation - <@> mkNamedAPI @"add-members-to-conversation-unqualified" addMembersUnqualified - <@> mkNamedAPI @"add-members-to-conversation-unqualified2" addMembersUnqualifiedV2 - <@> mkNamedAPI @"add-members-to-conversation" addMembers - <@> mkNamedAPI @"join-conversation-by-id-unqualified" (joinConversationById @Cassandra) - <@> mkNamedAPI @"join-conversation-by-code-unqualified" (joinConversationByReusableCode @Cassandra) - <@> mkNamedAPI @"code-check" (checkReusableCode @Cassandra) - <@> mkNamedAPI @"create-conversation-code-unqualified" (addCodeUnqualified @Cassandra) - <@> mkNamedAPI @"get-conversation-guest-links-status" (getConversationGuestLinksStatus @Cassandra) - <@> mkNamedAPI @"remove-code-unqualified" rmCodeUnqualified - <@> mkNamedAPI @"get-code" (getCode @Cassandra) - <@> mkNamedAPI @"member-typing-unqualified" isTypingUnqualified - <@> mkNamedAPI @"remove-member-unqualified" removeMemberUnqualified - <@> mkNamedAPI @"remove-member" removeMemberQualified - <@> mkNamedAPI @"update-other-member-unqualified" updateOtherMemberUnqualified - <@> mkNamedAPI @"update-other-member" updateOtherMember - <@> mkNamedAPI @"update-conversation-name-deprecated" updateUnqualifiedConversationName - <@> mkNamedAPI @"update-conversation-name-unqualified" updateUnqualifiedConversationName - <@> mkNamedAPI @"update-conversation-name" updateConversationName - <@> mkNamedAPI @"update-conversation-message-timer-unqualified" updateConversationMessageTimerUnqualified - <@> mkNamedAPI @"update-conversation-message-timer" updateConversationMessageTimer - <@> mkNamedAPI @"update-conversation-receipt-mode-unqualified" updateConversationReceiptModeUnqualified - <@> mkNamedAPI @"update-conversation-receipt-mode" updateConversationReceiptMode - <@> mkNamedAPI @"update-conversation-access-unqualified" updateConversationAccessUnqualified - <@> mkNamedAPI @"update-conversation-access" updateConversationAccess - <@> mkNamedAPI @"get-conversation-self-unqualified" getLocalSelf - <@> mkNamedAPI @"update-conversation-self-unqualified" updateUnqualifiedSelfMember - <@> mkNamedAPI @"update-conversation-self" updateSelfMember - - teamConversations :: API TeamConversationAPI GalleyEffects - teamConversations = - mkNamedAPI @"get-team-conversation-roles" getTeamConversationRoles - <@> mkNamedAPI @"get-team-conversations" getTeamConversations - <@> mkNamedAPI @"get-team-conversation" getTeamConversation - <@> mkNamedAPI @"delete-team-conversation" deleteTeamConversation - - messaging :: API MessagingAPI GalleyEffects - messaging = - mkNamedAPI @"post-otr-message-unqualified" postOtrMessageUnqualified - <@> mkNamedAPI @"post-otr-broadcast-unqualified" postOtrBroadcastUnqualified - <@> mkNamedAPI @"post-proteus-message" postProteusMessage - <@> mkNamedAPI @"post-proteus-broadcast" postProteusBroadcast - - bot :: API BotAPI GalleyEffects - bot = mkNamedAPI @"post-bot-message-unqualified" postBotMessageUnqualified - - team = - mkNamedAPI @"create-non-binding-team" createNonBindingTeamH - <@> mkNamedAPI @"update-team" updateTeamH - <@> mkNamedAPI @"get-teams" getManyTeams - <@> mkNamedAPI @"get-team" getTeamH - <@> mkNamedAPI @"delete-team" deleteTeam - - features :: API FeatureAPI GalleyEffects - features = - mkNamedAPI @'("get", SSOConfig) (getFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("get", LegalholdConfig) (getFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("put", LegalholdConfig) (setFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("get", SearchVisibilityAvailableConfig) (getFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("put", SearchVisibilityAvailableConfig) (setFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("get-deprecated", SearchVisibilityAvailableConfig) (getFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("put-deprecated", SearchVisibilityAvailableConfig) (setFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @"get-search-visibility" getSearchVisibility - <@> mkNamedAPI @"set-search-visibility" (setSearchVisibility @Cassandra (featureEnabledForTeam @Cassandra @SearchVisibilityAvailableConfig)) - <@> mkNamedAPI @'("get", ValidateSAMLEmailsConfig) (getFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("get-deprecated", ValidateSAMLEmailsConfig) (getFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("get", DigitalSignaturesConfig) (getFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("get-deprecated", DigitalSignaturesConfig) (getFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("get", AppLockConfig) (getFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("put", AppLockConfig) (setFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("get", FileSharingConfig) (getFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("put", FileSharingConfig) (setFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("get", ClassifiedDomainsConfig) (getFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("get", ConferenceCallingConfig) (getFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("get", SelfDeletingMessagesConfig) (getFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("put", SelfDeletingMessagesConfig) (setFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("get", GuestLinksConfig) (getFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("put", GuestLinksConfig) (setFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("get", SndFactorPasswordChallengeConfig) (getFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("put", SndFactorPasswordChallengeConfig) (setFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("get", MLSConfig) (getFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("put", MLSConfig) (setFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("get", ExposeInvitationURLsToTeamAdminConfig) (getFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("put", ExposeInvitationURLsToTeamAdminConfig) (setFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("get", SearchVisibilityInboundConfig) (getFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @'("put", SearchVisibilityInboundConfig) (setFeatureStatus @Cassandra . DoAuth) - <@> mkNamedAPI @"get-all-feature-configs-for-user" (getAllFeatureConfigsForUser @Cassandra) - <@> mkNamedAPI @"get-all-feature-configs-for-team" (getAllFeatureConfigsForTeam @Cassandra) - <@> mkNamedAPI @'("get-config", LegalholdConfig) (getFeatureStatusForUser @Cassandra) - <@> mkNamedAPI @'("get-config", SSOConfig) (getFeatureStatusForUser @Cassandra) - <@> mkNamedAPI @'("get-config", SearchVisibilityAvailableConfig) (getFeatureStatusForUser @Cassandra) - <@> mkNamedAPI @'("get-config", ValidateSAMLEmailsConfig) (getFeatureStatusForUser @Cassandra) - <@> mkNamedAPI @'("get-config", DigitalSignaturesConfig) (getFeatureStatusForUser @Cassandra) - <@> mkNamedAPI @'("get-config", AppLockConfig) (getFeatureStatusForUser @Cassandra) - <@> mkNamedAPI @'("get-config", FileSharingConfig) (getFeatureStatusForUser @Cassandra) - <@> mkNamedAPI @'("get-config", ClassifiedDomainsConfig) (getFeatureStatusForUser @Cassandra) - <@> mkNamedAPI @'("get-config", ConferenceCallingConfig) (getFeatureStatusForUser @Cassandra) - <@> mkNamedAPI @'("get-config", SelfDeletingMessagesConfig) (getFeatureStatusForUser @Cassandra) - <@> mkNamedAPI @'("get-config", GuestLinksConfig) (getFeatureStatusForUser @Cassandra) - <@> mkNamedAPI @'("get-config", SndFactorPasswordChallengeConfig) (getFeatureStatusForUser @Cassandra) - <@> mkNamedAPI @'("get-config", MLSConfig) (getFeatureStatusForUser @Cassandra) - - mls :: API MLSAPI GalleyEffects - mls = - mkNamedAPI @"mls-welcome-message" postMLSWelcomeFromLocalUser - <@> mkNamedAPI @"mls-message-v1" postMLSMessageFromLocalUserV1 - <@> mkNamedAPI @"mls-message" postMLSMessageFromLocalUser - <@> mkNamedAPI @"mls-commit-bundle" postMLSCommitBundleFromLocalUser - <@> mkNamedAPI @"mls-public-keys" getMLSPublicKeys - - customBackend :: API CustomBackendAPI GalleyEffects - customBackend = mkNamedAPI @"get-custom-backend-by-domain" getCustomBackendByDomain - - legalHold :: API LegalHoldAPI GalleyEffects - legalHold = - mkNamedAPI @"create-legal-hold-settings" (createSettings @Cassandra) - <@> mkNamedAPI @"get-legal-hold-settings" (getSettings @Cassandra) - <@> mkNamedAPI @"delete-legal-hold-settings" (removeSettingsInternalPaging @Cassandra) - <@> mkNamedAPI @"get-legal-hold" getUserStatus - <@> mkNamedAPI @"consent-to-legal-hold" grantConsent - <@> mkNamedAPI @"request-legal-hold-device" (requestDevice @Cassandra) - <@> mkNamedAPI @"disable-legal-hold-for-user" disableForUser - <@> mkNamedAPI @"approve-legal-hold-device" (approveDevice @Cassandra) - - teamMember :: API TeamMemberAPI GalleyEffects - teamMember = - mkNamedAPI @"get-team-members" getTeamMembers - <@> mkNamedAPI @"get-team-member" getTeamMember - <@> mkNamedAPI @"get-team-members-by-ids" bulkGetTeamMembers - <@> mkNamedAPI @"add-team-member" (addTeamMember @Cassandra) - <@> mkNamedAPI @"delete-team-member" deleteTeamMember - <@> mkNamedAPI @"delete-non-binding-team-member" deleteNonBindingTeamMember - <@> mkNamedAPI @"update-team-member" updateTeamMember - <@> mkNamedAPI @"get-team-members-csv" getTeamMembersCSV + conversationAPI + <@> teamConversationAPI + <@> messagingAPI + <@> botAPI + <@> teamAPI + <@> featureAPI + <@> mlsAPI + <@> customBackendAPI + <@> legalHoldAPI + <@> teamMemberAPI diff --git a/services/galley/src/Galley/API/Public/Team.hs b/services/galley/src/Galley/API/Public/Team.hs new file mode 100644 index 0000000000..9cea78cea8 --- /dev/null +++ b/services/galley/src/Galley/API/Public/Team.hs @@ -0,0 +1,31 @@ +-- 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 Galley.API.Public.Team where + +import Galley.API.Teams +import Galley.App +import Wire.API.Routes.API +import Wire.API.Routes.Public.Galley.Team + +teamAPI :: API TeamAPI GalleyEffects +teamAPI = + mkNamedAPI @"create-non-binding-team" createNonBindingTeamH + <@> mkNamedAPI @"update-team" updateTeamH + <@> mkNamedAPI @"get-teams" getManyTeams + <@> mkNamedAPI @"get-team" getTeamH + <@> mkNamedAPI @"delete-team" deleteTeam diff --git a/services/galley/src/Galley/API/Public/TeamConversation.hs b/services/galley/src/Galley/API/Public/TeamConversation.hs new file mode 100644 index 0000000000..359c69f1db --- /dev/null +++ b/services/galley/src/Galley/API/Public/TeamConversation.hs @@ -0,0 +1,30 @@ +-- 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 Galley.API.Public.TeamConversation where + +import Galley.API.Teams +import Galley.App +import Wire.API.Routes.API +import Wire.API.Routes.Public.Galley.TeamConversation + +teamConversationAPI :: API TeamConversationAPI GalleyEffects +teamConversationAPI = + mkNamedAPI @"get-team-conversation-roles" getTeamConversationRoles + <@> mkNamedAPI @"get-team-conversations" getTeamConversations + <@> mkNamedAPI @"get-team-conversation" getTeamConversation + <@> mkNamedAPI @"delete-team-conversation" deleteTeamConversation diff --git a/services/galley/src/Galley/API/Public/TeamMember.hs b/services/galley/src/Galley/API/Public/TeamMember.hs new file mode 100644 index 0000000000..af7e761c66 --- /dev/null +++ b/services/galley/src/Galley/API/Public/TeamMember.hs @@ -0,0 +1,35 @@ +-- 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 Galley.API.Public.TeamMember where + +import Galley.API.Teams +import Galley.App +import Galley.Cassandra.TeamFeatures +import Wire.API.Routes.API +import Wire.API.Routes.Public.Galley.TeamMember + +teamMemberAPI :: API TeamMemberAPI GalleyEffects +teamMemberAPI = + mkNamedAPI @"get-team-members" getTeamMembers + <@> mkNamedAPI @"get-team-member" getTeamMember + <@> mkNamedAPI @"get-team-members-by-ids" bulkGetTeamMembers + <@> mkNamedAPI @"add-team-member" (addTeamMember @Cassandra) + <@> mkNamedAPI @"delete-team-member" deleteTeamMember + <@> mkNamedAPI @"delete-non-binding-team-member" deleteNonBindingTeamMember + <@> mkNamedAPI @"update-team-member" updateTeamMember + <@> mkNamedAPI @"get-team-members-csv" getTeamMembersCSV diff --git a/services/galley/src/Galley/API/Teams.hs b/services/galley/src/Galley/API/Teams.hs index 32caec47d1..7e79d38213 100644 --- a/services/galley/src/Galley/API/Teams.hs +++ b/services/galley/src/Galley/API/Teams.hs @@ -135,14 +135,14 @@ import Wire.API.Federation.Error import qualified Wire.API.Message as Conv import qualified Wire.API.Notification as Public import Wire.API.Routes.MultiTablePaging (MultiTablePage (MultiTablePage), MultiTablePagingState (mtpsState)) -import Wire.API.Routes.Public.Galley +import Wire.API.Routes.Public.Galley.TeamMember import Wire.API.Team import qualified Wire.API.Team as Public import Wire.API.Team.Conversation import qualified Wire.API.Team.Conversation as Public import Wire.API.Team.Export (TeamExportUser (..)) import Wire.API.Team.Feature -import Wire.API.Team.Member (HardTruncationLimit, ListType (ListComplete, ListTruncated), NewTeamMember, TeamMember, TeamMemberList, TeamMemberListOptPerms, TeamMemberOptPerms, TeamMembersPage (..), TeamMembersPagingState, hardTruncationLimit, invitation, nPermissions, nUserId, newTeamMemberList, ntmNewTeamMember, permissions, setOptionalPerms, setOptionalPermsMany, teamMemberListType, teamMemberPagingState, teamMembers, tmdAuthPassword, userId) +import Wire.API.Team.Member import qualified Wire.API.Team.Member as Public import Wire.API.Team.Permission (Perm (..), Permissions (..), SPerm (..), copy, fullPermissions, self) import Wire.API.Team.Role diff --git a/services/galley/src/Galley/API/Update.hs b/services/galley/src/Galley/API/Update.hs index 0ee2281513..91a0c14b37 100644 --- a/services/galley/src/Galley/API/Update.hs +++ b/services/galley/src/Galley/API/Update.hs @@ -128,7 +128,7 @@ import Wire.API.Federation.API.Galley import Wire.API.Federation.Error import Wire.API.Message import Wire.API.Provider.Service (ServiceRef) -import Wire.API.Routes.Public.Galley +import Wire.API.Routes.Public.Galley.Messaging import Wire.API.Routes.Public.Util (UpdateResult (..)) import Wire.API.ServantProto (RawProto (..)) import Wire.API.Team.Feature hiding (setStatus) diff --git a/services/galley/src/Galley/API/Util.hs b/services/galley/src/Galley/API/Util.hs index c35b4f8a48..29d03b8151 100644 --- a/services/galley/src/Galley/API/Util.hs +++ b/services/galley/src/Galley/API/Util.hs @@ -76,7 +76,7 @@ import Wire.API.Event.Conversation import Wire.API.Federation.API import Wire.API.Federation.API.Galley import Wire.API.Federation.Error -import Wire.API.Routes.Public.Galley +import Wire.API.Routes.Public.Galley.Conversation import Wire.API.Routes.Public.Util import Wire.API.Team.Member import Wire.API.Team.Role