From 8e33fdf49f6954db690b3a61bd11d64e4df6bb69 Mon Sep 17 00:00:00 2001 From: Nanobyte Date: Sun, 4 Oct 2020 21:37:35 +0200 Subject: [PATCH] Added segmentShift See #151 --- src/app.js | 4 + src/routes/postSegmentShift.js | 101 ++++++++++++ test/cases/segmentShift.js | 273 +++++++++++++++++++++++++++++++++ 3 files changed, 378 insertions(+) create mode 100644 src/routes/postSegmentShift.js create mode 100644 test/cases/segmentShift.js diff --git a/src/app.js b/src/app.js index a102a76..854031a 100644 --- a/src/app.js +++ b/src/app.js @@ -26,6 +26,7 @@ var getTotalStats = require('./routes/getTotalStats.js'); var getDaysSavedFormatted = require('./routes/getDaysSavedFormatted.js'); var postNoSegments = require('./routes/postNoSegments.js'); var getIsUserVIP = require('./routes/getIsUserVIP.js'); +var postSegmentShift = require('./routes/postSegmentShift.js'); // Old Routes var oldGetVideoSponsorTimes = require('./routes/oldGetVideoSponsorTimes.js'); @@ -102,6 +103,9 @@ app.post('/api/noSegments', postNoSegments); //get if user is a vip app.get('/api/isUserVIP', getIsUserVIP); +//get if user is a vip +app.post('/api/segmentShift', postSegmentShift); + app.get('/database.db', function (req, res) { res.sendFile("./databases/sponsorTimes.db", { root: "./" }); diff --git a/src/routes/postSegmentShift.js b/src/routes/postSegmentShift.js new file mode 100644 index 0000000..fd8c568 --- /dev/null +++ b/src/routes/postSegmentShift.js @@ -0,0 +1,101 @@ +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'); + +const ACTION_NONE = Symbol('none'); +const ACTION_UPDATE = Symbol('update'); +const ACTION_REMOVE = Symbol('remove'); + +function shiftSegment(segment, shift) { + if (segment.startTime >= segment.endTime) return {action: ACTION_NONE, segment}; + if (shift.startTime >= shift.endTime) return {action: ACTION_NONE, segment}; + const duration = shift.endTime - shift.startTime; + if (shift.endTime < segment.startTime) { + // Scenario #1 cut before segment + segment.startTime -= duration; + segment.endTime -= duration; + return {action: ACTION_UPDATE, segment}; + } + if (shift.startTime > segment.endTime) { + // Scenario #2 cut after segment + return {action: ACTION_NONE, segment}; + } + if (segment.startTime < shift.startTime && segment.endTime > shift.endTime) { + // Scenario #3 cut inside segment + segment.endTime -= duration; + return {action: ACTION_UPDATE, segment}; + } + if (segment.startTime >= shift.startTime && segment.endTime > shift.endTime) { + // Scenario #4 cut overlap startTime + segment.startTime = shift.startTime; + segment.endTime -= duration; + return {action: ACTION_UPDATE, segment}; + } + if (segment.startTime < shift.startTime && segment.endTime <= shift.endTime) { + // Scenario #5 cut overlap endTime + segment.endTime = shift.startTime; + return {action: ACTION_UPDATE, segment}; + } + if (segment.startTime >= shift.startTime && segment.endTime <= shift.endTime) { + // Scenario #6 cut overlap startTime and endTime + return {action: ACTION_REMOVE, segment}; + } + return {action: ACTION_NONE, segment}; +} + +module.exports = (req, res) => { + // Collect user input data + const videoID = req.body.videoID; + const startTime = req.body.startTime; + const endTime = req.body.endTime; + let userID = req.body.userID; + + // Check input data is valid + if (!videoID + || !userID + || !startTime + || !endTime + ) { + res.status(400).json({ + message: 'Bad Format' + }); + return; + } + + // Check if user is VIP + userID = getHash(userID); + const userIsVIP = isUserVIP(userID); + + if (!userIsVIP) { + res.status(403).json({ + message: 'Must be a VIP to perform this action.' + }); + return; + } + + try { + const segments = db.prepare('all', 'SELECT startTime, endTime, UUID FROM sponsorTimes WHERE videoID = ?', [videoID]); + const shift = { + startTime, + endTime, + }; + segments.forEach(segment => { + const result = shiftSegment(segment, shift); + switch (result.action) { + case ACTION_UPDATE: + db.prepare('run', 'UPDATE sponsorTimes SET startTime = ?, endTime = ? WHERE UUID = ?', [result.segment.startTime, result.segment.endTime, result.segment.UUID]); + break; + case ACTION_REMOVE: + db.prepare('run', 'UPDATE sponsorTimes SET startTime = ?, endTime = ?, votes = -2 WHERE UUID = ?', [result.segment.startTime, result.segment.endTime, result.segment.UUID]); + break; + } + }); + } + catch(err) { + logger.error(err); + res.sendStatus(500); + } + + res.sendStatus(200); +}; diff --git a/test/cases/segmentShift.js b/test/cases/segmentShift.js new file mode 100644 index 0000000..e1011e2 --- /dev/null +++ b/test/cases/segmentShift.js @@ -0,0 +1,273 @@ +const request = require('request'); +const utils = require('../utils.js'); +const { db } = require('../../src/databases/databases.js'); +const getHash = require('../../src/utils/getHash.js'); + +function dbSponsorTimesAdd(db, videoID, startTime, endTime, UUID, category) { + const votes = 0, + userID = 0, + timeSubmitted = 0, + views = 0, + shadowHidden = 0, + hashedVideoID = `hash_${UUID}`; + db.exec(`INSERT INTO + sponsorTimes (videoID, startTime, endTime, votes, UUID, + userID, timeSubmitted, views, category, shadowHidden, hashedVideoID) + VALUES + ('${videoID}', ${startTime}, ${endTime}, ${votes}, '${UUID}', + '${userID}', ${timeSubmitted}, ${views}, '${category}', ${shadowHidden}, '${hashedVideoID}') + `); +} + +function dbSponsorTimesSetByUUID(db, UUID, startTime, endTime) { + db.prepare('run', `UPDATE sponsorTimes SET startTime = ?, endTime = ? WHERE UUID = ?`, [startTime, endTime, UUID]); +} + +function dbSponsorTimesCompareExpect(db, expect) { + for (let i=0, len=expect.length; i { + if (err) return done(err); + return done(res.statusCode === 403 ? undefined : res.statusCode); + }); + }); + + it('Shift is outside segments', function(done) { + request.post(`${baseURL}/api/segmentShift`, { + json: { + videoID: 'vsegshift01', + userID: privateVipUserID, + startTime: 20, + endTime: 30, + } + }, (err, res, body) => { + if (err) return done(err); + if (res.statusCode !== 200) return done(`Status code was ${res.statusCode}`); + const expect = [ + { + UUID: 'vsegshifttest01uuid01', + startTime: 0, + endTime: 10, + }, + { + UUID: 'vsegshifttest01uuid02', + startTime: 50, + endTime: 80, + }, + { + UUID: 'vsegshifttest01uuid03', + startTime: 30, + endTime: 35, + }, + { + UUID: 'vsegshifttest01uuid04', + startTime: 110, + endTime: 130, + }, + ]; + done(dbSponsorTimesCompareExpect(db, expect)); + }); + }); + + it('Shift is inside segment', function(done) { + request.post(`${baseURL}/api/segmentShift`, { + json: { + videoID: 'vsegshift01', + userID: privateVipUserID, + startTime: 65, + endTime: 75, + } + }, (err, res, body) => { + if (err) return done(err); + if (res.statusCode !== 200) return done(`Status code was ${res.statusCode}`); + const expect = [ + { + UUID: 'vsegshifttest01uuid01', + startTime: 0, + endTime: 10, + }, + { + UUID: 'vsegshifttest01uuid02', + startTime: 60, + endTime: 80, + }, + { + UUID: 'vsegshifttest01uuid03', + startTime: 40, + endTime: 45, + }, + { + UUID: 'vsegshifttest01uuid04', + startTime: 110, + endTime: 130, + }, + ]; + done(dbSponsorTimesCompareExpect(db, expect)); + }); + }); + + it('Shift is overlaping startTime of segment', function(done) { + request.post(`${baseURL}/api/segmentShift`, { + json: { + videoID: 'vsegshift01', + userID: privateVipUserID, + startTime: 32, + endTime: 42, + } + }, (err, res, body) => { + if (err) return done(err); + if (res.statusCode !== 200) return done(`Status code was ${res.statusCode}`); + const expect = [ + { + UUID: 'vsegshifttest01uuid01', + startTime: 0, + endTime: 10, + }, + { + UUID: 'vsegshifttest01uuid02', + startTime: 50, + endTime: 80, + }, + { + UUID: 'vsegshifttest01uuid03', + startTime: 32, + endTime: 35, + }, + { + UUID: 'vsegshifttest01uuid04', + startTime: 110, + endTime: 130, + }, + ]; + done(dbSponsorTimesCompareExpect(db, expect)); + }); + }); + + it('Shift is overlaping endTime of segment', function(done) { + request.post(`${baseURL}/api/segmentShift`, { + json: { + videoID: 'vsegshift01', + userID: privateVipUserID, + startTime: 85, + endTime: 95, + } + }, (err, res, body) => { + if (err) return done(err); + if (res.statusCode !== 200) return done(`Status code was ${res.statusCode}`); + const expect = [ + { + UUID: 'vsegshifttest01uuid01', + startTime: 0, + endTime: 10, + }, + { + UUID: 'vsegshifttest01uuid02', + startTime: 60, + endTime: 85, + }, + { + UUID: 'vsegshifttest01uuid03', + startTime: 40, + endTime: 45, + }, + { + UUID: 'vsegshifttest01uuid04', + startTime: 110, + endTime: 130, + }, + ]; + done(dbSponsorTimesCompareExpect(db, expect)); + }); + }); + + it('Shift is overlaping segment', function(done) { + request.post(`${baseURL}/api/segmentShift`, { + json: { + videoID: 'vsegshift01', + userID: privateVipUserID, + startTime: 35, + endTime: 55, + } + }, (err, res, body) => { + if (err) return done(err); + if (res.statusCode !== 200) return done(`Status code was ${res.statusCode}`); + const expect = [ + { + UUID: 'vsegshifttest01uuid01', + startTime: 0, + endTime: 10, + }, + { + UUID: 'vsegshifttest01uuid02', + startTime: 40, + endTime: 70, + }, + { + UUID: 'vsegshifttest01uuid03', + startTime: 40, + endTime: 45, + removed: true, + }, + { + UUID: 'vsegshifttest01uuid04', + startTime: 100, + endTime: 120, + }, + ]; + done(dbSponsorTimesCompareExpect(db, expect)); + }); + }); + + +});