Implement WooCommerce authentication
This commit is contained in:
parent
0eae258dee
commit
daa4f59faa
5 changed files with 145 additions and 2 deletions
|
@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- New utility to refresh Xero tokens periodically.
|
- New utility to refresh Xero tokens periodically.
|
||||||
|
- New module for WooCommerce interaction.
|
||||||
|
- New `/api/auth` endpoint to authenticate with the WooCommerce plugin
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
40
src/WooCommerce.hs
Normal file
40
src/WooCommerce.hs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
|
module WooCommerce where
|
||||||
|
|
||||||
|
import Data.Aeson
|
||||||
|
import qualified Data.Bson as B
|
||||||
|
import Data.Maybe
|
||||||
|
import qualified Data.Text as T
|
||||||
|
import Database.MongoDB
|
||||||
|
|
||||||
|
-- | Type to represent the WooCommerce token
|
||||||
|
data WooToken =
|
||||||
|
WooToken
|
||||||
|
{ w_id :: Maybe ObjectId
|
||||||
|
, w_owner :: ObjectId
|
||||||
|
, w_token :: T.Text
|
||||||
|
, w_url :: Maybe T.Text
|
||||||
|
}
|
||||||
|
deriving (Eq, Show)
|
||||||
|
|
||||||
|
instance Val WooToken where
|
||||||
|
val (WooToken i o t u) =
|
||||||
|
if isJust i
|
||||||
|
then Doc ["_id" =: i, "owner" =: o, "token" =: t, "url" =: u]
|
||||||
|
else Doc ["owner" =: o, "token" =: t, "url" =: u]
|
||||||
|
cast' (Doc d) = do
|
||||||
|
i <- B.lookup "_id" d
|
||||||
|
o <- B.lookup "owner" d
|
||||||
|
t <- B.lookup "token" d
|
||||||
|
u <- B.lookup "url" d
|
||||||
|
Just (WooToken i o t u)
|
||||||
|
cast' _ = Nothing
|
||||||
|
|
||||||
|
-- Database actions
|
||||||
|
findWooToken :: ObjectId -> Action IO (Maybe Document)
|
||||||
|
findWooToken oid = findOne (select ["owner" =: oid] "wootokens")
|
||||||
|
|
||||||
|
addUrl :: WooToken -> T.Text -> Action IO ()
|
||||||
|
addUrl t u =
|
||||||
|
modify (select ["_id" =: w_id t] "wootokens") ["$set" =: ["url" =: u]]
|
|
@ -52,6 +52,7 @@ import Text.Regex
|
||||||
import Text.Regex.Base
|
import Text.Regex.Base
|
||||||
import User
|
import User
|
||||||
import Web.Scotty
|
import Web.Scotty
|
||||||
|
import WooCommerce
|
||||||
import Xero
|
import Xero
|
||||||
import ZGoTx
|
import ZGoTx
|
||||||
|
|
||||||
|
@ -604,6 +605,46 @@ routes pipe config = do
|
||||||
c <- param "code"
|
c <- param "code"
|
||||||
liftAndCatchIO $ run (addAccCode oAdd c)
|
liftAndCatchIO $ run (addAccCode oAdd c)
|
||||||
status accepted202
|
status accepted202
|
||||||
|
-- Authenticate the WooCommerce plugin
|
||||||
|
get "/api/auth" $ do
|
||||||
|
oid <- param "ownerid"
|
||||||
|
t <- param "token"
|
||||||
|
siteurl <- param "siteurl"
|
||||||
|
res <- liftAndCatchIO $ run (findWooToken (read oid))
|
||||||
|
let c = cast' . Doc =<< res
|
||||||
|
case c of
|
||||||
|
Nothing -> do
|
||||||
|
status accepted202
|
||||||
|
Web.Scotty.json
|
||||||
|
(object
|
||||||
|
["authorized" .= False, "message" .= ("Owner not found" :: String)])
|
||||||
|
Just c ->
|
||||||
|
if t == w_token c
|
||||||
|
then if isNothing (w_url c)
|
||||||
|
then do
|
||||||
|
liftAndCatchIO $ run (addUrl c siteurl)
|
||||||
|
status ok200
|
||||||
|
Web.Scotty.json
|
||||||
|
(object
|
||||||
|
[ "authorized" .= True
|
||||||
|
, "message" .= ("Authorized!" :: String)
|
||||||
|
])
|
||||||
|
else do
|
||||||
|
status accepted202
|
||||||
|
Web.Scotty.json
|
||||||
|
(object
|
||||||
|
[ "authorized" .= False
|
||||||
|
, "message" .=
|
||||||
|
("ZGo shop already linked to" <>
|
||||||
|
fromMaybe "" (w_url c))
|
||||||
|
])
|
||||||
|
else do
|
||||||
|
status accepted202
|
||||||
|
Web.Scotty.json
|
||||||
|
(object
|
||||||
|
[ "authorized" .= False
|
||||||
|
, "message" .= ("Token mismatch" :: String)
|
||||||
|
])
|
||||||
--Get user associated with session
|
--Get user associated with session
|
||||||
get "/api/user" $ do
|
get "/api/user" $ do
|
||||||
sess <- param "session"
|
sess <- param "session"
|
||||||
|
|
63
test/Spec.hs
63
test/Spec.hs
|
@ -33,6 +33,7 @@ import Test.QuickCheck.Gen
|
||||||
import Test.QuickCheck.Monadic
|
import Test.QuickCheck.Monadic
|
||||||
import User
|
import User
|
||||||
import Web.Scotty
|
import Web.Scotty
|
||||||
|
import WooCommerce
|
||||||
import Xero
|
import Xero
|
||||||
import ZGoBackend
|
import ZGoBackend
|
||||||
import ZGoTx
|
import ZGoTx
|
||||||
|
@ -156,7 +157,7 @@ main = do
|
||||||
res <- httpJSON req
|
res <- httpJSON req
|
||||||
getResponseStatus (res :: Response A.Value) `shouldBe` ok200
|
getResponseStatus (res :: Response A.Value) `shouldBe` ok200
|
||||||
describe "blockheight endpoint" $ do
|
describe "blockheight endpoint" $ do
|
||||||
xit "returns a block number" $ do
|
it "returns a block number" $ do
|
||||||
req <- testGet "/api/blockheight" []
|
req <- testGet "/api/blockheight" []
|
||||||
res <- httpJSON req
|
res <- httpJSON req
|
||||||
height (getResponseBody (res :: Response Block)) `shouldSatisfy` \x ->
|
height (getResponseBody (res :: Response Block)) `shouldSatisfy` \x ->
|
||||||
|
@ -250,6 +251,48 @@ main = do
|
||||||
req <- testDelete "/api/item/" "627d7ba92b05a76be3000003"
|
req <- testDelete "/api/item/" "627d7ba92b05a76be3000003"
|
||||||
res <- httpLBS req
|
res <- httpLBS req
|
||||||
getResponseStatus res `shouldBe` ok200
|
getResponseStatus res `shouldBe` ok200
|
||||||
|
describe "WooCommerce endpoints" $ do
|
||||||
|
it "generate token" pending
|
||||||
|
it "authenticate with incorrect owner" $ do
|
||||||
|
req <-
|
||||||
|
testGet
|
||||||
|
"/api/auth/"
|
||||||
|
[ ("ownerid", Just "62cca13f5530331e2a900001")
|
||||||
|
, ("token", Just "89bd9d8d69a674e0f467cc8796ed151a")
|
||||||
|
, ("siteurl", Just "testyMcTest")
|
||||||
|
]
|
||||||
|
res <- httpJSON req
|
||||||
|
getResponseStatus (res :: Response A.Value) `shouldBe` accepted202
|
||||||
|
it "authenticate with incorrect token" $ do
|
||||||
|
req <-
|
||||||
|
testGet
|
||||||
|
"/api/auth/"
|
||||||
|
[ ("ownerid", Just "62cca13f5530331e2a97c78e")
|
||||||
|
, ("token", Just "89bd9d8d69a674e0f467cc8796000000")
|
||||||
|
, ("siteurl", Just "testyMcTest")
|
||||||
|
]
|
||||||
|
res <- httpJSON req
|
||||||
|
getResponseStatus (res :: Response A.Value) `shouldBe` accepted202
|
||||||
|
it "authenticate with correct token" $ do
|
||||||
|
req <-
|
||||||
|
testGet
|
||||||
|
"/api/auth/"
|
||||||
|
[ ("ownerid", Just "62cca13f5530331e2a97c78e")
|
||||||
|
, ("token", Just "89bd9d8d69a674e0f467cc8796ed151a")
|
||||||
|
, ("siteurl", Just "testyMcTest")
|
||||||
|
]
|
||||||
|
res <- httpJSON req
|
||||||
|
getResponseStatus (res :: Response A.Value) `shouldBe` ok200
|
||||||
|
it "authenticate with correct token on existing shop" $ do
|
||||||
|
req <-
|
||||||
|
testGet
|
||||||
|
"/api/auth/"
|
||||||
|
[ ("ownerid", Just "62cca13f5530331e2a97c78e")
|
||||||
|
, ("token", Just "89bd9d8d69a674e0f467cc8796ed151a")
|
||||||
|
, ("siteurl", Just "testyMcTest")
|
||||||
|
]
|
||||||
|
res <- httpJSON req
|
||||||
|
getResponseStatus (res :: Response A.Value) `shouldBe` accepted202
|
||||||
around handleDb $
|
around handleDb $
|
||||||
describe "Database actions" $ do
|
describe "Database actions" $ do
|
||||||
describe "authentication" $ do
|
describe "authentication" $ do
|
||||||
|
@ -304,7 +347,7 @@ main = do
|
||||||
it "deleted" $ \p -> do
|
it "deleted" $ \p -> do
|
||||||
t <- access p master "test" $ findOne (select [] "users")
|
t <- access p master "test" $ findOne (select [] "users")
|
||||||
let s = parseUserBson =<< t
|
let s = parseUserBson =<< t
|
||||||
let userId = maybe Nothing u_id s
|
let userId = u_id =<< s
|
||||||
let idString = maybe "" show userId
|
let idString = maybe "" show userId
|
||||||
_ <- access p master "test" $ deleteUser idString
|
_ <- access p master "test" $ deleteUser idString
|
||||||
q <-
|
q <-
|
||||||
|
@ -332,6 +375,7 @@ main = do
|
||||||
let ordTest = val myOrder
|
let ordTest = val myOrder
|
||||||
case ordTest of
|
case ordTest of
|
||||||
Doc oT -> access p master "test" (insert_ "orders" oT)
|
Doc oT -> access p master "test" (insert_ "orders" oT)
|
||||||
|
_ -> fail "Couldn't save Order in DB"
|
||||||
_ <-
|
_ <-
|
||||||
access p master "test" $
|
access p master "test" $
|
||||||
markOrderPaid ("627ab3ea2b05a76be3000001", 0)
|
markOrderPaid ("627ab3ea2b05a76be3000001", 0)
|
||||||
|
@ -576,6 +620,8 @@ startAPI config = do
|
||||||
c <- access pipe master "zgo" (auth "zgo" "zcashrules")
|
c <- access pipe master "zgo" (auth "zgo" "zcashrules")
|
||||||
let appRoutes = routes pipe config
|
let appRoutes = routes pipe config
|
||||||
_ <- forkIO (scotty 3000 appRoutes)
|
_ <- forkIO (scotty 3000 appRoutes)
|
||||||
|
_ <-
|
||||||
|
access pipe master "test" (Database.MongoDB.delete (select [] "wootokens"))
|
||||||
let myUser =
|
let myUser =
|
||||||
User
|
User
|
||||||
(Just (read "6272a90f2b05a74cf1000001" :: ObjectId))
|
(Just (read "6272a90f2b05a74cf1000001" :: ObjectId))
|
||||||
|
@ -629,6 +675,7 @@ startAPI config = do
|
||||||
let o = val myOwner
|
let o = val myOwner
|
||||||
case o of
|
case o of
|
||||||
Doc d -> access pipe master "test" (insert_ "owners" d)
|
Doc d -> access pipe master "test" (insert_ "owners" d)
|
||||||
|
_ -> fail "Couldn't save Owner in DB"
|
||||||
_ <- access pipe master "test" (Database.MongoDB.delete (select [] "orders"))
|
_ <- access pipe master "test" (Database.MongoDB.delete (select [] "orders"))
|
||||||
myTs <- liftIO getCurrentTime
|
myTs <- liftIO getCurrentTime
|
||||||
let myOrder =
|
let myOrder =
|
||||||
|
@ -649,6 +696,7 @@ startAPI config = 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)
|
||||||
|
_ -> fail "Couldn't save Order in DB"
|
||||||
let myItem1 =
|
let myItem1 =
|
||||||
Item
|
Item
|
||||||
(Just (read "627d7ba92b05a76be3000003"))
|
(Just (read "627d7ba92b05a76be3000003"))
|
||||||
|
@ -659,6 +707,17 @@ startAPI config = do
|
||||||
let itemTest = val myItem1
|
let itemTest = val myItem1
|
||||||
case itemTest of
|
case itemTest of
|
||||||
Doc iT -> access pipe master "test" (insert_ "items" iT)
|
Doc iT -> access pipe master "test" (insert_ "items" iT)
|
||||||
|
_ -> fail "Couldn't save test Item in DB"
|
||||||
|
let myWooToken =
|
||||||
|
WooToken
|
||||||
|
Nothing
|
||||||
|
(read "62cca13f5530331e2a97c78e")
|
||||||
|
"89bd9d8d69a674e0f467cc8796ed151a"
|
||||||
|
Nothing
|
||||||
|
let wooTest = val myWooToken
|
||||||
|
case wooTest of
|
||||||
|
Doc wT -> access pipe master "test" (insert_ "wootokens" wT)
|
||||||
|
_ -> fail "Couldn't save test WooToken in DB"
|
||||||
threadDelay 1000000
|
threadDelay 1000000
|
||||||
putStrLn "Test server is up!"
|
putStrLn "Test server is up!"
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ library
|
||||||
Owner
|
Owner
|
||||||
Payment
|
Payment
|
||||||
User
|
User
|
||||||
|
WooCommerce
|
||||||
Xero
|
Xero
|
||||||
ZGoBackend
|
ZGoBackend
|
||||||
ZGoTx
|
ZGoTx
|
||||||
|
|
Loading…
Reference in a new issue