module Controller.Index ( get , signOut ) where import Control.Monad.IO.Class (liftIO) import Data.Text (Text) import Data.Time.Clock (getCurrentTime, diffUTCTime) import Network.HTTP.Types.Status (ok200) import Web.Scotty hiding (get) import Conf (Conf(..)) import Model.Init (getInit) import Model.Json.Init (InitResult(..)) import Model.Message.Key import Model.User (User) import qualified LoginSession import qualified Model.Json.Conf as M 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 . InitError $ errorKey Right user -> liftIO . Query.run . fmap InitSuccess . getInit $ user Nothing -> do mbLoggedUser <- getLoggedUser case mbLoggedUser of Nothing -> return InitEmpty Just user -> liftIO . Query.run . fmap InitSuccess . getInit $ user html $ page (M.Conf { M.currency = currency conf }) 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 $ SignInInvalid Just signIn -> if SignIn.isUsed signIn then return . Left $ SignInUsed else let diffTime = now `diffUTCTime` (SignIn.creation signIn) in if diffTime > signInExpiration conf then return . Left $ SignInExpired else do LoginSession.put conf (SignIn.token signIn) mbUser <- liftIO . Query.run $ do SignIn.signInTokenToUsed . SignIn.id $ signIn User.getUser . SignIn.email $ signIn return $ case mbUser of Nothing -> Left UnauthorizedSignIn 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