module Controller.Index ( get , signOut ) where import Control.Monad.IO.Class (liftIO) import Data.Text (Text) import Data.Time.Clock (diffUTCTime, getCurrentTime) import Network.HTTP.Types.Status (ok200) import Prelude hiding (error) import Web.Scotty hiding (get) import Common.Model (InitResult (..), User (..)) import Common.Msg (Key) import qualified Common.Msg as Msg import Conf (Conf (..)) import qualified LoginSession import Model.Init (getInit) import qualified Model.Query as Query import qualified Model.SignIn as SignIn import qualified Model.User as User import Secure (getUserFromToken) import View.Page (page) get :: Conf -> Maybe Text -> ActionM () get conf mbToken = do initResult <- case mbToken of Just token -> do userOrError <- validateSignIn conf token case userOrError of Left errorKey -> return . InitEmpty . Left . Msg.get $ errorKey Right user -> liftIO . Query.run . fmap InitSuccess $ getInit user conf Nothing -> do mbLoggedUser <- getLoggedUser case mbLoggedUser of Nothing -> return . InitEmpty . Right $ Nothing Just user -> liftIO . Query.run . fmap InitSuccess $ getInit user conf html $ page initResult validateSignIn :: Conf -> Text -> ActionM (Either Key User) validateSignIn conf textToken = do mbLoggedUser <- getLoggedUser case mbLoggedUser of Just loggedUser -> return . Right $ loggedUser Nothing -> do mbSignIn <- liftIO . Query.run $ SignIn.getSignIn textToken now <- liftIO getCurrentTime case mbSignIn of Nothing -> return . Left $ Msg.SignIn_LinkInvalid Just signIn -> if SignIn.isUsed signIn then return . Left $ Msg.SignIn_LinkUsed else let diffTime = now `diffUTCTime` (SignIn.creation signIn) in if diffTime > signInExpiration conf then return . Left $ Msg.SignIn_LinkExpired else do LoginSession.put conf (SignIn.token signIn) mbUser <- liftIO . Query.run $ do SignIn.signInTokenToUsed . SignIn.id $ signIn User.get . SignIn.email $ signIn return $ case mbUser of Nothing -> Left Msg.Secure_Unauthorized Just user -> Right user getLoggedUser :: ActionM (Maybe User) getLoggedUser = do mbToken <- LoginSession.get case mbToken of Nothing -> return Nothing Just token -> do liftIO . Query.run . getUserFromToken $ token signOut :: Conf -> ActionM () signOut conf = LoginSession.delete conf >> status ok200