From e4e808f1180e50590eab150efd1e49602e3dc65d Mon Sep 17 00:00:00 2001 From: joostdecock Date: Tue, 30 May 2023 09:50:46 +0200 Subject: [PATCH] feat(backend): Allow loading of patterns as yaml/json --- sites/backend/src/controllers/patterns.mjs | 11 ++++ sites/backend/src/models/pattern.mjs | 58 ++++++++++++++++++++-- sites/backend/src/routes/patterns.mjs | 4 ++ 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/sites/backend/src/controllers/patterns.mjs b/sites/backend/src/controllers/patterns.mjs index 3ade35c64ad..15805b4da8b 100644 --- a/sites/backend/src/controllers/patterns.mjs +++ b/sites/backend/src/controllers/patterns.mjs @@ -70,3 +70,14 @@ PatternsController.prototype.clone = async (req, res, tools) => { return Pattern.sendResponse(res) } + +/* + * Read a public pattern + * See: https://freesewing.dev/reference/backend/api + */ +PatternsController.prototype.readPublic = async (req, res, tools, format = 'json') => { + const Pattern = new PatternModel(tools) + await Pattern.publicRead(req) + + return format === 'yaml' ? Pattern.sendYamlResponse(res) : Pattern.sendResponse(res) +} diff --git a/sites/backend/src/models/pattern.mjs b/sites/backend/src/models/pattern.mjs index 94de7a07409..81a6a360557 100644 --- a/sites/backend/src/models/pattern.mjs +++ b/sites/backend/src/models/pattern.mjs @@ -1,5 +1,6 @@ import { log } from '../utils/log.mjs' import { setPatternAvatar } from '../utils/sanity.mjs' +import yaml from 'js-yaml' export function PatternModel(tools) { this.config = tools.config @@ -119,6 +120,22 @@ PatternModel.prototype.read = async function (where) { return this.setExists() } +/* + * Loads a pattern from the database but only if it's public + * + * Stores result in this.record + */ +PatternModel.prototype.publicRead = async function ({ params }) { + await this.read({ id: parseInt(params.id) }) + if (this.record.public !== true) { + // Note that we return 404 + // because we don't want to reveal that a non-public pattern exists. + return this.setResponse(404) + } + + return this.setResponse(200, false, this.asPublicPattern(), true) +} + /* * Loads a pattern from the database based on the where clause you pass it * In addition prepares it for returning the pattern data @@ -314,6 +331,8 @@ PatternModel.prototype.revealPattern = function (pattern) { //console.log(err) } } + if (pattern.set) delete pattern.set.measies + if (pattern.cset) delete pattern.cset.measies return { ...pattern, ...clear } } @@ -323,13 +342,20 @@ PatternModel.prototype.revealPattern = function (pattern) { * * Will be used by this.sendResponse() */ -PatternModel.prototype.setResponse = function (status = 200, error = false, data = {}) { +PatternModel.prototype.setResponse = function ( + status = 200, + error = false, + data = {}, + rawData = false +) { this.response = { status, - body: { - result: 'success', - ...data, - }, + body: rawData + ? data + : { + result: 'success', + ...data, + }, } if (status > 201) { this.response.body.error = error @@ -346,3 +372,25 @@ PatternModel.prototype.setResponse = function (status = 200, error = false, data PatternModel.prototype.sendResponse = async function (res) { return res.status(this.response.status).send(this.response.body) } + +/* + * Helper method to send response as YAML + */ +PatternModel.prototype.sendYamlResponse = async function (res) { + return res.status(this.response.status).type('yaml').send(yaml.dump(this.response.body)) +} + +/* + * Returns record data fit for public publishing + */ +PatternModel.prototype.asPublicPattern = function () { + const data = { + author: 'FreeSewing.org', + type: 'pattern', + ...this.asPattern(), + } + delete data.userId + delete data.public + + return data +} diff --git a/sites/backend/src/routes/patterns.mjs b/sites/backend/src/routes/patterns.mjs index 577cab54df5..95aa6e9a10f 100644 --- a/sites/backend/src/routes/patterns.mjs +++ b/sites/backend/src/routes/patterns.mjs @@ -54,4 +54,8 @@ export function patternsRoutes(tools) { app.delete('/patterns/:id/key', passport.authenticate(...bsc), (req, res) => Patterns.delete(req, res, tools) ) + + // Read a public pattern as JSON or YAML (no auth needed, but will only work for public patterns) + app.get('/patterns/:id.json', (req, res) => Patterns.readPublic(req, res, tools, 'json')) + app.get('/patterns/:id.yaml', (req, res) => Patterns.readPublic(req, res, tools, 'yaml')) }