From 9b8ef8f2e70d36e30d7c65f67c63527238d3055d Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Sat, 30 Jan 2021 07:40:04 +1100 Subject: [PATCH] Publish and edit routes are working --- .envdev | 3 +- README.md | 11 +++---- package-lock.json | 1 + package.json | 7 +++-- server/database/models/revisions.js | 7 +---- server/news/edit.js | 48 +++++++++++++++++++++++++++++ server/news/index.js | 6 ++++ server/news/publish.js | 34 ++++++++++++++++++++ server/news/query.js | 7 ++--- server/server.js | 4 +++ 10 files changed, 107 insertions(+), 21 deletions(-) create mode 100644 server/news/edit.js create mode 100644 server/news/publish.js diff --git a/.envdev b/.envdev index 6b4c7a7..a509bf3 100644 --- a/.envdev +++ b/.envdev @@ -6,4 +6,5 @@ DB_USERNAME=news DB_PASSWORD=charizard DB_TIMEZONE=Australia/Sydney -QUERY_LIMIT=10 \ No newline at end of file +QUERY_LIMIT=10 +QUERY_KEY=key \ No newline at end of file diff --git a/README.md b/README.md index ba9acf9..a89ebc6 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,8 @@ An API centric news server. Uses Sequelize and mariaDB by default. # API ``` -//NOTE: you can add a "limit" parameter to change the default limit +//NOTE: you can add a "limit" query parameter to change the default limit +/news?limit=10 //GET get latest news, up to a default limit, or specify the index "id" /news/:id @@ -42,7 +43,7 @@ An API centric news server. Uses Sequelize and mariaDB by default. ] //POST send a formatted JSON object, returns new index on success, or error on failure -/publish +/news/publish //arguments: { @@ -59,8 +60,8 @@ An API centric news server. Uses Sequelize and mariaDB by default. "error": error //error encountered, or undefined } -//POST similar to /publish, but allows overwriting an existing post -/edit +//PATCH similar to `/news/publish`, but allows overwriting an existing post +/news/edit/:id //arguments: { @@ -68,7 +69,6 @@ An API centric news server. Uses Sequelize and mariaDB by default. "title": title //title of the article "author": author //author of the article "body": body //body of the article - "overwrite": index //the index to save as - } //result @@ -78,4 +78,3 @@ An API centric news server. Uses Sequelize and mariaDB by default. } ``` - diff --git a/package-lock.json b/package-lock.json index 2a4919e..8683938 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "body-parser": "^1.19.0", "dotenv": "^8.2.0", "express": "^4.17.1", "mariadb": "^2.5.2", diff --git a/package.json b/package.json index a6bb771..1b8410b 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,9 @@ "description": "An API centric news server. Uses Sequelize and mariaDB by default.", "main": "server/server.js", "scripts": { - "start": "node server/server.js", - "dev": "npm run watch:server", - "watch:server": "nodemon . --ext js,jsx,json --ignore 'node_modules/*'" + "start": "node server/server.js", + "dev": "npm run watch:server", + "watch:server": "nodemon . --ext js,jsx,json --ignore 'node_modules/*'" }, "repository": { "type": "git", @@ -19,6 +19,7 @@ }, "homepage": "https://github.com/krgamestudios/news-server#readme", "dependencies": { + "body-parser": "^1.19.0", "dotenv": "^8.2.0", "express": "^4.17.1", "mariadb": "^2.5.2", diff --git a/server/database/models/revisions.js b/server/database/models/revisions.js index 88b168f..1ab45d7 100644 --- a/server/database/models/revisions.js +++ b/server/database/models/revisions.js @@ -17,16 +17,11 @@ const revisions = sequelize.define('revisions', { body: { type: Sequelize.TEXT, defaultValue: '' - }, - - revision: { - type: Sequelize.INTEGER(11), - defaultValue: 0 } }); //relationships -revisions.hasOne(articles, { as: 'article' }); +articles.hasOne(revisions, { as: 'original' }); sequelize.sync(); diff --git a/server/news/edit.js b/server/news/edit.js new file mode 100644 index 0000000..ad9af11 --- /dev/null +++ b/server/news/edit.js @@ -0,0 +1,48 @@ +const { Op } = require('sequelize'); +const { articles, revisions } = require('../database/models'); + +const route = async (req, res) => { + //check the key + if (req.body.key != process.env.QUERY_KEY) { + return res.status(401).json({ ok: false, error: 'invalid key' }); + } + + //get the existing record + const record = await articles.findOne({ + where: { + index: { + [Op.eq]: req.params.id + } + } + }); + + if (!record) { + return res.status(500).json({ ok: false, error: 'failed to update non-existing record' }); + } + + //store the revision + await revisions.upsert({ + title: record.title, + author: record.author, + body: record.body, + originalIndex: record.index + }); + + //update the data + await articles.update({ + title: req.body.title, + author: req.body.author, + body: req.body.body, + edits: record.edits + 1 + }, { + where: { + index: req.params.id + } + }); + + return res.status(200).json({ + ok: true + }); +}; + +module.exports = route; \ No newline at end of file diff --git a/server/news/index.js b/server/news/index.js index 5dfb962..bcadbda 100644 --- a/server/news/index.js +++ b/server/news/index.js @@ -3,6 +3,8 @@ const router = express.Router(); //the routes const query = require('./query'); +const publish = require('./publish'); +const edit = require('./edit'); //basic route management router.get('/', query(false, false)); @@ -14,4 +16,8 @@ router.get('/titles/:id(\\d+)', query(false, true)); router.get('/archive/titles', query(true, true)); router.get('/archive/titles/:id(\\d+)', query(true, true)); +router.post('/', publish); + +router.patch('/:id(\\d+)', edit); + module.exports = router; diff --git a/server/news/publish.js b/server/news/publish.js new file mode 100644 index 0000000..51d03e8 --- /dev/null +++ b/server/news/publish.js @@ -0,0 +1,34 @@ +const { articles } = require('../database/models'); + +const route = async (req, res) => { + //check the key + if (req.body.key != process.env.QUERY_KEY) { + return res.status(401).json({ ok: false, error: 'invalid key' }); + } + + //upsert the data + const [instance, created] = await articles.upsert({ + title: req.body.title, + author: req.body.author, + body: req.body.body + }); + + if (!created) { + return res.status(500).json({ ok: false, error: 'failed to create record' }); + } + + //BUGFIX + const result = await articles.findOne({ + order: [ + ['index', 'DESC'] + ] + }); + + return res.status(200).json({ + ok: true, +// index: instance.get('index') + index: result.index + }); +}; + +module.exports = route; \ No newline at end of file diff --git a/server/news/query.js b/server/news/query.js index 937cc80..705e77c 100644 --- a/server/news/query.js +++ b/server/news/query.js @@ -2,9 +2,6 @@ const { articles } = require('../database/models'); //the query function that can be reused const query = (ascending, titlesOnly) => async (req, res) => { - console.log(ascending, titlesOnly); - console.log(req.params); - //specific search if (req.params.id && typeof(parseInt(req.params.id)) === 'number') { const result = await articles.findOne({ @@ -14,7 +11,7 @@ const query = (ascending, titlesOnly) => async (req, res) => { order: [ ['index', ascending ? 'ASC' : 'DESC'] ], - offset: parseInt(req.params.id), + offset: parseInt(req.query.id) || 0, limit: 1 }); @@ -30,7 +27,7 @@ const query = (ascending, titlesOnly) => async (req, res) => { order: [ ['index', ascending ? 'ASC' : 'DESC'] ], - count: req.params.limit || process.env.QUERY_LIMIT || 999 + limit: parseInt(req.query.limit) || parseInt(process.env.QUERY_LIMIT) || 999 }); return res.status(200).json(result.rows || result); diff --git a/server/server.js b/server/server.js index daac73c..c937135 100644 --- a/server/server.js +++ b/server/server.js @@ -5,6 +5,10 @@ require('dotenv').config(); const express = require('express'); const app = express(); const server = require('http').Server(app); +const bodyParser = require('body-parser'); + +//config +app.use(bodyParser.json()); //database connection const database = require('./database');