diff --git a/changelog.d/5-internal/user-events b/changelog.d/5-internal/user-events new file mode 100644 index 00000000000..b2e75283007 --- /dev/null +++ b/changelog.d/5-internal/user-events @@ -0,0 +1 @@ +Use schema-profunctor for user event serialisation and introduce golden tests diff --git a/libs/brig-types/brig-types.cabal b/libs/brig-types/brig-types.cabal index d7a933c90bb..4d4d0640dd1 100644 --- a/libs/brig-types/brig-types.cabal +++ b/libs/brig-types/brig-types.cabal @@ -23,7 +23,6 @@ library Brig.Types.Team.LegalHold Brig.Types.Test.Arbitrary Brig.Types.User - Brig.Types.User.Event other-modules: Paths_brig_types hs-source-dirs: src @@ -85,7 +84,6 @@ library , imports , QuickCheck >=2.9 , text >=0.11 - , tinylog , types-common >=0.16 , wire-api diff --git a/libs/brig-types/default.nix b/libs/brig-types/default.nix index 173b83591b0..78932b5d379 100644 --- a/libs/brig-types/default.nix +++ b/libs/brig-types/default.nix @@ -19,7 +19,6 @@ , tasty-hunit , tasty-quickcheck , text -, tinylog , types-common , wire-api }: @@ -38,7 +37,6 @@ mkDerivation { imports QuickCheck text - tinylog types-common wire-api ]; diff --git a/libs/brig-types/src/Brig/Types/User/Event.hs b/libs/brig-types/src/Brig/Types/User/Event.hs deleted file mode 100644 index 96aed364a76..00000000000 --- a/libs/brig-types/src/Brig/Types/User/Event.hs +++ /dev/null @@ -1,223 +0,0 @@ -{-# LANGUAGE RecordWildCards #-} - --- 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 Brig.Types.User.Event where - -import Data.ByteString.Conversion -import Data.Handle (Handle) -import Data.Id -import Data.Qualified -import Imports -import System.Logger.Class -import Wire.API.Connection -import Wire.API.Properties -import Wire.API.User -import Wire.API.User.Client -import Wire.API.User.Client.Prekey - -data Event - = UserEvent !UserEvent - | ConnectionEvent !ConnectionEvent - | PropertyEvent !PropertyEvent - | ClientEvent !ClientEvent - -data UserEvent - = UserCreated !User - | -- | A user is activated when the first user identity (email address or phone number) - -- is verified. {#RefActivationEvent} - UserActivated !User - | -- | Account & API access of a user has been suspended. - UserSuspended !UserId - | -- | Account & API access of a previously suspended user - -- has been restored. - UserResumed !UserId - | -- | The user account has been deleted. - UserDeleted !(Qualified UserId) - | UserUpdated !UserUpdatedData - | UserIdentityUpdated !UserIdentityUpdatedData - | UserIdentityRemoved !UserIdentityRemovedData - | UserLegalHoldDisabled !UserId - | UserLegalHoldEnabled !UserId - | LegalHoldClientRequested LegalHoldClientRequestedData - -data ConnectionEvent = ConnectionUpdated - { ucConn :: !UserConnection, - ucPrev :: !(Maybe Relation), - ucName :: !(Maybe Name) - } - -data PropertyEvent - = PropertySet !UserId !PropertyKey !PropertyValue - | PropertyDeleted !UserId !PropertyKey - | PropertiesCleared !UserId - -data ClientEvent - = ClientAdded !UserId !Client - | ClientRemoved !UserId !ClientId - -data UserUpdatedData = UserUpdatedData - { eupId :: !UserId, - eupName :: !(Maybe Name), - -- | DEPRECATED - eupPict :: !(Maybe Pict), - eupAccentId :: !(Maybe ColourId), - eupAssets :: !(Maybe [Asset]), - eupHandle :: !(Maybe Handle), - eupLocale :: !(Maybe Locale), - eupManagedBy :: !(Maybe ManagedBy), - eupSSOId :: !(Maybe UserSSOId), - eupSSOIdRemoved :: Bool, - eupSupportedProtocols :: !(Maybe (Set BaseProtocolTag)) - } - deriving stock (Show) - -data UserIdentityUpdatedData = UserIdentityUpdatedData - { eiuId :: !UserId, - eiuEmail :: !(Maybe Email), - eiuPhone :: !(Maybe Phone) - } - deriving stock (Show) - -data UserIdentityRemovedData = UserIdentityRemovedData - { eirId :: !UserId, - eirEmail :: !(Maybe Email), - eirPhone :: !(Maybe Phone) - } - deriving stock (Show) - -data LegalHoldClientRequestedData = LegalHoldClientRequestedData - { -- | the user that is under legalhold - lhcTargetUser :: !UserId, - -- | the last prekey of the user that is under legalhold - lhcLastPrekey :: !LastPrekey, - -- | the client id of the legalhold device - lhcClientId :: !ClientId - } - deriving stock (Show) - -emailRemoved :: UserId -> Email -> UserEvent -emailRemoved u e = - UserIdentityRemoved $ UserIdentityRemovedData u (Just e) Nothing - -phoneRemoved :: UserId -> Phone -> UserEvent -phoneRemoved u p = - UserIdentityRemoved $ UserIdentityRemovedData u Nothing (Just p) - -emailUpdated :: UserId -> Email -> UserEvent -emailUpdated u e = - UserIdentityUpdated $ UserIdentityUpdatedData u (Just e) Nothing - -phoneUpdated :: UserId -> Phone -> UserEvent -phoneUpdated u p = - UserIdentityUpdated $ UserIdentityUpdatedData u Nothing (Just p) - -handleUpdated :: UserId -> Handle -> UserEvent -handleUpdated u h = - UserUpdated $ (emptyUserUpdatedData u) {eupHandle = Just h} - -localeUpdate :: UserId -> Locale -> UserEvent -localeUpdate u loc = - UserUpdated $ (emptyUserUpdatedData u) {eupLocale = Just loc} - -managedByUpdate :: UserId -> ManagedBy -> UserEvent -managedByUpdate u mb = - UserUpdated $ (emptyUserUpdatedData u) {eupManagedBy = Just mb} - -supportedProtocolUpdate :: UserId -> Set BaseProtocolTag -> UserEvent -supportedProtocolUpdate u prots = - UserUpdated $ (emptyUserUpdatedData u) {eupSupportedProtocols = Just prots} - -profileUpdated :: UserId -> UserUpdate -> UserEvent -profileUpdated u UserUpdate {..} = - UserUpdated $ - (emptyUserUpdatedData u) - { eupName = uupName, - eupPict = uupPict, - eupAccentId = uupAccentId, - eupAssets = uupAssets - } - -emptyUpdate :: UserId -> UserEvent -emptyUpdate = UserUpdated . emptyUserUpdatedData - -emptyUserUpdatedData :: UserId -> UserUpdatedData -emptyUserUpdatedData u = - UserUpdatedData - { eupId = u, - eupName = Nothing, - eupPict = Nothing, - eupAccentId = Nothing, - eupAssets = Nothing, - eupHandle = Nothing, - eupLocale = Nothing, - eupManagedBy = Nothing, - eupSSOId = Nothing, - eupSSOIdRemoved = False, - eupSupportedProtocols = Nothing - } - -connEventUserId :: ConnectionEvent -> UserId -connEventUserId ConnectionUpdated {..} = ucFrom ucConn - -propEventUserId :: PropertyEvent -> UserId -propEventUserId (PropertySet u _ _) = u -propEventUserId (PropertyDeleted u _) = u -propEventUserId (PropertiesCleared u) = u - -logConnection :: UserId -> Qualified UserId -> Msg -> Msg -logConnection from (Qualified toUser toDomain) = - "connection.from" .= toByteString from - ~~ "connection.to" .= toByteString toUser - ~~ "connection.to_domain" .= toByteString toDomain - -logLocalConnection :: UserId -> UserId -> Msg -> Msg -logLocalConnection from to = - "connection.from" .= toByteString from - ~~ "connection.to" .= toByteString to - -instance ToBytes Event where - bytes (UserEvent e) = bytes e - bytes (ConnectionEvent e) = bytes e - bytes (PropertyEvent e) = bytes e - bytes (ClientEvent e) = bytes e - -instance ToBytes UserEvent where - bytes (UserCreated u) = val "user.new: " +++ toByteString (userId u) - bytes (UserActivated u) = val "user.activate: " +++ toByteString (userId u) - bytes (UserUpdated u) = val "user.update: " +++ toByteString (eupId u) - bytes (UserIdentityUpdated u) = val "user.update: " +++ toByteString (eiuId u) - bytes (UserIdentityRemoved u) = val "user.identity-remove: " +++ toByteString (eirId u) - bytes (UserSuspended u) = val "user.suspend: " +++ toByteString u - bytes (UserResumed u) = val "user.resume: " +++ toByteString u - bytes (UserDeleted u) = val "user.delete: " +++ toByteString (qUnqualified u) +++ val "@" +++ toByteString (qDomain u) - bytes (UserLegalHoldDisabled u) = val "user.legalhold-disable: " +++ toByteString u - bytes (UserLegalHoldEnabled u) = val "user.legalhold-enable: " +++ toByteString u - bytes (LegalHoldClientRequested payload) = val "user.legalhold-request: " +++ show payload - -instance ToBytes ConnectionEvent where - bytes e@ConnectionUpdated {} = val "user.connection: " +++ toByteString (connEventUserId e) - -instance ToBytes PropertyEvent where - bytes e@PropertySet {} = val "user.properties-set: " +++ toByteString (propEventUserId e) - bytes e@PropertyDeleted {} = val "user.properties-delete: " +++ toByteString (propEventUserId e) - bytes e@PropertiesCleared {} = val "user.properties-clear: " +++ toByteString (propEventUserId e) - -instance ToBytes ClientEvent where - bytes (ClientAdded u _) = val "user.client-add: " +++ toByteString u - bytes (ClientRemoved u _) = val "user.client-remove: " +++ toByteString u diff --git a/libs/types-common/src/Data/Id.hs b/libs/types-common/src/Data/Id.hs index c707a4ea02d..2f57ba3d920 100644 --- a/libs/types-common/src/Data/Id.hs +++ b/libs/types-common/src/Data/Id.hs @@ -38,6 +38,7 @@ module Data.Id ScimTokenId, parseIdFromText, idToText, + idObjectSchema, IdObject (..), -- * Client IDs @@ -444,7 +445,7 @@ newtype IdObject a = IdObject {fromIdObject :: a} deriving (ToJSON, FromJSON, S.ToSchema) via Schema (IdObject a) instance ToSchema a => ToSchema (IdObject a) where - schema = - object "Id" $ - IdObject - <$> fromIdObject .= field "id" schema + schema = idObjectSchema (IdObject <$> fromIdObject .= schema) + +idObjectSchema :: ValueSchemaP NamedSwaggerDoc a b -> ValueSchemaP NamedSwaggerDoc a b +idObjectSchema sch = object "Id" (field "id" sch) diff --git a/libs/wire-api/default.nix b/libs/wire-api/default.nix index 87dc1bf9b84..581ac8b9612 100644 --- a/libs/wire-api/default.nix +++ b/libs/wire-api/default.nix @@ -93,6 +93,7 @@ , tasty-quickcheck , text , time +, tinylog , transitive-anns , types-common , unliftio @@ -190,6 +191,7 @@ mkDerivation { tagged text time + tinylog transitive-anns types-common unordered-containers diff --git a/libs/wire-api/src/Wire/API/UserEvent.hs b/libs/wire-api/src/Wire/API/UserEvent.hs new file mode 100644 index 00000000000..6ed42e3690c --- /dev/null +++ b/libs/wire-api/src/Wire/API/UserEvent.hs @@ -0,0 +1,451 @@ +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE TemplateHaskell #-} + +-- 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.UserEvent where + +import Control.Lens.TH +import Data.Aeson qualified as A +import Data.Aeson.KeyMap qualified as KM +import Data.ByteString.Conversion +import Data.Handle (Handle) +import Data.Id +import Data.Json.Util +import Data.Qualified +import Data.Schema +import Imports +import System.Logger.Message hiding (field, (.=)) +import Wire.API.Connection +import Wire.API.Properties +import Wire.API.User +import Wire.API.User.Client +import Wire.API.User.Client.Prekey + +data Event + = UserEvent !UserEvent + | ConnectionEvent !ConnectionEvent + | PropertyEvent !PropertyEvent + | ClientEvent !ClientEvent + deriving stock (Eq, Show) + +eventType :: Event -> EventType +eventType (UserEvent (UserCreated _)) = EventTypeUserCreated +eventType (UserEvent (UserActivated _)) = EventTypeUserActivated +eventType (UserEvent (UserSuspended _)) = EventTypeUserSuspended +eventType (UserEvent (UserResumed _)) = EventTypeUserResumed +eventType (UserEvent (UserDeleted _)) = EventTypeUserDeleted +eventType (UserEvent (UserUpdated _)) = EventTypeUserUpdated +eventType (UserEvent (UserIdentityUpdated _)) = EventTypeUserUpdated +eventType (UserEvent (UserIdentityRemoved _)) = EventTypeUserIdentityRemoved +eventType (UserEvent (UserLegalHoldDisabled _)) = EventTypeUserLegalholdDisabled +eventType (UserEvent (UserLegalHoldEnabled _)) = EventTypeUserLegalholdEnabled +eventType (UserEvent (LegalHoldClientRequested _)) = EventTypeUserLegalholdRequested +eventType (ConnectionEvent _) = EventTypeConnection +eventType (PropertyEvent (PropertySet _ _)) = EventTypePropertiesSet +eventType (PropertyEvent (PropertyDeleted _)) = EventTypePropertiesDeleted +eventType (PropertyEvent PropertiesCleared) = EventTypePropertiesCleared +eventType (ClientEvent (ClientAdded _)) = EventTypeClientAdded +eventType (ClientEvent (ClientRemoved _)) = EventTypeClientRemoved + +data EventType + = EventTypeUserCreated + | EventTypeUserActivated + | EventTypeUserUpdated + | EventTypeUserIdentityRemoved + | EventTypeUserSuspended + | EventTypeUserResumed + | EventTypeUserDeleted + | EventTypeUserLegalholdEnabled + | EventTypeUserLegalholdDisabled + | EventTypeUserLegalholdRequested + | EventTypePropertiesSet + | EventTypePropertiesDeleted + | EventTypePropertiesCleared + | EventTypeClientAdded + | EventTypeClientRemoved + | EventTypeConnection + deriving stock (Eq, Enum, Bounded) + +instance ToSchema EventType where + schema = + enum @Text "EventType" $ + mconcat + [ element "user.new" EventTypeUserCreated, + element "user.activate" EventTypeUserActivated, + element "user.update" EventTypeUserUpdated, + element "user.identity-remove" EventTypeUserIdentityRemoved, + element "user.suspend" EventTypeUserSuspended, + element "user.resume" EventTypeUserResumed, + element "user.delete" EventTypeUserDeleted, + element "user.legalhold-enable" EventTypeUserLegalholdEnabled, + element "user.legalhold-disable" EventTypeUserLegalholdDisabled, + element "user.legalhold-request" EventTypeUserLegalholdRequested, + element "user.properties-set" EventTypePropertiesSet, + element "user.properties-delete" EventTypePropertiesDeleted, + element "user.properties-clear" EventTypePropertiesCleared, + element "user.client-add" EventTypeClientAdded, + element "user.client-remove" EventTypeClientRemoved, + element "user.connection" EventTypeConnection + ] + +data UserEvent + = UserCreated !User + | -- | A user is activated when the first user identity (email address or phone number) + -- is verified. {#RefActivationEvent} + UserActivated !User + | -- | Account & API access of a user has been suspended. + UserSuspended !UserId + | -- | Account & API access of a previously suspended user + -- has been restored. + UserResumed !UserId + | -- | The user account has been deleted. + UserDeleted !(Qualified UserId) + | UserUpdated !UserUpdatedData + | UserIdentityUpdated !UserIdentityUpdatedData + | UserIdentityRemoved !UserIdentityRemovedData + | UserLegalHoldDisabled !UserId + | UserLegalHoldEnabled !UserId + | LegalHoldClientRequested LegalHoldClientRequestedData + deriving stock (Eq, Show) + +data ConnectionEvent = ConnectionUpdated + { ucConn :: !UserConnection, + ucName :: !(Maybe Name) + } + deriving stock (Eq, Show) + +data PropertyEvent + = PropertySet !PropertyKey !A.Value + | PropertyDeleted !PropertyKey + | PropertiesCleared + deriving stock (Eq, Show) + +data ClientEvent + = ClientAdded !Client + | ClientRemoved !ClientId + deriving stock (Eq, Show) + +data UserUpdatedData = UserUpdatedData + { eupId :: !UserId, + eupName :: !(Maybe Name), + -- | DEPRECATED + eupPict :: !(Maybe Pict), + eupAccentId :: !(Maybe ColourId), + eupAssets :: !(Maybe [Asset]), + eupHandle :: !(Maybe Handle), + eupLocale :: !(Maybe Locale), + eupManagedBy :: !(Maybe ManagedBy), + eupSSOId :: !(Maybe UserSSOId), + eupSSOIdRemoved :: Bool, + eupSupportedProtocols :: !(Maybe (Set BaseProtocolTag)) + } + deriving stock (Eq, Show) + +data UserIdentityUpdatedData = UserIdentityUpdatedData + { eiuId :: !UserId, + eiuEmail :: !(Maybe Email), + eiuPhone :: !(Maybe Phone) + } + deriving stock (Eq, Show) + +data UserIdentityRemovedData = UserIdentityRemovedData + { eirId :: !UserId, + eirEmail :: !(Maybe Email), + eirPhone :: !(Maybe Phone) + } + deriving stock (Eq, Show) + +data LegalHoldClientRequestedData = LegalHoldClientRequestedData + { -- | the user that is under legalhold + lhcTargetUser :: !UserId, + -- | the last prekey of the user that is under legalhold + lhcLastPrekey :: !LastPrekey, + -- | the client id of the legalhold device + lhcClientId :: !ClientId + } + deriving stock (Eq, Show) + +emailRemoved :: UserId -> Email -> UserEvent +emailRemoved u e = + UserIdentityRemoved $ UserIdentityRemovedData u (Just e) Nothing + +phoneRemoved :: UserId -> Phone -> UserEvent +phoneRemoved u p = + UserIdentityRemoved $ UserIdentityRemovedData u Nothing (Just p) + +emailUpdated :: UserId -> Email -> UserEvent +emailUpdated u e = + UserIdentityUpdated $ UserIdentityUpdatedData u (Just e) Nothing + +phoneUpdated :: UserId -> Phone -> UserEvent +phoneUpdated u p = + UserIdentityUpdated $ UserIdentityUpdatedData u Nothing (Just p) + +handleUpdated :: UserId -> Handle -> UserEvent +handleUpdated u h = + UserUpdated $ (emptyUserUpdatedData u) {eupHandle = Just h} + +localeUpdate :: UserId -> Locale -> UserEvent +localeUpdate u loc = + UserUpdated $ (emptyUserUpdatedData u) {eupLocale = Just loc} + +managedByUpdate :: UserId -> ManagedBy -> UserEvent +managedByUpdate u mb = + UserUpdated $ (emptyUserUpdatedData u) {eupManagedBy = Just mb} + +supportedProtocolUpdate :: UserId -> Set BaseProtocolTag -> UserEvent +supportedProtocolUpdate u prots = + UserUpdated $ (emptyUserUpdatedData u) {eupSupportedProtocols = Just prots} + +profileUpdated :: UserId -> UserUpdate -> UserEvent +profileUpdated u UserUpdate {..} = + UserUpdated $ + (emptyUserUpdatedData u) + { eupName = uupName, + eupPict = uupPict, + eupAccentId = uupAccentId, + eupAssets = uupAssets + } + +emptyUpdate :: UserId -> UserEvent +emptyUpdate = UserUpdated . emptyUserUpdatedData + +emptyUserUpdatedData :: UserId -> UserUpdatedData +emptyUserUpdatedData u = + UserUpdatedData + { eupId = u, + eupName = Nothing, + eupPict = Nothing, + eupAccentId = Nothing, + eupAssets = Nothing, + eupHandle = Nothing, + eupLocale = Nothing, + eupManagedBy = Nothing, + eupSSOId = Nothing, + eupSSOIdRemoved = False, + eupSupportedProtocols = Nothing + } + +-- Event schema + +$(makePrisms ''Event) +$(makePrisms ''UserEvent) +$(makePrisms ''PropertyEvent) +$(makePrisms ''ClientEvent) + +eventObjectSchema :: ObjectSchema SwaggerDoc Event +eventObjectSchema = + snd + <$> bind + (eventType .= field "type" schema) + ( dispatch $ \case + EventTypeUserCreated -> + tag _UserEvent (tag _UserCreated (noId .= userSchema)) + EventTypeUserActivated -> + tag _UserEvent (tag _UserActivated userSchema) + EventTypeUserUpdated -> + tag + _UserEvent + ( tag + _UserUpdated + ( field + "user" + ( object + "UserUpdatedData" + ( UserUpdatedData + <$> eupId .= field "id" schema + <*> eupName .= maybe_ (optField "name" schema) + <*> eupPict .= maybe_ (optField "picture" schema) -- DEPRECATED + <*> eupAccentId .= maybe_ (optField "accent_id" schema) + <*> eupAssets .= maybe_ (optField "assets" (array schema)) + <*> eupHandle .= maybe_ (optField "handle" schema) + <*> eupLocale .= maybe_ (optField "locale" schema) + <*> eupManagedBy .= maybe_ (optField "managed_by" schema) + <*> eupSSOId .= maybe_ (optField "sso_id" genericToSchema) + <*> eupSSOIdRemoved .= field "sso_id_deleted" schema + <*> eupSupportedProtocols + .= maybe_ + ( optField + "supported_protocols" + (set schema) + ) + ) + ) + ) + <|> tag + _UserIdentityUpdated + ( field + "user" + ( object + "UserIdentityUpdatedData" + ( UserIdentityUpdatedData + <$> eiuId .= field "id" schema + <*> eiuEmail .= maybe_ (optField "email" schema) + <*> eiuPhone .= maybe_ (optField "phone" schema) + ) + ) + ) + ) + EventTypeUserIdentityRemoved -> + tag + _UserEvent + ( tag + _UserIdentityRemoved + ( field + "user" + ( object + "UserIdentityRemovedData" + ( UserIdentityRemovedData + <$> eirId .= field "id" schema + <*> eirEmail .= maybe_ (optField "email" schema) + <*> eirPhone .= maybe_ (optField "phone" schema) + ) + ) + ) + ) + EventTypeUserSuspended -> tag _UserEvent (tag _UserSuspended (field "id" schema)) + EventTypeUserResumed -> tag _UserEvent (tag _UserResumed (field "id" schema)) + EventTypeUserDeleted -> + tag + _UserEvent + ( tag + _UserDeleted + ( field "qualified_id" schema + <* qUnqualified .= field "id" schema + ) + ) + EventTypeUserLegalholdEnabled -> + tag + _UserEvent + ( tag _UserLegalHoldEnabled (field "id" schema) + ) + EventTypeUserLegalholdDisabled -> + tag + _UserEvent + ( tag _UserLegalHoldDisabled (field "id" schema) + ) + EventTypeUserLegalholdRequested -> + tag + _UserEvent + ( tag + _LegalHoldClientRequested + ( LegalHoldClientRequestedData + <$> lhcTargetUser .= field "id" schema + <*> lhcLastPrekey .= field "last_prekey" schema + <*> lhcClientId .= field "client" (idObjectSchema schema) + ) + ) + EventTypePropertiesSet -> + tag + _PropertyEvent + ( tag + _PropertySet + ( (,) + <$> fst .= field "key" genericToSchema + <*> snd .= field "value" jsonValue + ) + ) + EventTypePropertiesDeleted -> + tag + _PropertyEvent + ( tag + _PropertyDeleted + (field "key" genericToSchema) + ) + EventTypePropertiesCleared -> + tag + _PropertyEvent + ( tag + _PropertiesCleared + (pure ()) + ) + EventTypeClientAdded -> + tag + _ClientEvent + ( tag + _ClientAdded + (field "client" schema) + ) + EventTypeClientRemoved -> + tag + _ClientEvent + ( tag + _ClientRemoved + (field "client" (idObjectSchema schema)) + ) + EventTypeConnection -> + tag + _ConnectionEvent + ( ConnectionUpdated + <$> ucConn .= field "connection" schema + <*> ucName .= maybe_ (optField "user" (object "UserName" (field "name" schema))) + ) + ) + where + noId :: User -> User + noId u = u {userIdentity = Nothing} + + userSchema :: ObjectSchema SwaggerDoc User + userSchema = field "user" schema + +instance ToJSONObject Event where + toJSONObject = KM.fromList . fold . schemaOut eventObjectSchema + +instance ToSchema Event where + schema = object "UserEvent" eventObjectSchema + +deriving via (Schema Event) instance A.ToJSON Event + +deriving via (Schema Event) instance A.FromJSON Event + +-- Logging + +connEventUserId :: ConnectionEvent -> UserId +connEventUserId ConnectionUpdated {..} = ucFrom ucConn + +instance ToBytes Event where + bytes (UserEvent e) = bytes e + bytes (ConnectionEvent e) = bytes e + bytes (PropertyEvent e) = bytes e + bytes (ClientEvent e) = bytes e + +instance ToBytes UserEvent where + bytes (UserCreated u) = val "user.new: " +++ toByteString (userId u) + bytes (UserActivated u) = val "user.activate: " +++ toByteString (userId u) + bytes (UserUpdated u) = val "user.update: " +++ toByteString (eupId u) + bytes (UserIdentityUpdated u) = val "user.update: " +++ toByteString (eiuId u) + bytes (UserIdentityRemoved u) = val "user.identity-remove: " +++ toByteString (eirId u) + bytes (UserSuspended u) = val "user.suspend: " +++ toByteString u + bytes (UserResumed u) = val "user.resume: " +++ toByteString u + bytes (UserDeleted u) = val "user.delete: " +++ toByteString (qUnqualified u) +++ val "@" +++ toByteString (qDomain u) + bytes (UserLegalHoldDisabled u) = val "user.legalhold-disable: " +++ toByteString u + bytes (UserLegalHoldEnabled u) = val "user.legalhold-enable: " +++ toByteString u + bytes (LegalHoldClientRequested payload) = val "user.legalhold-request: " +++ show payload + +instance ToBytes ConnectionEvent where + bytes e@ConnectionUpdated {} = val "user.connection: " +++ toByteString (connEventUserId e) + +instance ToBytes PropertyEvent where + bytes PropertySet {} = val "user.properties-set" + bytes PropertyDeleted {} = val "user.properties-delete" + bytes PropertiesCleared {} = val "user.properties-clear" + +instance ToBytes ClientEvent where + bytes (ClientAdded _) = val "user.client-add" + bytes (ClientRemoved _) = val "user.client-remove" diff --git a/libs/wire-api/test/golden/Test/Wire/API/Golden/Manual.hs b/libs/wire-api/test/golden/Test/Wire/API/Golden/Manual.hs index ed40d1157bd..40e7f101a28 100644 --- a/libs/wire-api/test/golden/Test/Wire/API/Golden/Manual.hs +++ b/libs/wire-api/test/golden/Test/Wire/API/Golden/Manual.hs @@ -44,6 +44,7 @@ import Test.Wire.API.Golden.Manual.SubConversation import Test.Wire.API.Golden.Manual.TeamSize import Test.Wire.API.Golden.Manual.Token import Test.Wire.API.Golden.Manual.UserClientPrekeyMap +import Test.Wire.API.Golden.Manual.UserEvent import Test.Wire.API.Golden.Manual.UserIdList import Test.Wire.API.Golden.Runner import Wire.API.Routes.Version @@ -197,5 +198,25 @@ tests = [ (testObject_ConversationRemoveMembers_1, "testObject_ConversationRemoveMembers_1.json"), (testObject_ConversationRemoveMembers_2, "testObject_ConversationRemoveMembers_2.json"), (testObject_ConversationRemoveMembers_3, "testObject_ConversationRemoveMembers_3.json") + ], + testGroup "UserEvent" $ + testObjects + [ (testObject_UserEvent_1, "testObject_UserEvent_1.json"), + (testObject_UserEvent_2, "testObject_UserEvent_2.json"), + (testObject_UserEvent_3, "testObject_UserEvent_3.json"), + (testObject_UserEvent_4, "testObject_UserEvent_4.json"), + (testObject_UserEvent_5, "testObject_UserEvent_5.json"), + (testObject_UserEvent_6, "testObject_UserEvent_6.json"), + (testObject_UserEvent_7, "testObject_UserEvent_7.json"), + (testObject_UserEvent_8, "testObject_UserEvent_8.json"), + (testObject_UserEvent_9, "testObject_UserEvent_9.json"), + (testObject_UserEvent_10, "testObject_UserEvent_10.json"), + (testObject_UserEvent_11, "testObject_UserEvent_11.json"), + (testObject_UserEvent_12, "testObject_UserEvent_12.json"), + (testObject_UserEvent_13, "testObject_UserEvent_13.json"), + (testObject_UserEvent_14, "testObject_UserEvent_14.json"), + (testObject_UserEvent_15, "testObject_UserEvent_15.json"), + (testObject_UserEvent_16, "testObject_UserEvent_16.json"), + (testObject_UserEvent_17, "testObject_UserEvent_17.json") ] ] diff --git a/libs/wire-api/test/golden/Test/Wire/API/Golden/Manual/UserEvent.hs b/libs/wire-api/test/golden/Test/Wire/API/Golden/Manual/UserEvent.hs new file mode 100644 index 00000000000..3c063f6fde5 --- /dev/null +++ b/libs/wire-api/test/golden/Test/Wire/API/Golden/Manual/UserEvent.hs @@ -0,0 +1,249 @@ +-- This file is part of the Wire Server implementation. +-- +-- Copyright (C) 2024 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 Test.Wire.API.Golden.Manual.UserEvent + ( testObject_UserEvent_1, + testObject_UserEvent_2, + testObject_UserEvent_3, + testObject_UserEvent_4, + testObject_UserEvent_5, + testObject_UserEvent_6, + testObject_UserEvent_7, + testObject_UserEvent_8, + testObject_UserEvent_9, + testObject_UserEvent_10, + testObject_UserEvent_11, + testObject_UserEvent_12, + testObject_UserEvent_13, + testObject_UserEvent_14, + testObject_UserEvent_15, + testObject_UserEvent_16, + testObject_UserEvent_17, + ) +where + +import Data.Aeson (toJSON) +import Data.Domain +import Data.ISO3166_CountryCodes +import Data.Id +import Data.Json.Util +import Data.LanguageCodes as L +import Data.Qualified +import Data.UUID qualified as UUID (fromString) +import Imports +import Wire.API.Connection +import Wire.API.Properties +import Wire.API.User +import Wire.API.User.Client +import Wire.API.User.Client.Prekey +import Wire.API.UserEvent + +testObject_UserEvent_1 :: Event +testObject_UserEvent_1 = UserEvent (UserCreated alice) + +testObject_UserEvent_2 :: Event +testObject_UserEvent_2 = UserEvent (UserActivated alice) + +testObject_UserEvent_3 :: Event +testObject_UserEvent_3 = + UserEvent + ( UserSuspended + (Id (fromJust (UUID.fromString "dd56271c-181a-43f5-874b-1a8951f7fcc7"))) + ) + +testObject_UserEvent_4 :: Event +testObject_UserEvent_4 = + UserEvent + ( UserSuspended + (Id (fromJust (UUID.fromString "3ddb960e-8ea3-4d14-95bc-97f9da795ca6"))) + ) + +testObject_UserEvent_5 :: Event +testObject_UserEvent_5 = + UserEvent + ( UserDeleted + ( Qualified + (Id (fromJust (UUID.fromString "78f9ba2e-a6b0-48c6-a644-662617bb8bcc"))) + (Domain "bar.example.com") + ) + ) + +testObject_UserEvent_6 :: Event +testObject_UserEvent_6 = + UserEvent + ( UserUpdated + ( UserUpdatedData + alice.userId + (Just alice.userDisplayName) + (Just alice.userPict) + (Just alice.userAccentId) + (Just alice.userAssets) + alice.userHandle + (Just alice.userLocale) + (Just alice.userManagedBy) + Nothing + False + (Just mempty) + ) + ) + +testObject_UserEvent_7 :: Event +testObject_UserEvent_7 = + UserEvent + ( UserIdentityUpdated + ( UserIdentityUpdatedData + alice.userId + (Just (Email "alice" "foo.example.com")) + Nothing + ) + ) + +testObject_UserEvent_8 :: Event +testObject_UserEvent_8 = + UserEvent + ( UserIdentityRemoved + ( UserIdentityRemovedData + alice.userId + (Just (Email "alice" "foo.example.com")) + Nothing + ) + ) + +testObject_UserEvent_9 :: Event +testObject_UserEvent_9 = UserEvent (UserLegalHoldDisabled alice.userId) + +testObject_UserEvent_10 :: Event +testObject_UserEvent_10 = UserEvent (UserLegalHoldEnabled alice.userId) + +testObject_UserEvent_11 :: Event +testObject_UserEvent_11 = + UserEvent + ( LegalHoldClientRequested + ( LegalHoldClientRequestedData + alice.userId + (lastPrekey "foo") + (ClientId 3728) + ) + ) + +testObject_UserEvent_12 :: Event +testObject_UserEvent_12 = + ConnectionEvent + ( ConnectionUpdated + ( UserConnection + bob.userId + bob.userQualifiedId + Accepted + (fromJust (readUTCTimeMillis "2007-02-03T10:51:17.329Z")) + Nothing + ) + (Just (Name "hi bob")) + ) + +testObject_UserEvent_13 :: Event +testObject_UserEvent_13 = + PropertyEvent + ( PropertySet (PropertyKey "a") (toJSON (39 :: Int)) + ) + +testObject_UserEvent_14 :: Event +testObject_UserEvent_14 = + PropertyEvent + ( PropertyDeleted (PropertyKey "a") + ) + +testObject_UserEvent_15 :: Event +testObject_UserEvent_15 = PropertyEvent PropertiesCleared + +testObject_UserEvent_16 :: Event +testObject_UserEvent_16 = + ClientEvent + ( ClientAdded + ( Client + (ClientId 2839) + PermanentClientType + (fromJust (readUTCTimeMillis "2007-02-03T10:51:17.329Z")) + (Just DesktopClient) + (Just "%*") + Nothing + (Just "bazz") + (ClientCapabilityList mempty) + mempty + Nothing + ) + ) + +testObject_UserEvent_17 :: Event +testObject_UserEvent_17 = ClientEvent (ClientRemoved (ClientId 2839)) + +-------------------------------------------------------------------------------- + +alice :: User +alice = + User + { userId = Id (fromJust (UUID.fromString "539d9183-32a5-4fc4-ba5c-4634454e7585")), + userQualifiedId = + Qualified + { qUnqualified = Id (fromJust (UUID.fromString "539d9183-32a5-4fc4-ba5c-4634454e7585")), + qDomain = Domain {_domainText = "foo.example.com"} + }, + userIdentity = Nothing, + userDisplayName = Name "alice", + userPict = Pict {fromPict = []}, + userAssets = [], + userAccentId = ColourId {fromColourId = 1}, + userDeleted = True, + userLocale = + Locale + { lLanguage = Language L.TN, + lCountry = Just (Country {fromCountry = SB}) + }, + userService = Nothing, + userHandle = Nothing, + userExpire = Nothing, + userTeam = Nothing, + userManagedBy = ManagedByWire, + userSupportedProtocols = defSupportedProtocols + } + +bob :: User +bob = + User + { userId = Id (fromJust (UUID.fromString "284d1c86-5117-4c58-aa18-c0068f3f7d8c")), + userQualifiedId = + Qualified + { qUnqualified = Id (fromJust (UUID.fromString "284d1c86-5117-4c58-aa18-c0068f3f7d8c")), + qDomain = Domain {_domainText = "baz.example.com"} + }, + userIdentity = Nothing, + userDisplayName = Name "bob", + userPict = Pict {fromPict = []}, + userAssets = [], + userAccentId = ColourId {fromColourId = 2}, + userDeleted = False, + userLocale = + Locale + { lLanguage = Language L.CA, + lCountry = Just (Country {fromCountry = JP}) + }, + userService = Nothing, + userHandle = Nothing, + userExpire = Nothing, + userTeam = Nothing, + userManagedBy = ManagedByWire, + userSupportedProtocols = defSupportedProtocols + } diff --git a/libs/wire-api/test/golden/testObject_UserEvent_1.json b/libs/wire-api/test/golden/testObject_UserEvent_1.json new file mode 100644 index 00000000000..09940cd4e9e --- /dev/null +++ b/libs/wire-api/test/golden/testObject_UserEvent_1.json @@ -0,0 +1,20 @@ +{ + "type": "user.new", + "user": { + "accent_id": 1, + "assets": [], + "deleted": true, + "id": "539d9183-32a5-4fc4-ba5c-4634454e7585", + "locale": "tn-SB", + "managed_by": "wire", + "name": "alice", + "picture": [], + "qualified_id": { + "domain": "foo.example.com", + "id": "539d9183-32a5-4fc4-ba5c-4634454e7585" + }, + "supported_protocols": [ + "proteus" + ] + } +} diff --git a/libs/wire-api/test/golden/testObject_UserEvent_10.json b/libs/wire-api/test/golden/testObject_UserEvent_10.json new file mode 100644 index 00000000000..c8aceb979de --- /dev/null +++ b/libs/wire-api/test/golden/testObject_UserEvent_10.json @@ -0,0 +1,4 @@ +{ + "id": "539d9183-32a5-4fc4-ba5c-4634454e7585", + "type": "user.legalhold-enable" +} diff --git a/libs/wire-api/test/golden/testObject_UserEvent_11.json b/libs/wire-api/test/golden/testObject_UserEvent_11.json new file mode 100644 index 00000000000..3a391a8781b --- /dev/null +++ b/libs/wire-api/test/golden/testObject_UserEvent_11.json @@ -0,0 +1,11 @@ +{ + "client": { + "id": "e90" + }, + "id": "539d9183-32a5-4fc4-ba5c-4634454e7585", + "last_prekey": { + "id": 65535, + "key": "foo" + }, + "type": "user.legalhold-request" +} diff --git a/libs/wire-api/test/golden/testObject_UserEvent_12.json b/libs/wire-api/test/golden/testObject_UserEvent_12.json new file mode 100644 index 00000000000..f342079b4ea --- /dev/null +++ b/libs/wire-api/test/golden/testObject_UserEvent_12.json @@ -0,0 +1,16 @@ +{ + "connection": { + "from": "284d1c86-5117-4c58-aa18-c0068f3f7d8c", + "last_update": "2007-02-03T10:51:17.329Z", + "qualified_to": { + "domain": "baz.example.com", + "id": "284d1c86-5117-4c58-aa18-c0068f3f7d8c" + }, + "status": "accepted", + "to": "284d1c86-5117-4c58-aa18-c0068f3f7d8c" + }, + "type": "user.connection", + "user": { + "name": "hi bob" + } +} diff --git a/libs/wire-api/test/golden/testObject_UserEvent_13.json b/libs/wire-api/test/golden/testObject_UserEvent_13.json new file mode 100644 index 00000000000..25a0a1dd05b --- /dev/null +++ b/libs/wire-api/test/golden/testObject_UserEvent_13.json @@ -0,0 +1,5 @@ +{ + "key": "a", + "type": "user.properties-set", + "value": 39 +} diff --git a/libs/wire-api/test/golden/testObject_UserEvent_14.json b/libs/wire-api/test/golden/testObject_UserEvent_14.json new file mode 100644 index 00000000000..0b359af6e4b --- /dev/null +++ b/libs/wire-api/test/golden/testObject_UserEvent_14.json @@ -0,0 +1,4 @@ +{ + "key": "a", + "type": "user.properties-delete" +} diff --git a/libs/wire-api/test/golden/testObject_UserEvent_15.json b/libs/wire-api/test/golden/testObject_UserEvent_15.json new file mode 100644 index 00000000000..529b84e9598 --- /dev/null +++ b/libs/wire-api/test/golden/testObject_UserEvent_15.json @@ -0,0 +1,3 @@ +{ + "type": "user.properties-clear" +} diff --git a/libs/wire-api/test/golden/testObject_UserEvent_16.json b/libs/wire-api/test/golden/testObject_UserEvent_16.json new file mode 100644 index 00000000000..88168e5d582 --- /dev/null +++ b/libs/wire-api/test/golden/testObject_UserEvent_16.json @@ -0,0 +1,15 @@ +{ + "client": { + "capabilities": { + "capabilities": [] + }, + "class": "desktop", + "id": "b17", + "label": "%*", + "mls_public_keys": {}, + "model": "bazz", + "time": "2007-02-03T10:51:17.329Z", + "type": "permanent" + }, + "type": "user.client-add" +} diff --git a/libs/wire-api/test/golden/testObject_UserEvent_17.json b/libs/wire-api/test/golden/testObject_UserEvent_17.json new file mode 100644 index 00000000000..9ddeee4ce50 --- /dev/null +++ b/libs/wire-api/test/golden/testObject_UserEvent_17.json @@ -0,0 +1,6 @@ +{ + "client": { + "id": "b17" + }, + "type": "user.client-remove" +} diff --git a/libs/wire-api/test/golden/testObject_UserEvent_2.json b/libs/wire-api/test/golden/testObject_UserEvent_2.json new file mode 100644 index 00000000000..36ec06060ef --- /dev/null +++ b/libs/wire-api/test/golden/testObject_UserEvent_2.json @@ -0,0 +1,20 @@ +{ + "type": "user.activate", + "user": { + "accent_id": 1, + "assets": [], + "deleted": true, + "id": "539d9183-32a5-4fc4-ba5c-4634454e7585", + "locale": "tn-SB", + "managed_by": "wire", + "name": "alice", + "picture": [], + "qualified_id": { + "domain": "foo.example.com", + "id": "539d9183-32a5-4fc4-ba5c-4634454e7585" + }, + "supported_protocols": [ + "proteus" + ] + } +} diff --git a/libs/wire-api/test/golden/testObject_UserEvent_3.json b/libs/wire-api/test/golden/testObject_UserEvent_3.json new file mode 100644 index 00000000000..2dfeaa90444 --- /dev/null +++ b/libs/wire-api/test/golden/testObject_UserEvent_3.json @@ -0,0 +1,4 @@ +{ + "id": "dd56271c-181a-43f5-874b-1a8951f7fcc7", + "type": "user.suspend" +} diff --git a/libs/wire-api/test/golden/testObject_UserEvent_4.json b/libs/wire-api/test/golden/testObject_UserEvent_4.json new file mode 100644 index 00000000000..ab6fc97882e --- /dev/null +++ b/libs/wire-api/test/golden/testObject_UserEvent_4.json @@ -0,0 +1,4 @@ +{ + "id": "3ddb960e-8ea3-4d14-95bc-97f9da795ca6", + "type": "user.suspend" +} diff --git a/libs/wire-api/test/golden/testObject_UserEvent_5.json b/libs/wire-api/test/golden/testObject_UserEvent_5.json new file mode 100644 index 00000000000..34d8c0d81a1 --- /dev/null +++ b/libs/wire-api/test/golden/testObject_UserEvent_5.json @@ -0,0 +1,8 @@ +{ + "id": "78f9ba2e-a6b0-48c6-a644-662617bb8bcc", + "qualified_id": { + "domain": "bar.example.com", + "id": "78f9ba2e-a6b0-48c6-a644-662617bb8bcc" + }, + "type": "user.delete" +} diff --git a/libs/wire-api/test/golden/testObject_UserEvent_6.json b/libs/wire-api/test/golden/testObject_UserEvent_6.json new file mode 100644 index 00000000000..328b2cb2193 --- /dev/null +++ b/libs/wire-api/test/golden/testObject_UserEvent_6.json @@ -0,0 +1,14 @@ +{ + "type": "user.update", + "user": { + "accent_id": 1, + "assets": [], + "id": "539d9183-32a5-4fc4-ba5c-4634454e7585", + "locale": "tn-SB", + "managed_by": "wire", + "name": "alice", + "picture": [], + "sso_id_deleted": false, + "supported_protocols": [] + } +} diff --git a/libs/wire-api/test/golden/testObject_UserEvent_7.json b/libs/wire-api/test/golden/testObject_UserEvent_7.json new file mode 100644 index 00000000000..71c1b5a163a --- /dev/null +++ b/libs/wire-api/test/golden/testObject_UserEvent_7.json @@ -0,0 +1,7 @@ +{ + "type": "user.update", + "user": { + "email": "alice@foo.example.com", + "id": "539d9183-32a5-4fc4-ba5c-4634454e7585" + } +} diff --git a/libs/wire-api/test/golden/testObject_UserEvent_8.json b/libs/wire-api/test/golden/testObject_UserEvent_8.json new file mode 100644 index 00000000000..9998a51fdbc --- /dev/null +++ b/libs/wire-api/test/golden/testObject_UserEvent_8.json @@ -0,0 +1,7 @@ +{ + "type": "user.identity-remove", + "user": { + "email": "alice@foo.example.com", + "id": "539d9183-32a5-4fc4-ba5c-4634454e7585" + } +} diff --git a/libs/wire-api/test/golden/testObject_UserEvent_9.json b/libs/wire-api/test/golden/testObject_UserEvent_9.json new file mode 100644 index 00000000000..fc025dd9ad6 --- /dev/null +++ b/libs/wire-api/test/golden/testObject_UserEvent_9.json @@ -0,0 +1,4 @@ +{ + "id": "539d9183-32a5-4fc4-ba5c-4634454e7585", + "type": "user.legalhold-disable" +} diff --git a/libs/wire-api/wire-api.cabal b/libs/wire-api/wire-api.cabal index b191dbfbdec..81859cef566 100644 --- a/libs/wire-api/wire-api.cabal +++ b/libs/wire-api/wire-api.cabal @@ -232,6 +232,7 @@ library Wire.API.User.Saml Wire.API.User.Scim Wire.API.User.Search + Wire.API.UserEvent Wire.API.UserMap Wire.API.Util.Aeson Wire.API.VersionInfo @@ -316,6 +317,7 @@ library , tagged , text >=0.11 , time >=1.4 + , tinylog , transitive-anns , types-common >=0.16 , unordered-containers >=0.2 @@ -587,6 +589,7 @@ test-suite wire-api-golden-tests Test.Wire.API.Golden.Manual.TeamSize Test.Wire.API.Golden.Manual.Token Test.Wire.API.Golden.Manual.UserClientPrekeyMap + Test.Wire.API.Golden.Manual.UserEvent Test.Wire.API.Golden.Manual.UserIdList Test.Wire.API.Golden.Protobuf Test.Wire.API.Golden.Run diff --git a/services/brig/brig.cabal b/services/brig/brig.cabal index 6158288d854..4e0c272153d 100644 --- a/services/brig/brig.cabal +++ b/services/brig/brig.cabal @@ -149,6 +149,7 @@ library Brig.InternalEvent.Types Brig.IO.Intra Brig.IO.Journal + Brig.IO.Logging Brig.Locale Brig.Options Brig.Phone diff --git a/services/brig/src/Brig/API/Client.hs b/services/brig/src/Brig/API/Client.hs index 9eeda792e29..17071f56ef3 100644 --- a/services/brig/src/Brig/API/Client.hs +++ b/services/brig/src/Brig/API/Client.hs @@ -69,7 +69,6 @@ import Brig.Options qualified as Opt import Brig.Queue qualified as Queue import Brig.Types.Intra import Brig.Types.Team.LegalHold (LegalHoldClientRequest (..)) -import Brig.Types.User.Event import Brig.User.Auth qualified as UserAuth import Brig.User.Auth.Cookie qualified as Auth import Brig.User.Email @@ -108,6 +107,7 @@ import Wire.API.User qualified as Code import Wire.API.User.Client import Wire.API.User.Client.DPoPAccessToken import Wire.API.User.Client.Prekey +import Wire.API.UserEvent import Wire.API.UserMap (QualifiedUserMap (QualifiedUserMap, qualifiedUserMap), UserMap (userMap)) import Wire.NotificationSubsystem import Wire.Sem.Concurrency @@ -211,7 +211,7 @@ addClientWithReAuthPolicy policy u con new = do lift $ do for_ old $ execDelete u con liftSem $ GalleyProvider.newClient u (clientId clt) - liftSem $ Intra.onClientEvent u con (ClientAdded u clt) + liftSem $ Intra.onClientEvent u con (ClientAdded clt) when (clientType clt == LegalHoldClientType) $ liftSem $ Intra.onUserEvent u con (UserLegalHoldEnabled u) when (count > 1) $ for_ (userEmail usr) $ diff --git a/services/brig/src/Brig/API/Connection.hs b/services/brig/src/Brig/API/Connection.hs index b7ba931541f..c5b8de1c4c2 100644 --- a/services/brig/src/Brig/API/Connection.hs +++ b/services/brig/src/Brig/API/Connection.hs @@ -45,9 +45,9 @@ import Brig.Effects.FederationConfigStore import Brig.Effects.GalleyProvider import Brig.Effects.GalleyProvider qualified as GalleyProvider import Brig.IO.Intra qualified as Intra +import Brig.IO.Logging import Brig.Options import Brig.Types.Connection -import Brig.Types.User.Event import Control.Error import Control.Lens (view) import Control.Monad.Catch (throwM) @@ -69,6 +69,7 @@ import Wire.API.Error import Wire.API.Error.Brig qualified as E import Wire.API.Routes.Public.Util (ResponseForExistedCreated (..)) import Wire.API.User +import Wire.API.UserEvent import Wire.NotificationSubsystem ensureNotSameTeam :: Member GalleyProvider r => Local UserId -> Local UserId -> (ConnectionM r) () @@ -121,10 +122,10 @@ createConnectionToLocalUser self conn target = do Just rs -> rs Nothing -> do checkLimit self - Created <$> insert Nothing Nothing + Created <$> insert where - insert :: Maybe UserConnection -> Maybe UserConnection -> ExceptT ConnectionError (AppT r) UserConnection - insert s2o o2s = lift $ do + insert :: ExceptT ConnectionError (AppT r) UserConnection + insert = lift $ do Log.info $ logConnection (tUnqualified self) (tUntagged target) . msg (val "Creating connection") @@ -132,9 +133,8 @@ createConnectionToLocalUser self conn target = do s2o' <- wrapClient $ Data.insertConnection self (tUntagged target) SentWithHistory qcnv o2s' <- wrapClient $ Data.insertConnection target (tUntagged self) PendingWithHistory qcnv e2o <- - ConnectionUpdated o2s' (ucStatus <$> o2s) - <$> wrapClient (Data.lookupName (tUnqualified self)) - let e2s = ConnectionUpdated s2o' (ucStatus <$> s2o) Nothing + ConnectionUpdated o2s' <$> wrapClient (Data.lookupName (tUnqualified self)) + let e2s = ConnectionUpdated s2o' Nothing liftSem $ mapM_ (Intra.onConnectionEvent (tUnqualified self) (Just conn)) [e2o, e2s] pure s2o' @@ -149,9 +149,9 @@ createConnectionToLocalUser self conn target = do (_, Blocked) -> change s2o SentWithHistory (_, Sent) -> accept s2o o2s (_, Accepted) -> accept s2o o2s - (_, Ignored) -> resend s2o o2s - (_, Pending) -> resend s2o o2s - (_, Cancelled) -> resend s2o o2s + (_, Ignored) -> resend s2o + (_, Pending) -> resend s2o + (_, Cancelled) -> resend s2o accept :: UserConnection -> UserConnection -> ExceptT ConnectionError (AppT r) (ResponseForExistedCreated UserConnection) accept s2o o2s = do @@ -169,21 +169,19 @@ createConnectionToLocalUser self conn target = do else Data.updateConnection o2s AcceptedWithHistory e2o <- lift . wrapClient $ - ConnectionUpdated o2s' (Just $ ucStatus o2s) - <$> Data.lookupName (tUnqualified self) - let e2s = ConnectionUpdated s2o' (Just $ ucStatus s2o) Nothing + ConnectionUpdated o2s' <$> Data.lookupName (tUnqualified self) + let e2s = ConnectionUpdated s2o' Nothing lift $ liftSem $ mapM_ (Intra.onConnectionEvent (tUnqualified self) (Just conn)) [e2o, e2s] pure $ Existed s2o' - resend :: UserConnection -> UserConnection -> ExceptT ConnectionError (AppT r) (ResponseForExistedCreated UserConnection) - resend s2o o2s = do + resend :: UserConnection -> ExceptT ConnectionError (AppT r) (ResponseForExistedCreated UserConnection) + resend s2o = do unless (ucStatus s2o `elem` [Sent, Accepted]) $ checkLimit self lift . Log.info $ logLocalConnection (tUnqualified self) (qUnqualified (ucTo s2o)) . msg (val "Resending connection request") - s2o' <- insert (Just s2o) (Just o2s) - pure $ Existed s2o' + Existed <$> insert change :: UserConnection -> RelationWithHistory -> ExceptT ConnectionError (AppT r) (ResponseForExistedCreated UserConnection) change c s = Existed <$> lift (wrapClient $ Data.updateConnection c s) @@ -305,7 +303,7 @@ updateConnectionToLocalUser self other newStatus conn = do _ -> throwE $ InvalidTransition (tUnqualified self) let s2oUserConn = s2o' lift . liftSem . for_ s2oUserConn $ \c -> - let e2s = ConnectionUpdated c (Just $ ucStatus s2o) Nothing + let e2s = ConnectionUpdated c Nothing in Intra.onConnectionEvent (tUnqualified self) conn e2s pure s2oUserConn where @@ -327,7 +325,7 @@ updateConnectionToLocalUser self other newStatus conn = do then Data.updateConnection o2s AcceptedWithHistory else Data.updateConnection o2s BlockedWithHistory e2o <- - ConnectionUpdated o2s' (Just $ ucStatus o2s) + ConnectionUpdated o2s' <$> wrapClient (Data.lookupName (tUnqualified self)) liftSem $ Intra.onConnectionEvent (tUnqualified self) conn e2o lift . wrapClient $ Just <$> Data.updateConnection s2o AcceptedWithHistory @@ -368,7 +366,7 @@ updateConnectionToLocalUser self other newStatus conn = do else Data.updateConnection o2s BlockedWithHistory e2o :: ConnectionEvent <- wrapClient $ - ConnectionUpdated o2s' (Just $ ucStatus o2s) + ConnectionUpdated o2s' <$> Data.lookupName (tUnqualified self) -- TODO: is this correct? shouldnt o2s be sent to other? liftSem $ Intra.onConnectionEvent (tUnqualified self) conn e2o @@ -382,7 +380,7 @@ updateConnectionToLocalUser self other newStatus conn = do lfrom <- qualifyLocal (ucFrom s2o) lift $ traverse_ (liftSem . Intra.blockConv lfrom) (ucConvId s2o) o2s' <- lift . wrapClient $ Data.updateConnection o2s CancelledWithHistory - let e2o = ConnectionUpdated o2s' (Just $ ucStatus o2s) Nothing + let e2o = ConnectionUpdated o2s' Nothing lift $ liftSem $ Intra.onConnectionEvent (tUnqualified self) conn e2o change s2o Cancelled @@ -454,7 +452,7 @@ updateConnectionInternal = \case lfrom <- qualifyLocal (ucFrom uconn) traverse_ (liftSem . Intra.blockConv lfrom) (ucConvId uconn) uconn' <- wrapClient $ Data.updateConnection uconn (mkRelationWithHistory (ucStatus uconn) MissingLegalholdConsent) - let ev = ConnectionUpdated uconn' (Just $ ucStatus uconn) Nothing + let ev = ConnectionUpdated uconn' Nothing liftSem $ Intra.onConnectionEvent (tUnqualified self) Nothing ev removeLHBlocksInvolving :: Local UserId -> ExceptT ConnectionError (AppT r) () @@ -494,7 +492,6 @@ updateConnectionInternal = \case let connEvent = ConnectionUpdated { ucConn = uconnRev', - ucPrev = Just $ ucStatus uconnRev, ucName = connName } lift $ liftSem $ Intra.onConnectionEvent (ucFrom uconn) Nothing connEvent diff --git a/services/brig/src/Brig/API/Connection/Remote.hs b/services/brig/src/Brig/API/Connection/Remote.hs index 5b6240a09ec..c96ecd24a5b 100644 --- a/services/brig/src/Brig/API/Connection/Remote.hs +++ b/services/brig/src/Brig/API/Connection/Remote.hs @@ -33,7 +33,6 @@ import Brig.Effects.GalleyProvider import Brig.Federation.Client as Federation import Brig.IO.Intra qualified as Intra import Brig.Options -import Brig.Types.User.Event import Control.Comonad import Control.Error.Util ((??)) import Control.Lens (view) @@ -52,6 +51,7 @@ import Wire.API.Federation.API.Brig import Wire.API.Routes.Internal.Galley.ConversationsIntra import Wire.API.Routes.Public.Util (ResponseForExistedCreated (..)) import Wire.API.User +import Wire.API.UserEvent import Wire.NotificationSubsystem data LocalConnectionAction @@ -220,7 +220,7 @@ pushEvent :: UserConnection -> AppT r () pushEvent self mzcon connection = do - let event = ConnectionUpdated connection Nothing Nothing + let event = ConnectionUpdated connection Nothing liftSem $ Intra.onConnectionEvent (tUnqualified self) mzcon event performLocalAction :: diff --git a/services/brig/src/Brig/API/Federation.hs b/services/brig/src/Brig/API/Federation.hs index 067d14389f5..9a6559663c6 100644 --- a/services/brig/src/Brig/API/Federation.hs +++ b/services/brig/src/Brig/API/Federation.hs @@ -36,7 +36,6 @@ import Brig.Effects.FederationConfigStore qualified as E import Brig.Effects.GalleyProvider (GalleyProvider) import Brig.IO.Intra (notify) import Brig.Options -import Brig.Types.User.Event import Brig.User.API.Handle import Brig.User.Search.SearchIndex qualified as Q import Control.Error.Util @@ -69,6 +68,7 @@ import Wire.API.User (UserProfile) import Wire.API.User.Client import Wire.API.User.Client.Prekey import Wire.API.User.Search hiding (searchPolicy) +import Wire.API.UserEvent import Wire.API.UserMap (UserMap) import Wire.NotificationSubsystem import Wire.Sem.Concurrency diff --git a/services/brig/src/Brig/API/Internal.hs b/services/brig/src/Brig/API/Internal.hs index 9adc85b9af0..315ad9ae22f 100644 --- a/services/brig/src/Brig/API/Internal.hs +++ b/services/brig/src/Brig/API/Internal.hs @@ -58,7 +58,6 @@ import Brig.Types.Connection import Brig.Types.Intra import Brig.Types.Team.LegalHold (LegalHoldClientRequest (..)) import Brig.Types.User -import Brig.Types.User.Event (UserEvent (UserUpdated), UserUpdatedData (eupSSOId, eupSSOIdRemoved), emptyUserUpdatedData) import Brig.User.API.Search qualified as Search import Brig.User.EJPD qualified import Brig.User.Search.Index qualified as Index @@ -99,6 +98,7 @@ import Wire.API.User import Wire.API.User.Activation import Wire.API.User.Client import Wire.API.User.RichInfo +import Wire.API.UserEvent import Wire.NotificationSubsystem import Wire.Rpc import Wire.Sem.Concurrency diff --git a/services/brig/src/Brig/API/Properties.hs b/services/brig/src/Brig/API/Properties.hs index 3443ace2956..814b899962a 100644 --- a/services/brig/src/Brig/API/Properties.hs +++ b/services/brig/src/Brig/API/Properties.hs @@ -30,25 +30,25 @@ import Brig.App import Brig.Data.Properties (PropertiesDataError) import Brig.Data.Properties qualified as Data import Brig.IO.Intra qualified as Intra -import Brig.Types.User.Event import Control.Error import Data.Id import Imports import Polysemy import Wire.API.Properties +import Wire.API.UserEvent import Wire.NotificationSubsystem setProperty :: (Member NotificationSubsystem r) => UserId -> ConnId -> PropertyKey -> PropertyValue -> ExceptT PropertiesDataError (AppT r) () setProperty u c k v = do wrapClientE $ Data.insertProperty u k (propertyRaw v) - lift $ liftSem $ Intra.onPropertyEvent u c (PropertySet u k v) + lift $ liftSem $ Intra.onPropertyEvent u c (PropertySet k (propertyValue v)) deleteProperty :: (Member NotificationSubsystem r) => UserId -> ConnId -> PropertyKey -> AppT r () deleteProperty u c k = do wrapClient $ Data.deleteProperty u k - liftSem $ Intra.onPropertyEvent u c (PropertyDeleted u k) + liftSem $ Intra.onPropertyEvent u c (PropertyDeleted k) clearProperties :: (Member NotificationSubsystem r) => UserId -> ConnId -> AppT r () clearProperties u c = do wrapClient $ Data.clearProperties u - liftSem $ Intra.onPropertyEvent u c (PropertiesCleared u) + liftSem $ Intra.onPropertyEvent u c PropertiesCleared diff --git a/services/brig/src/Brig/API/User.hs b/services/brig/src/Brig/API/User.hs index 8b70410265d..4b565ce4509 100644 --- a/services/brig/src/Brig/API/User.hs +++ b/services/brig/src/Brig/API/User.hs @@ -132,7 +132,6 @@ import Brig.Team.Types (ShowOrHideInvitationUrl (..)) import Brig.Types.Activation (ActivationPair) import Brig.Types.Connection import Brig.Types.Intra -import Brig.Types.User.Event import Brig.User.Auth.Cookie (listCookies, revokeAllCookies) import Brig.User.Email import Brig.User.Handle @@ -189,6 +188,7 @@ import Wire.API.User.Activation import Wire.API.User.Client import Wire.API.User.Password import Wire.API.User.RichInfo +import Wire.API.UserEvent import Wire.NotificationSubsystem import Wire.Sem.Concurrency import Wire.Sem.Paging.Cassandra (InternalPaging) diff --git a/services/brig/src/Brig/IO/Intra.hs b/services/brig/src/Brig/IO/Intra.hs index 2dbd9109b0e..c8e82c586d0 100644 --- a/services/brig/src/Brig/IO/Intra.hs +++ b/services/brig/src/Brig/IO/Intra.hs @@ -57,20 +57,19 @@ import Brig.Effects.ConnectionStore (ConnectionStore) import Brig.Effects.ConnectionStore qualified as E import Brig.Federation.Client (notifyUserDeleted, sendConnectionAction) import Brig.IO.Journal qualified as Journal +import Brig.IO.Logging import Brig.RPC -import Brig.Types.User.Event import Brig.User.Search.Index qualified as Search import Control.Error (ExceptT, runExceptT) import Control.Lens (view, (.~), (?~), (^.), (^?)) import Control.Monad.Catch import Control.Monad.Trans.Except (throwE) import Data.Aeson hiding (json) -import Data.Aeson.KeyMap qualified as KeyMap import Data.Aeson.Lens import Data.ByteString.Conversion import Data.ByteString.Lazy qualified as BL import Data.Id -import Data.Json.Util (toUTCTimeMillis, (#)) +import Data.Json.Util import Data.List.NonEmpty (NonEmpty (..)) import Data.List1 (List1, singleton) import Data.Proxy @@ -91,13 +90,13 @@ import Wire.API.Conversation hiding (Member) import Wire.API.Event.Conversation (Connect (Connect)) import Wire.API.Federation.API.Brig import Wire.API.Federation.Error -import Wire.API.Properties import Wire.API.Routes.Internal.Galley.ConversationsIntra import Wire.API.Routes.Internal.Galley.TeamsIntra (GuardLegalholdPolicyConflicts (GuardLegalholdPolicyConflicts)) import Wire.API.Team.LegalHold (LegalholdProtectee) import Wire.API.Team.Member qualified as Team import Wire.API.User import Wire.API.User.Client +import Wire.API.UserEvent import Wire.NotificationSubsystem import Wire.Rpc import Wire.Sem.Logger qualified as Log @@ -171,7 +170,7 @@ onClientEvent orig conn e = do let event = ClientEvent e let rcps = Recipient orig V2.RecipientClientsAll :| [] pushNotifications - [ newPush1 (Just orig) (toPushFormat event) rcps + [ newPush1 (Just orig) (toJSONObject event) rcps & pushConn .~ conn & pushApsData .~ toApsData event ] @@ -302,7 +301,7 @@ notifyUserDeletionLocals deleted conn event = do Cancelled now (ucConvId uc) - let e = ConnectionUpdated ucCancelled Nothing Nothing + let e = ConnectionUpdated ucCancelled Nothing onConnectionEvent deleted conn e ) @@ -372,7 +371,7 @@ notify :: notify (toList -> events) orig route conn recipients = do rs <- (\u -> Recipient u RecipientClientsAll) <$$> recipients let pushes = flip map events $ \event -> - newPush1 (Just orig) (toPushFormat event) rs + newPush1 (Just orig) (toJSONObject event) rs & pushConn .~ conn & pushRoute .~ route & pushApsData .~ toApsData event @@ -422,130 +421,8 @@ notifyContacts events orig route conn = do view Team.userId <$> mems ^. Team.teamMembers screenMemberList _ = [] --- Event Serialisation: - -toPushFormat :: Event -> Object -toPushFormat (UserEvent (UserCreated u)) = - KeyMap.fromList - [ "type" .= ("user.new" :: Text), - "user" .= SelfProfile (u {userIdentity = Nothing}) - ] -toPushFormat (UserEvent (UserActivated u)) = - KeyMap.fromList - [ "type" .= ("user.activate" :: Text), - "user" .= SelfProfile u - ] -toPushFormat (UserEvent (UserUpdated (UserUpdatedData i n pic acc ass hdl loc mb ssoId ssoIdDel prots))) = - KeyMap.fromList - [ "type" .= ("user.update" :: Text), - "user" - .= object - ( "id" .= i - # "name" .= n - # "picture" .= pic -- DEPRECATED - # "accent_id" .= acc - # "assets" .= ass - # "handle" .= hdl - # "locale" .= loc - # "managed_by" .= mb - # "sso_id" .= ssoId - # "sso_id_deleted" .= ssoIdDel - # "supported_protocols" .= prots - # [] - ) - ] -toPushFormat (UserEvent (UserIdentityUpdated UserIdentityUpdatedData {..})) = - KeyMap.fromList - [ "type" .= ("user.update" :: Text), - "user" - .= object - ( "id" .= eiuId - # "email" .= eiuEmail - # "phone" .= eiuPhone - # [] - ) - ] -toPushFormat (UserEvent (UserIdentityRemoved (UserIdentityRemovedData i e p))) = - KeyMap.fromList - [ "type" .= ("user.identity-remove" :: Text), - "user" - .= object - ( "id" .= i - # "email" .= e - # "phone" .= p - # [] - ) - ] -toPushFormat (ConnectionEvent (ConnectionUpdated uc _ name)) = - KeyMap.fromList $ - "type" .= ("user.connection" :: Text) - # "connection" .= uc - # "user" .= case name of - Just n -> Just $ object ["name" .= n] - Nothing -> Nothing - # [] -toPushFormat (UserEvent (UserSuspended i)) = - KeyMap.fromList - [ "type" .= ("user.suspend" :: Text), - "id" .= i - ] -toPushFormat (UserEvent (UserResumed i)) = - KeyMap.fromList - [ "type" .= ("user.resume" :: Text), - "id" .= i - ] -toPushFormat (UserEvent (UserDeleted qid)) = - KeyMap.fromList - [ "type" .= ("user.delete" :: Text), - "id" .= qUnqualified qid, - "qualified_id" .= qid - ] -toPushFormat (UserEvent (UserLegalHoldDisabled i)) = - KeyMap.fromList - [ "type" .= ("user.legalhold-disable" :: Text), - "id" .= i - ] -toPushFormat (UserEvent (UserLegalHoldEnabled i)) = - KeyMap.fromList - [ "type" .= ("user.legalhold-enable" :: Text), - "id" .= i - ] -toPushFormat (PropertyEvent (PropertySet _ k v)) = - KeyMap.fromList - [ "type" .= ("user.properties-set" :: Text), - "key" .= k, - "value" .= propertyValue v - ] -toPushFormat (PropertyEvent (PropertyDeleted _ k)) = - KeyMap.fromList - [ "type" .= ("user.properties-delete" :: Text), - "key" .= k - ] -toPushFormat (PropertyEvent (PropertiesCleared _)) = - KeyMap.fromList - [ "type" .= ("user.properties-clear" :: Text) - ] -toPushFormat (ClientEvent (ClientAdded _ c)) = - KeyMap.fromList - [ "type" .= ("user.client-add" :: Text), - "client" .= c - ] -toPushFormat (ClientEvent (ClientRemoved _ clientId)) = - KeyMap.fromList - [ "type" .= ("user.client-remove" :: Text), - "client" .= IdObject clientId - ] -toPushFormat (UserEvent (LegalHoldClientRequested payload)) = - let LegalHoldClientRequestedData targetUser lastPrekey' clientId = payload - in KeyMap.fromList - [ "type" .= ("user.legalhold-request" :: Text), - "id" .= targetUser, - "last_prekey" .= lastPrekey', - "client" .= IdObject clientId - ] - toApsData :: Event -> Maybe V2.ApsData -toApsData (ConnectionEvent (ConnectionUpdated uc _ name)) = +toApsData (ConnectionEvent (ConnectionUpdated uc name)) = case (ucStatus uc, name) of (MissingLegalholdConsent, _) -> Nothing (Pending, n) -> apsConnRequest <$> n diff --git a/services/brig/src/Brig/IO/Logging.hs b/services/brig/src/Brig/IO/Logging.hs new file mode 100644 index 00000000000..ec733caa119 --- /dev/null +++ b/services/brig/src/Brig/IO/Logging.hs @@ -0,0 +1,34 @@ +-- 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 Brig.IO.Logging where + +import Data.ByteString.Conversion +import Data.Id +import Data.Qualified +import System.Logger + +logConnection :: UserId -> Qualified UserId -> Msg -> Msg +logConnection from (Qualified toUser toDomain) = + "connection.from" .= toByteString from + ~~ "connection.to" .= toByteString toUser + ~~ "connection.to_domain" .= toByteString toDomain + +logLocalConnection :: UserId -> UserId -> Msg -> Msg +logLocalConnection from to = + "connection.from" .= toByteString from + ~~ "connection.to" .= toByteString to diff --git a/services/brig/src/Brig/InternalEvent/Process.hs b/services/brig/src/Brig/InternalEvent/Process.hs index 9bca2320e37..b0e0ba1c870 100644 --- a/services/brig/src/Brig/InternalEvent/Process.hs +++ b/services/brig/src/Brig/InternalEvent/Process.hs @@ -28,7 +28,6 @@ import Brig.IO.Intra qualified as Intra import Brig.InternalEvent.Types import Brig.Options (defDeleteThrottleMillis, setDeleteThrottleMillis) import Brig.Provider.API qualified as API -import Brig.Types.User.Event import Control.Lens (view) import Control.Monad.Catch import Data.ByteString.Conversion @@ -41,6 +40,7 @@ import Polysemy.Input (Input) import Polysemy.Time import Polysemy.TinyLog as Log import System.Logger.Class (field, msg, val, (~~)) +import Wire.API.UserEvent import Wire.NotificationSubsystem import Wire.Sem.Delay import Wire.Sem.Paging.Cassandra (InternalPaging) @@ -63,7 +63,7 @@ onEvent :: onEvent n = handleTimeout $ case n of DeleteClient clientId uid mcon -> do rmClient uid clientId - Intra.onClientEvent uid mcon (ClientRemoved uid clientId) + Intra.onClientEvent uid mcon (ClientRemoved clientId) DeleteUser uid -> do Log.info $ msg (val "Processing user delete event") diff --git a/services/galley/test/integration/API/Teams/LegalHold/DisabledByDefault.hs b/services/galley/test/integration/API/Teams/LegalHold/DisabledByDefault.hs index 8be3b158517..5f85b3a1259 100644 --- a/services/galley/test/integration/API/Teams/LegalHold/DisabledByDefault.hs +++ b/services/galley/test/integration/API/Teams/LegalHold/DisabledByDefault.hs @@ -31,7 +31,6 @@ import Bilge hiding (accept, head, timeout, trace) import Bilge.Assert import Brig.Types.Intra (UserSet (..)) import Brig.Types.Test.Arbitrary () -import Brig.Types.User.Event qualified as Ev import Cassandra.Exec qualified as Cql import Control.Category ((>>>)) import Control.Concurrent.Chan @@ -71,6 +70,7 @@ import Wire.API.Team.Permission import Wire.API.Team.Role import Wire.API.User.Client import Wire.API.User.Client qualified as Client +import Wire.API.UserEvent qualified as Ev tests :: IO TestSetup -> TestTree tests s = @@ -237,7 +237,7 @@ testApproveLegalHoldDevice = do UserLegalHoldEnabled userStatus let pluck = \case - Ev.ClientAdded _ eClient -> do + Ev.ClientAdded eClient -> do clientId eClient @?= someClientId clientType eClient @?= LegalHoldClientType clientClass eClient @?= Just LegalHoldClient @@ -316,7 +316,7 @@ testDisableLegalHoldForUser = do requestLegalHoldDevice owner member tid !!! testResponse 201 Nothing approveLegalHoldDevice (Just defPassword) member member tid !!! testResponse 200 Nothing assertNotification mws $ \case - Ev.ClientAdded _ client -> do + Ev.ClientAdded client -> do clientId client @?= someClientId clientType client @?= LegalHoldClientType clientClass client @?= Just LegalHoldClient @@ -332,7 +332,7 @@ testDisableLegalHoldForUser = do assertEqual "method" "POST" (requestMethod req) assertEqual "path" (pathInfo req) ["legalhold", "remove"] assertNotification mws $ \case - Ev.ClientEvent (Ev.ClientRemoved _ clientId') -> clientId' @?= someClientId + Ev.ClientEvent (Ev.ClientRemoved clientId') -> clientId' @?= someClientId _ -> assertBool "Unexpected event" False assertNotification mws $ \case Ev.UserEvent (Ev.UserLegalHoldDisabled uid) -> uid @?= member diff --git a/services/galley/test/integration/API/Teams/LegalHold/Util.hs b/services/galley/test/integration/API/Teams/LegalHold/Util.hs index f4362f81507..e0b2d06481b 100644 --- a/services/galley/test/integration/API/Teams/LegalHold/Util.hs +++ b/services/galley/test/integration/API/Teams/LegalHold/Util.hs @@ -11,7 +11,6 @@ import API.Util import Bilge hiding (accept, head, timeout, trace) import Bilge.Assert import Brig.Types.Test.Arbitrary () -import Brig.Types.User.Event qualified as Ev import Control.Concurrent.Async qualified as Async import Control.Concurrent.Chan import Control.Concurrent.Timeout hiding (threadDelay) @@ -61,6 +60,7 @@ import Wire.API.Team.LegalHold.External import Wire.API.Team.Member qualified as Team import Wire.API.User (UserProfile (..)) import Wire.API.User.Client +import Wire.API.UserEvent qualified as Ev -------------------------------------------------------------------- -- setup helpers @@ -487,26 +487,6 @@ requestLegalHoldDevice' g zusr uid tid = do ---------------------------------------------------------------------- -- test helpers -deriving instance Show Ev.Event - -deriving instance Show Ev.UserEvent - -deriving instance Show Ev.ClientEvent - -deriving instance Show Ev.PropertyEvent - -deriving instance Show Ev.ConnectionEvent - --- (partial implementation, just good enough to make the tests work) -instance FromJSON Ev.Event where - parseJSON ev = flip (withObject "Ev.Event") ev $ \o -> do - typ :: Text <- o .: "type" - if - | typ `elem` ["user.legalhold-request", "user.legalhold-enable", "user.legalhold-disable"] -> Ev.UserEvent <$> Aeson.parseJSON ev - | typ `elem` ["user.client-add", "user.client-remove"] -> Ev.ClientEvent <$> Aeson.parseJSON ev - | typ == "user.connection" -> Ev.ConnectionEvent <$> Aeson.parseJSON ev - | otherwise -> fail $ "Ev.Event: unsupported event type: " <> show typ - -- (partial implementation, just good enough to make the tests work) instance FromJSON Ev.UserEvent where parseJSON = withObject "Ev.UserEvent" $ \o -> do @@ -528,11 +508,9 @@ instance FromJSON Ev.ClientEvent where parseJSON = withObject "Ev.ClientEvent" $ \o -> do tag :: Text <- o .: "type" case tag of - "user.client-add" -> Ev.ClientAdded fakeuid <$> o .: "client" - "user.client-remove" -> Ev.ClientRemoved fakeuid <$> (o .: "client" >>= withObject "id" (.: "id")) + "user.client-add" -> Ev.ClientAdded <$> o .: "client" + "user.client-remove" -> Ev.ClientRemoved <$> (o .: "client" >>= withObject "id" (.: "id")) x -> fail $ "Ev.ClientEvent: unsupported event type: " ++ show x - where - fakeuid = read @UserId "6980fb5e-ba64-11eb-a339-0b3625bf01be" instance FromJSON Ev.ConnectionEvent where parseJSON = Aeson.withObject "ConnectionEvent" $ \o -> do @@ -542,7 +520,6 @@ instance FromJSON Ev.ConnectionEvent where Ev.ConnectionUpdated <$> o .: "connection" <*> pure Nothing - <*> pure Nothing x -> fail $ "unspported event type: " ++ show x assertNotification :: (HasCallStack, FromJSON a, MonadIO m) => WS.WebSocket -> (a -> Assertion) -> m ()