{-# LANGUAGE StrictData #-}

-- 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.EmailSubsystem.Template
  ( module Wire.EmailSubsystem.Template,

    -- * Re-exports
    Template,
  )
where

import Data.Map qualified as Map
import Data.Text.Lazy qualified as Lazy
import Data.Text.Template
import HTMLEntities.Text qualified as HTML
import Imports
import Wire.API.Locale
import Wire.API.User

-- | Lookup a localised item from a 'Localised' structure.
forLocale ::
  -- | 'Just' the preferred locale or 'Nothing' for
  -- the default locale.
  Maybe Locale ->
  -- | The 'Localised' structure.
  Localised a ->
  -- | Pair of the effectively chosen locale and the
  -- associated value.
  (Locale, a)
forLocale :: forall a. Maybe Locale -> Localised a -> (Locale, a)
forLocale Maybe Locale
pref Localised a
t = case Maybe Locale
pref of
  Just Locale
l -> (Locale, a) -> Maybe (Locale, a) -> (Locale, a)
forall a. a -> Maybe a -> a
fromMaybe (Localised a -> (Locale, a)
forall a. Localised a -> (Locale, a)
locDefault Localised a
t) (Locale -> Maybe (Locale, a)
select Locale
l)
  Maybe Locale
Nothing -> Localised a -> (Locale, a)
forall a. Localised a -> (Locale, a)
locDefault Localised a
t
  where
    select :: Locale -> Maybe (Locale, a)
select Locale
l =
      let l' :: Locale
l' = Locale
l {lCountry = Nothing}
          loc :: Maybe a
loc = Locale -> Map Locale a -> Maybe a
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Locale
l (Localised a -> Map Locale a
forall a. Localised a -> Map Locale a
locOther Localised a
t)
          lan :: Maybe a
lan = Locale -> Map Locale a -> Maybe a
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Locale
l' (Localised a -> Map Locale a
forall a. Localised a -> Map Locale a
locOther Localised a
t)
       in (Locale
l,) (a -> (Locale, a)) -> Maybe a -> Maybe (Locale, a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe a
loc Maybe (Locale, a) -> Maybe (Locale, a) -> Maybe (Locale, a)
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Locale
l',) (a -> (Locale, a)) -> Maybe a -> Maybe (Locale, a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe a
lan

-- | See 'genTemplateBranding'.
type TemplateBranding = Text -> Text

-- | Localised templates.
data Localised a = Localised
  { forall a. Localised a -> (Locale, a)
locDefault :: (Locale, a),
    forall a. Localised a -> Map Locale a
locOther :: (Map Locale a)
  }

-- | Uses a replace and a branding function, to replaces all placeholders from the
-- given template to produce a Text. To be used on plain text templates
renderTextWithBranding :: Template -> (Text -> Text) -> TemplateBranding -> Lazy.Text
renderTextWithBranding :: Template -> (Text -> Text) -> (Text -> Text) -> Text
renderTextWithBranding Template
tpl Text -> Text
replace Text -> Text
branding = Template -> (Text -> Text) -> Text
render Template
tpl (Text -> Text
replace (Text -> Text) -> (Text -> Text) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
branding)

-- | Uses a replace and a branding function to replace all placeholders from the
-- given template to produce a Text. To be used on HTML templates
renderHtmlWithBranding :: Template -> (Text -> Text) -> TemplateBranding -> Lazy.Text
renderHtmlWithBranding :: Template -> (Text -> Text) -> (Text -> Text) -> Text
renderHtmlWithBranding Template
tpl Text -> Text
replace Text -> Text
branding = Template -> (Text -> Text) -> Text
render Template
tpl (Text -> Text
HTML.text (Text -> Text) -> (Text -> Text) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
replace (Text -> Text) -> (Text -> Text) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
branding)

data UserTemplates = UserTemplates
  { UserTemplates -> ActivationSmsTemplate
activationSms :: ActivationSmsTemplate,
    UserTemplates -> ActivationCallTemplate
activationCall :: ActivationCallTemplate,
    UserTemplates -> VerificationEmailTemplate
verificationEmail :: VerificationEmailTemplate,
    UserTemplates -> ActivationEmailTemplate
activationEmail :: ActivationEmailTemplate,
    UserTemplates -> ActivationEmailTemplate
activationEmailUpdate :: ActivationEmailTemplate,
    UserTemplates -> TeamActivationEmailTemplate
teamActivationEmail :: TeamActivationEmailTemplate,
    UserTemplates -> PasswordResetSmsTemplate
passwordResetSms :: PasswordResetSmsTemplate,
    UserTemplates -> PasswordResetEmailTemplate
passwordResetEmail :: PasswordResetEmailTemplate,
    UserTemplates -> LoginSmsTemplate
loginSms :: LoginSmsTemplate,
    UserTemplates -> LoginCallTemplate
loginCall :: LoginCallTemplate,
    UserTemplates -> DeletionSmsTemplate
deletionSms :: DeletionSmsTemplate,
    UserTemplates -> DeletionEmailTemplate
deletionEmail :: DeletionEmailTemplate,
    UserTemplates -> UpgradePersonalToTeamEmailTemplate
upgradePersonalToTeamEmail :: UpgradePersonalToTeamEmailTemplate,
    UserTemplates -> NewClientEmailTemplate
newClientEmail :: NewClientEmailTemplate,
    UserTemplates -> SecondFactorVerificationEmailTemplate
verificationLoginEmail :: SecondFactorVerificationEmailTemplate,
    UserTemplates -> SecondFactorVerificationEmailTemplate
verificationScimTokenEmail :: SecondFactorVerificationEmailTemplate,
    UserTemplates -> SecondFactorVerificationEmailTemplate
verificationTeamDeletionEmail :: SecondFactorVerificationEmailTemplate
  }

data ActivationSmsTemplate = ActivationSmsTemplate
  { ActivationSmsTemplate -> Template
activationSmslUrl :: Template,
    ActivationSmsTemplate -> Template
activationSmsText :: Template,
    ActivationSmsTemplate -> Text
activationSmsSender :: Text
  }

data ActivationCallTemplate = ActivationCallTemplate
  { ActivationCallTemplate -> Template
activationCallText :: Template
  }

data VerificationEmailTemplate = VerificationEmailTemplate
  { VerificationEmailTemplate -> Template
verificationEmailUrl :: Template,
    VerificationEmailTemplate -> Template
verificationEmailSubject :: Template,
    VerificationEmailTemplate -> Template
verificationEmailBodyText :: Template,
    VerificationEmailTemplate -> Template
verificationEmailBodyHtml :: Template,
    VerificationEmailTemplate -> EmailAddress
verificationEmailSender :: EmailAddress,
    VerificationEmailTemplate -> Text
verificationEmailSenderName :: Text
  }

data ActivationEmailTemplate = ActivationEmailTemplate
  { ActivationEmailTemplate -> Template
activationEmailUrl :: Template,
    ActivationEmailTemplate -> Template
activationEmailSubject :: Template,
    ActivationEmailTemplate -> Template
activationEmailBodyText :: Template,
    ActivationEmailTemplate -> Template
activationEmailBodyHtml :: Template,
    ActivationEmailTemplate -> EmailAddress
activationEmailSender :: EmailAddress,
    ActivationEmailTemplate -> Text
activationEmailSenderName :: Text
  }

data TeamActivationEmailTemplate = TeamActivationEmailTemplate
  { TeamActivationEmailTemplate -> Template
teamActivationEmailUrl :: Template,
    TeamActivationEmailTemplate -> Template
teamActivationEmailSubject :: Template,
    TeamActivationEmailTemplate -> Template
teamActivationEmailBodyText :: Template,
    TeamActivationEmailTemplate -> Template
teamActivationEmailBodyHtml :: Template,
    TeamActivationEmailTemplate -> EmailAddress
teamActivationEmailSender :: EmailAddress,
    TeamActivationEmailTemplate -> Text
teamActivationEmailSenderName :: Text
  }

data DeletionEmailTemplate = DeletionEmailTemplate
  { DeletionEmailTemplate -> Template
deletionEmailUrl :: Template,
    DeletionEmailTemplate -> Template
deletionEmailSubject :: Template,
    DeletionEmailTemplate -> Template
deletionEmailBodyText :: Template,
    DeletionEmailTemplate -> Template
deletionEmailBodyHtml :: Template,
    DeletionEmailTemplate -> EmailAddress
deletionEmailSender :: EmailAddress,
    DeletionEmailTemplate -> Text
deletionEmailSenderName :: Text
  }

data UpgradePersonalToTeamEmailTemplate = UpgradePersonalToTeamEmailTemplate
  { UpgradePersonalToTeamEmailTemplate -> Template
upgradePersonalToTeamEmailSubject :: Template,
    UpgradePersonalToTeamEmailTemplate -> Template
upgradePersonalToTeamEmailBodyText :: Template,
    UpgradePersonalToTeamEmailTemplate -> Template
upgradePersonalToTeamEmailBodyHtml :: Template,
    UpgradePersonalToTeamEmailTemplate -> EmailAddress
upgradePersonalToTeamEmailSender :: EmailAddress,
    UpgradePersonalToTeamEmailTemplate -> Text
upgradePersonalToTeamEmailSenderName :: Text
  }

data PasswordResetEmailTemplate = PasswordResetEmailTemplate
  { PasswordResetEmailTemplate -> Template
passwordResetEmailUrl :: Template,
    PasswordResetEmailTemplate -> Template
passwordResetEmailSubject :: Template,
    PasswordResetEmailTemplate -> Template
passwordResetEmailBodyText :: Template,
    PasswordResetEmailTemplate -> Template
passwordResetEmailBodyHtml :: Template,
    PasswordResetEmailTemplate -> EmailAddress
passwordResetEmailSender :: EmailAddress,
    PasswordResetEmailTemplate -> Text
passwordResetEmailSenderName :: Text
  }

data PasswordResetSmsTemplate = PasswordResetSmsTemplate
  { PasswordResetSmsTemplate -> Template
passwordResetSmsText :: Template,
    PasswordResetSmsTemplate -> Text
passwordResetSmsSender :: Text
  }

data LoginSmsTemplate = LoginSmsTemplate
  { LoginSmsTemplate -> Template
loginSmsUrl :: Template,
    LoginSmsTemplate -> Template
loginSmsText :: Template,
    LoginSmsTemplate -> Text
loginSmsSender :: Text
  }

data LoginCallTemplate = LoginCallTemplate
  { LoginCallTemplate -> Template
loginCallText :: Template
  }

data DeletionSmsTemplate = DeletionSmsTemplate
  { DeletionSmsTemplate -> Template
deletionSmsUrl :: Template,
    DeletionSmsTemplate -> Template
deletionSmsText :: Template,
    DeletionSmsTemplate -> Text
deletionSmsSender :: Text
  }

data NewClientEmailTemplate = NewClientEmailTemplate
  { NewClientEmailTemplate -> Template
newClientEmailSubject :: Template,
    NewClientEmailTemplate -> Template
newClientEmailBodyText :: Template,
    NewClientEmailTemplate -> Template
newClientEmailBodyHtml :: Template,
    NewClientEmailTemplate -> EmailAddress
newClientEmailSender :: EmailAddress,
    NewClientEmailTemplate -> Text
newClientEmailSenderName :: Text
  }

data SecondFactorVerificationEmailTemplate = SecondFactorVerificationEmailTemplate
  { SecondFactorVerificationEmailTemplate -> Template
sndFactorVerificationEmailSubject :: Template,
    SecondFactorVerificationEmailTemplate -> Template
sndFactorVerificationEmailBodyText :: Template,
    SecondFactorVerificationEmailTemplate -> Template
sndFactorVerificationEmailBodyHtml :: Template,
    SecondFactorVerificationEmailTemplate -> EmailAddress
sndFactorVerificationEmailSender :: EmailAddress,
    SecondFactorVerificationEmailTemplate -> Text
sndFactorVerificationEmailSenderName :: Text
  }

data InvitationEmailTemplate = InvitationEmailTemplate
  { InvitationEmailTemplate -> Template
invitationEmailUrl :: !Template,
    InvitationEmailTemplate -> Template
invitationEmailSubject :: !Template,
    InvitationEmailTemplate -> Template
invitationEmailBodyText :: !Template,
    InvitationEmailTemplate -> Template
invitationEmailBodyHtml :: !Template,
    InvitationEmailTemplate -> EmailAddress
invitationEmailSender :: !EmailAddress,
    InvitationEmailTemplate -> Text
invitationEmailSenderName :: !Text
  }

data CreatorWelcomeEmailTemplate = CreatorWelcomeEmailTemplate
  { CreatorWelcomeEmailTemplate -> Text
creatorWelcomeEmailUrl :: !Text,
    CreatorWelcomeEmailTemplate -> Template
creatorWelcomeEmailSubject :: !Template,
    CreatorWelcomeEmailTemplate -> Template
creatorWelcomeEmailBodyText :: !Template,
    CreatorWelcomeEmailTemplate -> Template
creatorWelcomeEmailBodyHtml :: !Template,
    CreatorWelcomeEmailTemplate -> EmailAddress
creatorWelcomeEmailSender :: !EmailAddress,
    CreatorWelcomeEmailTemplate -> Text
creatorWelcomeEmailSenderName :: !Text
  }

data MemberWelcomeEmailTemplate = MemberWelcomeEmailTemplate
  { MemberWelcomeEmailTemplate -> Text
memberWelcomeEmailUrl :: !Text,
    MemberWelcomeEmailTemplate -> Template
memberWelcomeEmailSubject :: !Template,
    MemberWelcomeEmailTemplate -> Template
memberWelcomeEmailBodyText :: !Template,
    MemberWelcomeEmailTemplate -> Template
memberWelcomeEmailBodyHtml :: !Template,
    MemberWelcomeEmailTemplate -> EmailAddress
memberWelcomeEmailSender :: !EmailAddress,
    MemberWelcomeEmailTemplate -> Text
memberWelcomeEmailSenderName :: !Text
  }

data TeamTemplates = TeamTemplates
  { TeamTemplates -> InvitationEmailTemplate
invitationEmail :: !InvitationEmailTemplate,
    TeamTemplates -> InvitationEmailTemplate
existingUserInvitationEmail :: !InvitationEmailTemplate,
    TeamTemplates -> CreatorWelcomeEmailTemplate
creatorWelcomeEmail :: !CreatorWelcomeEmailTemplate,
    TeamTemplates -> MemberWelcomeEmailTemplate
memberWelcomeEmail :: !MemberWelcomeEmailTemplate
  }