diff options
| author | Joris Guyonvarch | 2015-07-19 18:50:49 +0200 | 
|---|---|---|
| committer | Joris Guyonvarch | 2015-07-19 18:50:49 +0200 | 
| commit | f687b15d4d3f55fb231cd03b773b163ed131b129 (patch) | |
| tree | d2a45041640c8620b64e92001b8dfe9fce011247 | |
| parent | 331d506281760ac62e8f1715ef729e1b2a91e280 (diff) | |
Send the login token by email
| -rw-r--r-- | sharedCost.cabal | 1 | ||||
| -rw-r--r-- | src/server/Application.hs | 27 | ||||
| -rw-r--r-- | src/server/Mail.hs | 58 | ||||
| -rw-r--r-- | src/server/Model/Message.hs | 3 | 
4 files changed, 79 insertions, 10 deletions
| diff --git a/sharedCost.cabal b/sharedCost.cabal index 60a2da2..8a55707 100644 --- a/sharedCost.cabal +++ b/sharedCost.cabal @@ -31,3 +31,4 @@ executable          sharedCost                      , clientsession == 0.9.1.1                      , uuid == 1.3.10                      , email-validate == 2.1.3 +                    , mime-mail == 0.4.9 diff --git a/src/server/Application.hs b/src/server/Application.hs index 6a18102..7bb305e 100644 --- a/src/server/Application.hs +++ b/src/server/Application.hs @@ -23,7 +23,6 @@ import Control.Monad.IO.Class (liftIO)  import Data.Text (Text)  import qualified Data.Text as T -import qualified Data.Text.IO as TIO  import qualified Data.Text.Encoding as TE  import Data.String (fromString) @@ -41,6 +40,8 @@ import Model.Message  import View.Page (page) +import Mail +  getIndexAction :: ActionM ()  getIndexAction = html page @@ -87,14 +88,22 @@ signInAction login =          (Just _, Just host) -> do            token <- liftIO . runDb $ createSignInToken login            let url = T.concat ["http://", host ,"/validateSignIn?token=", token] -          liftIO . TIO.putStrLn $ url -          status ok200 -        _ -> do -          status badRequest400 -          json (Message "You are not authorized to sign in.") -    else do -      status badRequest400 -      json (Message "Please enter a valid email address.") +          let mail = Mail [login] "Sign in" url url +          maybeSentMail <- liftIO . sendMail $ mail +          case maybeSentMail of +            Right _ -> +              status ok200 +            Left _ -> +              errorResponse "Sorry, we failed to send you the sign up email." +        _ -> +          errorResponse "You are not authorized to sign in." +    else +      errorResponse "Please enter a valid email address." + +errorResponse :: Text -> ActionM () +errorResponse message = do +  status badRequest400 +  json (Message message)  validateSignInAction :: Text -> ActionM ()  validateSignInAction token = do diff --git a/src/server/Mail.hs b/src/server/Mail.hs new file mode 100644 index 0000000..c649d59 --- /dev/null +++ b/src/server/Mail.hs @@ -0,0 +1,58 @@ +{-# LANGUAGE OverloadedStrings #-} + +module Mail +  ( Mail(..) +  , sendMail +  ) where + +import Data.Text (Text) +import qualified Data.Text as T +import qualified Data.Text.Lazy as LT +import Data.Text.Lazy.Builder (toLazyText, fromText) +import Data.Either (isLeft) + +import Control.Exception (SomeException, try) + +import qualified Network.Mail.Mime as M + +data Mail = Mail +  { to :: [Text] +  , subject :: Text +  , plainBody :: Text +  , htmlBody :: Text +  } deriving (Eq, Show) + +sendMail :: Mail -> IO (Either Text ()) +sendMail mail = do +  result <- mapLeft (T.pack . show) <$> (try (M.renderSendMail . getMimeMail $ mail) :: IO (Either SomeException ())) +  if isLeft result +    then putStrLn ("Error sending the following email:" ++ (show mail)) +    else return () +  return result + +mapLeft :: (a -> c) -> Either a b -> Either c b +mapLeft f (Left l) = Left (f l) +mapLeft _ (Right r) = (Right r) + +getMimeMail :: Mail -> M.Mail +getMimeMail (Mail to subject plainBody htmlBody) = +  let fromMail = M.emptyMail (address "no-reply@shared-cost.guyonvarch.me") +  in  fromMail +        { M.mailTo = map address to +        , M.mailParts = +            [ [ M.plainPart . strictToLazy $ plainBody +              , M.htmlPart . strictToLazy $ htmlBody +              ] +            ] +        , M.mailHeaders = [("Subject", subject)] +        } + +strictToLazy :: Text -> LT.Text +strictToLazy = toLazyText . fromText + +address :: Text -> M.Address +address addressEmail = +  M.Address +    { M.addressName = Nothing +    , M.addressEmail = addressEmail +    } diff --git a/src/server/Model/Message.hs b/src/server/Model/Message.hs index 6b4287e..d84aaa9 100644 --- a/src/server/Model/Message.hs +++ b/src/server/Model/Message.hs @@ -5,10 +5,11 @@ module Model.Message    ) where  import Data.Aeson +import Data.Text (Text)  import GHC.Generics  data Message = Message -  { message :: String +  { message :: Text    } deriving (Show, Generic)  instance FromJSON Message | 
