diff --git a/api/ani/v1/router.js b/api/ani/v1/router.js index 7738460..4b15daf 100644 --- a/api/ani/v1/router.js +++ b/api/ani/v1/router.js @@ -11,5 +11,7 @@ module.exports = app => { fs.readdirSync('./ani/v1/routes').filter(file => file.endsWith('.js')) .forEach(route => require(`./routes/${route}`)(app, router)); //execute all router functions + router.location = '/ani/v1'; + return router; }; \ No newline at end of file diff --git a/api/ani/v1/routes/series.js b/api/ani/v1/routes/series.js new file mode 100644 index 0000000..1650cdf --- /dev/null +++ b/api/ani/v1/routes/series.js @@ -0,0 +1,15 @@ +const {Router} = require("express"); +const fs = require('fs'); + +module.exports = (app, parentRouter) => { + const router = Router() + .get('/', (req, res) => res.send('/series/:id')); + + router.location = '/series'; + fs.readdirSync('./ani/v1/routes/series').filter(file => file.endsWith('.js')) + .forEach(route => require(`./series/${route}`)(app, router)); //execute all router functions + + parentRouter.use('/series', router); + + //TODO get all series +}; \ No newline at end of file diff --git a/api/ani/v1/routes/user.js b/api/ani/v1/routes/user.js index ffecac3..9ef0506 100644 --- a/api/ani/v1/routes/user.js +++ b/api/ani/v1/routes/user.js @@ -5,6 +5,7 @@ module.exports = (app, router) => { const Users = app.db.models.ani.users; router.get('/user', (req, res) => res.send("/user: /user/:id required.")); + //router.use(app.util.list(router, '/user')); //list users router.route('/user/:id') .get(async (req, res) => { @@ -21,7 +22,7 @@ module.exports = (app, router) => { 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.toLowerCase().match(/^[\w_]+$/gm) || req.params.id.toLowerCase().length > 15 + || !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.");} @@ -74,4 +75,19 @@ module.exports = (app, router) => { permissions: req.user.permissions }); }); + + router.use('/user/:id/permissions', async (req, res, next) => { + if (!req.params.id) {return 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!");} + 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) {permissions[permissions.length - 1] = permission.toLowerCase();} + req.user.permissions = permissions; + req.user.markModified('permissions'); + await req.user.save(); + })); }; \ No newline at end of file diff --git a/api/index.js b/api/index.js index 86c9ca6..7f5785d 100644 --- a/api/index.js +++ b/api/index.js @@ -34,8 +34,20 @@ server = app.listen(4062, async () => { require('../db/build')(app); //place all models in memory to prevent double-compiling - app.auth.token = require('./baseAuthorize')(app); //jwt token validation + app.auth.token = require('./util/baseAuthorize')(app); //jwt token validation + app.auth.tokenPass = require('./util/baseAuthorize')(app, true); //"next()" will run even if auth is not passed + + app.util = {}; + app.util.list = require('./util/list'); require('./v1/index')(app); //initialize bot API branch require('./ani/index')(app); //initialize ani API branch + + const checkMiddleware = (middleware, string) => { + if (middleware.route) {Object.keys(middleware.route.methods).forEach(method => { + if (middleware.route.methods[method]) {console.log(`[${method.toUpperCase()}] ${string}${middleware.route.path}`);} + });} else if (middleware.name === 'router') {middleware.handle.stack.forEach(handler => {checkMiddleware(handler, string + middleware.handle.location);});} + }; + app._router.stack.forEach(middleware => checkMiddleware(middleware, '')); //log all routes + console.log('\n[Access logs for all routes]'); }); \ No newline at end of file diff --git a/api/baseAuthorize.js b/api/util/baseAuthorize.js similarity index 78% rename from api/baseAuthorize.js rename to api/util/baseAuthorize.js index aedf69b..d70cf7d 100644 --- a/api/baseAuthorize.js +++ b/api/util/baseAuthorize.js @@ -1,11 +1,11 @@ const {verify} = require("jsonwebtoken"); -module.exports = app => { +module.exports = (app, passAuth) => { const Users = app.db.models.ani.users return (req, res, next) => { if (req.headers && req.headers.authorization && req.headers.authorization.split(" ")[0] === "JWT") { verify(req.headers.authorization.split(' ')[1], app.auth.jwt_secret, (e, d) => { - if (e) {req.user = undefined; return next();} + if (e) {req.user = undefined; return passAuth ? next() : res.status(401).send("You are not authenticated!");} Users.findOne({id: d.id}) .exec((err, user) => { if (err) {res.status(500).send("Something went trying to authorize you!");} diff --git a/api/util/list.js b/api/util/list.js new file mode 100644 index 0000000..3e37b30 --- /dev/null +++ b/api/util/list.js @@ -0,0 +1,36 @@ +const {Router} = require("express"); + +module.exports = (parentRouter, path, modifiable, bodyName, save) => { + const router = Router(); + + router.get("/", (req, res) => res.json(req.listData)); + router.get("/list", (req, res) => res.json(!Array.isArray(req.listData) ? Object.keys(req.listData) : req.listData)); + 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 + 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); + } + router.post('/add', add); + router.post('/', add); + router.post('/clear', async (req, res) => { + req.listData = []; + return await save(req, res, req.listData) || res.json(req.listData); + }); + router.delete('/remove', 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 (index === -1) {return res.status(400).send("The server was unable to find an item matching the specified criteria.");} + let length = req.listData.length; + req.listData = req.listData.length === 1 && req.listData[0] === req.body[bodyName] ? [] : req.listData.splice(req.listData.indexOf(req.body[bodyName]), 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); + }); + } + + router.location = path; + + return router; +}; \ No newline at end of file diff --git a/api/util/search.js b/api/util/search.js new file mode 100644 index 0000000..34a86af --- /dev/null +++ b/api/util/search.js @@ -0,0 +1,3 @@ +module.exports = (model) => { + +}; \ No newline at end of file diff --git a/db/ani/series.js b/db/ani/series.js new file mode 100644 index 0000000..258b62c --- /dev/null +++ b/db/ani/series.js @@ -0,0 +1,33 @@ +const {Schema} = require("mongoose"); + +module.exports = (connection) => connection.model('series', new Schema({ + id: {type: String, unique: true}, + meta: { + locked: {type: Boolean, default: false}, + creator: String, //uid + edits: {type: [{ + user: String, //uid + timestamp: String, //Date.getTime(), + action: String + }], default: []}, + completed: {type: Boolean, default: false}, + approved: {type: { + approved: Boolean, + by: String + }, default: false} + }, + + name: String, + romaji: String, + kanji: String, + altNames: [String], + id: Number, + + synopsis: { + synopsis: String, + by: String + }, + genres: [String], + tags: [String], + +})); \ No newline at end of file diff --git a/db/ani/users.js b/db/ani/users.js index 0d984b2..33d11dc 100644 --- a/db/ani/users.js +++ b/db/ani/users.js @@ -1,4 +1,4 @@ -const {model, Schema} = require("mongoose"); +const {Schema} = require("mongoose"); module.exports = (connection) => connection.model('users', new Schema({ name: String,