From 7e4d74a882ff5568ffe6ecdcd5dba8293ede44e9 Mon Sep 17 00:00:00 2001 From: "jay.poff@outlook.com" Date: Sun, 28 Mar 2021 15:20:36 -0500 Subject: [PATCH] Added ability to ban users from admin console. Added custom error messages when users are banned. Added account status check when making new posts --- src/models/user.js | 1 + src/services/juxt-web/routes/admin/api.js | 115 +++++++++++ src/services/juxt-web/routes/admin/home.js | 194 ++++++++++++++----- src/services/juxt-web/routes/portal/posts.js | 4 +- src/views/admin_audit.ejs | 2 +- src/views/admin_community.ejs | 123 ++++++++---- src/views/admin_edit_user.ejs | 70 +++++++ src/views/admin_user.ejs | 167 ++++++++++++++++ src/views/admin_users.ejs | 2 +- src/views/portal_ban_notification.ejs | 12 ++ src/views/portal_community.ejs | 2 +- src/views/portal_community_ajax.ejs | 2 +- 12 files changed, 606 insertions(+), 88 deletions(-) create mode 100644 src/views/admin_edit_user.ejs create mode 100644 src/views/admin_user.ejs create mode 100644 src/views/portal_ban_notification.ejs diff --git a/src/models/user.js b/src/models/user.js index 16c3407..81591c3 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -21,6 +21,7 @@ const UserSchema = new Schema({ default: 0 }, ban_lift_date: Date, + ban_reason: String, official: { type: Boolean, default: false diff --git a/src/services/juxt-web/routes/admin/api.js b/src/services/juxt-web/routes/admin/api.js index ebde96b..6d93167 100644 --- a/src/services/juxt-web/routes/admin/api.js +++ b/src/services/juxt-web/routes/admin/api.js @@ -319,4 +319,119 @@ router.get('/users/all', function (req, res) { }); }); +router.get('/users/:userID', function (req, res) { + database.connect().then(async e => { + if(req.cookies.token === null) + throw new Error('No service token supplied'); + + let pid = util.data.processServiceToken(req.cookies.token); + + if(pid === null) + throw new Error('Invalid credentials supplied'); + + let user = await database.getUserByPID(pid); + + if(user !== null) + { + if(config.authorized_PNIDs.indexOf(user.pid) === -1) + throw new Error('Invalid credentials supplied'); + + res.send(await database.getUserByPID(req.params.userID)) + } + else + throw new Error('Invalid account ID or password'); + + }).catch(error => + { + res.statusCode = 400; + let response = { + error_code: 400, + message: error.message + }; + res.send(response); + }); +}); + +router.post('/users/:userID/update', upload.none(), function (req, res) { + database.connect().then(async e => { + if(req.cookies.token === null) + throw new Error('No service token supplied'); + + let pid = util.data.processServiceToken(req.cookies.token); + + if(pid === null) + throw new Error('Invalid credentials supplied'); + + let parentUser = await database.getUserByPID(pid); + let user = await database.getUserByPID(req.params.userID); + + if(user !== null) + { + if(config.authorized_PNIDs.indexOf(parentUser.pid) === -1) + throw new Error('Invalid credentials supplied'); + user.account_status = req.body.account_status; + user.ban_reason = req.body.ban_reason; + user.ban_lift_date = moment(req.body.ban_date); + user.save(); + res.sendStatus(200); + logger.audit('[' + parentUser.user_id + ' - ' + parentUser.pid + '] banned ' + user.user_id + ' until ' + user.ban_lift_date + ' for ' + user.ban_reason); + } + else + throw new Error('Invalid account ID or password'); + + }).catch(error => + { + res.statusCode = 400; + let response = { + error_code: 400, + message: error.message + }; + res.send(response); + }); +}); + +router.post('/posts/:postID/delete', function (req, res) { + database.connect().then(async e => { + if(req.cookies.token === null) + throw new Error('No service token supplied'); + + let pid = util.data.processServiceToken(req.cookies.token); + + if(pid === null) + throw new Error('Invalid credentials supplied'); + + let user = await database.getUserByPID(pid); + + if(user !== null) + { + if(config.authorized_PNIDs.indexOf(user.pid) === -1) { + logger.audit('[' + user.user_id + ' - ' + user.pid + '] attempted to delete a community and is not authorized'); + throw new Error('Invalid credentials supplied'); + } + + let post = await database.getPostByID(req.params.postID); + if(post !== null) { + post.delete().then(err => function () { + res.send(err); + }); + res.sendStatus(200); + logger.audit('[' + user.user_id + ' - ' + user.pid + '] deleted post by ' + post.screen_name); + } + else + res.sendStatus(404) + } + else + throw new Error('Invalid account ID or password'); + + }).catch(error => + { + res.statusCode = 400; + let response = { + error_code: 400, + message: error.message + }; + res.send(response); + }); +}); + module.exports = router; \ No newline at end of file diff --git a/src/services/juxt-web/routes/admin/home.js b/src/services/juxt-web/routes/admin/home.js index 8a6d613..97976c8 100644 --- a/src/services/juxt-web/routes/admin/home.js +++ b/src/services/juxt-web/routes/admin/home.js @@ -1,11 +1,12 @@ var express = require('express'); var xml = require('object-to-xml'); const database = require('../../../../database'); +const logger = require('../../../../logger'); const util = require('../../../../authentication'); const config = require('../../../../config.json'); const request = require("request"); var path = require('path'); -const ejs = require('ejs'); +var moment = require('moment'); var multer = require('multer'); var upload = multer({ dest: 'uploads/' }); var router = express.Router(); @@ -143,8 +144,6 @@ router.get('/communities', upload.none(), function (req, res) { router.get('/audit', upload.none(), function (req, res) { database.connect().then(async e => { - - //let paramPackData = util.data.decodeParamPack(req.headers["x-nintendo-parampack"]); if(req.cookies.token === null) { res.redirect('/login'); @@ -152,7 +151,6 @@ router.get('/audit', upload.none(), function (req, res) { } let pid = util.data.processServiceToken(req.cookies.token); - //console.log(req.headers["x-nintendo-servicetoken"]); if(pid === null) { res.redirect('/login'); @@ -222,48 +220,6 @@ router.get('/communities/new', upload.none(), function (req, res) { }); -router.get('/communities/:communityID/edit', upload.none(), function (req, res) { - - database.connect().then(async e => { - //let paramPackData = util.data.decodeParamPack(req.headers["x-nintendo-parampack"]); - if(req.cookies.token === null) - { - res.redirect('/login'); - return; - } - - let pid = util.data.processServiceToken(req.cookies.token); - //console.log(req.headers["x-nintendo-servicetoken"]); - if(pid === null) - { - res.redirect('/login'); - return; - } - let user = await database.getUserByPID(pid); - let community = await database.getCommunityByID(req.params.communityID.toString()); - res.render('admin_edit_community.ejs', { - user: user, - community: community, - }); - - }).catch(error => { - console.log(error); - res.set("Content-Type", "application/xml"); - res.statusCode = 400; - response = { - result: { - has_error: 1, - version: 1, - code: 400, - error_code: 15, - message: "SERVER_ERROR" - } - }; - res.send("\n" + xml(response)); - }); - -}); - router.get('/communities/:communityID', upload.none(), function (req, res) { database.connect().then(async e => { @@ -311,6 +267,48 @@ router.get('/communities/:communityID', upload.none(), function (req, res) { }); +router.get('/communities/:communityID/edit', upload.none(), function (req, res) { + + database.connect().then(async e => { + //let paramPackData = util.data.decodeParamPack(req.headers["x-nintendo-parampack"]); + if(req.cookies.token === null) + { + res.redirect('/login'); + return; + } + + let pid = util.data.processServiceToken(req.cookies.token); + //console.log(req.headers["x-nintendo-servicetoken"]); + if(pid === null) + { + res.redirect('/login'); + return; + } + let user = await database.getUserByPID(pid); + let community = await database.getCommunityByID(req.params.communityID.toString()); + res.render('admin_edit_community.ejs', { + user: user, + community: community, + }); + + }).catch(error => { + console.log(error); + res.set("Content-Type", "application/xml"); + res.statusCode = 400; + response = { + result: { + has_error: 1, + version: 1, + code: 400, + error_code: 15, + message: "SERVER_ERROR" + } + }; + res.send("\n" + xml(response)); + }); + +}); + router.get('/users', upload.none(), function (req, res) { database.connect().then(async e => { @@ -352,6 +350,104 @@ router.get('/users', upload.none(), function (req, res) { }); +router.get('/users/:userID', upload.none(), function (req, res) { + + database.connect().then(async e => { + if(req.cookies.token === null) + { + res.redirect('/login'); + return; + } + + let pid = util.data.processServiceToken(req.cookies.token); + if(pid === null) + { + res.redirect('/login'); + return; + } + let user = await database.getUserByPID(req.params.userID); + let parentUser = await database.getUserByPID(pid) + if(user === null) + res.sendStatus(404); + let newPosts = await database.getNumberUserPostsByID(req.params.userID, 50); + let numPosts = await database.getTotalPostsByUserID(req.params.userID); + let communityMap = await util.data.getCommunityHash(); + + res.render('admin_user.ejs', { + communityMap: communityMap, + moment: moment, + parentUser: parentUser, + user: user, + newPosts: newPosts, + numPosts: numPosts, + }); + + }).catch(error => { + console.log(error); + res.set("Content-Type", "application/xml"); + res.statusCode = 400; + response = { + result: { + has_error: 1, + version: 1, + code: 400, + error_code: 15, + message: "SERVER_ERROR" + } + }; + res.send("\n" + xml(response)); + }); + +}); + +router.get('/users/:userID/edit', upload.none(), function (req, res) { + + database.connect().then(async e => { + if(req.cookies.token === null) + { + res.redirect('/login'); + return; + } + + let pid = util.data.processServiceToken(req.cookies.token); + if(pid === null) + { + res.redirect('/login'); + return; + } + let user = await database.getUserByPID(req.params.userID); + let parentUser = await database.getUserByPID(pid) + if(user === null) + res.sendStatus(404); + let newPosts = await database.getNumberUserPostsByID(req.params.userID, 50); + let numPosts = await database.getTotalPostsByUserID(req.params.userID); + + res.render('admin_edit_user.ejs', { + moment: moment, + parentUser: parentUser, + user: user, + newPosts: newPosts, + numPosts: numPosts, + }); + + }).catch(error => { + console.log(error); + res.set("Content-Type", "application/xml"); + res.statusCode = 400; + response = { + result: { + has_error: 1, + version: 1, + code: 400, + error_code: 15, + message: "SERVER_ERROR" + } + }; + res.send("\n" + xml(response)); + }); + +}); + router.get('/login', upload.none(), function (req, res) { database.connect().then(async e => { @@ -424,8 +520,11 @@ router.post('/login', upload.none(), function (req, res) { let password = req.body.password; if(user !== null && password !== null) { - if(config.authorized_PNIDs.indexOf(user.pid) === -1) + if(config.authorized_PNIDs.indexOf(user.pid) === -1) { + logger.audit('[' + user.user_id + ' - ' + user.pid + '] is not authorized to access the application'); throw new Error('User is not authorized to access the application'); + } + let password_hash = await util.data.nintendoPasswordHash(password, user.pid); await request.post({ url: "http://" + config.account_server_domain + "/v1/api/oauth20/access_token/generate", @@ -442,6 +541,7 @@ router.post('/login', upload.none(), function (req, res) { } }, function (error, response, body) { if (!error && response.statusCode === 200) { + logger.audit('[' + user.user_id + ' - ' + user.pid + '] signed into the application'); res.send(body); } else diff --git a/src/services/juxt-web/routes/portal/posts.js b/src/services/juxt-web/routes/portal/posts.js index 3b77dd7..28da1d8 100644 --- a/src/services/juxt-web/routes/portal/posts.js +++ b/src/services/juxt-web/routes/portal/posts.js @@ -59,7 +59,9 @@ router.post('/new', upload.none(), async function (req, res, next) { else { let usrObj = await database.getUserByPID(pid); - //let community_id = req.body.olive_title_id.substring(0, req.body.olive_title_id.indexOf(',')); + if(usrObj.account_status !== 0) { + throw new Error('User not allowed to post') + } let community = await database.getCommunityByID(req.body.olive_community_id); let appData = ""; if (req.body.app_data) { diff --git a/src/views/admin_audit.ejs b/src/views/admin_audit.ejs index 0395b8e..4915f9e 100644 --- a/src/views/admin_audit.ejs +++ b/src/views/admin_audit.ejs @@ -21,7 +21,7 @@
-

Posts

+

Audit Log

diff --git a/src/views/admin_community.ejs b/src/views/admin_community.ejs index 3d27000..c47b0cb 100644 --- a/src/views/admin_community.ejs +++ b/src/views/admin_community.ejs @@ -64,48 +64,99 @@
<% newPosts.forEach(function(post) { %> -
+ diff --git a/src/views/admin_edit_user.ejs b/src/views/admin_edit_user.ejs new file mode 100644 index 0000000..cc277ac --- /dev/null +++ b/src/views/admin_edit_user.ejs @@ -0,0 +1,70 @@ + + + + + Edit - <%= user.user_id %> + + + + +

Juxt Admin Panel - <%= parentUser.user_id %>

+ +
+ + +
+

Update <%= user.user_id %>

+
+
+ +
+
+ Account Status + checked <%}%>> + + checked <%}%>> + + checked <%}%>> + + checked <%}%>> + +
+ + + + +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + diff --git a/src/views/admin_user.ejs b/src/views/admin_user.ejs new file mode 100644 index 0000000..de0fecf --- /dev/null +++ b/src/views/admin_user.ejs @@ -0,0 +1,167 @@ + + + + + Juxt Admin Panel + + + + +

Juxt Admin Panel - <%= parentUser.user_id %>

+ +
+ + +
+
+ +

<%= user.user_id %>

+

<%= user.profile_comment %>

+ +
+ + + + + + + + +
+
+

Country

+

N/A

+
+
+
+

Birthday

+

N/A

+
+
+
+

Game experience

+

+ <%if(user.game_skill === 0) {%> + Beginner + <%} else if(user.game_skill === 1) {%> + Intermediate + <%} else if(user.game_skill === 2) {%> + Expert + <%} else {%> + N/A + <%}%> +

+
+
+
+
+ <% if(numPosts === 0) {%> +

No Posts

+ <%} else { %> + <% newPosts.forEach(function(post) { %> +
+ +
+ <% if(post.body !== '' && post.painting === '' && post.screenshot === '' && !post.url) { %> +

<%= post.body %>

+ <%} else { %> + <% if(post.screenshot !== '') { %> + + <%}%> + <% if(post.painting !== '') { %> + + <%}%> + <% if(post.url) { %> + + <%}%> + <% if(post.body) { %> +
+

<%= post.body %>

+
+ <%}%> + <%}%> +
+
+ <% }); %> + + <%}%> +
+
+
+ + + diff --git a/src/views/admin_users.ejs b/src/views/admin_users.ejs index 8009a50..3b2de53 100644 --- a/src/views/admin_users.ejs +++ b/src/views/admin_users.ejs @@ -70,7 +70,7 @@ for(let i = 0; i < data.length; i++) { body += - '' + + '' + '' + '' + data[i].user_id + '' + '' + data[i].created_at + '' + diff --git a/src/views/portal_ban_notification.ejs b/src/views/portal_ban_notification.ejs new file mode 100644 index 0000000..71bc811 --- /dev/null +++ b/src/views/portal_ban_notification.ejs @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/src/views/portal_community.ejs b/src/views/portal_community.ejs index 7f79c8e..796b5f5 100644 --- a/src/views/portal_community.ejs +++ b/src/views/portal_community.ejs @@ -130,7 +130,7 @@
-
style="display: none" <%}%>> +
style="display: none" <%}%>>
+ New Post
diff --git a/src/views/portal_community_ajax.ejs b/src/views/portal_community_ajax.ejs index a64d895..3ac46ac 100644 --- a/src/views/portal_community_ajax.ejs +++ b/src/views/portal_community_ajax.ejs @@ -103,7 +103,7 @@
-
style="display: none" <%}%>> +
style="display: none" <%}%>>
+ New Post