diff --git a/DatabaseSchema.md b/DatabaseSchema.md index 6814131..485c4c3 100644 --- a/DatabaseSchema.md +++ b/DatabaseSchema.md @@ -92,6 +92,7 @@ | userID | TEXT | not null | | category | TEXT | not null | | hashedVideoID | TEXT | not null, default '' | +| reason | TEXT | not null, default '' | | index | field | | -- | :--: | diff --git a/databases/_upgrade_sponsorTimes_20.sql b/databases/_upgrade_sponsorTimes_20.sql new file mode 100644 index 0000000..a827cb6 --- /dev/null +++ b/databases/_upgrade_sponsorTimes_20.sql @@ -0,0 +1,8 @@ +BEGIN TRANSACTION; + +/* Add hash field */ +ALTER TABLE "lockCategories" ADD "reason" TEXT NOT NULL default ''; + +UPDATE "config" SET value = 20 WHERE key = 'version'; + +COMMIT; diff --git a/src/routes/postLockCategories.ts b/src/routes/postLockCategories.ts index 767fba3..e444b5b 100644 --- a/src/routes/postLockCategories.ts +++ b/src/routes/postLockCategories.ts @@ -10,6 +10,7 @@ export async function postLockCategories(req: Request, res: Response): Promise { + let filteredCategories = categories.filter((category) => { return !!category.match(/^[_a-zA-Z]+$/); - }).filter((category) => { - return noCategoryList.indexOf(category) === -1; + }); + // remove any duplicates + filteredCategories = filteredCategories.filter((category, index) => { + return filteredCategories.indexOf(category) === index; }); - // remove any duplicates - categoriesToMark = categoriesToMark.filter((category, index) => { - return categoriesToMark.indexOf(category) === index; + const categoriesToMark = filteredCategories.filter((category) => { + return noCategoryList.indexOf(category) === -1; }); // calculate hash of videoID @@ -63,7 +65,7 @@ export async function postLockCategories(req: Request, res: Response): Promise { + return noCategoryList.indexOf(category) !== -1; + }); + + for (const category of overlapCategories) { + try { + await db.prepare('run', + 'UPDATE "lockCategories" SET "reason" = ?, "userID" = ? WHERE "videoID" = ? AND "category" = ?', + [reason, userID, videoID, category]); + } catch (err) { + Logger.error("Error submitting 'lockCategories' marker for category '" + category + "' for video '" + videoID + "'"); + Logger.error(err); + res.status(500).json({ + message: "Internal Server Error: Could not write marker to the database.", + }); + } + } + } + res.status(200).json({ - submitted: categoriesToMark, + submitted: [...categoriesToMark, ...overlapCategories], }); } diff --git a/src/types/segments.model.ts b/src/types/segments.model.ts index 9d72829..23af6a7 100644 --- a/src/types/segments.model.ts +++ b/src/types/segments.model.ts @@ -92,4 +92,11 @@ export interface SegmentCache { export enum CategoryActionType { Skippable, POI +} + +export interface LockCategory { + category: Category, + reason: string, + videoID: VideoID, + userID: UserID } \ No newline at end of file diff --git a/test/cases/lockCategoriesRecords.ts b/test/cases/lockCategoriesRecords.ts index 2cb9070..e05154f 100644 --- a/test/cases/lockCategoriesRecords.ts +++ b/test/cases/lockCategoriesRecords.ts @@ -2,25 +2,26 @@ import fetch from 'node-fetch'; import {Done, getbaseURL} from '../utils'; import {getHash} from '../../src/utils/getHash'; import {db} from '../../src/databases/databases'; +import {LockCategory} from '../../src/types/segments.model'; describe('lockCategoriesRecords', () => { before(async () => { const insertVipUserQuery = 'INSERT INTO "vipUsers" ("userID") VALUES (?)'; await db.prepare("run", insertVipUserQuery, [getHash("VIPUser-lockCategories")]); - - const insertLockCategoryQuery = 'INSERT INTO "lockCategories" ("userID", "videoID", "category") VALUES (?, ?, ?)'; - await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-lockCategories"), 'no-segments-video-id', 'sponsor']); - await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-lockCategories"), 'no-segments-video-id', 'intro']); - - await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-lockCategories"), 'no-segments-video-id-1', 'sponsor']); - await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-lockCategories"), 'no-segments-video-id-1', 'intro']); - await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-lockCategories"), 'lockCategoryVideo', 'sponsor']); - - await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-lockCategories"), 'delete-record', 'sponsor']); - - await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-lockCategories"), 'delete-record-1', 'sponsor']); - await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-lockCategories"), 'delete-record-1', 'intro']); + + const insertLockCategoryQuery = 'INSERT INTO "lockCategories" ("userID", "videoID", "category", "reason") VALUES (?, ?, ?, ?)'; + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-lockCategories"), 'no-segments-video-id', 'sponsor', 'reason-1']); + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-lockCategories"), 'no-segments-video-id', 'intro', 'reason-1']); + + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-lockCategories"), 'no-segments-video-id-1', 'sponsor', 'reason-2']); + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-lockCategories"), 'no-segments-video-id-1', 'intro', 'reason-2']); + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-lockCategories"), 'lockCategoryVideo', 'sponsor', 'reason-3']); + + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-lockCategories"), 'delete-record', 'sponsor', 'reason-4']); + + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-lockCategories"), 'delete-record-1', 'sponsor', 'reason-5']); + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-lockCategories"), 'delete-record-1', 'intro', 'reason-5']); }); it('Should update the database version when starting the application', async () => { @@ -95,11 +96,125 @@ describe('lockCategoriesRecords', () => { }) .then(async res => { if (res.status === 200) { - const result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['no-segments-video-id-1']); + const result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['no-segments-video-id-1']) as LockCategory[]; if (result.length !== 4) { done("Expected 4 entrys in db, got " + result.length); } else { + const oldRecordNotChangeReason = result.filter(item => { + return item.reason === 'reason-2' && ['sponsor', 'intro'].includes(item.category); + }); + + const newRecordWithEmptyReason = result.filter(item => { + return item.reason === '' && ['outro', 'shilling'].includes(item.category); + }); + + if (newRecordWithEmptyReason.length !== 2 || oldRecordNotChangeReason.length !== 2) { + done(`Incorrect reason update with oldRecordNotChangeReason=${oldRecordNotChangeReason} instead of 2 or newRecordWithEmptyReason=${newRecordWithEmptyReason} instead of 2`); + } else { + done(); + } + } + } else { + done("Status code was " + res.status); + } + }) + .catch(err => done(err)); + }); + + it('Should be able to submit categories not in video with reason (http response)', (done: Done) => { + const json = { + videoID: 'no-segments-video-id', + userID: 'VIPUser-lockCategories', + categories: [ + 'outro', + 'shilling', + 'shilling', + 'shil ling', + '', + 'intro', + ], + reason: 'new reason' + }; + + const expected = { + submitted: [ + 'outro', + 'shilling', + 'intro' + ], + }; + + fetch(getbaseURL() + "/api/lockCategories", { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(json) + }) + .then(async res => { + if (res.status === 200) { + const data = await res.json(); + if (JSON.stringify(data) === JSON.stringify(expected)) { done(); + } else { + done("Incorrect response: expected " + JSON.stringify(expected) + " got " + JSON.stringify(data)); + } + } else { + done("Status code was " + res.status); + } + }) + .catch(err => done(err)); + }); + + it('Should be able to submit categories not in video with reason (sql check)', (done: Done) => { + const json = { + videoID: 'no-segments-video-id-1', + userID: 'VIPUser-lockCategories', + categories: [ + 'outro', + 'shilling', + 'shilling', + 'shil ling', + '', + 'intro', + ], + reason: 'new reason' + }; + + const expectedWithNewReason = [ + 'outro', + 'shilling', + 'intro' + ]; + + fetch(getbaseURL() + "/api/lockCategories", { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(json) + }) + .then(async res => { + if (res.status === 200) { + const result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['no-segments-video-id-1']) as LockCategory[]; + if (result.length !== 4) { + done("Expected 4 entrys in db, got " + result.length); + } else { + const newRecordWithNewReason = result.filter(item => { + return expectedWithNewReason.includes(item.category) && item.reason === 'new reason'; + }); + + const oldRecordNotChangeReason = result.filter(item => { + return item.reason === 'reason-2'; + }); + + if (newRecordWithNewReason.length !== 3) { + done("Expected 3 entrys in db with new reason, got " + newRecordWithNewReason.length); + } else if (oldRecordNotChangeReason.length !== 1) { + done("Expected 1 entrys in db with old reason, got " + oldRecordNotChangeReason.length); + } else { + done(); + } } } else { done("Status code was " + res.status);