diff --git a/app.js b/app.js index a24fcc6..b3b741a 100644 --- a/app.js +++ b/app.js @@ -14,6 +14,7 @@ const profileRouter = require('./routes/v1/profile') const nicknameRouter = require('./routes/v1/nicknames') const publicRouter = require('./routes/v1/oracle') const feedbackRouter = require('./routes/v1/feedback') +const energyRequestRouter = require('./routes/v1/energyRequest') var boolParser = require('express-query-boolean') const { json } = require('express') @@ -25,8 +26,8 @@ const { const { clientErrorHandler } = require('./src/middlewear/aurahandler') var app = express() -app.use(express.json({limit: '10mb'})); -app.use(express.urlencoded({limit: '10mb'})); +app.use(express.json({ limit: '10mb' })) +app.use(express.urlencoded({ limit: '10mb' })) app.use(logger('dev')) app.use(express.json()) app.use(boolParser()) @@ -45,5 +46,6 @@ app.use('/v1/profile', profileRouter) app.use('/v1/nickname', nicknameRouter) app.use('/v1/public', publicRouter) app.use('/v1/feedback', feedbackRouter) +app.use('/v1/energyRequest', energyRequestRouter) module.exports = app diff --git a/migrations/1668332788267_energy-request.js b/migrations/1668332788267_energy-request.js new file mode 100644 index 0000000..6746ec2 --- /dev/null +++ b/migrations/1668332788267_energy-request.js @@ -0,0 +1,21 @@ +/* eslint-disable camelcase */ + +exports.shorthands = undefined + +exports.up = (pgm) => { + pgm.createTable('energyRequest', { + id: 'id', + brightId: { + type: 'varchar', + notNull: true, + unique: true, + }, + createdAt: { + type: 'timestamp', + notNull: true, + default: pgm.func('current_timestamp'), + }, + }) +} + +exports.down = (pgm) => {} diff --git a/package.json b/package.json index a5c444e..910404c 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,9 @@ "scripts": { "start": "nodemon ./bin/www", "migrate": "node-pg-migrate", - "run-migration": "PGSSLMODE=require node-pg-migrate up --no-reject-unauthorized", - "heroku-postbuild": "PGSSLMODE=require node-pg-migrate up --no-reject-unauthorized" + "run-migration": "PGSSLMODE=require node-pg-migrate up --no-reject-unauthorized --no-check-order", + "heroku-postbuild": "PGSSLMODE=require node-pg-migrate up --no-reject-unauthorized --no-check-order", + "run-migration-local": "node-pg-migrate up --no-check-order" }, "dependencies": { "apisauce": "^2.1.5", diff --git a/routes/v1/connections.js b/routes/v1/connections.js index 0a8e966..170156a 100644 --- a/routes/v1/connections.js +++ b/routes/v1/connections.js @@ -1,73 +1,111 @@ -var express = require('express'); -const {getConnection, getConnections, get4Unrated} = require("../../src/controllers/connectionController"); -const {getRating, getConnectionsRated} = require("../../src/controllers/ratingController"); -const {getSpecificEnergy} = require("../../src/controllers/energyAllocationController"); -const shuffleSeed = require('shuffle-seed'); -var router = express.Router(); +var express = require('express') +const { + getConnection, + getConnections, + get4Unrated, +} = require('../../src/controllers/connectionController') +const { + getRating, + getConnectionsRated, +} = require('../../src/controllers/ratingController') +const { + getSpecificEnergy, +} = require('../../src/controllers/energyAllocationController') + +const { + getRequestForEnergyRecord, +} = require('../../src/controllers/requestForEnergyController') + +const shuffleSeed = require('shuffle-seed') +var router = express.Router() router.get('/:fromBrightId/:toBrightId', async function (req, res, next) { - let fromBrightId = req.params.fromBrightId; - let toBrightId = req.params.toBrightId; - - let connection = (await getConnection(fromBrightId, toBrightId))[0]; - if (connection === undefined) { - res.status(500).send("No connection between these two brightId"); - } - let rating = (await getRating(fromBrightId, toBrightId)).rows[0] - let energyTransfer = (await getSpecificEnergy(fromBrightId, toBrightId)).rows[0] - let fourUnrated = await get4Unrated(fromBrightId) - - res.json({ - previousRating: rating, - energyAllocated: energyTransfer, - connectedTimestamp: connection.conn.timestamp, - fourUnrated - }) -}); + let fromBrightId = req.params.fromBrightId + let toBrightId = req.params.toBrightId + + let connection = (await getConnection(fromBrightId, toBrightId))[0] + if (connection === undefined) { + res.status(500).send('No connection between these two brightId') + } + let rating = (await getRating(fromBrightId, toBrightId)).rows[0] + let energyTransfer = (await getSpecificEnergy(fromBrightId, toBrightId)) + .rows[0] + let fourUnrated = await get4Unrated(fromBrightId) + + res.json({ + previousRating: rating, + energyAllocated: energyTransfer, + connectedTimestamp: connection.conn.timestamp, + fourUnrated, + }) +}) router.get('/search', normalizeQueryParams, async function (req, res, next) { - let connections = await getConnections(req.body.fromBrightId) - let ratings - if (!req.body.includeRated) { - ratings = (await getConnectionsRated(req.body.fromBrightId)).rows - } - - if (ratings) { - connections = connections.filter(connection => { - return !ratings.includes(connection._key) - }) - } - let resp = shuffleSeed.shuffle(connections, req.body.seed) - .slice(req.body.offset, req.body.limit) - res.json({ - "connections": resp + let connections = await getConnections(req.body.fromBrightId) + + let ratings + if (!req.body.includeRated) { + ratings = (await getConnectionsRated(req.body.fromBrightId)).rows + } + + if (ratings) { + connections = connections.filter((connection) => { + return !ratings.includes(connection._key) }) + } + + // add atribute requestedForEnergy and set the default to false + connections = connections.map((connection) => { + connection.requestedForEnergy = false + return connection + }) -}); + // extract _key from all connections and save them in an array + let connectionsKeys = connections.map((connection) => connection._key) + // getRequestForEnergyRecord for all connectionKeys + let requestForEnergyRecord = await ( + await getRequestForEnergyRecord(connectionsKeys) + ).rows + + // update the connections array with the requestedForEnergy attribute + requestForEnergyRecord.forEach((e) => { + connections.forEach((connection) => { + if (e.brightId === connection._key) { + connection.requestedForEnergy = true + } + }) + }) + + let resp = shuffleSeed + .shuffle(connections, req.body.seed) + .slice(req.body.offset, req.body.limit) + res.json({ + connections: resp, + }) +}) async function normalizeQueryParams(req, res, next) { - let offset = req.query.offset ? req.query.offset : 0 - let limit = req.query.limit ? req.query.limit : 20 - let includeRated = req.query.includeRated ? req.query.includeRated : false - let fromBrightId = req.query.fromBrightId - - if (req.query.seed === undefined) { - return res.status(500).send("need to include seed") - } - - if (fromBrightId === undefined) { - return res.status(500).send("need to include fromBrightId") - } - - req.body.offset = offset - req.body.limit = limit - req.body.includeRated = includeRated - req.body.fromBrightId = fromBrightId - req.body.seed = req.query.seed - - next() -} + let offset = req.query.offset ? req.query.offset : 0 + let limit = req.query.limit ? req.query.limit : 20 + let includeRated = req.query.includeRated ? req.query.includeRated : false + let fromBrightId = req.query.fromBrightId + if (req.query.seed === undefined) { + return res.status(500).send('need to include seed') + } + + if (fromBrightId === undefined) { + return res.status(500).send('need to include fromBrightId') + } + + req.body.offset = offset + req.body.limit = limit + req.body.includeRated = includeRated + req.body.fromBrightId = fromBrightId + req.body.seed = req.query.seed + + next() +} -module.exports = router; \ No newline at end of file +module.exports = router diff --git a/routes/v1/energyRequest.js b/routes/v1/energyRequest.js new file mode 100644 index 0000000..1f0a995 --- /dev/null +++ b/routes/v1/energyRequest.js @@ -0,0 +1,51 @@ +const express = require('express') +const { validateAuraPlayer } = require('../../src/middlewear/aurahandler') +const { decrypt } = require('../../src/middlewear/decryption') +const { + getRequestForEnergyRecord, + createRequestForEnergyRecord, +} = require('../../src/controllers/requestForEnergyController') + +var router = express.Router() + +router.post('/:fromBrightId/create/', validateAuraPlayer, async function ( + req, + res, + next, +) { + let decryptedPayload + + try { + decryptedPayload = decrypt(req.body.encryptedPayload, req.body.signingKey) + } catch (exception) { + res + .status(500) + .send('Could not decrypt using publicKey: ' + req.body.signingKey) + } + + let requestForEnergy + try { + requestForEnergy = decryptedPayload.requestForEnergy + } catch { + res.status(400).send('Invalid json request') + } + if (!requestForEnergy) { + res.status(400).send('requestForEnergy must be true') + } + + await createRequestForEnergyRecord(req.params.fromBrightId) + + res.sendStatus(200) +}) + +router.get('/:brightIds/', async function (req, res, next) { + let brightIds = req.params.brightIds + .replace('[', '') + .replace(']', '') + .split(',') + console.log(brightIds) + let requestForEnergyRecord = await getRequestForEnergyRecord(brightIds) + res.send(requestForEnergyRecord.rows) +}) + +module.exports = router diff --git a/src/controllers/brightIdController.js b/src/controllers/brightIdController.js index 0267f41..0b2f6ae 100644 --- a/src/controllers/brightIdController.js +++ b/src/controllers/brightIdController.js @@ -1,16 +1,17 @@ const Model = require('../models/model') -const keysModel = new Model('brightIdKeys'); +const keysModel = new Model('brightIdKeys') async function persistSigningKey(brightId, signingKey) { - let text = 'INSERT INTO "brightIdKeys"("brightId", "publicKey") VALUES ($1, $2) ON CONFLICT ("brightId") DO UPDATE SET "publicKey" = $2'; - return keysModel.pool.query(text, [brightId, signingKey]); + let text = + 'INSERT INTO "brightIdKeys"("brightId", "publicKey") VALUES ($1, $2) ON CONFLICT ("brightId") DO UPDATE SET "publicKey" = $2' + return keysModel.pool.query(text, [brightId, signingKey]) } async function getSigningKey(brightId) { - let query = `SELECT "publicKey" + let query = `SELECT "publicKey" from "brightIdKeys" where "brightId" = $1` - return keysModel.pool.query(query, [brightId]); + return keysModel.pool.query(query, [brightId]) } -module.exports = {persistSigningKey, getSigningKey} \ No newline at end of file +module.exports = { persistSigningKey, getSigningKey } diff --git a/src/controllers/requestForEnergyController.js b/src/controllers/requestForEnergyController.js new file mode 100644 index 0000000..5805cd4 --- /dev/null +++ b/src/controllers/requestForEnergyController.js @@ -0,0 +1,20 @@ +const { query } = require('express') +const { ids } = require('googleapis/build/src/apis/ids') +const Model = require('../models/model') +const eneregyRequestModel = new Model('energyRequest') + +async function createRequestForEnergyRecord(brightId) { + return eneregyRequestModel.pool.query( + 'Insert into "energyRequest"("brightId") values ($1)', + [brightId], + ) +} + +async function getRequestForEnergyRecord(brightIds) { + return eneregyRequestModel.pool.query( + `SELECT * from "energyRequest" where "brightId" = ANY($1::varchar[])`, + [brightIds], + ) +} + +module.exports = { createRequestForEnergyRecord, getRequestForEnergyRecord } diff --git a/src/middlewear/aurahandler.js b/src/middlewear/aurahandler.js index 0004245..b609d25 100644 --- a/src/middlewear/aurahandler.js +++ b/src/middlewear/aurahandler.js @@ -1,26 +1,26 @@ -const {getSigningKey} = require("../controllers/brightIdController"); +const { getSigningKey } = require('../controllers/brightIdController') async function validateAuraPlayer(req, res, next) { - let fromBrightId = req.params.fromBrightId; - let publicKey = (await getSigningKey(fromBrightId)).rows[0] + let fromBrightId = req.params.fromBrightId + let publicKey = (await getSigningKey(fromBrightId)).rows[0] - if(publicKey !== undefined) { - publicKey = publicKey.publicKey - } - if (publicKey === undefined) { - return res.status(500).send("No public key defined for brightId") - } + if (publicKey !== undefined) { + publicKey = publicKey.publicKey + } + if (publicKey === undefined) { + return res.status(500).send('No public key defined for brightId') + } - req.body.signingKey = publicKey - next() + req.body.signingKey = publicKey + next() } -function clientErrorHandler (err, req, res, next) { - if (req.xhr) { - res.status(500).send({ error: 'Something failed!' }) - } else { - next(err) - } +function clientErrorHandler(err, req, res, next) { + if (req.xhr) { + res.status(500).send({ error: 'Something failed!' }) + } else { + next(err) + } } -module.exports = {validateAuraPlayer, clientErrorHandler} \ No newline at end of file +module.exports = { validateAuraPlayer, clientErrorHandler } diff --git a/src/middlewear/decryption.js b/src/middlewear/decryption.js index fd57c6a..620928c 100644 --- a/src/middlewear/decryption.js +++ b/src/middlewear/decryption.js @@ -12,6 +12,7 @@ function decrypt(encryptedData, publicKey) { if (decoded === undefined || decoded === null) { throw new Error('Could not decode data') } + return JSON.parse(utf8Encode.decode(decoded)) } diff --git a/src/models/pool.js b/src/models/pool.js index 83462ef..820456f 100644 --- a/src/models/pool.js +++ b/src/models/pool.js @@ -1,10 +1,10 @@ var Pool = require('pg-pool') -const { Database } = require("arangojs"); +const { Database } = require('arangojs') require('dotenv').config() const arango = new Database({ url: process.env.DB_URL, -}); +}) const pool = new Pool({ connectionString: process.env.DATABASE_URL,