Skip to content
This repository has been archived by the owner on Sep 20, 2023. It is now read-only.

Commit

Permalink
Nick/shop (#4459)
Browse files Browse the repository at this point in the history
* Shop admin updates

* Shop updates

* Lint

* Deployer

* Lint
  • Loading branch information
nick authored May 12, 2020
1 parent ed6c4eb commit 6e25e97
Show file tree
Hide file tree
Showing 27 changed files with 706 additions and 228 deletions.
5 changes: 5 additions & 0 deletions dapps/shop/backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,8 @@ Export key pair in base64 with no newlines:
Add new migration:

npx sequelize migration:generate --name migrationName --migrations-path=./data/migrations

## Sync Repos

npm run build:dist
rsync -rv --exclude=.git --exclude=.gitignore --exclude=scripts/output --exclude=backend/data/dshop.db --exclude=/node_modules --delete backend/ DESTINATION
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.sequelize.transaction(() => {
return Promise.all([
queryInterface.createTable('external_payments', {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true
},
created_at: Sequelize.DATE,
updated_at: Sequelize.DATE,
external_id: Sequelize.STRING,
order_id: Sequelize.STRING,
data: Sequelize.TEXT,
payment_at: Sequelize.DATE,
amount: Sequelize.INTEGER,
fee: Sequelize.INTEGER,
net: Sequelize.INTEGER
}),
queryInterface.createTable('external_orders', {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true
},
created_at: Sequelize.DATE,
updated_at: Sequelize.DATE,
ordered_at: Sequelize.DATE,
external_id: Sequelize.STRING,
order_id: Sequelize.STRING,
data: Sequelize.TEXT,
amount: Sequelize.INTEGER
})
])
})
},
down: queryInterface => {
return queryInterface.sequelize.transaction(() => {
return Promise.all([
queryInterface.dropTable('external_payments'),
queryInterface.dropTable('external_orders')
])
})
}
}
51 changes: 51 additions & 0 deletions dapps/shop/backend/data/shop-templates/affiliate/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"title": "Affiliate Store",
"fullTitle": "Affiliate Store",
"byline": "",
"logo": "",
"css": "",
"isAffiliate": true,
"footer": "© 2019 <a href=\"https://www.originprotocol.com\">Origin Protocol</a>. <span class=\"ml-1\">Learn more about this decentralized e-commerce store <a class=\"ul\" href=\"https://medium.com/originprotocol/built-on-origin-a-decentralized-shopify-alternative-888adc4198b0\">here</a>.</span>",
"backendAuthToken": "affiliate",

"supportEmail": "My Store <[email protected]>",
"emailSubject": "Your Order",
"twitter": "",
"medium": "",
"instagram": "",
"facebook": "",

"stripe": false,
"beta": true,
"discountCodes": true,

"pgpPublicKey": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nXXXX\n-----END PGP PUBLIC KEY BLOCK-----\n",
"contentCDN": "",
"contentHash": "",
"stripeKey": "",

"networks": {
"1": {
"marketplaceContract": "0x698ff47b84837d3971118a369c570172ee7e54c2",
"listingId": "1-001-XXX",
"affiliate": "",
"arbitrator": "",
"backend": "http://0.0.0.0:3000",
"ipfsGateway": "https://ipfs.originprotocol.com",
"ipfsApi": "https://ipfs.originprotocol.com"
},
"4": {
"marketplaceContract": "0x3d608cce08819351ada81fc1550841ebc10686fd",
"listingId": "4-001-XXX",
"backend": "https://example.herokuapp.com",
"ipfsGateway": "https://ipfs.staging.originprotocol.com",
"ipfsApi": "https://ipfs.staging.originprotocol.com"
},
"999": {
"listingId": "999-001-01",
"backend": "http://0.0.0.0:3000",
"ipfsGateway": "http://localhost:8080",
"ipfsApi": "http://localhost:5002"
}
}
}
31 changes: 31 additions & 0 deletions dapps/shop/backend/models/external_orders.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module.exports = (sequelize, DataTypes) => {
const ExternalOrder = sequelize.define(
'ExternalOrder',
{
id: {
type: DataTypes.INTEGER,
unique: true,
primaryKey: true
},
created_at: DataTypes.DATE,
updated_at: DataTypes.DATE,
external_id: DataTypes.STRING,
order_id: DataTypes.STRING,
data: DataTypes.TEXT,
payment_at: DataTypes.DATE,
amount: DataTypes.INTEGER,
fee: DataTypes.INTEGER,
net: DataTypes.INTEGER
},
{
underscored: true,
tableName: 'external_orders'
}
)

ExternalOrder.associate = function(models) {
ExternalOrder.belongsTo(models.Order, { as: 'externalOrders', foreignKey: 'orderId' })
}

return ExternalOrder
}
32 changes: 32 additions & 0 deletions dapps/shop/backend/models/external_payment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module.exports = (sequelize, DataTypes) => {
const ExternalPayment = sequelize.define(
'ExternalPayment',
{
id: {
type: DataTypes.INTEGER,
unique: true,
primaryKey: true
},
created_at: DataTypes.DATE,
updated_at: DataTypes.DATE,
ordered_at: DataTypes.DATE,
external_id: DataTypes.STRING,
order_id: DataTypes.STRING,
data: DataTypes.TEXT,
amount: DataTypes.INTEGER
},
{
underscored: true,
tableName: 'external_payments'
}
)

ExternalPayment.associate = function(models) {
ExternalPayment.belongsTo(models.Order, {
as: 'externalPayments',
foreignKey: 'orderId'
})
}

return ExternalPayment
}
67 changes: 42 additions & 25 deletions dapps/shop/backend/routes/affiliate.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ const { BigQuery } = require('@google-cloud/bigquery')
const util = require('ethereumjs-util')
const dayjs = require('dayjs')

