-- This file is part of the Wire Server implementation.
--
-- Copyright (C) 2022 Wire Swiss GmbH <opensource@wire.com>
--
-- This program is free software: you can redistribute it and/or modify it under
-- the terms of the GNU Affero General Public License as published by the Free
-- Software Foundation, either version 3 of the License, or (at your option) any
-- later version.
--
-- This program is distributed in the hope that it will be useful, but WITHOUT
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
-- details.
--
-- You should have received a copy of the GNU Affero General Public License along
-- with this program. If not, see <https://www.gnu.org/licenses/>.

module Wire.InternalEvent
  ( InternalNotification (..),
  )
where

import Data.Aeson
import Data.Aeson.Types
import Data.Id
import Imports

data InternalNotification
  = DeleteClient !ClientId !UserId !(Maybe ConnId)
  | DeleteUser !UserId
  | DeleteService !ProviderId !ServiceId
  deriving (InternalNotification -> InternalNotification -> Bool
(InternalNotification -> InternalNotification -> Bool)
-> (InternalNotification -> InternalNotification -> Bool)
-> Eq InternalNotification
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: InternalNotification -> InternalNotification -> Bool
== :: InternalNotification -> InternalNotification -> Bool
$c/= :: InternalNotification -> InternalNotification -> Bool
/= :: InternalNotification -> InternalNotification -> Bool
Eq, Int -> InternalNotification -> ShowS
[InternalNotification] -> ShowS
InternalNotification -> String
(Int -> InternalNotification -> ShowS)
-> (InternalNotification -> String)
-> ([InternalNotification] -> ShowS)
-> Show InternalNotification
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> InternalNotification -> ShowS
showsPrec :: Int -> InternalNotification -> ShowS
$cshow :: InternalNotification -> String
show :: InternalNotification -> String
$cshowList :: [InternalNotification] -> ShowS
showList :: [InternalNotification] -> ShowS
Show)

data InternalNotificationType
  = ClientDeletion
  | UserDeletion
  | ServiceDeletion
  deriving (InternalNotificationType -> InternalNotificationType -> Bool
(InternalNotificationType -> InternalNotificationType -> Bool)
-> (InternalNotificationType -> InternalNotificationType -> Bool)
-> Eq InternalNotificationType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: InternalNotificationType -> InternalNotificationType -> Bool
== :: InternalNotificationType -> InternalNotificationType -> Bool
$c/= :: InternalNotificationType -> InternalNotificationType -> Bool
/= :: InternalNotificationType -> InternalNotificationType -> Bool
Eq, Int -> InternalNotificationType -> ShowS
[InternalNotificationType] -> ShowS
InternalNotificationType -> String
(Int -> InternalNotificationType -> ShowS)
-> (InternalNotificationType -> String)
-> ([InternalNotificationType] -> ShowS)
-> Show InternalNotificationType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> InternalNotificationType -> ShowS
showsPrec :: Int -> InternalNotificationType -> ShowS
$cshow :: InternalNotificationType -> String
show :: InternalNotificationType -> String
$cshowList :: [InternalNotificationType] -> ShowS
showList :: [InternalNotificationType] -> ShowS
Show)

instance FromJSON InternalNotificationType where
  parseJSON :: Value -> Parser InternalNotificationType
parseJSON = \case
    Value
"client.delete" -> InternalNotificationType -> Parser InternalNotificationType
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure InternalNotificationType
ClientDeletion
    Value
"user.delete" -> InternalNotificationType -> Parser InternalNotificationType
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure InternalNotificationType
UserDeletion
    Value
"service.delete" -> InternalNotificationType -> Parser InternalNotificationType
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure InternalNotificationType
ServiceDeletion
    Value
x -> String -> Parser InternalNotificationType
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Parser InternalNotificationType)
-> String -> Parser InternalNotificationType
forall a b. (a -> b) -> a -> b
$ String
"InternalNotificationType: Unknown type " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Value -> String
forall a. Show a => a -> String
show Value
x

instance ToJSON InternalNotificationType where
  toJSON :: InternalNotificationType -> Value
toJSON InternalNotificationType
ClientDeletion = Value
"client.delete"
  toJSON InternalNotificationType
