aboutsummaryrefslogtreecommitdiff
path: root/server/src/Persistence/User.hs
blob: 12145acfbc3d9be0c3847d30372361bd27c70345 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
module Persistence.User
  ( list
  , get
  , checkPassword
  , createSignInToken
  ) where

import qualified Data.Maybe             as Maybe
import           Data.Text              (Text)
import           Database.SQLite.Simple (FromRow (fromRow), NamedParam ((:=)))
import qualified Database.SQLite.Simple as SQLite

import           Common.Model           (Email (..), Password (..), User (..))

import           Model.HashedPassword   (HashedPassword (..))
import qualified Model.HashedPassword   as HashedPassword
import           Model.Query            (Query (Query))
import qualified Model.UUID             as UUID

newtype Row = Row User

instance FromRow Row where
  fromRow = Row <$> (User <$>
    SQLite.field <*>
    SQLite.field <*>
    SQLite.field <*>
    SQLite.field)

list :: Query [User]
list =
  Query (\conn -> do
    map (\(Row u) -> u) <$>
      SQLite.query_ conn "SELECT id, creation, email, name from user ORDER BY creation DESC"
  )

get :: Text -> Query (Maybe User)
get token =
  Query (\conn -> do
    fmap (\(Row u) -> u) . Maybe.listToMaybe <$>
      SQLite.queryNamed
        conn
        "SELECT id, creation, email, name FROM user WHERE sign_in_token = :sign_in_token LIMIT 1"
        [ ":sign_in_token" := token ]
  )

data HashedPasswordRow = HashedPasswordRow HashedPassword

instance FromRow HashedPasswordRow where
  fromRow = HashedPasswordRow <$> (HashedPassword <$> SQLite.field)

checkPassword :: Email -> Password -> Query Bool
checkPassword (Email email) password =
  Query (\conn -> do
    hashedPassword <- fmap (\(HashedPasswordRow p) -> p) . Maybe.listToMaybe <$>
      SQLite.queryNamed
        conn
        "SELECT password FROM user WHERE email = :email LIMIT 1"
        [ ":email" := email ]
    case hashedPassword of
      Just h ->
        return (HashedPassword.check password h)

      Nothing ->
        return False
  )

createSignInToken :: Email -> Query Text
createSignInToken (Email email) =
  Query (\conn -> do
    token <- UUID.generateUUID
    SQLite.executeNamed
      conn
      "UPDATE user SET sign_in_token = :sign_in_token WHERE email = :email"
      [ ":sign_in_token" := token
      , ":email" := email
      ]
    return token
  )