diff --git a/api/ani/v1/routes/series/add.js b/api/ani/v1/routes/series/add.js index 8f579bb..6c4edef 100644 --- a/api/ani/v1/routes/series/add.js +++ b/api/ani/v1/routes/series/add.js @@ -28,7 +28,7 @@ module.exports = (app, router) => { if ( !req.body //i just ate dinner and i can't even think straight || !req.body.name || !req.body.romaji || !req.params.id || !req.authenticatedUser || !req.authenticatedUser.id - || !req.body.name.match(/^[\w_\-!?.:; ]+$/gm) || req.body.name.length > 150 + || !req.body.name.match(/^[\w\-!?.:; ]+$/gm) || req.body.name.length > 150 || req.body.romaji.length > 150 || !req.params.id.match(/^[0-9_-]*[a-zA-Z][\w-]*$/gm) || req.params.id.length > 25 ) {return res.status(400).send("The server cannot accept your request as your body is missing fields or is malformed. Ensure fields aren't too long and that they don't contain illegal characters.");} diff --git a/api/ani/v1/routes/series/edits.js b/api/ani/v1/routes/series/edits.js index d9de626..649cc33 100644 --- a/api/ani/v1/routes/series/edits.js +++ b/api/ani/v1/routes/series/edits.js @@ -19,7 +19,7 @@ module.exports = (app, router) => { series.markModified('meta.edits'); }; - const edits = app.util.editString(pushEdit, editCheck, router, Anime); + const edits = app.util.editString('/:id', pushEdit, editCheck, router, Anime); router.route('/:id/synopsis') //completed i think? .patch(app.auth.token, app.auth.perms('series-submit'), async (req, res, next) => { @@ -47,11 +47,37 @@ module.exports = (app, router) => { }); [ - ['name', x => x.match(/^[\w_\-!?.:; ]+$/gm) && x.length < 150], + ['name', x => x.match(/^[\w\-!?.:; ]+$/gm) && x.length < 150], ['romaji', x => x.length < 150], - ['kanji', x => x.length < 150] + ['kanji', x => x.length < 150], + ['official-site', x => x.length] - ].forEach(field => edits.stringWrap(field[0], field[1])); + ].forEach(field => edits.stringWrap(...field)); + + const editStringList = async (name, match) => { + router.use(`/:id/${name}`, app.auth.tokenPass, app.auth.permsPass('series-approve'), async (req, res, next) => { + if (!req.params.id) {return res.status(400).send("Missing ID!");} + const series = await Anime.findOne({id: req.params.id.toLowerCase()}); + if (!editCheck(series, req, res)) {return;} + req.series = series; + req.listData = req.user.permissions; + next(); + }, app.util.list(router, `/:id/${name}`, true, name, async (req, res, permissions, permission) => { + if (permission && (!permission.match(/^[\w-]+$/gm) || permission.length > 15)) {res.status(400).send("The permission you provided is invalid."); return 0;} + if (permission) {permissions[permissions.length - 1] = permission.toLowerCase();} + req.user.permissions = permissions; + req.user.markModified('permissions'); + await req.user.save(); + }, (req, res, next) => { + if (!req.authenticatedUser) {return res.status(401).send("You must be authenticated before you do that!");} + if (req.unauthorized) {return res.status(401).send("You are not authorized to edit users!");} + return next(); + })); + }; + + [ + ['tags', x => x.match()] + ] diff --git a/api/ani/v1/routes/user.js b/api/ani/v1/routes/user.js index 2796131..acce197 100644 --- a/api/ani/v1/routes/user.js +++ b/api/ani/v1/routes/user.js @@ -22,8 +22,8 @@ module.exports = (app, router) => { if (!req.body) {return res.status(400).send("Missing body!");} if ( !req.body.name || !req.body.discord || !req.body.permissions || !Array.isArray(req.body.permissions) - || !req.body.name.match(/^[\w_\- ]+$/gm) || req.body.name.length > 20 - || !req.params.id.match(/^[\w_\-]+$/gm) || req.params.id.length > 15 + || !req.body.name.match(/^[\w- ]+$/gm) || req.body.name.length > 20 + || !req.params.id.match(/^[\w-]+$/gm) || req.params.id.length > 15 || !req.body.password || req.body.password.length > 30 ) {return res.status(400).send("Malformed body or missing body data. Make sure you have all the required parameters, and you don't have illegal characters present.");} @@ -78,14 +78,14 @@ module.exports = (app, router) => { }); router.use('/user/:id/permissions', app.auth.tokenPass, app.auth.permsPass('edit-users'), async (req, res, next) => { - if (!req.params.id) {return res.status(400).send("Missing ID!");} + if (!req.params.id) {return await res.status(400).send("Missing ID!");} const user = await Users.findOne({id: req.params.id.toLowerCase()}); - if (!user) {return res.status(404).send("That user doesn't exist!");} + if (!user) {return await res.status(404).send("That user doesn't exist!");} req.user = user; req.listData = req.user.permissions; next(); }, app.util.list(router, '/user/:id/permissions', true, 'permission', async (req, res, permissions, permission) => { - if (permission && (!permission.match(/^[\w_]+$/gm) || permission.length > 15)) {res.status(400).send("The permission you provided is invalid."); return 0;} + if (permission && (!permission.match(/^[\w-]+$/gm) || permission.length > 15)) {await res.status(400).send("The permission you provided is invalid."); return 1;} if (permission) {permissions[permissions.length - 1] = permission.toLowerCase();} req.user.permissions = permissions; req.user.markModified('permissions'); diff --git a/api/index.js b/api/index.js index 3656e05..a83d344 100644 --- a/api/index.js +++ b/api/index.js @@ -43,8 +43,9 @@ server = app.listen(4062, async () => { app.auth.permsPass = require('./util/auth/authorize')(app, true); app.util = {}; - app.util.list = require('./util/list'); + app.util.list = require('./util/list'); //automagically add list-based fields to an endpoint app.util.editString = require('./util/editstring').masterInit(app); //TODO consistency shithead + app.util.bodyCase = require('./util/bodycase'); //represent foo-bar as fooBar await require('./util/startup/cache')(app); diff --git a/api/util/bodycase.js b/api/util/bodycase.js new file mode 100644 index 0000000..1b99921 --- /dev/null +++ b/api/util/bodycase.js @@ -0,0 +1,3 @@ +module.exports = name => name.match(/.-./g) + ? `${name.split('-')[0]}${name.split('-').slice(1).map(x => `${x.slice(0, 1).toUpperCase()}${x.slice(1)}`).join()}` + : name; //moved to own file since some deps can't access central object \ No newline at end of file diff --git a/api/util/editstring.js b/api/util/editstring.js index ced7390..9cdf534 100644 --- a/api/util/editstring.js +++ b/api/util/editstring.js @@ -1,26 +1,27 @@ module.exports = { masterInit: (app) => { - return (pushEdit, editCheck, router, model) => { + return (routePrefix, pushEdit, editCheck, router, model) => { return { - string: async (req, res, name, match) => { + string: async function (req, res, name, match) { if (!req.params.id) {return;} - const series = await model.findOne({id: req.params.id.toLowerCase()}); - if (!editCheck(series, req, res)) {return;} - if (!req.body[name]) {return res.status(400).send(`You did not provide a new ${name} in your body.`);} - if (!match(req.body[name])) {return res.status(400).send(`Your new ${name} is too long or contains illegal characters.`);} + const document = await model.findOne({id: req.params.id.toLowerCase()}); + if (!editCheck(document, req, res)) {return;} + const camelName = app.util.bodyCase(name); + if (!req.body[camelName]) {return res.status(400).send(`You did not provide a new ${camelName} in your body.`);} + if (!match(req.body[camelName])) {return res.status(400).send(`Your new ${camelName} is too long or contains illegal characters.`);} try { - series[name] = req.body[name].trim(); - pushEdit(`Updated ${name}`, req, series); - return series.save() - .then(() => res.send(`${name.charAt(0)}${name.slice(1)} updated.`)) - .catch(() => res.status(500).send(`There was an error trying to update your ${name}. Please try again.`)); - } catch {return res.status(500).send(`There was an error trying to update your ${name}. Please try again.`);} + document[camelName] = req.body[camelName].trim(); + pushEdit(`Updated ${camelName}`, req, document); + return document.save() + .then(() => res.send(`${camelName.charAt(0).toUpperCase()}${camelName.slice(1)} updated.`)) + .catch(() => res.status(500).send(`There was an error trying to update your ${camelName}. Please try again.`)); + } catch {return res.status(500).send(`There was an error trying to update your ${camelName}. Please try again.`);} }, - stringWrap: (name, match) => { - const route = router.route(`/:id/${name}`); + stringWrap: function (name, match) { + const route = router.route(`${routePrefix}/${name}`); route.patch(app.auth.token, app.auth.permsPass('series-approve'), async (req, res) => { - await this.string(req, res, name, match); + await this.string(req, res, name, match).catch(() => res.status(500).send(`There was an error trying to update your ${name}. Please try again.`)); }); return route } diff --git a/api/util/list.js b/api/util/list.js index 4c7958e..15cb193 100644 --- a/api/util/list.js +++ b/api/util/list.js @@ -8,11 +8,12 @@ module.exports = (parentRouter, path, modifiable, bodyName, save, authHandler) = router.get('/random', (req, res) => res.json(!Array.isArray(req.listData) ? Object.keys(req.listData)[Math.floor(Math.random() * Object.keys(req.listData).length)] : req.listData[Math.floor(Math.random() * req.listData.length)])); //TODO search - if (modifiable) { //TODO auth + if (modifiable) { + const camelBodyName = require('./bodycase')(bodyName); const add = async (req, res) => { - if (!req.body[bodyName]) {return res.status(400).send(`Missing body param "${bodyName}".`);} - req.listData.push(req.body[bodyName]); - return await save(req, res, req.listData, req.body[bodyName]) || res.json(req.listData); + if (!req.body[bodyName]) {return await res.status(400).send(`Missing body param "${camelBodyName}".`);} + req.listData.push(req.body[camelBodyName]); + return await save(req, res, req.listData, req.body[camelBodyName]) || await res.json(req.listData); } router.post('/add', authHandler, add); router.post('/', authHandler, add); @@ -21,13 +22,13 @@ module.exports = (parentRouter, path, modifiable, bodyName, save, authHandler) = return await save(req, res, req.listData) || res.json(req.listData); }); router.delete('/remove', authHandler, async (req, res) => { - if (!req.body[bodyName]) {return res.status(400).send(`Missing body param "${bodyName}".`);} - let index = req.listData.indexOf(req.body[bodyName]); + if (!req.body[camelBodyName]) {return res.status(400).send(`Missing body param "${camelBodyName}".`);} + let index = req.listData.indexOf(req.body[camelBodyName]); if (index === -1) {return res.status(400).send("The server was unable to find an item matching the specified criteria.");} let length = req.listData.length; - if (req.listData.length === 1 && req.listData[0] === req.body[bodyName]) {req.listData = [];} - else {req.listData.splice(req.listData.indexOf(req.body[bodyName]), 1);} + if (req.listData.length === 1 && req.listData[0] === req.body[camelBodyName]) {req.listData = [];} + else {req.listData.splice(index, 1);} return req.listData.length === length ? res.status(500).send("For some reason, that couldn't be removed.") : await save(req, res, req.listData) || res.json(req.listData); });