You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

147 lines
4.0 KiB

{-# LANGUAGE OverloadedStrings #-}
-- {-# LANGUAGE QuasiQuotes #-}
module UserDB
( User(..), getSingleUser, getAllUsers, addUser, updateUser)
where
import Control.Exception
import Data.Text (Text)
-- import Data.Text.Encoding (decodeUtf8, encodeUtf8)
import Database.SQLite.Simple hiding (close)
import Database.SQLite.Simple as SQLite
-- import Database.SQLite.Simple.Types
import Data.Typeable
-- import Text.RawString.QQ
import Data.Maybe (catMaybes)
import Data.List (intersperse)
import Data.String (fromString)
import Data.Aeson
data User =
User {
userId :: Integer
, username :: Text
, shell :: Text
, homeDirectory :: Text
, realName :: Text
, phone :: Text
} deriving (Eq, Show)
instance FromRow User where
fromRow = User <$> field
<*> field
<*> field
<*> field
<*> field
<*> field
instance ToRow User where
toRow (User id_ uname sh hDir rName ph) =
toRow (id_, uname, sh, hDir, rName, ph)
instance FromJSON User where
parseJSON = withObject "User" $ \v -> User 0
<$> v .: "username"
<*> v .: "shell"
<*> v .: "homeDirectory"
<*> v .: "realName"
<*> v .: "phone"
-- createUsers :: Query
-- createUsers = [r|
-- CREATE TABLE IF NOT EXISTS users
-- (id INTEGER PRIMARY KEY AUTOINCREMENT,
-- username TEXT UNIQUE,
-- shell TEXT, homeDirectory TEXT,
-- realName TEXT, phone TEXT)
-- |]
insertUser :: Query
insertUser = "INSERT INTO users VALUES (?, ?, ?, ?, ?, ?)"
allUsers :: Query
allUsers = "SELECT * from users"
getUserQuery :: Query
getUserQuery = "SELECT * from users where username = ?"
data DuplicateData = DuplicateData deriving (Eq, Show, Typeable)
instance Exception DuplicateData
-- type UserRow = (Null, Text, Text, Text, Text, Text)
getUser :: Connection -> Text -> IO (Maybe User)
getUser conn uname = do
results <- query conn getUserQuery (Only uname)
case results of
[] -> return $ Nothing
[user] -> return $ Just user
_ -> throwIO DuplicateData
addUser :: User -> IO Bool
addUser u = do
conn <- getConnection
n <- query conn hasUser (Only $ username u) :: IO [Only Integer]
b <- case n of
[] -> (execute conn insertUser $ toRow u) >> return True
_ -> return False
rows <- query_ conn allUsers
mapM_ print (rows :: [User])
SQLite.close conn
return b
-- createDatabase :: IO ()
-- createDatabase = do
-- conn <- getConnection
-- execute_ conn createUsers
-- SQLite.close conn
getConnection :: IO Connection
getConnection = open "finger.db"
getSingleUser :: Text -> IO (Maybe User)
getSingleUser name = do
conn <- getConnection
result <- getUser conn name
SQLite.close conn
return result
getAllUsers :: IO [User]
getAllUsers = do
conn <- getConnection
rows <- query_ conn allUsers
SQLite.close conn
return rows
hasUser :: Query
hasUser = "SELECT 1 FROM users where username = ?"
updateUser :: String
-> Maybe String
-> Maybe String
-> Maybe String
-> Maybe String
-> IO Bool
updateUser name sh hDir rName ph = do
let xs = [sh, hDir, rName, ph]
columns = zip ["shell", "homeDirectory", "realName", "phone"] xs
newData = catMaybes $ fmap sequenceA columns
case newData of
[] -> return True
ys -> do
let pairs = fmap (\(a,b) -> a ++ "=\"" ++ b ++ "\"" ) ys
part = concat $ intersperse "," pairs
full = "update users set " ++ part
++ " where username = \"" ++ name ++ "\""
conn <- getConnection
n <- query conn hasUser (Only name) :: IO [Only Integer]
b <- case n of
[] -> return False
_ -> execute conn (fromString full) (Only name) >> return True
SQLite.close conn
return b
-- updateU :: User -> IO ()
-- update