module Model.SignIn ( SignIn(..) , createSignInToken , getSignIn , signInTokenToUsed , isLastTokenValid ) where import Data.Int (Int64) import Data.Maybe (listToMaybe) import Data.Text (Text) import Data.Time.Clock (getCurrentTime) import Data.Time.Clock (UTCTime) import Database.SQLite.Simple (FromRow (fromRow), Only (Only)) import qualified Database.SQLite.Simple as SQLite import Model.Query (Query (Query)) import Model.UUID (generateUUID) type SignInId = Int64 data SignIn = SignIn { id :: SignInId , token :: Text , creation :: UTCTime , email :: Text , isUsed :: Bool } deriving Show instance FromRow SignIn where fromRow = SignIn <$> SQLite.field <*> SQLite.field <*> SQLite.field <*> SQLite.field <*> SQLite.field createSignInToken :: Text -> Query Text createSignInToken signInEmail = Query (\conn -> do now <- getCurrentTime signInToken <- generateUUID SQLite.execute conn "INSERT INTO sign_in (token, creation, email, is_used) VALUES (?, ?, ?, ?)" (signInToken, now, signInEmail, False) return signInToken ) getSignIn :: Text -> Query (Maybe SignIn) getSignIn signInToken = Query (\conn -> do listToMaybe <$> (SQLite.query conn "SELECT * from sign_in WHERE token = ? LIMIT 1" (Only signInToken) :: IO [SignIn]) ) signInTokenToUsed :: SignInId -> Query () signInTokenToUsed tokenId = Query (\conn -> SQLite.execute conn "UPDATE sign_in SET is_used = ? WHERE id = ?" (True, tokenId) ) isLastTokenValid :: SignIn -> Query Bool isLastTokenValid signIn = Query (\conn -> do [ Only lastToken ] <- SQLite.query conn "SELECT token from sign_in WHERE email = ? AND is_used = ? ORDER BY creation DESC LIMIT 1" (email signIn, True) return . maybe False (== (token signIn)) $ lastToken )