1
1
{-# LANGUAGE OverloadedStrings #-}
2
+ {-# LANGUAGE DataKinds #-}
2
3
3
4
module Api.Api where
4
5
@@ -14,7 +15,7 @@ import Data.Time.Clock.POSIX (getPOSIXTime)
14
15
import Data.UUID (toString )
15
16
import Data.UUID.V4 (nextRandom )
16
17
17
- import Network.HTTP.Types.Status (Status , status200 , status400 , status404 )
18
+ import Network.HTTP.Types.Status (Status , status200 , status400 , status404 , status500 )
18
19
import Network.Wai (Request (pathInfo , requestMethod ), getRequestBodyChunk )
19
20
20
21
import Crypto.Random (getRandomBytes )
@@ -23,8 +24,8 @@ import Data.ByteString.Lazy (fromStrict, toStrict)
23
24
import Data.Password.Bcrypt (PasswordCheck (PasswordCheckFail , PasswordCheckSuccess ), PasswordHash (PasswordHash ), checkPassword , mkPassword )
24
25
import Data.Text (intercalate , pack , unpack , Text )
25
26
import Data.Text.Array (Array (ByteArray ))
26
- import Database.Persist (Entity (Entity ), Filter (Filter ), FilterValue (FilterValue ), PersistFilter (BackendSpecificFilter ), insertEntity , selectList , PersistQueryWrite (deleteWhere ), (==.) , (=.) )
27
- import Database.Schema (EntityField (TokenName , UserName , UserIndex , VisitIndex , GuestbookEntryIndex , SnakeIndex , TokenIndex , VisitUuid , TokenToken ), GuestbookEntry (GuestbookEntry , guestbookEntryContent , guestbookEntryName , guestbookEntryParentId , guestbookEntryIndex , guestbookEntryTimestamp ), Snake (Snake ), Token (Token , tokenToken ), User (User , userName , userPassword ), Visit (Visit ))
27
+ import Database.Persist (Entity (Entity , entityKey ), Filter (Filter ), FilterValue (FilterValue ), PersistFilter (BackendSpecificFilter ), insertEntity , selectList , PersistQueryWrite (deleteWhere ), (==.) , (=.) , PersistField ( toPersistValue ), PersistStoreRead ( get ))
28
+ import Database.Schema (EntityField (TokenName , UserName , VisitUuid , TokenToken , GuestbookEntryId , VisitId , SnakeId , UserId , TokenId , GuestbookEntryParentId ), GuestbookEntry (GuestbookEntry , guestbookEntryContent , guestbookEntryName , guestbookEntryParentId , guestbookEntryTimestamp ), Snake (Snake ), Token (Token , tokenToken ), User (User , userName , userPassword ), Visit (Visit ), Key ( GuestbookEntryKey ))
28
29
import Logger (info )
29
30
import Text.StringRandom (stringRandomIO )
30
31
@@ -38,6 +39,7 @@ import System.Directory (getDirectoryContents, removeFile)
38
39
import Settings (getEditorRoot )
39
40
import Tables (DatabaseDelete (DatabaseDelete , EmptyDatabaseDelete ))
40
41
import State (getCookies , getStates , loggedIn , accessToken )
42
+ import Database.Persist.Sql (toSqlKey )
41
43
42
44
type Header = (HeaderName , ByteString )
43
45
type APIResponse = IO (Status , String , [Header ])
@@ -79,10 +81,10 @@ apiMap = [
79
81
let pass = mkPassword $ pack password
80
82
rows <- getData [UserName ==. username] []
81
83
case rows of
82
- [user] -> case checkPassword pass (PasswordHash $ pack (userPassword user)) of
84
+ [Entity id user] -> case checkPassword pass (PasswordHash $ pack (userPassword user)) of
83
85
PasswordCheckSuccess -> do
84
86
token <- stringRandomIO " [0-9a-zA-Z]{4}-[0-9a-ZA-Z]{10}-[0-9a-zA-Z]{15}"
85
- runDb $ insertEntity $ Token 0 (unpack token) username
87
+ runDb $ insertEntity $ Token (unpack token) username
86
88
return (status200, j2s [aesonQQ |{"token":#{unpack token}}|], jsonHeaders)
87
89
PasswordCheckFail -> return (status400, messageResponse " Error, Wrong username or password" , jsonHeaders)
88
90
_ -> return (status400, messageResponse " Error, no user exists" , jsonHeaders)
@@ -115,11 +117,11 @@ apiMap = [
115
117
return (status200, j2s [aesonQQ |#{apiData}|], jsonHeaders)
116
118
),
117
119
(" ^/visits/get(/|)$" , \ _ -> do
118
- visits <- show . length <$> (getData [] [] :: IO [Visit ])
120
+ visits <- show . length <$> (getData [] [] :: IO [Entity Visit ])
119
121
return (status200, j2s [aesonQQ |{"visits":#{visits}}|], jsonHeaders)
120
122
),
121
123
(" ^/guestbook/get(/|)$" , \ _ -> do
122
- entries <- getData [] [] :: IO [GuestbookEntry ]
124
+ entries <- getData [] [] :: IO [Entity GuestbookEntry ]
123
125
let l = map toList entries
124
126
return (status200, j2s [aesonQQ |{"entries":#{l}}|], jsonHeaders)
125
127
),
@@ -147,8 +149,11 @@ apiMap = [
147
149
return (status400, messageResponse " Error, content cannot be empty" , jsonHeaders)
148
150
(T. GuestbookEntry name content parentId) -> do
149
151
time <- fmap round getPOSIXTime :: IO Int
150
- runDb $ insertEntity $ GuestbookEntry 0 time name content parentId
152
+ runDb $ do
153
+ insertEntity $ GuestbookEntry time name content parentId
151
154
return (status200, messageResponse " Success" , jsonHeaders)
155
+ _ -> do
156
+ return (status500, messageResponse " Error, server failed" , jsonHeaders)
152
157
),
153
158
(" ^/snake/add(/|)$" , \ r -> do
154
159
body <- getRequestBodyChunk r
@@ -157,7 +162,7 @@ apiMap = [
157
162
T. EmptyLeaderboard -> return (status400, messageResponse " Error, leaderboard empty" , jsonHeaders)
158
163
(T. LeaderboardEntry name score speed fruits) -> do
159
164
time <- fmap round getPOSIXTime :: IO Int
160
- runDb $ insertEntity $ Snake 0 time name score speed fruits
165
+ runDb $ insertEntity $ Snake time name score speed fruits
161
166
return (status200, messageResponse " Success" , jsonHeaders)
162
167
),
163
168
(" ^/editor/content/.*(/|)$" , \ r -> do
@@ -190,15 +195,15 @@ apiMap = [
190
195
(DatabaseDelete table id ) -> do
191
196
case table of
192
197
" visits" -> do
193
- runDb $ deleteWhere [VisitIndex ==. id ]
198
+ runDb $ deleteWhere [VisitId ==. (toSqlKey . read . show ) id ]
194
199
" guestbook" -> do
195
- runDb $ deleteWhere [GuestbookEntryIndex ==. id ]
200
+ runDb $ deleteWhere [GuestbookEntryId ==. (toSqlKey . read . show ) id ]
196
201
" snake" -> do
197
- runDb $ deleteWhere [SnakeIndex ==. id ]
202
+ runDb $ deleteWhere [SnakeId ==. (toSqlKey . read . show ) id ]
198
203
" users" -> do
199
- runDb $ deleteWhere [UserIndex ==. id ]
204
+ runDb $ deleteWhere [UserId ==. (toSqlKey . read . show ) id ]
200
205
" valid_tokens" -> do
201
- runDb $ deleteWhere [TokenIndex ==. id ]
206
+ runDb $ deleteWhere [TokenId ==. (toSqlKey . read . show ) id ]
202
207
_ -> putStr " no table, doing nothing..."
203
208
return (status200, messageResponse " ok" , jsonHeaders)
204
209
EmptyDatabaseDelete -> return (status400, messageResponse " Invalid JSON" , jsonHeaders)
0 commit comments