From f803dde5c94b89ffb876d89b188d59a57a512c3c Mon Sep 17 00:00:00 2001 From: Louis Capitanchik <contact@louiscap.co> Date: Wed, 8 Dec 2021 21:55:21 +0000 Subject: [PATCH] Add routes and models for classification roots --- src/database/models/ClassificationRoot.js | 64 +++++++++++++++++ .../controllers/api/v2/classifications.js | 71 +++++++++++++++++++ src/http/params/classification.js | 7 ++ src/http/routers/routes_v2.js | 4 ++ 4 files changed, 146 insertions(+) create mode 100644 src/database/models/ClassificationRoot.js create mode 100644 src/http/controllers/api/v2/classifications.js create mode 100644 src/http/params/classification.js diff --git a/src/database/models/ClassificationRoot.js b/src/database/models/ClassificationRoot.js new file mode 100644 index 0000000..fe18ca2 --- /dev/null +++ b/src/database/models/ClassificationRoot.js @@ -0,0 +1,64 @@ +const BaseModel = require('./BaseModel') +const timestamps = require('./properties/timestamps') + +class ClassificationRoot extends BaseModel { + static associate(models) { + this.belongsTo(models.Upload, { foreignKey: 'upload_id' }) + } + + toJSON() { + return { + metric_id: this.metric_id, + upload_id: this.upload_id, + image_id: this.image_id, + url: this.url, + status: this.status, + } + } + +} + +module.exports = (sequelize, DataTypes) => { + ClassificationRoot.init(Object.assign( + { + metric_id: { + type: DataTypes.UUID, + primaryKey: true, + defaultValue: DataTypes.UUIDV4, + validate: { + isUUID: 4, + }, + }, + upload_id: { + type: DataTypes.UUID, + validate: { + isUUID: 4, + }, + }, + image_id: { + type: DataTypes.UUID, + validate: { + isUUID: 4, + }, + }, + url: { + type: DataTypes.TEXT, + }, + status: { + type: DataTypes.TEXT, + }, + meta: { + type: DataTypes.JSONB, + }, + }, + timestamps(DataTypes), + ), { + sequelize, + paranoid: true, + tableName: 'classification_roots', + }) + + return ClassificationRoot +} + +module.exports.Model = ClassificationRoot diff --git a/src/http/controllers/api/v2/classifications.js b/src/http/controllers/api/v2/classifications.js new file mode 100644 index 0000000..00f5d55 --- /dev/null +++ b/src/http/controllers/api/v2/classifications.js @@ -0,0 +1,71 @@ +const publicStatus = new Set(['accepted']) +const privateStatus = new Set(['pending', 'rejected']) + +const { Sequelize, ClassificationRoot } = require('database/models') +const NotFoundError = require("core/errors/NotFoundError"); +const UnauthorizedError = require("core/errors/UnauthorizedError"); +const InputValidationError = require("core/errors/InputValidationError"); + +exports.listRoots = async ctx => { + const { status = '', limit = 25, after = null } = ctx.query + + const requestedStatus = status.split(',') + .map(s => s.trim()) + .filter(s => publicStatus.has(s) || privateStatus.has(s)) + + const query = { + order: ['metric_id', 'created_at'], + where: { + status: { + [Sequelize.Op.in]: requestedStatus, + } + }, + limit, + } + + const count = await ClassificationRoot.count(query) + + if (after) { + query.where.metric_id = { + [Sequelize.Op.gt]: after, + } + } + + const roots = await ClassificationRoot.findAll(query) + + ctx.body = { + roots, + meta: { + total: count, + } + } +} + +exports.putRootStatus = async ctx => { + const user = await ctx.services['core.auth'].getUser() + + if (!user) { + throw new UnauthorizedError() + } + + if (ctx.models.classification == null) { + throw new NotFoundError('Classification Root') + } + + const { status } = ctx.request.body + const { classification } = ctx.models + + if (!publicStatus.has(status) && !privateStatus.has(status)) { + throw new InputValidationError(['status']) + } + + classification.status = status + classification.meta = { + approved_by: user.id, + } + await classification.save() + + ctx.body = { + root: classification, + } +} \ No newline at end of file diff --git a/src/http/params/classification.js b/src/http/params/classification.js new file mode 100644 index 0000000..23362fe --- /dev/null +++ b/src/http/params/classification.js @@ -0,0 +1,7 @@ +const { ClassificationRoot } = require('database/models') + +module.exports = async (id, ctx, next) => { + ctx.models = ctx.models ?? {} + ctx.models.classification = await ClassificationRoot.findByPk(id) + return await next() +} diff --git a/src/http/routers/routes_v2.js b/src/http/routers/routes_v2.js index 45691f1..3a1e040 100644 --- a/src/http/routers/routes_v2.js +++ b/src/http/routers/routes_v2.js @@ -54,6 +54,7 @@ router.put('/uploads/:upload_id/:property', noop) router.param('survey', param('survey')) router.param('excerpt', param('survey_excerpt')) +router.param('classification', param('classification')) router.get('/surveys', controller('api/v2/surveys', 'list')) router.get('/excerpts', controller('api/v2/surveys', 'listExcerpts')) @@ -65,6 +66,9 @@ if (config('app.dev')) { router.post('/surveys/factory', safemode, controller('api/v2/factories', 'survey')) } +router.get('/classifications/roots', controller('api/v2/classifications', 'listRoots')) +router.put('/classifications/roots/:classification/status', controller('api/v2/classifications', 'putRootStatus')) + router.post('/an/ev', safemode, controller('api/analytics', 'track')) module.exports = router -- GitLab