const { authShop, optionalAuthShop } = require('./_auth')
const { authShop } = require('./_auth')
const { Order } = require('../models')

const BQ_PRODUCTS_TABLE = 'origin-214503.dshop.products'
const encConf = require('../utils/encryptedConfig')

function authAffiliate(req, res, next) {
try {
Expand All @@ -31,12 +30,12 @@ function authAffiliate(req, res, next) {
* Formats a BigQuery product row into a dshop product obj
*/
function bqProductFormatter(product) {
const listingIdFromProductId = (id) => {
const listingIdFromProductId = id => {
const parts = id.split('-')
parts.pop()
return parts.join('-')
}
const makeId = (product) => {
const makeId = product => {
// product ID is only in the IPFS path returned
const productId = product.ipfs_path.split('/')[2]
// listing ID is part of the "product_id" returned by BQ
Expand All @@ -45,11 +44,7 @@ function bqProductFormatter(product) {
}

const id = makeId(product)
const {
price,
title,
image
} = product
const { price, title, image } = product

return {
id,
Expand All @@ -63,8 +58,13 @@ function bqProductFormatter(product) {
/**
* Get the products from BigQuery for a specific shop
*/
async function fetchAffiliateProducts(listingId) {
const bq = new BigQuery()
async function fetchAffiliateProducts({ listingId, credentials, table }) {
let bq
if (credentials) {
bq = new BigQuery({ projectId: credentials.project_id, credentials })
} else {
bq = new BigQuery()
}

let where = `parent_external_id = ''`

Expand All @@ -74,11 +74,10 @@ async function fetchAffiliateProducts(listingId) {

const grouped = `product_id, ipfs_path, title, price, image`
const query = `SELECT MAX(block_number) as block_number, ${grouped}
FROM ${BQ_PRODUCTS_TABLE}
FROM ${table}
WHERE ${where}
GROUP BY ${grouped}
ORDER BY block_number DESC, product_id
LIMIT 50;`
ORDER BY block_number DESC, product_id;`

const [job] = await bq.createQueryJob({ query })
const [rows] = await job.getQueryResults()
Expand All @@ -87,13 +86,16 @@ async function fetchAffiliateProducts(listingId) {

const seen = new Set()

return rows.filter(row => {
if (seen.has(row.ipfs_path)) {
return false
}
seen.add(row.ipfs_path)
return true
}).map(row => bqProductFormatter(row))
return rows
.filter(row => {
if (seen.has(row.ipfs_path)) {
return false
}
seen.add(row.ipfs_path)
return true
})
.slice(0, 50)
.map(row => bqProductFormatter(row))
}

module.exports = function(app) {
Expand Down Expand Up @@ -126,9 +128,24 @@ module.exports = function(app) {
res.send(results)
})

app.get('/affiliate/products', optionalAuthShop, async (req, res) => {
const listingId = req.shop ? req.shop.dataValues.listingId : null
const products = await fetchAffiliateProducts(listingId)
app.get('/affiliate/products', authShop, async (req, res) => {
const shopConfig = encConf.getConfig(req.shop.config)
// const listingId = req.shop ? req.shop.dataValues.listingId : null

let credentials
try {
credentials = JSON.parse(shopConfig.bigQueryCredentials)
} catch (e) {
console.log('No BigQuery credentials found in shop config')
}

const table = shopConfig.bigQueryTable || process.env.BIG_QUERY_TABLE
if (!table) {
console.log('No BigQuery table configured')
return res.json([])
}

const products = await fetchAffiliateProducts({ credentials, table })
res.json(products)
})
}
24 changes: 18 additions & 6 deletions dapps/shop/backend/routes/networks.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const startListener = require('../listener')
module.exports = function(app) {
app.post('/networks', authSuperUser, async (req, res) => {
const networkObj = {
networkId: req.body.netId,
networkId: req.body.networkId,
provider: req.body.provider,
providerWs: req.body.providerWs,
ipfs: req.body.ipfs,
Expand All @@ -24,7 +24,7 @@ module.exports = function(app) {
}

const existing = await Network.findOne({
where: { networkId: req.body.netId }
where: { networkId: networkObj.networkId }
})
if (existing) {
await Network.update(networkObj, {
Expand All @@ -40,13 +40,25 @@ module.exports = function(app) {
})

app.get('/networks/:netId', authSuperUser, async (req, res) => {
const network = await Network.findOne({
where: { networkId: req.params.netId }
})
const where = { networkId: req.params.netId }
const network = await Network.findOne({ where })
if (!network) {
return res.json({ success: false, reason: 'no-network' })
}
if (!network.config) {
return res.json({ success: false, reason: 'no-network-config' })
}

const config = getConfig(network.config)
res.json({ network, config })
})

app.put('/networks/:netId', authSuperUser, async (req, res) => {
const where = { networkId: req.params.netId }
const network = await Network.findOne({ where })
if (!network) {
return res.json({ success: false, reason: 'no-network' })
}
console.log(network)
if (!network.config) {
return res.json({ success: false, reason: 'no-network-config' })
}
Expand Down
Loading

0 comments on commit 6e25e97

Please sign in to comment.