-- 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/>.
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE StrictData #-}
{-# LANGUAGE TemplateHaskell #-}

module Wire.InvitationStore where

import Data.Id (InvitationId, TeamId, UserId)
import Data.Json.Util (UTCTimeMillis)
import Data.Range (Range)
import Database.CQL.Protocol (Record (..), TupleType, recordInstance)
import Imports
import Polysemy
import URI.ByteString
import Util.Timeout
import Wire.API.Team.Invitation (Invitation (inviteeEmail))
import Wire.API.Team.Invitation qualified as Public
import Wire.API.Team.Role (Role, defaultRole)
import Wire.API.User (EmailAddress, InvitationCode, Name)
import Wire.Arbitrary (Arbitrary, GenericUniform (..))

data StoredInvitation = MkStoredInvitation
  { StoredInvitation -> TeamId
teamId :: TeamId,
    StoredInvitation -> Maybe Role
role :: Maybe Role,
    StoredInvitation -> InvitationId
invitationId :: InvitationId,
    StoredInvitation -> UTCTimeMillis
createdAt :: UTCTimeMillis,
    StoredInvitation -> Maybe UserId
createdBy :: Maybe UserId,
    StoredInvitation -> EmailAddress
email :: EmailAddress,
    StoredInvitation -> Maybe Name
name :: Maybe Name,
    StoredInvitation -> InvitationCode
code :: InvitationCode
  }
  deriving (Int -> StoredInvitation -> ShowS
[StoredInvitation] -> ShowS
StoredInvitation -> String
(Int -> StoredInvitation -> ShowS)
-> (StoredInvitation -> String)
-> ([StoredInvitation] -> ShowS)
-> Show StoredInvitation
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> StoredInvitation -> ShowS
showsPrec :: Int -> StoredInvitation -> ShowS
$cshow :: StoredInvitation -> String
show :: StoredInvitation -> String
$cshowList :: [StoredInvitation] -> ShowS
showList :: [StoredInvitation] -> ShowS
Show, StoredInvitation -> StoredInvitation -> Bool
(StoredInvitation -> StoredInvitation -> Bool)
-> (StoredInvitation -> StoredInvitation -> Bool)
-> Eq StoredInvitation
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: StoredInvitation -> StoredInvitation -> Bool
== :: StoredInvitation -> StoredInvitation -> Bool
$c/= :: StoredInvitation -> StoredInvitation -> Bool
/= :: StoredInvitation -> StoredInvitation -> Bool
Eq, (forall x. StoredInvitation -> Rep StoredInvitation x)
-> (forall x. Rep StoredInvitation x -> StoredInvitation)
-> Generic StoredInvitation
forall x. Rep StoredInvitation x -> StoredInvitation
forall x. StoredInvitation -> Rep StoredInvitation x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. StoredInvitation -> Rep StoredInvitation x
from :: forall x. StoredInvitation -> Rep StoredInvitation x
$cto :: forall x. Rep StoredInvitation x -> StoredInvitation
to :: forall x. Rep StoredInvitation x -> StoredInvitation
Generic)
  deriving (Gen StoredInvitation
Gen StoredInvitation
-> (StoredInvitation -> [StoredInvitation])
-> Arbitrary StoredInvitation
StoredInvitation -> [StoredInvitation]
forall a. Gen a -> (a -> [a]) -> Arbitrary a
$carbitrary :: Gen StoredInvitation
arbitrary :: Gen StoredInvitation
$cshrink :: StoredInvitation -> [StoredInvitation]
shrink :: StoredInvitation -> [StoredInvitation]
Arbitrary) via (GenericUniform StoredInvitation)

recordInstance ''StoredInvitation

data InsertInvitation = MkInsertInvitation
  { InsertInvitation -> InvitationId
invitationId :: InvitationId,
    InsertInvitation -> TeamId
teamId :: TeamId,
    InsertInvitation -> Role
role :: Role,
    InsertInvitation -> UTCTime
createdAt :: UTCTime,
    InsertInvitation -> Maybe UserId
createdBy :: Maybe UserId,
    InsertInvitation -> EmailAddress
inviteeEmail :: EmailAddress,
    InsertInvitation -> Maybe Name
inviteeName :: Maybe Name,
    InsertInvitation -> InvitationCode
code :: InvitationCode
  }
  deriving (Int -> InsertInvitation -> ShowS
[InsertInvitation] -> ShowS
InsertInvitation -> String
(Int -> InsertInvitation -> ShowS)
-> (InsertInvitation -> String)
-> ([InsertInvitation] -> ShowS)
-> Show InsertInvitation
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> InsertInvitation -> ShowS
showsPrec :: Int -> InsertInvitation -> ShowS
$cshow :: InsertInvitation -> String
show :: InsertInvitation -> String
$cshowList :: [InsertInvitation] -> ShowS
showList :: [InsertInvitation] -> ShowS
Show, InsertInvitation -> InsertInvitation -> Bool
(InsertInvitation -> InsertInvitation -> Bool)
-> (InsertInvitation -> InsertInvitation -> Bool)
-> Eq InsertInvitation
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: InsertInvitation -> InsertInvitation -> Bool
== :: InsertInvitation -> InsertInvitation -> Bool
$c/= :: InsertInvitation -> InsertInvitation -> Bool
/= :: InsertInvitation -> InsertInvitation -> Bool
Eq, (forall x. InsertInvitation -> Rep InsertInvitation x)
-> (forall x. Rep InsertInvitation x -> InsertInvitation)
-> Generic InsertInvitation
forall x. Rep InsertInvitation x -> InsertInvitation
forall x. InsertInvitation -> Rep InsertInvitation x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. InsertInvitation -> Rep InsertInvitation x
from :: forall x. InsertInvitation -> Rep InsertInvitation x
$cto :: forall x. Rep InsertInvitation x -> InsertInvitation
to :: forall x. Rep InsertInvitation x -> InsertInvitation
Generic)

recordInstance ''InsertInvitation

data PaginatedResult a
  = PaginatedResultHasMore a
  | PaginatedResult a
  deriving stock (PaginatedResult a -> PaginatedResult a -> Bool
(PaginatedResult a -> PaginatedResult a -> Bool)
-> (PaginatedResult a -> PaginatedResult a -> Bool)
-> Eq (PaginatedResult a)
forall a. Eq a => PaginatedResult a -> PaginatedResult a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall a. Eq a => PaginatedResult a -> PaginatedResult a -> Bool
== :: PaginatedResult a -> PaginatedResult a -> Bool
$c/= :: forall a. Eq a => PaginatedResult a -> PaginatedResult a -> Bool
/= :: PaginatedResult a -> PaginatedResult a -> Bool
Eq, Eq (PaginatedResult a)
Eq (PaginatedResult a) =>
(PaginatedResult a -> PaginatedResult a -> Ordering)
-> (PaginatedResult a -> PaginatedResult a -> Bool)
-> (PaginatedResult a -> PaginatedResult a -> Bool)
-> (PaginatedResult a -> PaginatedResult a -> Bool)
-> (PaginatedResult a -> PaginatedResult a -> Bool)
-> (PaginatedResult a -> PaginatedResult a -> PaginatedResult a)
-> (PaginatedResult a -> PaginatedResult a -> PaginatedResult a)
-> Ord (PaginatedResult a)
PaginatedResult a -> PaginatedResult a -> Bool
PaginatedResult a -> PaginatedResult a -> Ordering
PaginatedResult a -> PaginatedResult a -> PaginatedResult a
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall a. Ord a => Eq (PaginatedResult a)
forall a. Ord a => PaginatedResult a -> PaginatedResult a -> Bool
forall a.
Ord a =>
PaginatedResult a -> PaginatedResult a -> Ordering
forall a.
Ord a =>
PaginatedResult a -> PaginatedResult a -> PaginatedResult a
$ccompare :: forall a.
Ord a =>
PaginatedResult a -> PaginatedResult a -> Ordering
compare :: PaginatedResult a -> PaginatedResult a -> Ordering
$c< :: forall a. Ord a => PaginatedResult a -> PaginatedResult a -> Bool
< :: PaginatedResult a -> PaginatedResult a -> Bool
$c<= :: forall a. Ord a => PaginatedResult a -> PaginatedResult a -> Bool
<= :: PaginatedResult a -> PaginatedResult a -> Bool
$c> :: forall a. Ord a => PaginatedResult a -> PaginatedResult a -> Bool
> :: PaginatedResult a -> PaginatedResult a -> Bool
$c>= :: forall a. Ord a => PaginatedResult a -> PaginatedResult a -> Bool
>= :: PaginatedResult a -> PaginatedResult a -> Bool
$cmax :: forall a.
Ord a =>
PaginatedResult a -> PaginatedResult a -> PaginatedResult a
max :: PaginatedResult a -> PaginatedResult a -> PaginatedResult a
$cmin :: forall a.
Ord a =>
PaginatedResult a -> PaginatedResult a -> PaginatedResult a
min :: PaginatedResult a -> PaginatedResult a -> PaginatedResult a
Ord, Int -> PaginatedResult a -> ShowS
[PaginatedResult a] -> ShowS
PaginatedResult a -> String
(Int -> PaginatedResult a -> ShowS)
-> (PaginatedResult a -> String)
-> ([PaginatedResult a] -> ShowS)
-> Show (PaginatedResult a)
forall a. Show a => Int -> PaginatedResult a -> ShowS
forall a. Show a => [PaginatedResult a] -> ShowS
forall a. Show a => PaginatedResult a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall a. Show a => Int -> PaginatedResult a -> ShowS
showsPrec :: Int -> PaginatedResult a -> ShowS
$cshow :: forall a. Show a => PaginatedResult a -> String
show :: PaginatedResult a -> String
$cshowList :: forall a. Show a => [PaginatedResult a] -> ShowS
showList :: [PaginatedResult a] -> ShowS
Show, (forall a b. (a -> b) -> PaginatedResult a -> PaginatedResult b)
-> (forall a b. a -> PaginatedResult b -> PaginatedResult a)
-> Functor PaginatedResult
forall a b. a -> PaginatedResult b -> PaginatedResult a
forall a b. (a -> b) -> PaginatedResult a -> PaginatedResult b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a b. (a -> b) -> PaginatedResult a -> PaginatedResult b
fmap :: forall a b. (a -> b) -> PaginatedResult a -> PaginatedResult b
$c<$ :: forall a b. a -> PaginatedResult b -> PaginatedResult a
<$ :: forall a b. a -> PaginatedResult b -> PaginatedResult a
Functor, (forall m. Monoid m => PaginatedResult m -> m)
-> (forall m a. Monoid m => (a -> m) -> PaginatedResult a -> m)
-> (forall m a. Monoid m => (a -> m) -> PaginatedResult a -> m)
-> (forall a b. (a -> b -> b) -> b -> PaginatedResult a -> b)
-> (forall a b. (a -> b -> b) -> b -> PaginatedResult a -> b)
-> (forall b a. (b -> a -> b) -> b -> PaginatedResult a -> b)
-> (forall b a. (b -> a -> b) -> b -> PaginatedResult a -> b)
-> (forall a. (a -> a -> a) -> PaginatedResult a -> a)
-> (forall a. (a -> a -> a) -> PaginatedResult a -> a)
-> (forall a. PaginatedResult a -> [a])
-> (forall a. PaginatedResult a -> Bool)
-> (forall a. PaginatedResult a -> Int)
-> (forall a. Eq a => a -> PaginatedResult a -> Bool)
-> (forall a. Ord a => PaginatedResult a -> a)
-> (forall a. Ord a => PaginatedResult a -> a)
-> (forall a. Num a => PaginatedResult a -> a)
-> (forall a. Num a => PaginatedResult a -> a)
-> Foldable PaginatedResult
forall a. Eq a => a -> PaginatedResult a -> Bool
forall a. Num a => PaginatedResult a -> a
forall a. Ord a => PaginatedResult a -> a
forall m. Monoid m => PaginatedResult m -> m
forall a. PaginatedResult a -> Bool
forall a. PaginatedResult a -> Int
forall a. PaginatedResult a -> [a]
forall a. (a -> a -> a) -> PaginatedResult a -> a
forall m a. Monoid m => (a -> m) -> PaginatedResult a -> m
forall b a. (b -> a -> b) -> b -> PaginatedResult a -> b
forall a b. (a -> b -> b) -> b -> PaginatedResult a -> b
forall (t :: * -> *).
(forall m. Monoid m => t m -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. t a -> [a])
-> (forall a. t a -> Bool)
-> (forall a. t a -> Int)
-> (forall a. Eq a => a -> t a -> Bool)
-> (forall a. Ord a => t a -> a)
-> (forall a. Ord a => t a -> a)
-> (forall a. Num a => t a -> a)
-> (forall a. Num a => t a -> a)
-> Foldable t
$cfold :: forall m. Monoid m => PaginatedResult m -> m
fold :: forall m. Monoid m => PaginatedResult m -> m
$cfoldMap :: forall m a. Monoid m => (a -> m) -> PaginatedResult a -> m
foldMap :: forall m a. Monoid m => (a -> m) -> PaginatedResult a -> m
$cfoldMap' :: forall m a. Monoid m => (a -> m) -> PaginatedResult a -> m
foldMap' :: forall m a. Monoid m => (a -> m) -> PaginatedResult a -> m
$cfoldr :: forall a b. (a -> b -> b) -> b -> PaginatedResult a -> b
foldr :: forall a b. (a -> b -> b) -> b -> PaginatedResult a -> b
$cfoldr' :: forall a b. (a -> b -> b) -> b -> PaginatedResult a -> b
foldr' :: forall a b. (a -> b -> b) -> b -> PaginatedResult a -> b
$cfoldl :: forall b a. (b -> a -> b) -> b -> PaginatedResult a -> b
foldl :: forall b a. (b -> a -> b) -> b -> PaginatedResult a -> b
$cfoldl' :: forall b a. (b -> a -> b) -> b -> PaginatedResult a -> b
foldl' :: forall b a. (b -> a -> b) -> b -> PaginatedResult a -> b
$cfoldr1 :: forall a. (a -> a -> a) -> PaginatedResult a -> a
foldr1 :: forall a. (a -> a -> a) -> PaginatedResult a -> a
$cfoldl1 :: forall a. (a -> a -> a) -> PaginatedResult a -> a
foldl1 :: forall a. (a -> a -> a) -> PaginatedResult a -> a
$ctoList :: forall a. PaginatedResult a -> [a]
toList :: forall a. PaginatedResult a -> [a]
$cnull :: forall a. PaginatedResult a -> Bool
null :: forall a. PaginatedResult a -> Bool
$clength :: forall a. PaginatedResult a -> Int
length :: forall a. PaginatedResult a -> Int
$celem :: forall a. Eq a => a -> PaginatedResult a -> Bool
elem :: forall a. Eq a => a -> PaginatedResult a -> Bool
$cmaximum :: forall a. Ord a => PaginatedResult a -> a
maximum :: forall a. Ord a => PaginatedResult a -> a
$cminimum :: forall a. Ord a => PaginatedResult a -> a
minimum :: forall a. Ord a => PaginatedResult a -> a
$csum :: forall a. Num a => PaginatedResult a -> a
sum :: forall a. Num a => PaginatedResult a -> a
$cproduct :: forall a. Num a => PaginatedResult a -> a
product :: forall a. Num a => PaginatedResult a -> a
Foldable)

----------------------------

data InvitationStore :: Effect where
  InsertInvitation :: InsertInvitation -> Timeout -> InvitationStore m StoredInvitation
  LookupInvitation :: TeamId -> InvitationId -> InvitationStore m (Maybe StoredInvitation)
  LookupInvitationByCode :: InvitationCode -> InvitationStore m (Maybe StoredInvitation)
  LookupInvitationsByEmail :: EmailAddress -> InvitationStore m [StoredInvitation]
  -- | Range is page size, it defaults to 100
  LookupInvitationsPaginated :: Maybe (Range 1 500 Int32) -> TeamId -> Maybe InvitationId -> InvitationStore m (PaginatedResult [StoredInvitation])
  CountInvitations :: TeamId -> InvitationStore m Int64
  DeleteInvitation :: TeamId -> InvitationId -> InvitationStore m ()
  DeleteAllTeamInvitations :: TeamId -> InvitationStore m ()

makeSem ''InvitationStore

----------------------------

invitationFromStored :: Maybe (URIRef Absolute) -> StoredInvitation -> Public.Invitation
invitationFromStored :: Maybe (URIRef Absolute) -> StoredInvitation -> Invitation
invitationFromStored Maybe (URIRef Absolute)
maybeUrl MkStoredInvitation {Maybe UserId
Maybe Role
Maybe Name
EmailAddress
InvitationId
TeamId
UTCTimeMillis
InvitationCode
$sel:teamId:MkStoredInvitation :: StoredInvitation -> TeamId
$sel:role:MkStoredInvitation :: StoredInvitation -> Maybe Role
$sel:invitationId:MkStoredInvitation :: StoredInvitation -> InvitationId
$sel:createdAt:MkStoredInvitation :: StoredInvitation -> UTCTimeMillis
$sel:createdBy:MkStoredInvitation :: StoredInvitation -> Maybe UserId
$sel:email:MkStoredInvitation :: StoredInvitation -> EmailAddress
$sel:name:MkStoredInvitation :: StoredInvitation -> Maybe Name
$sel:code:MkStoredInvitation :: StoredInvitation -> InvitationCode
teamId :: TeamId
role :: Maybe Role
invitationId :: InvitationId
createdAt :: UTCTimeMillis
createdBy :: Maybe UserId
email :: EmailAddress
name :: Maybe Name
code :: InvitationCode
..} =
  Public.Invitation
    { $sel:team:Invitation :: TeamId
team = TeamId
teamId,
      $sel:role:Invitation :: Role
role = Role -> Maybe Role -> Role
forall a. a -> Maybe a -> a
fromMaybe Role
defaultRole Maybe Role
role,
      $sel:invitationId:Invitation :: InvitationId
invitationId = InvitationId
invitationId,
      $sel:createdAt:Invitation :: UTCTimeMillis
createdAt = UTCTimeMillis
createdAt,
      $sel:createdBy:Invitation :: Maybe UserId
createdBy = Maybe UserId
createdBy,
      $sel:inviteeEmail:Invitation :: EmailAddress
inviteeEmail = EmailAddress
email,
      $sel:inviteeName:Invitation :: Maybe Name
inviteeName = Maybe Name
name,
      $sel:inviteeUrl:Invitation :: Maybe (URIRef Absolute)
inviteeUrl = Maybe (URIRef Absolute)
maybeUrl
    }