UserDeletion = Value
"user.delete"
  toJSON InternalNotificationType
ServiceDeletion = Value
"service.delete"

instance FromJSON InternalNotification where
  parseJSON :: Value -> Parser InternalNotification
parseJSON = String
-> (Object -> Parser InternalNotification)
-> Value
-> Parser InternalNotification
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"InternalNotification" ((Object -> Parser InternalNotification)
 -> Value -> Parser InternalNotification)
-> (Object -> Parser InternalNotification)
-> Value
-> Parser InternalNotification
forall a b. (a -> b) -> a -> b
$ \Object
o -> do
    InternalNotificationType
t <- Object
o Object -> Key -> Parser InternalNotificationType
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"type"
    case (InternalNotificationType
t :: InternalNotificationType) of
      InternalNotificationType
ClientDeletion -> ClientId -> UserId -> Maybe ConnId -> InternalNotification
DeleteClient (ClientId -> UserId -> Maybe ConnId -> InternalNotification)
-> Parser ClientId
-> Parser (UserId -> Maybe ConnId -> InternalNotification)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Value -> Parser ClientId
adaptOldFormat (Value -> Parser ClientId) -> Parser Value -> Parser ClientId
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (Object
o Object -> Key -> Parser Value
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"client")) Parser (UserId -> Maybe ConnId -> InternalNotification)
-> Parser UserId -> Parser (Maybe ConnId -> InternalNotification)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o Object -> Key -> Parser UserId
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"user" Parser (Maybe ConnId -> InternalNotification)
-> Parser (Maybe ConnId) -> Parser InternalNotification
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o Object -> Key -> Parser (Maybe ConnId)
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"connection"
      InternalNotificationType
UserDeletion -> UserId -> InternalNotification
DeleteUser (UserId -> InternalNotification)
-> Parser UserId -> Parser InternalNotification
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o Object -> Key -> Parser UserId
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"user"
      InternalNotificationType
ServiceDeletion -> ProviderId -> ServiceId -> InternalNotification
DeleteService (ProviderId -> ServiceId -> InternalNotification)
-> Parser ProviderId -> Parser (ServiceId -> InternalNotification)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o Object -> Key -> Parser ProviderId
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"provider" Parser (ServiceId -> InternalNotification)
-> Parser ServiceId -> Parser InternalNotification
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o Object -> Key -> Parser ServiceId
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"service"
    where
      adaptOldFormat :: Value -> Parser ClientId
      adaptOldFormat :: Value -> Parser ClientId
adaptOldFormat (Object Object
ob) = Object
ob Object -> Key -> Parser ClientId
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"id"
      adaptOldFormat v :: Value
v@(String Text
_) = Value -> Parser ClientId
forall a. FromJSON a => Value -> Parser a
parseJSON Value
v
      adaptOldFormat Value
_ = String -> Parser ClientId
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"adaptOld: "

instance ToJSON InternalNotification where
  toJSON :: InternalNotification -> Value
toJSON (DeleteClient ClientId
c UserId
uid Maybe ConnId
con) =
    [Pair] -> Value
object
      [ Key
"client" Key -> ClientId -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= ClientId
c,
        Key
"user" Key -> UserId -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= UserId
uid,
        Key
"connection" Key -> Maybe ConnId -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= Maybe ConnId
con,
        Key
"type" Key -> InternalNotificationType -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= InternalNotificationType
ClientDeletion
      ]
  toJSON (DeleteUser UserId
uid) =
    [Pair] -> Value
object
      [ Key
"user" Key -> UserId -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= UserId
uid,
        Key
"type" Key -> InternalNotificationType -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= InternalNotificationType
UserDeletion
      ]
  toJSON (DeleteService ProviderId
pid ServiceId
sid) =
    [Pair] -> Value
object
      [ Key
"provider" Key -> ProviderId -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= ProviderId
pid,
        Key
"service" Key -> ServiceId -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= ServiceId
sid,
        Key
"type" Key -> InternalNotificationType -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
forall v. ToJSON v => Key -> v -> Pair
.= InternalNotificationType
ServiceDeletion
      ]