{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TypeOperators #-}

module Server.Auth.PasswordReset
    ( PasswordResetRequest (..)
    , PasswordResetConfirm (..)
    , PasswordResetToken (..)
    , PasswordResetAPI
    ) where

import Data.Aeson (FromJSON)
import Data.OpenApi (ToSchema)
import Data.Text (Text)
import Data.Time (UTCTime)
import Data.UUID (UUID)
import GHC.Generics (Generic)
import Servant.API
import UserManagement.User (UserID)

-- | Request data for initiating a password reset
newtype PasswordResetRequest = PasswordResetRequest
    { PasswordResetRequest -> Text
resetRequestEmail :: Text
    }
    deriving ((forall x. PasswordResetRequest -> Rep PasswordResetRequest x)
-> (forall x. Rep PasswordResetRequest x -> PasswordResetRequest)
-> Generic PasswordResetRequest
forall x. Rep PasswordResetRequest x -> PasswordResetRequest
forall x. PasswordResetRequest -> Rep PasswordResetRequest x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. PasswordResetRequest -> Rep PasswordResetRequest x
from :: forall x. PasswordResetRequest -> Rep PasswordResetRequest x
$cto :: forall x. Rep PasswordResetRequest x -> PasswordResetRequest
to :: forall x. Rep PasswordResetRequest x -> PasswordResetRequest
Generic, Maybe PasswordResetRequest
Value -> Parser [PasswordResetRequest]
Value -> Parser PasswordResetRequest
(Value -> Parser PasswordResetRequest)
-> (Value -> Parser [PasswordResetRequest])
-> Maybe PasswordResetRequest
-> FromJSON PasswordResetRequest
forall a.
(Value -> Parser a)
-> (Value -> Parser [a]) -> Maybe a -> FromJSON a
$cparseJSON :: Value -> Parser PasswordResetRequest
parseJSON :: Value -> Parser PasswordResetRequest
$cparseJSONList :: Value -> Parser [PasswordResetRequest]
parseJSONList :: Value -> Parser [PasswordResetRequest]
$comittedField :: Maybe PasswordResetRequest
omittedField :: Maybe PasswordResetRequest
FromJSON, Typeable PasswordResetRequest
Typeable PasswordResetRequest =>
(Proxy PasswordResetRequest
 -> Declare (Definitions Schema) NamedSchema)
-> ToSchema PasswordResetRequest
Proxy PasswordResetRequest
-> Declare (Definitions Schema) NamedSchema
forall a.
Typeable a =>
(Proxy a -> Declare (Definitions Schema) NamedSchema) -> ToSchema a
$cdeclareNamedSchema :: Proxy PasswordResetRequest
-> Declare (Definitions Schema) NamedSchema
declareNamedSchema :: Proxy PasswordResetRequest
-> Declare (Definitions Schema) NamedSchema
ToSchema)

-- | Data for confirming a password reset with token
data PasswordResetConfirm = PasswordResetConfirm
    { PasswordResetConfirm -> Text
resetConfirmToken :: Text
    , PasswordResetConfirm -> Text
resetConfirmNewPassword :: Text
    }
    deriving ((forall x. PasswordResetConfirm -> Rep PasswordResetConfirm x)
-> (forall x. Rep PasswordResetConfirm x -> PasswordResetConfirm)
-> Generic PasswordResetConfirm
forall x. Rep PasswordResetConfirm x -> PasswordResetConfirm
forall x. PasswordResetConfirm -> Rep PasswordResetConfirm x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. PasswordResetConfirm -> Rep PasswordResetConfirm x
from :: forall x. PasswordResetConfirm -> Rep PasswordResetConfirm x
$cto :: forall x. Rep PasswordResetConfirm x -> PasswordResetConfirm
to :: forall x. Rep PasswordResetConfirm x -> PasswordResetConfirm
Generic, Maybe PasswordResetConfirm
Value -> Parser [PasswordResetConfirm]
Value -> Parser PasswordResetConfirm
(Value -> Parser PasswordResetConfirm)
-> (Value -> Parser [PasswordResetConfirm])
-> Maybe PasswordResetConfirm
-> FromJSON PasswordResetConfirm
forall a.
(Value -> Parser a)
-> (Value -> Parser [a]) -> Maybe a -> FromJSON a
$cparseJSON :: Value -> Parser PasswordResetConfirm
parseJSON :: Value -> Parser PasswordResetConfirm
$cparseJSONList :: Value -> Parser [PasswordResetConfirm]
parseJSONList :: Value -> Parser [PasswordResetConfirm]
$comittedField :: Maybe PasswordResetConfirm
omittedField :: Maybe PasswordResetConfirm
FromJSON, Typeable PasswordResetConfirm
Typeable PasswordResetConfirm =>
(Proxy PasswordResetConfirm
 -> Declare (Definitions Schema) NamedSchema)
-> ToSchema PasswordResetConfirm
Proxy PasswordResetConfirm
-> Declare (Definitions Schema) NamedSchema
forall a.
Typeable a =>
(Proxy a -> Declare (Definitions Schema) NamedSchema) -> ToSchema a
$cdeclareNamedSchema :: Proxy PasswordResetConfirm
-> Declare (Definitions Schema) NamedSchema
declareNamedSchema :: Proxy PasswordResetConfirm
-> Declare (Definitions Schema) NamedSchema
ToSchema)

-- | Internal representation of a password reset token
data PasswordResetToken = PasswordResetToken
    { PasswordResetToken -> UUID
tokenId :: UUID
    , PasswordResetToken -> UUID
tokenUserId :: UserID
    , PasswordResetToken -> Text
tokenHash :: Text
    , PasswordResetToken -> UTCTime
tokenExpiresAt :: UTCTime
    , PasswordResetToken -> UTCTime
tokenCreatedAt :: UTCTime
    , PasswordResetToken -> Maybe UTCTime
tokenUsedAt :: Maybe UTCTime
    }
    deriving ((forall x. PasswordResetToken -> Rep PasswordResetToken x)
-> (forall x. Rep PasswordResetToken x -> PasswordResetToken)
-> Generic PasswordResetToken
forall x. Rep PasswordResetToken x -> PasswordResetToken
forall x. PasswordResetToken -> Rep PasswordResetToken x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. PasswordResetToken -> Rep PasswordResetToken x
from :: forall x. PasswordResetToken -> Rep PasswordResetToken x
$cto :: forall x. Rep PasswordResetToken x -> PasswordResetToken
to :: forall x. Rep PasswordResetToken x -> PasswordResetToken
Generic, Int -> PasswordResetToken -> ShowS
[PasswordResetToken] -> ShowS
PasswordResetToken -> String
(Int -> PasswordResetToken -> ShowS)
-> (PasswordResetToken -> String)
-> ([PasswordResetToken] -> ShowS)
-> Show PasswordResetToken
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PasswordResetToken -> ShowS
showsPrec :: Int -> PasswordResetToken -> ShowS
$cshow :: PasswordResetToken -> String
show :: PasswordResetToken -> String
$cshowList :: [PasswordResetToken] -> ShowS
showList :: [PasswordResetToken] -> ShowS
Show, PasswordResetToken -> PasswordResetToken -> Bool
(PasswordResetToken -> PasswordResetToken -> Bool)
-> (PasswordResetToken -> PasswordResetToken -> Bool)
-> Eq PasswordResetToken
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PasswordResetToken -> PasswordResetToken -> Bool
== :: PasswordResetToken -> PasswordResetToken -> Bool
$c/= :: PasswordResetToken -> PasswordResetToken -> Bool
/= :: PasswordResetToken -> PasswordResetToken -> Bool
Eq)

-- | API definition for password reset endpoints
type PasswordResetAPI =
    "password-reset"
        :> ( "request" :> ReqBody '[JSON] PasswordResetRequest :> Post '[JSON] NoContent
                :<|> "confirm" :> ReqBody '[JSON] PasswordResetConfirm :> Post '[JSON] NoContent
           )