Refactor Payment type
This commit is contained in:
parent
37912d35b1
commit
5a0bf9aee4
8 changed files with 300 additions and 46 deletions
|
@ -26,7 +26,8 @@ main = do
|
||||||
putStrLn "Starting Server..."
|
putStrLn "Starting Server..."
|
||||||
pipe <- connect $ host "127.0.0.1"
|
pipe <- connect $ host "127.0.0.1"
|
||||||
j <- access pipe master "zgo" (auth dbUser dbPassword)
|
j <- access pipe master "zgo" (auth dbUser dbPassword)
|
||||||
{-_ <- forkIO (setInterval 60 (checkZcashPrices pipe))-}
|
_ <- forkIO (setInterval 60 (checkZcashPrices pipe "zgo"))
|
||||||
|
_ <- forkIO (setInterval 75 (scanZcash nodeAddress pipe "zgo"))
|
||||||
if j
|
if j
|
||||||
then putStrLn "Connected to MongoDB!"
|
then putStrLn "Connected to MongoDB!"
|
||||||
else fail "MongoDB connection failed!"
|
else fail "MongoDB connection failed!"
|
||||||
|
|
|
@ -45,6 +45,7 @@ library:
|
||||||
- array
|
- array
|
||||||
- random
|
- random
|
||||||
- vector
|
- vector
|
||||||
|
- wai-cors
|
||||||
|
|
||||||
executables:
|
executables:
|
||||||
zgo-backend-exe:
|
zgo-backend-exe:
|
||||||
|
|
15
src/Owner.hs
15
src/Owner.hs
|
@ -7,6 +7,7 @@ module Owner where
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import qualified Data.Bson as B
|
import qualified Data.Bson as B
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
|
import Data.Time.Clock
|
||||||
import Data.Typeable
|
import Data.Typeable
|
||||||
import Database.MongoDB
|
import Database.MongoDB
|
||||||
import GHC.Generics
|
import GHC.Generics
|
||||||
|
@ -35,11 +36,12 @@ data Owner =
|
||||||
, opaid :: Bool
|
, opaid :: Bool
|
||||||
, ozats :: Bool
|
, ozats :: Bool
|
||||||
, oinvoices :: Bool
|
, oinvoices :: Bool
|
||||||
|
, oexpiration :: UTCTime
|
||||||
}
|
}
|
||||||
deriving (Eq, Show, Generic, Typeable)
|
deriving (Eq, Show, Generic, Typeable)
|
||||||
|
|
||||||
instance ToJSON Owner where
|
instance ToJSON Owner where
|
||||||
toJSON (Owner i a n c t tV v vV f l e s ct st p ph w co paid zats inv) =
|
toJSON (Owner i a n c t tV v vV f l e s ct st p ph w co paid zats inv eTs) =
|
||||||
case i of
|
case i of
|
||||||
Just oid ->
|
Just oid ->
|
||||||
object
|
object
|
||||||
|
@ -64,6 +66,7 @@ instance ToJSON Owner where
|
||||||
, "paid" .= paid
|
, "paid" .= paid
|
||||||
, "zats" .= zats
|
, "zats" .= zats
|
||||||
, "invoices" .= inv
|
, "invoices" .= inv
|
||||||
|
, "expiration" .= eTs
|
||||||
]
|
]
|
||||||
Nothing ->
|
Nothing ->
|
||||||
object
|
object
|
||||||
|
@ -88,6 +91,7 @@ instance ToJSON Owner where
|
||||||
, "paid" .= paid
|
, "paid" .= paid
|
||||||
, "zats" .= zats
|
, "zats" .= zats
|
||||||
, "invoices" .= inv
|
, "invoices" .= inv
|
||||||
|
, "expiration" .= eTs
|
||||||
]
|
]
|
||||||
|
|
||||||
instance FromJSON Owner where
|
instance FromJSON Owner where
|
||||||
|
@ -114,6 +118,7 @@ instance FromJSON Owner where
|
||||||
paid <- obj .: "paid"
|
paid <- obj .: "paid"
|
||||||
zats <- obj .: "zats"
|
zats <- obj .: "zats"
|
||||||
inv <- obj .: "invoices"
|
inv <- obj .: "invoices"
|
||||||
|
ets <- obj .: "expiration"
|
||||||
pure $
|
pure $
|
||||||
Owner
|
Owner
|
||||||
(if not (null i)
|
(if not (null i)
|
||||||
|
@ -139,6 +144,7 @@ instance FromJSON Owner where
|
||||||
paid
|
paid
|
||||||
zats
|
zats
|
||||||
inv
|
inv
|
||||||
|
ets
|
||||||
|
|
||||||
instance Val Owner where
|
instance Val Owner where
|
||||||
cast' (Doc d) = do
|
cast' (Doc d) = do
|
||||||
|
@ -163,9 +169,10 @@ instance Val Owner where
|
||||||
paid <- B.lookup "paid" d
|
paid <- B.lookup "paid" d
|
||||||
zats <- B.lookup "zats" d
|
zats <- B.lookup "zats" d
|
||||||
inv <- B.lookup "invoices" d
|
inv <- B.lookup "invoices" d
|
||||||
Just (Owner i a n c t tV v vV f l e s ct st p ph w co paid zats inv)
|
ets <- B.lookup "expiration" d
|
||||||
|
Just (Owner i a n c t tV v vV f l e s ct st p ph w co paid zats inv ets)
|
||||||
cast' _ = Nothing
|
cast' _ = Nothing
|
||||||
val (Owner i a n c t tV v vV f l e s ct st p ph w co paid zats inv) =
|
val (Owner i a n c t tV v vV f l e s ct st p ph w co paid zats inv ets) =
|
||||||
case i of
|
case i of
|
||||||
Just oid ->
|
Just oid ->
|
||||||
Doc
|
Doc
|
||||||
|
@ -190,6 +197,7 @@ instance Val Owner where
|
||||||
, "paid" =: paid
|
, "paid" =: paid
|
||||||
, "zats" =: zats
|
, "zats" =: zats
|
||||||
, "invoices" =: inv
|
, "invoices" =: inv
|
||||||
|
, "expiration" =: ets
|
||||||
]
|
]
|
||||||
Nothing ->
|
Nothing ->
|
||||||
Doc
|
Doc
|
||||||
|
@ -213,6 +221,7 @@ instance Val Owner where
|
||||||
, "paid" =: paid
|
, "paid" =: paid
|
||||||
, "zats" =: zats
|
, "zats" =: zats
|
||||||
, "invoices" =: inv
|
, "invoices" =: inv
|
||||||
|
, "expiration" =: ets
|
||||||
]
|
]
|
||||||
|
|
||||||
-- Database actions
|
-- Database actions
|
||||||
|
|
95
src/Payment.hs
Normal file
95
src/Payment.hs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE DeriveGeneric #-}
|
||||||
|
{-# LANGUAGE DuplicateRecordFields #-}
|
||||||
|
|
||||||
|
module Payment where
|
||||||
|
|
||||||
|
import Data.Aeson
|
||||||
|
import qualified Data.Bson as B
|
||||||
|
import qualified Data.Text as T
|
||||||
|
import Data.Time.Clock
|
||||||
|
import Data.Typeable
|
||||||
|
import Database.MongoDB
|
||||||
|
import GHC.Generics
|
||||||
|
import ZGoTx
|
||||||
|
|
||||||
|
data Payment =
|
||||||
|
Payment
|
||||||
|
{ p_id :: Maybe ObjectId
|
||||||
|
, pdelta :: Integer
|
||||||
|
, pdone :: Bool
|
||||||
|
, paddress :: T.Text
|
||||||
|
, psession :: T.Text
|
||||||
|
, pblocktime :: Integer
|
||||||
|
, pamount :: Double
|
||||||
|
, ptxid :: T.Text
|
||||||
|
, pmemo :: T.Text
|
||||||
|
}
|
||||||
|
deriving (Eq, Show, Generic)
|
||||||
|
|
||||||
|
instance Val Payment where
|
||||||
|
cast' (Doc d) = do
|
||||||
|
i <- B.lookup "_id" d
|
||||||
|
delta <- B.lookup "delta" d
|
||||||
|
done <- B.lookup "done" d
|
||||||
|
a <- B.lookup "address" d
|
||||||
|
s <- B.lookup "session" d
|
||||||
|
bt <- B.lookup "blocktime" d
|
||||||
|
amt <- B.lookup "amount" d
|
||||||
|
t <- B.lookup "txid" d
|
||||||
|
m <- B.lookup "memo" d
|
||||||
|
Just (Payment i delta done a s bt amt t m)
|
||||||
|
cast' _ = Nothing
|
||||||
|
val (Payment i delta done a s bt amt t m) =
|
||||||
|
case i of
|
||||||
|
Just oid ->
|
||||||
|
Doc
|
||||||
|
[ "_id" =: oid
|
||||||
|
, "delta" =: delta
|
||||||
|
, "done" =: done
|
||||||
|
, "address" =: a
|
||||||
|
, "session" =: s
|
||||||
|
, "blocktime" =: bt
|
||||||
|
, "amount" =: amt
|
||||||
|
, "txid" =: t
|
||||||
|
, "memo" =: m
|
||||||
|
]
|
||||||
|
Nothing ->
|
||||||
|
Doc
|
||||||
|
[ "delta" =: delta
|
||||||
|
, "done" =: done
|
||||||
|
, "address" =: a
|
||||||
|
, "session" =: s
|
||||||
|
, "blocktime" =: bt
|
||||||
|
, "amount" =: amt
|
||||||
|
, "txid" =: t
|
||||||
|
, "memo" =: m
|
||||||
|
]
|
||||||
|
|
||||||
|
upsertPayment :: ZGoTx -> Action IO ()
|
||||||
|
upsertPayment p = do
|
||||||
|
let delta = sessionCalc $ amount p
|
||||||
|
let payTx =
|
||||||
|
Payment
|
||||||
|
Nothing
|
||||||
|
delta
|
||||||
|
False
|
||||||
|
(address p)
|
||||||
|
(session p)
|
||||||
|
(blocktime p)
|
||||||
|
(amount p)
|
||||||
|
(txid p)
|
||||||
|
(memo p)
|
||||||
|
let payment = val payTx
|
||||||
|
case payment of
|
||||||
|
Doc d -> upsert (select ["tx" =: payTx] "payments") d
|
||||||
|
_ -> return ()
|
||||||
|
|
||||||
|
sessionCalc :: Double -> Integer
|
||||||
|
sessionCalc zec
|
||||||
|
| zec >= hiPay = 2419200 -- 1 month in seconds
|
||||||
|
| zec >= medPay = 604800 -- 1 week in seconds
|
||||||
|
| zec >= lowPay = 86400 -- 1 day in seconds
|
||||||
|
| otherwise = 0
|
||||||
|
where
|
||||||
|
(lowPay, medPay, hiPay) = (0.005, 0.025, 0.1)
|
|
@ -19,6 +19,7 @@ import Data.SecureMem
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.Lazy as L
|
import qualified Data.Text.Lazy as L
|
||||||
import Data.Time.Clock
|
import Data.Time.Clock
|
||||||
|
import Data.Time.Clock.POSIX
|
||||||
import Data.Typeable
|
import Data.Typeable
|
||||||
import qualified Data.Vector as V
|
import qualified Data.Vector as V
|
||||||
import Data.Word
|
import Data.Word
|
||||||
|
@ -28,10 +29,12 @@ import GHC.Generics
|
||||||
import Item
|
import Item
|
||||||
import Network.HTTP.Simple
|
import Network.HTTP.Simple
|
||||||
import Network.HTTP.Types.Status
|
import Network.HTTP.Types.Status
|
||||||
|
import Network.Wai.Middleware.Cors
|
||||||
import Network.Wai.Middleware.HttpAuth
|
import Network.Wai.Middleware.HttpAuth
|
||||||
import Numeric
|
import Numeric
|
||||||
import Order
|
import Order
|
||||||
import Owner
|
import Owner
|
||||||
|
import Payment
|
||||||
import System.IO.Unsafe
|
import System.IO.Unsafe
|
||||||
import System.Random
|
import System.Random
|
||||||
import Test.QuickCheck
|
import Test.QuickCheck
|
||||||
|
@ -71,6 +74,16 @@ instance (FromJSON r) => FromJSON (RpcResponse r) where
|
||||||
MakeRpcResponse <$> obj .: "error" <*> obj .: "id" <*> obj .: "result"
|
MakeRpcResponse <$> obj .: "error" <*> obj .: "id" <*> obj .: "result"
|
||||||
parseJSON _ = mzero
|
parseJSON _ = mzero
|
||||||
|
|
||||||
|
data Payload r =
|
||||||
|
Payload
|
||||||
|
{ payload :: r
|
||||||
|
}
|
||||||
|
deriving (Show, Generic, ToJSON)
|
||||||
|
|
||||||
|
instance (FromJSON r) => FromJSON (Payload r) where
|
||||||
|
parseJSON (Object obj) = Payload <$> obj .: "payload"
|
||||||
|
parseJSON _ = mzero
|
||||||
|
|
||||||
-- | Type to model a (simplified) block of Zcash blockchain
|
-- | Type to model a (simplified) block of Zcash blockchain
|
||||||
data Block =
|
data Block =
|
||||||
Block
|
Block
|
||||||
|
@ -192,13 +205,13 @@ zToZGoTx (ZcashTx t a aZ bh bt c conf m) = do
|
||||||
then do
|
then do
|
||||||
let sess = T.pack (fst $ head reg ! 1)
|
let sess = T.pack (fst $ head reg ! 1)
|
||||||
let addy = T.pack (fst $ head reg ! 2)
|
let addy = T.pack (fst $ head reg ! 2)
|
||||||
ZGoTx "" addy sess conf bt a t m
|
ZGoTx Nothing addy sess conf bt a t m
|
||||||
else do
|
else do
|
||||||
if not (null reg2)
|
if not (null reg2)
|
||||||
then do
|
then do
|
||||||
let sess = T.pack (fst $ head reg2 ! 1)
|
let sess = T.pack (fst $ head reg2 ! 1)
|
||||||
ZGoTx "" "" sess conf bt a t m
|
ZGoTx Nothing "" sess conf bt a t m
|
||||||
else ZGoTx "" "" "" conf bt a t m
|
else ZGoTx Nothing "" "" conf bt a t m
|
||||||
|
|
||||||
-- |Type to model a price in the ZGo database
|
-- |Type to model a price in the ZGo database
|
||||||
data ZGoPrice =
|
data ZGoPrice =
|
||||||
|
@ -304,7 +317,16 @@ upsertZGoTx coll t = do
|
||||||
app :: Pipe -> T.Text -> SecureMem -> T.Text -> IO ()
|
app :: Pipe -> T.Text -> SecureMem -> T.Text -> IO ()
|
||||||
app pipe db passkey nodeAddress = do
|
app pipe db passkey nodeAddress = do
|
||||||
let run = access pipe master db
|
let run = access pipe master db
|
||||||
scotty 4000 $ do
|
scotty 3000 $ do
|
||||||
|
middleware $
|
||||||
|
cors $
|
||||||
|
const $
|
||||||
|
Just
|
||||||
|
simpleCorsResourcePolicy
|
||||||
|
{ corsRequestHeaders = ["Authorization", "Content-Type"]
|
||||||
|
, corsMethods = "DELETE" : simpleMethods
|
||||||
|
, corsOrigins = Nothing
|
||||||
|
}
|
||||||
middleware $
|
middleware $
|
||||||
basicAuth
|
basicAuth
|
||||||
(\u p -> return $ u == "user" && secureMemFromByteString p == passkey)
|
(\u p -> return $ u == "user" && secureMemFromByteString p == passkey)
|
||||||
|
@ -359,18 +381,18 @@ app pipe db passkey nodeAddress = do
|
||||||
liftIO $ run (deleteUser userId)
|
liftIO $ run (deleteUser userId)
|
||||||
status ok200
|
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-}
|
||||||
sess <- param "session"
|
{-sess <- param "session"-}
|
||||||
pending <- liftIO $ run (findPending sess)
|
{-pending <- liftIO $ run (findPending sess)-}
|
||||||
case pending of
|
{-case pending of-}
|
||||||
[] -> do
|
{-[] -> do-}
|
||||||
status noContent204
|
{-status noContent204-}
|
||||||
_ -> do
|
{-_ -> do-}
|
||||||
Web.Scotty.json
|
{-Web.Scotty.json-}
|
||||||
(object
|
{-(object-}
|
||||||
[ "message" .= ("Found pending transactions" :: String)
|
{-[ "message" .= ("Found pending transactions" :: String)-}
|
||||||
, "txs" .= toJSON (map parseZGoTxBson pending)
|
{-, "txs" .= toJSON (map parseZGoTxBson pending)-}
|
||||||
])
|
{-])-}
|
||||||
--Get current blockheight from Zcash node
|
--Get current blockheight from Zcash node
|
||||||
get "/api/blockheight" $ do
|
get "/api/blockheight" $ do
|
||||||
blockInfo <- makeZcashCall "getblock" ["-1"]
|
blockInfo <- makeZcashCall "getblock" ["-1"]
|
||||||
|
@ -401,7 +423,8 @@ app pipe db passkey nodeAddress = do
|
||||||
--Upsert owner to DB
|
--Upsert owner to DB
|
||||||
post "/api/owner" $ do
|
post "/api/owner" $ do
|
||||||
o <- jsonData
|
o <- jsonData
|
||||||
_ <- liftIO $ run (upsertOwner o)
|
let q = payload (o :: Payload Owner)
|
||||||
|
_ <- liftIO $ run (upsertOwner q)
|
||||||
status created201
|
status created201
|
||||||
--Get items associated with the given address
|
--Get items associated with the given address
|
||||||
get "/api/items" $ do
|
get "/api/items" $ do
|
||||||
|
@ -554,7 +577,7 @@ scanZcash addr pipe db = do
|
||||||
let k = map zToZGoTx (filter (matchTest r . T.unpack . zmemo) txs)
|
let k = map zToZGoTx (filter (matchTest r . T.unpack . zmemo) txs)
|
||||||
mapM_ (access pipe master db . upsertZGoTx "txs") k
|
mapM_ (access pipe master db . upsertZGoTx "txs") k
|
||||||
let j = map zToZGoTx (filter (matchTest p . T.unpack . zmemo) txs)
|
let j = map zToZGoTx (filter (matchTest p . T.unpack . zmemo) txs)
|
||||||
mapM_ (access pipe master db . upsertZGoTx "payments") j
|
mapM_ (access pipe master db . upsertPayment) j
|
||||||
|
|
||||||
-- | Function to generate users from login txs
|
-- | Function to generate users from login txs
|
||||||
updateLogins :: T.Text -> Pipe -> T.Text -> IO ()
|
updateLogins :: T.Text -> Pipe -> T.Text -> IO ()
|
||||||
|
@ -566,8 +589,60 @@ updateLogins addr pipe db = do
|
||||||
db
|
db
|
||||||
(rest =<<
|
(rest =<<
|
||||||
find (select ["confirmations" =: ["$lt" =: (100 :: Integer)]] "txs"))
|
find (select ["confirmations" =: ["$lt" =: (100 :: Integer)]] "txs"))
|
||||||
let parsed = map parseZGoTxBson results
|
let parsed = map (cast' . Doc) results
|
||||||
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!"
|
||||||
|
|
||||||
|
-- | Function to mark owners as paid
|
||||||
|
checkPayments :: Pipe -> T.Text -> IO ()
|
||||||
|
checkPayments pipe db = do
|
||||||
|
qPayments <-
|
||||||
|
access pipe master db (rest =<< find (select ["done" =: False] "payments"))
|
||||||
|
let parsedPayments = map (cast' . Doc) qPayments
|
||||||
|
mapM_ (payOwner pipe db) parsedPayments
|
||||||
|
|
||||||
|
payOwner :: Pipe -> T.Text -> Maybe Payment -> IO ()
|
||||||
|
payOwner p d x =
|
||||||
|
case x of
|
||||||
|
Nothing -> return ()
|
||||||
|
Just k -> do
|
||||||
|
now <- getCurrentTime
|
||||||
|
if posixSecondsToUTCTime (fromInteger (pblocktime k + pdelta k)) <= now
|
||||||
|
then markPaymentDone p d k
|
||||||
|
else markOwnerPaid p d k
|
||||||
|
where markPaymentDone :: Pipe -> T.Text -> Payment -> IO ()
|
||||||
|
markPaymentDone pipe db pmt = do
|
||||||
|
_ <-
|
||||||
|
access
|
||||||
|
pipe
|
||||||
|
master
|
||||||
|
db
|
||||||
|
(modify
|
||||||
|
(select ["_id" =: p_id pmt] "payments")
|
||||||
|
["$set" =: ["done" =: True]])
|
||||||
|
return ()
|
||||||
|
markOwnerPaid :: Pipe -> T.Text -> Payment -> IO ()
|
||||||
|
markOwnerPaid pipe db pmt = do
|
||||||
|
user <- access pipe master db (findUser $ psession pmt)
|
||||||
|
let parsedUser = parseUserBson =<< user
|
||||||
|
let zaddy = maybe "" uaddress parsedUser
|
||||||
|
owner <- access pipe master db $ findOwner zaddy
|
||||||
|
let parsedOwner = (cast' . Doc) =<< owner
|
||||||
|
let ownerId = o_id =<< parsedOwner
|
||||||
|
_ <-
|
||||||
|
access
|
||||||
|
pipe
|
||||||
|
master
|
||||||
|
db
|
||||||
|
(modify
|
||||||
|
(select ["_id" =: ownerId] "owners")
|
||||||
|
[ "$set" =:
|
||||||
|
[ "paid" =: True
|
||||||
|
, "expiration" =:
|
||||||
|
posixSecondsToUTCTime
|
||||||
|
(fromInteger (pblocktime pmt + pdelta pmt))
|
||||||
|
]
|
||||||
|
])
|
||||||
|
markPaymentDone pipe db pmt
|
||||||
|
|
||||||
debug = flip trace
|
debug = flip trace
|
||||||
|
|
45
src/ZGoTx.hs
45
src/ZGoTx.hs
|
@ -1,6 +1,5 @@
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE DeriveGeneric #-}
|
{-# LANGUAGE DeriveGeneric #-}
|
||||||
{-# LANGUAGE DeriveAnyClass #-}
|
|
||||||
{-# LANGUAGE DuplicateRecordFields #-}
|
{-# LANGUAGE DuplicateRecordFields #-}
|
||||||
|
|
||||||
module ZGoTx where
|
module ZGoTx where
|
||||||
|
@ -14,7 +13,7 @@ import GHC.Generics
|
||||||
-- | Type to model a ZGo transaction
|
-- | Type to model a ZGo transaction
|
||||||
data ZGoTx =
|
data ZGoTx =
|
||||||
ZGoTx
|
ZGoTx
|
||||||
{ _id :: String
|
{ _id :: Maybe ObjectId
|
||||||
, address :: T.Text
|
, address :: T.Text
|
||||||
, session :: T.Text
|
, session :: T.Text
|
||||||
, confirmations :: Integer
|
, confirmations :: Integer
|
||||||
|
@ -23,7 +22,7 @@ data ZGoTx =
|
||||||
, txid :: T.Text
|
, txid :: T.Text
|
||||||
, memo :: T.Text
|
, memo :: T.Text
|
||||||
}
|
}
|
||||||
deriving (Eq, Show, Generic, ToJSON)
|
deriving (Eq, Show, Generic)
|
||||||
|
|
||||||
parseZGoTxBson :: B.Document -> Maybe ZGoTx
|
parseZGoTxBson :: B.Document -> Maybe ZGoTx
|
||||||
parseZGoTxBson d = do
|
parseZGoTxBson d = do
|
||||||
|
@ -35,12 +34,12 @@ parseZGoTxBson d = do
|
||||||
t <- B.lookup "txid" d
|
t <- B.lookup "txid" d
|
||||||
m <- B.lookup "memo" d
|
m <- B.lookup "memo" d
|
||||||
bt <- B.lookup "blocktime" d
|
bt <- B.lookup "blocktime" d
|
||||||
pure $ ZGoTx (show (i :: B.ObjectId)) a s c bt am t m
|
pure $ ZGoTx i a s c bt am t m
|
||||||
|
|
||||||
encodeZGoTxBson :: ZGoTx -> B.Document
|
encodeZGoTxBson :: ZGoTx -> B.Document
|
||||||
encodeZGoTxBson (ZGoTx i a s c bt am t m) =
|
encodeZGoTxBson (ZGoTx i a s c bt am t m) =
|
||||||
if not (null i)
|
if not (null i)
|
||||||
then [ "_id" =: (read i :: B.ObjectId)
|
then [ "_id" =: i
|
||||||
, "address" =: a
|
, "address" =: a
|
||||||
, "session" =: s
|
, "session" =: s
|
||||||
, "confirmations" =: c
|
, "confirmations" =: c
|
||||||
|
@ -57,3 +56,39 @@ encodeZGoTxBson (ZGoTx i a s c bt am t m) =
|
||||||
, "txid" =: t
|
, "txid" =: t
|
||||||
, "memo" =: m
|
, "memo" =: m
|
||||||
]
|
]
|
||||||
|
|
||||||
|
instance Val ZGoTx where
|
||||||
|
cast' (Doc d) = do
|
||||||
|
i <- B.lookup "_id" d
|
||||||
|
a <- B.lookup "address" d
|
||||||
|
s <- B.lookup "session" d
|
||||||
|
c <- B.lookup "confirmations" d
|
||||||
|
am <- B.lookup "amount" d
|
||||||
|
t <- B.lookup "txid" d
|
||||||
|
m <- B.lookup "memo" d
|
||||||
|
bt <- B.lookup "blocktime" d
|
||||||
|
Just (ZGoTx i a s c bt am t m)
|
||||||
|
cast' _ = Nothing
|
||||||
|
val (ZGoTx i a s c bt am t m) =
|
||||||
|
case i of
|
||||||
|
Just oid ->
|
||||||
|
Doc
|
||||||
|
[ "_id" =: i
|
||||||
|
, "address" =: a
|
||||||
|
, "session" =: s
|
||||||
|
, "confirmations" =: c
|
||||||
|
, "blocktime" =: bt
|
||||||
|
, "amount" =: am
|
||||||
|
, "txid" =: t
|
||||||
|
, "memo" =: m
|
||||||
|
]
|
||||||
|
Nothing ->
|
||||||
|
Doc
|
||||||
|
[ "address" =: a
|
||||||
|
, "session" =: s
|
||||||
|
, "confirmations" =: c
|
||||||
|
, "blocktime" =: bt
|
||||||
|
, "amount" =: am
|
||||||
|
, "txid" =: t
|
||||||
|
, "memo" =: m
|
||||||
|
]
|
||||||
|
|
72
test/Spec.hs
72
test/Spec.hs
|
@ -12,12 +12,16 @@ import Data.Either
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.SecureMem
|
import Data.SecureMem
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
|
import Data.Time
|
||||||
|
import Data.Time.Calendar
|
||||||
import Data.Time.Clock
|
import Data.Time.Clock
|
||||||
import Database.MongoDB
|
import Database.MongoDB
|
||||||
|
import Item
|
||||||
import Network.HTTP.Simple
|
import Network.HTTP.Simple
|
||||||
import Network.HTTP.Types.Status
|
import Network.HTTP.Types.Status
|
||||||
import Order
|
import Order
|
||||||
import Owner
|
import Owner
|
||||||
|
import Payment
|
||||||
import System.IO.Unsafe
|
import System.IO.Unsafe
|
||||||
import Test.Hspec
|
import Test.Hspec
|
||||||
import Test.Hspec.Expectations.Json
|
import Test.Hspec.Expectations.Json
|
||||||
|
@ -68,7 +72,7 @@ main =
|
||||||
"ZGO::5d3d4494-51c0-432d-8495-050419957aea\nReply-To:\nzs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e"
|
"ZGO::5d3d4494-51c0-432d-8495-050419957aea\nReply-To:\nzs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e"
|
||||||
zToZGoTx t `shouldBe`
|
zToZGoTx t `shouldBe`
|
||||||
ZGoTx
|
ZGoTx
|
||||||
""
|
Nothing
|
||||||
"zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e"
|
"zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e"
|
||||||
"5d3d4494-51c0-432d-8495-050419957aea"
|
"5d3d4494-51c0-432d-8495-050419957aea"
|
||||||
20
|
20
|
||||||
|
@ -165,9 +169,15 @@ main =
|
||||||
res <- httpLBS req
|
res <- httpLBS req
|
||||||
getResponseStatus res `shouldBe` ok200
|
getResponseStatus res `shouldBe` ok200
|
||||||
describe "Item endpoint" $ do
|
describe "Item endpoint" $ do
|
||||||
it "add item" $ do pending
|
prop "add item" testItemAdd
|
||||||
it "get item" $ do pending
|
it "get items" $ do
|
||||||
it "delete item" $ do pending
|
req <- testGet "/api/items" [("address", Just "Zaddy")]
|
||||||
|
res <- httpJSON req
|
||||||
|
getResponseStatus (res :: Response A.Value) `shouldBe` ok200
|
||||||
|
it "delete item" $ do
|
||||||
|
req <- testDelete "/api/item/" "627d7ba92b05a76be3000003"
|
||||||
|
res <- httpLBS req
|
||||||
|
getResponseStatus res `shouldBe` ok200
|
||||||
around handleDb $
|
around handleDb $
|
||||||
describe "Database actions" $ do
|
describe "Database actions" $ do
|
||||||
describe "authentication" $ do
|
describe "authentication" $ do
|
||||||
|
@ -252,17 +262,13 @@ main =
|
||||||
_ <- scanZcash nodeAddress p "test"
|
_ <- scanZcash nodeAddress p "test"
|
||||||
threadDelay 1000000
|
threadDelay 1000000
|
||||||
t <- access p master "test" $ findOne (select [] "payments")
|
t <- access p master "test" $ findOne (select [] "payments")
|
||||||
case t of
|
let s = (cast' . Doc) =<< t
|
||||||
Nothing -> True `shouldBe` False
|
let payDelta = maybe 0 pdelta s
|
||||||
Just r -> do
|
payDelta `shouldSatisfy` (> 0)
|
||||||
let s = parseZGoTxBson r
|
|
||||||
case s of
|
|
||||||
Nothing -> True `shouldBe` False
|
|
||||||
Just z -> confirmations z `shouldSatisfy` (> 0)
|
|
||||||
xit "login txs are converted to users" $ \p -> do
|
xit "login txs are converted to users" $ \p -> do
|
||||||
let myTx =
|
let myTx =
|
||||||
ZGoTx
|
ZGoTx
|
||||||
""
|
Nothing
|
||||||
"zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e"
|
"zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e"
|
||||||
"35bfb9c2-9ad2-4fe5-adda-99d63b8dcdca"
|
"35bfb9c2-9ad2-4fe5-adda-99d63b8dcdca"
|
||||||
3
|
3
|
||||||
|
@ -289,7 +295,7 @@ testGet endpoint body = do
|
||||||
let pwd = "superSecret"
|
let pwd = "superSecret"
|
||||||
let testRequest =
|
let testRequest =
|
||||||
setRequestQueryString body $
|
setRequestQueryString body $
|
||||||
setRequestPort 4000 $
|
setRequestPort 3000 $
|
||||||
setRequestBasicAuth user pwd $
|
setRequestBasicAuth user pwd $
|
||||||
setRequestMethod "GET" $ setRequestPath endpoint defaultRequest
|
setRequestMethod "GET" $ setRequestPath endpoint defaultRequest
|
||||||
return testRequest
|
return testRequest
|
||||||
|
@ -300,7 +306,7 @@ testPost endpoint body = do
|
||||||
let pwd = "superSecret"
|
let pwd = "superSecret"
|
||||||
let testRequest =
|
let testRequest =
|
||||||
setRequestQueryString body $
|
setRequestQueryString body $
|
||||||
setRequestPort 4000 $
|
setRequestPort 3000 $
|
||||||
setRequestBasicAuth user pwd $
|
setRequestBasicAuth user pwd $
|
||||||
setRequestMethod "POST" $ setRequestPath endpoint defaultRequest
|
setRequestMethod "POST" $ setRequestPath endpoint defaultRequest
|
||||||
return testRequest
|
return testRequest
|
||||||
|
@ -311,7 +317,7 @@ testPostJson endpoint body = do
|
||||||
let pwd = "superSecret"
|
let pwd = "superSecret"
|
||||||
let testRequest =
|
let testRequest =
|
||||||
setRequestBodyJSON body $
|
setRequestBodyJSON body $
|
||||||
setRequestPort 4000 $
|
setRequestPort 3000 $
|
||||||
setRequestBasicAuth user pwd $
|
setRequestBasicAuth user pwd $
|
||||||
setRequestMethod "POST" $ setRequestPath endpoint defaultRequest
|
setRequestMethod "POST" $ setRequestPath endpoint defaultRequest
|
||||||
return testRequest
|
return testRequest
|
||||||
|
@ -321,7 +327,7 @@ testDelete endpoint par = do
|
||||||
let user = "user"
|
let user = "user"
|
||||||
let pwd = "superSecret"
|
let pwd = "superSecret"
|
||||||
let testRequest =
|
let testRequest =
|
||||||
setRequestPort 4000 $
|
setRequestPort 3000 $
|
||||||
setRequestBasicAuth user pwd $
|
setRequestBasicAuth user pwd $
|
||||||
setRequestMethod "DELETE" $
|
setRequestMethod "DELETE" $
|
||||||
setRequestPath (B.append endpoint par) defaultRequest
|
setRequestPath (B.append endpoint par) defaultRequest
|
||||||
|
@ -330,7 +336,8 @@ testDelete endpoint par = do
|
||||||
testOwnerAdd :: Owner -> Property
|
testOwnerAdd :: Owner -> Property
|
||||||
testOwnerAdd o =
|
testOwnerAdd o =
|
||||||
monadicIO $ do
|
monadicIO $ do
|
||||||
req <- run $ testPostJson "/api/owner" (A.toJSON o) --`debug` show o
|
req <-
|
||||||
|
run $ testPostJson "/api/owner" (A.object ["payload" A..= A.toJSON o]) --`debug` show o
|
||||||
res <- httpLBS req
|
res <- httpLBS req
|
||||||
assert $ getResponseStatus res == created201
|
assert $ getResponseStatus res == created201
|
||||||
|
|
||||||
|
@ -341,6 +348,13 @@ testOrderAdd o =
|
||||||
res <- httpLBS req
|
res <- httpLBS req
|
||||||
assert $ getResponseStatus res == created201
|
assert $ getResponseStatus res == created201
|
||||||
|
|
||||||
|
testItemAdd :: Item -> Property
|
||||||
|
testItemAdd i = do
|
||||||
|
monadicIO $ do
|
||||||
|
req <- run $ testPostJson "/api/item" (A.toJSON i)
|
||||||
|
res <- httpLBS req
|
||||||
|
assert $ getResponseStatus res == created201
|
||||||
|
|
||||||
-- | Open the MongoDB connection
|
-- | Open the MongoDB connection
|
||||||
openDbConnection :: IO Pipe
|
openDbConnection :: IO Pipe
|
||||||
openDbConnection = do
|
openDbConnection = do
|
||||||
|
@ -384,6 +398,7 @@ startAPI = do
|
||||||
, "pin" =: upin myUser
|
, "pin" =: upin myUser
|
||||||
, "validated" =: uvalidated myUser
|
, "validated" =: uvalidated myUser
|
||||||
])
|
])
|
||||||
|
myTstamp <- getCurrentTime
|
||||||
let myOwner =
|
let myOwner =
|
||||||
Owner
|
Owner
|
||||||
(Just (read "627ad3492b05a76be3000001"))
|
(Just (read "627ad3492b05a76be3000001"))
|
||||||
|
@ -407,6 +422,7 @@ startAPI = do
|
||||||
False
|
False
|
||||||
False
|
False
|
||||||
False
|
False
|
||||||
|
(UTCTime (fromGregorian 2022 5 16) (secondsToDiffTime 0))
|
||||||
_ <- access pipe master "test" (delete (select [] "owners"))
|
_ <- access pipe master "test" (delete (select [] "owners"))
|
||||||
let o = val myOwner
|
let o = val myOwner
|
||||||
case o of
|
case o of
|
||||||
|
@ -428,6 +444,16 @@ startAPI = do
|
||||||
let ordTest = val myOrder
|
let ordTest = val myOrder
|
||||||
case ordTest of
|
case ordTest of
|
||||||
Doc oT -> access pipe master "test" (insert_ "orders" oT)
|
Doc oT -> access pipe master "test" (insert_ "orders" oT)
|
||||||
|
let myItem1 =
|
||||||
|
Item
|
||||||
|
(Just (read "627d7ba92b05a76be3000003"))
|
||||||
|
"Chair"
|
||||||
|
"Made of wood"
|
||||||
|
"Zaddy"
|
||||||
|
101.99
|
||||||
|
let itemTest = val myItem1
|
||||||
|
case itemTest of
|
||||||
|
Doc iT -> access pipe master "test" (insert_ "items" iT)
|
||||||
threadDelay 1000000
|
threadDelay 1000000
|
||||||
putStrLn "Test server is up!"
|
putStrLn "Test server is up!"
|
||||||
|
|
||||||
|
@ -479,4 +505,14 @@ instance Arbitrary Owner where
|
||||||
co <- arbitrary
|
co <- arbitrary
|
||||||
paid <- arbitrary
|
paid <- arbitrary
|
||||||
zats <- arbitrary
|
zats <- arbitrary
|
||||||
Owner i a n c t tV v vV f l e s ct st p ph w co paid zats <$> arbitrary
|
inv <- arbitrary
|
||||||
|
exp <- arbitrary
|
||||||
|
pure $ Owner i a n c t tV v vV f l e s ct st p ph w co paid zats inv exp
|
||||||
|
|
||||||
|
instance Arbitrary Item where
|
||||||
|
arbitrary = do
|
||||||
|
i <- arbitrary
|
||||||
|
n <- arbitrary
|
||||||
|
d <- arbitrary
|
||||||
|
o <- arbitrary
|
||||||
|
Item i n d o <$> arbitrary
|
||||||
|
|
|
@ -28,6 +28,7 @@ library
|
||||||
Item
|
Item
|
||||||
Order
|
Order
|
||||||
Owner
|
Owner
|
||||||
|
Payment
|
||||||
User
|
User
|
||||||
ZGoBackend
|
ZGoBackend
|
||||||
ZGoTx
|
ZGoTx
|
||||||
|
@ -55,6 +56,7 @@ library
|
||||||
, time
|
, time
|
||||||
, unordered-containers
|
, unordered-containers
|
||||||
, vector
|
, vector
|
||||||
|
, wai-cors
|
||||||
, wai-extra
|
, wai-extra
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue