diff --git a/src/routes/getLockCategories.ts b/src/routes/getLockCategories.ts index e27acea..d7707f9 100644 --- a/src/routes/getLockCategories.ts +++ b/src/routes/getLockCategories.ts @@ -13,11 +13,15 @@ export async function getLockCategories(req: Request, res: Response): Promise entry.category); + const row = await db.prepare('all', 'SELECT "category", "reason" from "lockCategories" where "videoID" = ?', [videoID]) as {category: Category, reason: string}[]; + // map categories to array in JS becaues of SQL incompatibilities + const categories = row.map(item => item.category); + if (categories.length === 0 || !categories[0]) return res.sendStatus(404); + // Get longest lock reason + const reason = row.map(item => item.reason) + .reduce((a,b) => (a.length > b.length) ? a : b); return res.send({ + reason, categories }); } catch (err) { diff --git a/src/routes/getLockCategoriesByHash.ts b/src/routes/getLockCategoriesByHash.ts index 90772b2..0027888 100644 --- a/src/routes/getLockCategoriesByHash.ts +++ b/src/routes/getLockCategoriesByHash.ts @@ -7,13 +7,15 @@ import { Category, VideoID, VideoIDHash } from "../types/segments.model"; interface LockResultByHash { videoID: VideoID, hash: VideoIDHash, + reason: string, categories: Category[] } interface DBLock { videoID: VideoID, hash: VideoIDHash, - category: Category + category: Category, + reason: string, } const mergeLocks = (source: DBLock[]) => { @@ -22,12 +24,15 @@ const mergeLocks = (source: DBLock[]) => { // videoID already exists const destMatch = dest.find(s => s.videoID === obj.videoID); if (destMatch) { + // override longer reason + if (obj.reason.length > destMatch.reason.length) destMatch.reason = obj.reason; // push to categories destMatch.categories.push(obj.category); } else { dest.push({ videoID: obj.videoID, hash: obj.hash, + reason: obj.reason, categories: [obj.category] }); } @@ -45,7 +50,7 @@ export async function getLockCategoriesByHash(req: Request, res: Response): Prom try { // Get existing lock categories markers - const lockedRows = await db.prepare('all', 'SELECT "videoID", "hashedVideoID" as "hash", "category" from "lockCategories" where "hashedVideoID" LIKE ?', [hashPrefix + '%']) as DBLock[]; + const lockedRows = await db.prepare('all', 'SELECT "videoID", "hashedVideoID" as "hash", "category", "reason" from "lockCategories" where "hashedVideoID" LIKE ?', [hashPrefix + '%']) as DBLock[]; if (lockedRows.length === 0 || !lockedRows[0]) return res.sendStatus(404); // merge all locks return res.send(mergeLocks(lockedRows)); diff --git a/src/routes/getSkipSegments.ts b/src/routes/getSkipSegments.ts index af322ad..08618e5 100644 --- a/src/routes/getSkipSegments.ts +++ b/src/routes/getSkipSegments.ts @@ -275,6 +275,10 @@ async function chooseSegments(segments: DBSegment[], max: number): Promise { const videoID = req.query.videoID as VideoID; + if (!videoID) { + res.status(400).send("videoID not specified"); + return false; + } // Default to sponsor // If using params instead of JSON, only one category can be pulled const categories: Category[] = req.query.categories diff --git a/src/routes/getSkipSegmentsByHash.ts b/src/routes/getSkipSegmentsByHash.ts index eb2c99c..1518f09 100644 --- a/src/routes/getSkipSegmentsByHash.ts +++ b/src/routes/getSkipSegmentsByHash.ts @@ -5,7 +5,7 @@ import { ActionType, Category, SegmentUUID, Service, VideoIDHash } from '../type export async function getSkipSegmentsByHash(req: Request, res: Response): Promise { let hashPrefix = req.params.prefix as VideoIDHash; - if (!hashPrefixTester(req.params.prefix)) { + if (!req.params.prefix || !hashPrefixTester(req.params.prefix)) { return res.status(400).send("Hash prefix does not match format requirements."); // Exit early on faulty prefix } hashPrefix = hashPrefix.toLowerCase() as VideoIDHash; diff --git a/src/routes/postWarning.ts b/src/routes/postWarning.ts index 015a9f8..583fbe2 100644 --- a/src/routes/postWarning.ts +++ b/src/routes/postWarning.ts @@ -6,6 +6,8 @@ import {getHash} from '../utils/getHash'; import { HashedUserID, UserID } from '../types/user.model'; export async function postWarning(req: Request, res: Response): Promise { + // exit early if no body passed in + if (!req.body.userID && !req.body.issuerUserID) return res.status(400).json({"message": "Missing parameters"}); // Collect user input data const issuerUserID: HashedUserID = getHash( req.body.issuerUserID); const userID: UserID = req.body.userID; diff --git a/test/cases/getLockCategories.ts b/test/cases/getLockCategories.ts index eab9950..5bfb467 100644 --- a/test/cases/getLockCategories.ts +++ b/test/cases/getLockCategories.ts @@ -10,19 +10,19 @@ describe('getLockCategories', () => { const insertVipUserQuery = 'INSERT INTO "vipUsers" ("userID") VALUES (?)'; await db.prepare("run", insertVipUserQuery, [getHash("VIPUser-getLockCategories")]); - const insertLockCategoryQuery = 'INSERT INTO "lockCategories" ("userID", "videoID", "category") VALUES (?, ?, ?)'; - await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'getLock-1', 'sponsor']); - await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'getLock-1', 'interaction']); + const insertLockCategoryQuery = 'INSERT INTO "lockCategories" ("userID", "videoID", "category", "reason") VALUES (?, ?, ?, ?)'; + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'getLock-1', 'sponsor', '1-short']); + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'getLock-1', 'interaction', '1-longer-reason']); - await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'getLock-2', 'preview']); + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'getLock-2', 'preview', '2-reason']); - await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'getLock-3', 'nonmusic']); + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'getLock-3', 'nonmusic', '3-reason']); }); it('Should update the database version when starting the application', async () => { const version = (await db.prepare('get', 'SELECT key, value FROM config where key = ?', ['version'])).value; - if (version > 1) return; - else return 'Version isn\'t greater than 1. Version is ' + version; + if (version > 20) return; + else return 'Version isn\'t greater than 20. Version is ' + version; }); it('Should be able to get multiple locks', (done: Done) => { @@ -34,7 +34,8 @@ describe('getLockCategories', () => { categories: [ "sponsor", "interaction" - ] + ], + reason: "1-longer-reason" }; assert.deepStrictEqual(data, expected); done(); @@ -50,7 +51,8 @@ describe('getLockCategories', () => { const expected = { categories: [ "preview" - ] + ], + reason: "2-reason" }; assert.deepStrictEqual(data, expected); done(); diff --git a/test/cases/getLockCategoriesByHash.ts b/test/cases/getLockCategoriesByHash.ts index 7734e58..a93f9bd 100644 --- a/test/cases/getLockCategoriesByHash.ts +++ b/test/cases/getLockCategoriesByHash.ts @@ -4,29 +4,28 @@ import {getHash} from '../../src/utils/getHash'; import {db} from '../../src/databases/databases'; import assert from 'assert'; - describe('getLockCategoriesByHash', () => { before(async () => { const insertVipUserQuery = 'INSERT INTO "vipUsers" ("userID") VALUES (?)'; await db.prepare("run", insertVipUserQuery, [getHash("VIPUser-getLockCategories")]); - const insertLockCategoryQuery = 'INSERT INTO "lockCategories" ("userID", "videoID", "category", "hashedVideoID") VALUES (?, ?, ?, ?)'; - await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'getLockHash-1', 'sponsor', '67a654898fda3a5541774aea345796c7709982bb6018cb08d22a18eeddccc1d0']); - await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'getLockHash-1', 'interaction', '67a654898fda3a5541774aea345796c7709982bb6018cb08d22a18eeddccc1d0']); + const insertLockCategoryQuery = 'INSERT INTO "lockCategories" ("userID", "videoID", "category", "reason", "hashedVideoID") VALUES (?, ?, ?, ?, ?)'; + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'getLockHash-1', 'sponsor', '1-reason-short', '67a654898fda3a5541774aea345796c7709982bb6018cb08d22a18eeddccc1d0']); + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'getLockHash-1', 'interaction', '1-reason-longer', '67a654898fda3a5541774aea345796c7709982bb6018cb08d22a18eeddccc1d0']); - await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'getLockHash-2', 'preview', 'dff09120437b4bd594dffae5f3cde3cfc5f6099fb01d0ef4051919b2908d9a50']); + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'getLockHash-2', 'preview', '2-reason', 'dff09120437b4bd594dffae5f3cde3cfc5f6099fb01d0ef4051919b2908d9a50']); - await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'getLockHash-3', 'nonmusic', 'bf1b122fd5630e0df8626d00c4a95c58954ad715e5595b0f75a19ac131e28928']); + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'getLockHash-3', 'nonmusic', '3-reason', 'bf1b122fd5630e0df8626d00c4a95c58954ad715e5595b0f75a19ac131e28928']); - await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'fakehash-1', 'outro', 'b05a20424f24a53dac1b059fb78d861ba9723645026be2174c93a94f9106bb35']); - await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'fakehash-2', 'intro', 'b05acd1cd6ec7dffe5ffea64ada91ae7469d6db2ce21c7e30ad7fa62075d450']); - await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'fakehash-2', 'preview', 'b05acd1cd6ec7dffe5ffea64ada91ae7469d6db2ce21c7e30ad7fa62075d450']); + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'fakehash-1', 'outro', 'fake1-reason', 'b05a20424f24a53dac1b059fb78d861ba9723645026be2174c93a94f9106bb35']); + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'fakehash-2', 'intro', 'fake2-longer-reason', 'b05acd1cd6ec7dffe5ffea64ada91ae7469d6db2ce21c7e30ad7fa62075d450']); + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'fakehash-2', 'preview', 'fake2-short', 'b05acd1cd6ec7dffe5ffea64ada91ae7469d6db2ce21c7e30ad7fa62075d450']); }); - it('Database should be greater or equal to version 18', async () => { + it('Database should be greater or equal to version 20', async () => { const version = (await db.prepare('get', 'SELECT key, value FROM config where key = ?', ['version'])).value; - if (version >= 18) return; - else return 'Version isn\'t greater than 18. Version is ' + version; + if (version >= 20) return; + else return 'Version isn\'t greater than 20. Version is ' + version; }); it('Should be able to get multiple locks in one object', (done: Done) => { @@ -40,7 +39,8 @@ describe('getLockCategoriesByHash', () => { categories: [ "sponsor", "interaction" - ] + ], + reason: "1-reason-longer" }]; assert.deepStrictEqual(data, expected); done(); @@ -58,7 +58,8 @@ describe('getLockCategoriesByHash', () => { hash: getHash("getLockHash-2", 1), categories: [ "preview" - ] + ], + reason: "2-reason" }]; assert.deepStrictEqual(data, expected); done(); @@ -76,7 +77,8 @@ describe('getLockCategoriesByHash', () => { hash: getHash("getLockHash-3", 1), categories: [ "nonmusic" - ] + ], + reason: "3-reason" }]; assert.deepStrictEqual(data, expected); done(); @@ -94,14 +96,16 @@ describe('getLockCategoriesByHash', () => { hash: "b05a20424f24a53dac1b059fb78d861ba9723645026be2174c93a94f9106bb35", categories: [ "outro" - ] + ], + reason: "fake1-reason" }, { videoID: "fakehash-2", hash: "b05acd1cd6ec7dffe5ffea64ada91ae7469d6db2ce21c7e30ad7fa62075d450", categories: [ "intro", "preview" - ] + ], + reason: "fake2-longer-reason" }]; assert.deepStrictEqual(data, expected); done(); @@ -144,4 +148,22 @@ describe('getLockCategoriesByHash', () => { }) .catch(err => done(err)); }); + + it('should return 400 if hash too short', (done: Done) => { + fetch(getbaseURL() + '/api/lockCategories/00') + .then(res => { + assert.strictEqual(res.status, 400); + done(); + }) + .catch(err => done(err)); + }); + + it('should return 400 if no hash specified', (done: Done) => { + fetch(getbaseURL() + '/api/lockCategories/') + .then(res => { + assert.strictEqual(res.status, 400); + done(); + }) + .catch(err => done(err)); + }); }); diff --git a/test/cases/getSkipSegments.ts b/test/cases/getSkipSegments.ts index a48fb62..1116191 100644 --- a/test/cases/getSkipSegments.ts +++ b/test/cases/getSkipSegments.ts @@ -340,4 +340,13 @@ describe('getSkipSegments', () => { }) .catch(err => done(err)); }); + + it('Should get 400 if no videoID passed in', (done: Done) => { + fetch(getbaseURL() + '/api/skipSegments') + .then(async res => { + assert.strictEqual(res.status, 400); + done(); + }) + .catch(err => done(err)); + }); }); diff --git a/test/cases/getSkipSegmentsByHash.ts b/test/cases/getSkipSegmentsByHash.ts index e4112ae..a32c208 100644 --- a/test/cases/getSkipSegmentsByHash.ts +++ b/test/cases/getSkipSegmentsByHash.ts @@ -11,7 +11,7 @@ const mockManager = ImportMock.mockStaticClass(YouTubeAPIModule, 'YouTubeAPI'); const sinonStub = mockManager.mock('listVideos'); sinonStub.callsFake(YouTubeApiMock.listVideos); -describe('getSegmentsByHash', () => { +describe('getSkipSegmentsByHash', () => { before(async () => { const query = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "actionType", "service", "hidden", "shadowHidden", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; await db.prepare("run", query, ['getSegmentsByHash-0', 1, 10, 2, 'getSegmentsByHash-0-0', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 'fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910']); @@ -106,10 +106,10 @@ describe('getSegmentsByHash', () => { .catch(err => done(err)); }); - it('Should return 404 for no hash', (done: Done) => { + it('Should return 400 for no hash', (done: Done) => { fetch(getbaseURL() + '/api/skipSegments/?categories=["shilling"]') .then(res => { - assert.strictEqual(res.status, 404); + assert.strictEqual(res.status, 400); done(); }) .catch(err => done(err)); diff --git a/test/cases/getUserID.ts b/test/cases/getUserID.ts index 64863f9..7959ea1 100644 --- a/test/cases/getUserID.ts +++ b/test/cases/getUserID.ts @@ -313,4 +313,13 @@ describe('getUserID', () => { }) .catch(err => done(err)); }); + + it('should return 400 if no username parameter specified', (done: Done) => { + fetch(getbaseURL() + '/api/userID') + .then(res => { + assert.strictEqual(res.status, 400); + done(); + }) + .catch(() => ("couldn't call endpoint")); + }); }); diff --git a/test/cases/postPurgeAllSegments.ts b/test/cases/postPurgeAllSegments.ts index a900893..9bc20c1 100644 --- a/test/cases/postPurgeAllSegments.ts +++ b/test/cases/postPurgeAllSegments.ts @@ -81,4 +81,18 @@ describe('postPurgeAllSegments', function () { }) .catch(err => done(err)); }); + + it('Should return 400 if missing body', function (done: Done) { + fetch(`${baseURL}${route}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + } + }) + .then(async res => { + assert.strictEqual(res.status, 400); + done(); + }) + .catch(err => done(err)); + }); }); diff --git a/test/cases/postWarning.ts b/test/cases/postWarning.ts index 0e6d3dc..f954fe1 100644 --- a/test/cases/postWarning.ts +++ b/test/cases/postWarning.ts @@ -102,4 +102,19 @@ describe('postWarning', () => { }) .catch(err => done(err)); }); + + it('Should return 400 if missing body', (done: Done) => { + fetch(getbaseURL() + + "/api/warnUser", { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + } + }) + .then(async res => { + assert.strictEqual(res.status, 400); + done(); + }) + .catch(err => done(err)); + }); });