Add user validation and deletion
Tests included
This commit is contained in:
parent
71450efc2e
commit
a0e24d9742
2 changed files with 157 additions and 33 deletions
|
@ -196,7 +196,27 @@ data User =
|
||||||
, upin :: T.Text
|
, upin :: T.Text
|
||||||
, uvalidated :: Bool
|
, uvalidated :: Bool
|
||||||
}
|
}
|
||||||
deriving (Eq, Show, Generic, ToJSON)
|
deriving (Eq, Show, Generic)
|
||||||
|
|
||||||
|
instance ToJSON User where
|
||||||
|
toJSON (User i a s bt p v) =
|
||||||
|
object
|
||||||
|
[ "_id" .= i
|
||||||
|
, "address" .= a
|
||||||
|
, "session" .= s
|
||||||
|
, "blocktime" .= bt
|
||||||
|
, "validated" .= v
|
||||||
|
]
|
||||||
|
|
||||||
|
instance FromJSON User where
|
||||||
|
parseJSON =
|
||||||
|
withObject "User" $ \obj -> do
|
||||||
|
i <- obj .: "_id"
|
||||||
|
a <- obj .: "address"
|
||||||
|
s <- obj .: "session"
|
||||||
|
bt <- obj .: "blocktime"
|
||||||
|
v <- obj .: "validated"
|
||||||
|
pure $ User i a s bt "" v
|
||||||
|
|
||||||
parseUserBson :: B.Document -> Maybe User
|
parseUserBson :: B.Document -> Maybe User
|
||||||
parseUserBson d = do
|
parseUserBson d = do
|
||||||
|
@ -320,19 +340,34 @@ addUser :: Pipe -> T.Text -> T.Text -> Maybe ZGoTx -> Action IO ()
|
||||||
addUser _ _ _ Nothing = return () --`debug` "addUser got Nothing"
|
addUser _ _ _ Nothing = return () --`debug` "addUser got Nothing"
|
||||||
addUser p db node (Just tx) = do
|
addUser p db node (Just tx) = do
|
||||||
isNew <- liftIO $ isUserNew p db tx
|
isNew <- liftIO $ isUserNew p db tx
|
||||||
if isNew
|
when isNew $ do
|
||||||
then do
|
let newPin = unsafePerformIO generatePin
|
||||||
let newPin = unsafePerformIO generatePin
|
_ <- sendPin node (address tx) newPin
|
||||||
_ <- sendPin node (address tx) newPin
|
insert_
|
||||||
insert_
|
"users"
|
||||||
"users"
|
[ "address" =: address tx
|
||||||
[ "address" =: address tx
|
, "session" =: session tx
|
||||||
, "session" =: session tx
|
, "blocktime" =: blocktime tx
|
||||||
, "blocktime" =: blocktime tx
|
, "pin" =: newPin
|
||||||
, "pin" =: newPin
|
, "validated" =: False
|
||||||
, "validated" =: False
|
]
|
||||||
]
|
|
||||||
else return ()
|
-- | Function to delete user by ID
|
||||||
|
deleteUser :: String -> Action IO ()
|
||||||
|
deleteUser i = deleteOne (select ["_id" =: (read i :: B.ObjectId)] "users")
|
||||||
|
|
||||||
|
-- | Function to verify if the given ZGoTx represents an already existing User
|
||||||
|
isUserNew :: Pipe -> T.Text -> ZGoTx -> IO Bool
|
||||||
|
isUserNew p db tx =
|
||||||
|
isNothing <$>
|
||||||
|
access p master db (findOne (select ["session" =: session tx] "users"))
|
||||||
|
|
||||||
|
-- | Function to mark user as validated
|
||||||
|
validateUser :: T.Text -> Action IO ()
|
||||||
|
validateUser session =
|
||||||
|
modify
|
||||||
|
(select ["session" =: session] "users")
|
||||||
|
["$set" =: ["validated" =: True]]
|
||||||
|
|
||||||
sendPin :: T.Text -> T.Text -> T.Text -> Action IO String
|
sendPin :: T.Text -> T.Text -> T.Text -> Action IO String
|
||||||
sendPin nodeAddress addr pin = do
|
sendPin nodeAddress addr pin = do
|
||||||
|
@ -343,7 +378,7 @@ sendPin nodeAddress addr pin = do
|
||||||
[ object
|
[ object
|
||||||
[ "address" .= addr
|
[ "address" .= addr
|
||||||
, "amount" .= (0.00000001 :: Double)
|
, "amount" .= (0.00000001 :: Double)
|
||||||
, "memo" .= encodeHexText ("ZGo PIN: " ++ T.unpack (pin))
|
, "memo" .= encodeHexText ("ZGo PIN: " ++ T.unpack pin)
|
||||||
]
|
]
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
|
@ -398,8 +433,6 @@ app pipe db passkey nodeAddress = do
|
||||||
case countries of
|
case countries of
|
||||||
[] -> do
|
[] -> do
|
||||||
status noContent204
|
status noContent204
|
||||||
Web.Scotty.json
|
|
||||||
(object ["message" .= ("No countries available" :: String)])
|
|
||||||
_ -> do
|
_ -> do
|
||||||
Web.Scotty.json
|
Web.Scotty.json
|
||||||
(object
|
(object
|
||||||
|
@ -418,10 +451,29 @@ app pipe db passkey nodeAddress = do
|
||||||
[ "message" .= ("User found" :: String)
|
[ "message" .= ("User found" :: String)
|
||||||
, "user" .= toJSON (parseUserBson u)
|
, "user" .= toJSON (parseUserBson u)
|
||||||
])
|
])
|
||||||
--Add user
|
--Validate user, updating record
|
||||||
post "/api/user" $ do text "Added that guy"
|
post "/api/validateuser" $ do
|
||||||
|
providedPin <- param "pin"
|
||||||
|
session <- param "session"
|
||||||
|
user <- liftIO $ run (findUser session)
|
||||||
|
case user of
|
||||||
|
Nothing -> status noContent204
|
||||||
|
Just u -> do
|
||||||
|
let parsedUser = parseUserBson u
|
||||||
|
case parsedUser of
|
||||||
|
Nothing -> status noContent204
|
||||||
|
Just pUser -> do
|
||||||
|
let result = upin pUser == providedPin
|
||||||
|
if result
|
||||||
|
then do
|
||||||
|
liftIO $ run (validateUser session)
|
||||||
|
status accepted202
|
||||||
|
else status noContent204
|
||||||
--Delete user
|
--Delete user
|
||||||
Web.Scotty.delete "/api/user/:id" $ do text "Deleted that guy!"
|
Web.Scotty.delete "/api/user/:id" $ do
|
||||||
|
userId <- param "id"
|
||||||
|
liftIO $ run (deleteUser userId)
|
||||||
|
status ok200
|
||||||
--Get txs from DB that have less than 10 confirmations
|
--Get txs from DB that have less than 10 confirmations
|
||||||
get "/api/pending" $ do
|
get "/api/pending" $ do
|
||||||
session <- param "session"
|
session <- param "session"
|
||||||
|
@ -449,8 +501,6 @@ app pipe db passkey nodeAddress = do
|
||||||
get "/api/owner" $ do text "Here's an owner for you"
|
get "/api/owner" $ do text "Here's an owner for you"
|
||||||
--Upsert owner to DB
|
--Upsert owner to DB
|
||||||
post "/api/owner" $ do text "I added an owner for you"
|
post "/api/owner" $ do text "I added an owner for you"
|
||||||
--Validate user, updating record
|
|
||||||
post "/api/validateuser" $ do text "Marked user as validated"
|
|
||||||
--Get items associated with the given address
|
--Get items associated with the given address
|
||||||
get "/api/items" $ do text "Here are your items"
|
get "/api/items" $ do text "Here are your items"
|
||||||
--Upsert item
|
--Upsert item
|
||||||
|
@ -554,10 +604,4 @@ updateLogins addr pipe db = do
|
||||||
mapM_ (access pipe master db . ZGoBackend.addUser pipe db addr) parsed
|
mapM_ (access pipe master db . ZGoBackend.addUser pipe db addr) parsed
|
||||||
putStrLn "Updated logins!"
|
putStrLn "Updated logins!"
|
||||||
|
|
||||||
isUserNew :: Pipe -> T.Text -> ZGoTx -> IO Bool
|
|
||||||
isUserNew p db tx = do
|
|
||||||
res <-
|
|
||||||
(access p master db (findOne (select ["session" =: (session tx)] "users")))
|
|
||||||
return $ isNothing res
|
|
||||||
|
|
||||||
debug = flip trace
|
debug = flip trace
|
||||||
|
|
90
test/Spec.hs
90
test/Spec.hs
|
@ -9,6 +9,7 @@ import qualified Data.Aeson as A
|
||||||
import qualified Data.ByteString as B
|
import qualified Data.ByteString as B
|
||||||
import Data.Char (isAscii)
|
import Data.Char (isAscii)
|
||||||
import Data.Either
|
import Data.Either
|
||||||
|
import Data.Maybe
|
||||||
import Data.SecureMem
|
import Data.SecureMem
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import Database.MongoDB
|
import Database.MongoDB
|
||||||
|
@ -97,11 +98,33 @@ main =
|
||||||
describe "unconfirmed Zcash txs" $ do
|
describe "unconfirmed Zcash txs" $ do
|
||||||
it "returns txs with less than 2 confirmations" $ do pending
|
it "returns txs with less than 2 confirmations" $ do pending
|
||||||
describe "User endpoint" $ do
|
describe "User endpoint" $ do
|
||||||
it "adds a user" $ do pending
|
it "returns a user for a session" $ do
|
||||||
it "returns a user for a session" $ do pending
|
req <-
|
||||||
it "returns 204 when no user" $ do pending
|
testGet
|
||||||
it "marks user as validated" $ do pending
|
"/api/user"
|
||||||
it "deletes user by id" $ do pending
|
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdca")]
|
||||||
|
res <- httpJSON req
|
||||||
|
getResponseStatus (res :: Response A.Value) `shouldBe` ok200
|
||||||
|
it "returns 204 when no user" $ do
|
||||||
|
req <-
|
||||||
|
testGet
|
||||||
|
"/api/user"
|
||||||
|
[("session", Just "suchafak-euui-dican-eve-nbelieveitca")]
|
||||||
|
res <- httpLBS req
|
||||||
|
getResponseStatus res `shouldBe` noContent204
|
||||||
|
it "validate with correct pin" $ do
|
||||||
|
req <-
|
||||||
|
testPost
|
||||||
|
"/api/validateuser/"
|
||||||
|
[ ("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdca")
|
||||||
|
, ("pin", Just "5989845")
|
||||||
|
]
|
||||||
|
res <- httpLBS req
|
||||||
|
getResponseStatus res `shouldBe` accepted202
|
||||||
|
it "deletes user by id" $ do
|
||||||
|
req <- testDelete "/api/user/" "6272a90f2b05a74cf1000001"
|
||||||
|
res <- httpLBS req
|
||||||
|
getResponseStatus res `shouldBe` ok200
|
||||||
describe "Owner endpoint" $ do
|
describe "Owner endpoint" $ do
|
||||||
it "add owner" $ do pending
|
it "add owner" $ do pending
|
||||||
it "return owner" $ do pending
|
it "return owner" $ do pending
|
||||||
|
@ -189,6 +212,41 @@ main =
|
||||||
case s of
|
case s of
|
||||||
Nothing -> True `shouldBe` False
|
Nothing -> True `shouldBe` False
|
||||||
Just z -> length (T.unpack (usession z)) `shouldSatisfy` (> 0)
|
Just z -> length (T.unpack (usession z)) `shouldSatisfy` (> 0)
|
||||||
|
describe "user is" $ do
|
||||||
|
it "validated" $ \p -> do
|
||||||
|
t <-
|
||||||
|
access p master "test" $
|
||||||
|
findOne (select ["validated" =: False] "users")
|
||||||
|
case t of
|
||||||
|
Nothing -> True `shouldBe` False
|
||||||
|
Just r -> do
|
||||||
|
let s = parseUserBson r
|
||||||
|
case s of
|
||||||
|
Nothing -> True `shouldBe` False
|
||||||
|
Just z -> do
|
||||||
|
_ <- access p master "test" $ validateUser (usession z)
|
||||||
|
q <-
|
||||||
|
access p master "test" $
|
||||||
|
findOne
|
||||||
|
(select
|
||||||
|
["validated" =: True, "session" =: usession z]
|
||||||
|
"users")
|
||||||
|
isNothing q `shouldBe` False
|
||||||
|
it "deleted" $ \p -> do
|
||||||
|
t <- access p master "test" $ findOne (select [] "users")
|
||||||
|
case t of
|
||||||
|
Nothing -> True `shouldBe` False
|
||||||
|
Just r -> do
|
||||||
|
let s = parseUserBson r
|
||||||
|
case s of
|
||||||
|
Nothing -> True `shouldBe` False
|
||||||
|
Just z -> do
|
||||||
|
_ <- access p master "test" $ deleteUser (u_id z)
|
||||||
|
q <-
|
||||||
|
access p master "test" $
|
||||||
|
findOne
|
||||||
|
(select ["_id" =: (read (u_id z) :: ObjectId)] "users")
|
||||||
|
isNothing q `shouldBe` True
|
||||||
|
|
||||||
testGet :: B.ByteString -> [(B.ByteString, Maybe B.ByteString)] -> IO Request
|
testGet :: B.ByteString -> [(B.ByteString, Maybe B.ByteString)] -> IO Request
|
||||||
testGet endpoint body = do
|
testGet endpoint body = do
|
||||||
|
@ -201,6 +259,28 @@ testGet endpoint body = do
|
||||||
setRequestMethod "GET" $ setRequestPath endpoint defaultRequest
|
setRequestMethod "GET" $ setRequestPath endpoint defaultRequest
|
||||||
return testRequest
|
return testRequest
|
||||||
|
|
||||||
|
testPost :: B.ByteString -> [(B.ByteString, Maybe B.ByteString)] -> IO Request
|
||||||
|
testPost endpoint body = do
|
||||||
|
let user = "user"
|
||||||
|
let pwd = "superSecret"
|
||||||
|
let testRequest =
|
||||||
|
setRequestQueryString body $
|
||||||
|
setRequestPort 4000 $
|
||||||
|
setRequestBasicAuth user pwd $
|
||||||
|
setRequestMethod "POST" $ setRequestPath endpoint defaultRequest
|
||||||
|
return testRequest
|
||||||
|
|
||||||
|
testDelete :: B.ByteString -> B.ByteString -> IO Request
|
||||||
|
testDelete endpoint par = do
|
||||||
|
let user = "user"
|
||||||
|
let pwd = "superSecret"
|
||||||
|
let testRequest =
|
||||||
|
setRequestPort 4000 $
|
||||||
|
setRequestBasicAuth user pwd $
|
||||||
|
setRequestMethod "DELETE" $
|
||||||
|
setRequestPath (B.append endpoint par) defaultRequest
|
||||||
|
return testRequest
|
||||||
|
|
||||||
-- | Open the MongoDB connection
|
-- | Open the MongoDB connection
|
||||||
openDbConnection :: IO Pipe
|
openDbConnection :: IO Pipe
|
||||||
openDbConnection = do
|
openDbConnection = do
|
||||||
|
|
Loading…
Reference in a new issue