diff --git a/databases/_upgrade_sponsorTimes_4.sql b/databases/_upgrade_sponsorTimes_4.sql new file mode 100644 index 0000000..91e51e2 --- /dev/null +++ b/databases/_upgrade_sponsorTimes_4.sql @@ -0,0 +1,12 @@ +BEGIN TRANSACTION; + +/* Create warnings table */ +CREATE TABLE "warnings" ( + userID TEXT NOT NULL, + issueTime INTEGER NOT NULL, + issuerUserID TEXT NOT NULL +); + +UPDATE config SET value = 4 WHERE key = "version"; + +COMMIT; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 0878451..5f08ab3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1866,6 +1866,11 @@ "semver": "^5.7.0" } }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + }, "node-forge": { "version": "0.7.6", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.6.tgz", diff --git a/src/app.js b/src/app.js index 787f32e..7e14923 100644 --- a/src/app.js +++ b/src/app.js @@ -27,6 +27,7 @@ var getDaysSavedFormatted = require('./routes/getDaysSavedFormatted.js'); var getUserInfo = require('./routes/getUserInfo.js'); var postNoSegments = require('./routes/postNoSegments.js'); var getIsUserVIP = require('./routes/getIsUserVIP.js'); +var warnUser = require('./routes/postWarning.js'); // Old Routes var oldGetVideoSponsorTimes = require('./routes/oldGetVideoSponsorTimes.js'); @@ -105,6 +106,9 @@ app.post('/api/noSegments', postNoSegments); //get if user is a vip app.get('/api/isUserVIP', getIsUserVIP); +//sent user a warning +app.post('/api/warnUser', warnUser); + app.get('/database.db', function (req, res) { res.sendFile("./databases/sponsorTimes.db", { root: "./" }); diff --git a/src/routes/getUserInfo.js b/src/routes/getUserInfo.js index 8479129..de17999 100644 --- a/src/routes/getUserInfo.js +++ b/src/routes/getUserInfo.js @@ -48,6 +48,16 @@ function dbGetViewsForUser (userID) { } } +function dbGetWarningsForUser (userID) { + try { + let rows = db.prepare('all', "SELECT * FROM warnings WHERE userID = ?", [userID]); + return rows.length; + } catch (err) { + logger.error('Couldn\'t get warnings for user ' + userID + '. returning 0') ; + return 0; + } +} + module.exports = function getUserInfo (req, res) { let userID = req.query.userID; @@ -67,5 +77,6 @@ module.exports = function getUserInfo (req, res) { minutesSaved: segmentsSummary.minutesSaved, segmentCount: segmentsSummary.segmentCount, viewCount: dbGetViewsForUser(userID), + warnings: dbGetWarningsForUser(userID) }); } diff --git a/src/routes/postWarning.js b/src/routes/postWarning.js new file mode 100644 index 0000000..797d307 --- /dev/null +++ b/src/routes/postWarning.js @@ -0,0 +1,24 @@ +const db = require('../databases/databases.js').db; +const getHash = require('../utils/getHash.js'); +const isUserVIP = require('../utils/isUserVIP.js'); +const logger = require('../utils/logger.js'); + +module.exports = (req, res) => { + // Collect user input data + let issuerUserID = getHash(req.body.issuerUserID); + let userID = getHash(req.body.userID); + let issueTime = new Date().getTime(); + + // Ensure user is a VIP + if (!isUserVIP(issuerUserID)) { + logger.debug("Permission violation: User " + issuerUserID + " attempted to warn user " + userID + "."); // maybe warn? + res.status(403).json({"message": "Not a VIP"}); + return; + } + + db.prepare('run', 'INSERT INTO warnings (userID, issueTime, issuerUserID) VALUES (?, ?, ?)', [userID, issueTime, issuerUserID]); + res.status(200).json({ + message: "Warning issued to user '" + userID + "'." + }); + +}; \ No newline at end of file diff --git a/src/routes/voteOnSponsorTime.js b/src/routes/voteOnSponsorTime.js index e74dd3e..e8c4edc 100644 --- a/src/routes/voteOnSponsorTime.js +++ b/src/routes/voteOnSponsorTime.js @@ -270,6 +270,9 @@ async function voteOnSponsorTime(req, res) { } else if (votesRow.type === 2) { //extra downvote oldIncrementAmount = -4; + } else if (votesRow.type === 20) { + //undo/cancel vote + oldIncrementAmount = 0; } else if (votesRow.type < 0) { //vip downvote oldIncrementAmount = votesRow.type; diff --git a/test/cases/getUserInfo.js b/test/cases/getUserInfo.js index 499ae3c..f04c02f 100644 --- a/test/cases/getUserInfo.js +++ b/test/cases/getUserInfo.js @@ -16,6 +16,11 @@ describe('getUserInfo', () => { db.exec(startOfSponsorTimesQuery + "('zzzxxxyyy', 1, 11, 2, 'uuid000006', '" + getHash("getuserinfo_user_02") + "', 0, 10, 'sponsor', 0)"); db.exec(startOfSponsorTimesQuery + "('xxxyyyzzz', 1, 11, 2, 'uuid000007', '" + getHash("getuserinfo_user_02") + "', 0, 10, 'sponsor', 1)"); db.exec(startOfSponsorTimesQuery + "('xxxyyyzzz', 1, 11, 2, 'uuid000008', '" + getHash("getuserinfo_user_02") + "', 0, 10, 'sponsor', 1)"); + + + db.exec("INSERT INTO warnings (userID, issueTime, issuerUserID) VALUES ('" + getHash('getuserinfo_warning_0') + "', 10, 'getuserinfo_vip')"); + db.exec("INSERT INTO warnings (userID, issueTime, issuerUserID) VALUES ('" + getHash('getuserinfo_warning_1') + "', 10, 'getuserinfo_vip')"); + db.exec("INSERT INTO warnings (userID, issueTime, issuerUserID) VALUES ('" + getHash('getuserinfo_warning_1') + "', 10, 'getuserinfo_vip')"); }); it('Should be able to get a 200', (done) => { @@ -26,7 +31,7 @@ describe('getUserInfo', () => { done('couldn\'t call endpoint'); } else { if (res.statusCode !== 200) { - done('non 200'); + done('non 200 (' + res.statusCode + ')'); } else { done(); // pass } @@ -62,18 +67,79 @@ describe('getUserInfo', () => { } else { const data = JSON.parse(body); if (data.userName !== 'Username user 01') { - return done('Returned incorrect userName "' + data.userName + '"'); + done('Returned incorrect userName "' + data.userName + '"'); + } else if (data.minutesSaved !== 5) { + done('Returned incorrect minutesSaved "' + data.minutesSaved + '"'); + } else if (data.viewCount !== 30) { + done('Returned incorrect viewCount "' + data.viewCount + '"'); + } else if (data.segmentCount !== 3) { + done('Returned incorrect segmentCount "' + data.segmentCount + '"'); + } else { + done(); // pass } - if (data.minutesSaved !== 5) { - return done('Returned incorrect minutesSaved "' + data.minutesSaved + '"'); + } + } + }); + }); + + it('Should get warning data', (done) => { + request.get(utils.getbaseURL() + + '/api/getUserInfo?userID=getuserinfo_warning_0', null, + (err, res, body) => { + if (err) { + done("couldn't call endpoint"); + } else { + if (res.statusCode !== 200) { + done("non 200"); + } else { + const data = JSON.parse(body); + if (data.warnings !== 1) { + done('wrong number of warnings: ' + data.warnings + ', not ' + 1); + } else { + done(); // pass } - if (data.viewCount !== 30) { - return done('Returned incorrect viewCount "' + data.viewCount + '"'); + } + } + }); + }); + + it('Should get multiple warnings', (done) => { + request.get(utils.getbaseURL() + + '/api/getUserInfo?userID=getuserinfo_warning_1', null, + (err, res, body) => { + if (err) { + done("couldn't call endpoint"); + } else { + if (res.statusCode !== 200) { + done("non 200"); + } else { + const data = JSON.parse(body); + if (data.warnings !== 2) { + done('wrong number of warnings: ' + data.warnings + ', not ' + 2); + } else { + done(); // pass } - if (data.segmentCount !== 3) { - return done('Returned incorrect segmentCount "' + data.segmentCount + '"'); + } + } + }); + }); + + it('Should not get warnings if noe', (done) => { + request.get(utils.getbaseURL() + + '/api/getUserInfo?userID=getuserinfo_warning_2', null, + (err, res, body) => { + if (err) { + done("couldn't call endpoint"); + } else { + if (res.statusCode !== 200) { + done("non 200"); + } else { + const data = JSON.parse(body); + if (data.warnings !== 0) { + done('wrong number of warnings: ' + data.warnings + ', not ' + 0); + } else { + done(); // pass } - done(); // pass } } }); diff --git a/test/cases/postWarning.js b/test/cases/postWarning.js new file mode 100644 index 0000000..7661bf5 --- /dev/null +++ b/test/cases/postWarning.js @@ -0,0 +1,53 @@ +var request = require('request'); +var utils = require('../utils.js'); +var db = require('../../src/databases/databases.js').db; +var getHash = require('../../src/utils/getHash.js'); + +describe('postWarning', () => { + before(() => { + db.exec("INSERT INTO vipUsers (userID) VALUES ('" + getHash("warning-vip") + "')"); + }); + + it('Should update the database version when starting the application', (done) => { + let version = db.prepare('get', 'SELECT key, value FROM config where key = ?', ['version']).value; + if (version > 3) done(); + else done('Version isn\'t greater than 3. Version is ' + version); + }); + + it('Should be able to create warning if vip (exp 200)', (done) => { + let json = { + issuerUserID: 'warning-vip', + userID: 'warning-0' + }; + + request.post(utils.getbaseURL() + + "/api/warnUser", {json}, + (err, res, body) => { + if (err) done(err); + else if (res.statusCode === 200) { + done(); + } else { + console.log(body); + done("Status code was " + res.statusCode); + } + }); + }); + it('Should not be able to create warning if vip (exp 403)', (done) => { + let json = { + issuerUserID: 'warning-not-vip', + userID: 'warning-1' + }; + + request.post(utils.getbaseURL() + + "/api/warnUser", {json}, + (err, res, body) => { + if (err) done(err); + else if (res.statusCode === 403) { + done(); + } else { + console.log(body); + done("Status code was " + res.statusCode); + } + }); + }); +}); \ No newline at end of file