This commit is contained in:
Ajay Ramachandran
2021-07-19 16:14:17 -04:00
97 changed files with 4405 additions and 4433 deletions

View File

@@ -1,24 +1,29 @@
module.exports = {
env: {
browser: false,
es2021: true,
node: true,
},
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 12,
sourceType: "module",
},
plugins: ["@typescript-eslint"],
rules: {
// TODO: Remove warn rules when not needed anymore
"no-self-assign": "off",
"semi": "warn",
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-explicit-any": "off"
},
};
env: {
browser: false,
es2021: true,
node: true,
},
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 12,
sourceType: "module",
},
plugins: ["@typescript-eslint"],
rules: {
// TODO: Remove warn rules when not needed anymore
"no-self-assign": "off",
"semi": "warn",
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-explicit-any": "off",
"no-trailing-spaces": "warn",
"prefer-template": "warn",
"quotes": ["warn", "double", { "avoidEscape": true, "allowTemplateLiterals": true }],
"no-multiple-empty-lines": ["error", { max: 2, maxEOF: 0 }],
"indent": ["warn", 4],
},
};

View File

@@ -7,6 +7,7 @@
"test": "npm run tsc && ts-node test/test.ts",
"dev": "nodemon",
"dev:bash": "nodemon -x 'npm test ; npm start'",
"postgres:docker": "docker run --rm -p 5432:5432 -e POSTGRES_USER=ci_db_user -e POSTGRES_PASSWORD=ci_db_pass postgres:alpine",
"start": "ts-node src/index.ts",
"tsc": "tsc -p tsconfig.json",
"lint": "eslint src test",

View File

@@ -1,42 +1,42 @@
import express, {Request, RequestHandler, Response, Router} from 'express';
import {config} from './config';
import {oldSubmitSponsorTimes} from './routes/oldSubmitSponsorTimes';
import {oldGetVideoSponsorTimes} from './routes/oldGetVideoSponsorTimes';
import {postSegmentShift} from './routes/postSegmentShift';
import {postWarning} from './routes/postWarning';
import {getIsUserVIP} from './routes/getIsUserVIP';
import {deleteLockCategoriesEndpoint} from './routes/deleteLockCategories';
import {postLockCategories} from './routes/postLockCategories';
import {getUserInfo} from './routes/getUserInfo';
import {getDaysSavedFormatted} from './routes/getDaysSavedFormatted';
import {getTotalStats} from './routes/getTotalStats';
import {getTopUsers} from './routes/getTopUsers';
import {getViewsForUser} from './routes/getViewsForUser';
import {getSavedTimeForUser} from './routes/getSavedTimeForUser';
import {addUserAsVIP} from './routes/addUserAsVIP';
import {shadowBanUser} from './routes/shadowBanUser';
import {getUsername} from './routes/getUsername';
import {setUsername} from './routes/setUsername';
import {viewedVideoSponsorTime} from './routes/viewedVideoSponsorTime';
import {voteOnSponsorTime, getUserID as voteGetUserID} from './routes/voteOnSponsorTime';
import {getSkipSegmentsByHash} from './routes/getSkipSegmentsByHash';
import {postSkipSegments} from './routes/postSkipSegments';
import {endpoint as getSkipSegments} from './routes/getSkipSegments';
import {userCounter} from './middleware/userCounter';
import {loggerMiddleware} from './middleware/logger';
import {corsMiddleware} from './middleware/cors';
import {apiCspMiddleware} from './middleware/apiCsp';
import {rateLimitMiddleware} from './middleware/requestRateLimit';
import dumpDatabase, {redirectLink} from './routes/dumpDatabase';
import {endpoint as getSegmentInfo} from './routes/getSegmentInfo';
import {postClearCache} from './routes/postClearCache';
import { addUnlistedVideo } from './routes/addUnlistedVideo';
import {postPurgeAllSegments} from './routes/postPurgeAllSegments';
import {getUserID} from './routes/getUserID';
import {getLockCategories} from './routes/getLockCategories';
import {getLockCategoriesByHash} from './routes/getLockCategoriesByHash';
import ExpressPromiseRouter from 'express-promise-router';
import { Server } from 'http';
import express, {Request, RequestHandler, Response, Router} from "express";
import {config} from "./config";
import {oldSubmitSponsorTimes} from "./routes/oldSubmitSponsorTimes";
import {oldGetVideoSponsorTimes} from "./routes/oldGetVideoSponsorTimes";
import {postSegmentShift} from "./routes/postSegmentShift";
import {postWarning} from "./routes/postWarning";
import {getIsUserVIP} from "./routes/getIsUserVIP";
import {deleteLockCategoriesEndpoint} from "./routes/deleteLockCategories";
import {postLockCategories} from "./routes/postLockCategories";
import {getUserInfo} from "./routes/getUserInfo";
import {getDaysSavedFormatted} from "./routes/getDaysSavedFormatted";
import {getTotalStats} from "./routes/getTotalStats";
import {getTopUsers} from "./routes/getTopUsers";
import {getViewsForUser} from "./routes/getViewsForUser";
import {getSavedTimeForUser} from "./routes/getSavedTimeForUser";
import {addUserAsVIP} from "./routes/addUserAsVIP";
import {shadowBanUser} from "./routes/shadowBanUser";
import {getUsername} from "./routes/getUsername";
import {setUsername} from "./routes/setUsername";
import {viewedVideoSponsorTime} from "./routes/viewedVideoSponsorTime";
import {voteOnSponsorTime, getUserID as voteGetUserID} from "./routes/voteOnSponsorTime";
import {getSkipSegmentsByHash} from "./routes/getSkipSegmentsByHash";
import {postSkipSegments} from "./routes/postSkipSegments";
import {endpoint as getSkipSegments} from "./routes/getSkipSegments";
import {userCounter} from "./middleware/userCounter";
import {loggerMiddleware} from "./middleware/logger";
import {corsMiddleware} from "./middleware/cors";
import {apiCspMiddleware} from "./middleware/apiCsp";
import {rateLimitMiddleware} from "./middleware/requestRateLimit";
import dumpDatabase, {redirectLink} from "./routes/dumpDatabase";
import {endpoint as getSegmentInfo} from "./routes/getSegmentInfo";
import {postClearCache} from "./routes/postClearCache";
import { addUnlistedVideo } from "./routes/addUnlistedVideo";
import {postPurgeAllSegments} from "./routes/postPurgeAllSegments";
import {getUserID} from "./routes/getUserID";
import {getLockCategories} from "./routes/getLockCategories";
import {getLockCategoriesByHash} from "./routes/getLockCategoriesByHash";
import ExpressPromiseRouter from "express-promise-router";
import { Server } from "http";
export function createServer(callback: () => void): Server {
// Create a service (the app object is just a callback).
@@ -54,10 +54,10 @@ export function createServer(callback: () => void): Server {
if (config.userCounterURL) app.use(userCounter);
// Setup pretty JSON
if (config.mode === "development") app.set('json spaces', 2);
if (config.mode === "development") app.set("json spaces", 2);
// Set production mode
app.set('env', config.mode || 'production');
app.set("env", config.mode || "production");
setupRoutes(router);
@@ -74,102 +74,102 @@ function setupRoutes(router: Router) {
}
//add the get function
router.get('/api/getVideoSponsorTimes', oldGetVideoSponsorTimes);
router.get("/api/getVideoSponsorTimes", oldGetVideoSponsorTimes);
//add the oldpost function
router.get('/api/postVideoSponsorTimes', oldSubmitSponsorTimes);
router.post('/api/postVideoSponsorTimes', oldSubmitSponsorTimes);
router.get("/api/postVideoSponsorTimes", oldSubmitSponsorTimes);
router.post("/api/postVideoSponsorTimes", oldSubmitSponsorTimes);
//add the skip segments functions
router.get('/api/skipSegments', getSkipSegments);
router.post('/api/skipSegments', postSkipSegments);
router.get("/api/skipSegments", getSkipSegments);
router.post("/api/skipSegments", postSkipSegments);
// add the privacy protecting skip segments functions
router.get('/api/skipSegments/:prefix', getSkipSegmentsByHash);
router.get("/api/skipSegments/:prefix", getSkipSegmentsByHash);
//voting endpoint
router.get('/api/voteOnSponsorTime', ...voteEndpoints);
router.post('/api/voteOnSponsorTime', ...voteEndpoints);
router.get("/api/voteOnSponsorTime", ...voteEndpoints);
router.post("/api/voteOnSponsorTime", ...voteEndpoints);
//Endpoint when a submission is skipped
router.get('/api/viewedVideoSponsorTime', ...viewEndpoints);
router.post('/api/viewedVideoSponsorTime', ...viewEndpoints);
router.get("/api/viewedVideoSponsorTime", ...viewEndpoints);
router.post("/api/viewedVideoSponsorTime", ...viewEndpoints);
//To set your username for the stats view
router.post('/api/setUsername', setUsername);
router.post("/api/setUsername", setUsername);
//get what username this user has
router.get('/api/getUsername', getUsername);
router.get("/api/getUsername", getUsername);
//Endpoint used to hide a certain user's data
router.post('/api/shadowBanUser', shadowBanUser);
router.post("/api/shadowBanUser", shadowBanUser);
//Endpoint used to make a user a VIP user with special privileges
router.post('/api/addUserAsVIP', addUserAsVIP);
router.post("/api/addUserAsVIP", addUserAsVIP);
//Gets all the views added up for one userID
//Useful to see how much one user has contributed
router.get('/api/getViewsForUser', getViewsForUser);
router.get("/api/getViewsForUser", getViewsForUser);
//Gets all the saved time added up (views * sponsor length) for one userID
//Useful to see how much one user has contributed
//In minutes
router.get('/api/getSavedTimeForUser', getSavedTimeForUser);
router.get("/api/getSavedTimeForUser", getSavedTimeForUser);
router.get('/api/getTopUsers', getTopUsers);
router.get("/api/getTopUsers", getTopUsers);
//send out totals
//send the total submissions, total views and total minutes saved
router.get('/api/getTotalStats', getTotalStats);
router.get("/api/getTotalStats", getTotalStats);
router.get('/api/getUserInfo', getUserInfo);
router.get('/api/userInfo', getUserInfo);
router.get("/api/getUserInfo", getUserInfo);
router.get("/api/userInfo", getUserInfo);
//send out a formatted time saved total
router.get('/api/getDaysSavedFormatted', getDaysSavedFormatted);
router.get("/api/getDaysSavedFormatted", getDaysSavedFormatted);
//submit video to lock categories
router.post('/api/noSegments', postLockCategories);
router.post('/api/lockCategories', postLockCategories);
router.post("/api/noSegments", postLockCategories);
router.post("/api/lockCategories", postLockCategories);
router.delete('/api/noSegments', deleteLockCategoriesEndpoint);
router.delete('/api/lockCategories', deleteLockCategoriesEndpoint);
router.delete("/api/noSegments", deleteLockCategoriesEndpoint);
router.delete("/api/lockCategories", deleteLockCategoriesEndpoint);
//get if user is a vip
router.get('/api/isUserVIP', getIsUserVIP);
router.get("/api/isUserVIP", getIsUserVIP);
//sent user a warning
router.post('/api/warnUser', postWarning);
router.post("/api/warnUser", postWarning);
//get if user is a vip
router.post('/api/segmentShift', postSegmentShift);
router.post("/api/segmentShift", postSegmentShift);
//get segment info
router.get('/api/segmentInfo', getSegmentInfo);
router.get("/api/segmentInfo", getSegmentInfo);
//clear cache as VIP
router.post('/api/clearCache', postClearCache);
router.post("/api/clearCache", postClearCache);
//purge all segments for VIP
router.post('/api/purgeAllSegments', postPurgeAllSegments);
router.post("/api/purgeAllSegments", postPurgeAllSegments);
router.post("/api/unlistedVideo", addUnlistedVideo);
router.post('/api/unlistedVideo', addUnlistedVideo);
// get userID from username
router.get('/api/userID', getUserID);
router.get("/api/userID", getUserID);
// get lock categores from userID
router.get('/api/lockCategories', getLockCategories);
router.get("/api/lockCategories", getLockCategories);
// get privacy protecting lock categories functions
router.get('/api/lockCategories/:prefix', getLockCategoriesByHash);
router.get("/api/lockCategories/:prefix", getLockCategoriesByHash);
if (config.postgres) {
router.get('/database', (req, res) => dumpDatabase(req, res, true));
router.get('/database.json', (req, res) => dumpDatabase(req, res, false));
router.get('/database/*', redirectLink);
router.get("/database", (req, res) => dumpDatabase(req, res, true));
router.get("/database.json", (req, res) => dumpDatabase(req, res, false));
router.get("/database/*", redirectLink);
} else {
router.get('/database.db', function (req: Request, res: Response) {
router.get("/database.db", function (req: Request, res: Response) {
res.sendFile("./databases/sponsorTimes.db", {root: "./"});
});
}

View File

@@ -1,12 +1,12 @@
import fs from 'fs';
import fs from "fs";
import {SBSConfig} from "./types/config.model";
import packageJson from "../package.json";
const isTestMode = process.env.npm_lifecycle_script === packageJson.scripts.test;
const configFile = process.env.TEST_POSTGRES ? 'ci.json'
: isTestMode ? 'test.json'
: 'config.json';
export const config: SBSConfig = JSON.parse(fs.readFileSync(configFile).toString('utf8'));
const configFile = process.env.TEST_POSTGRES ? "ci.json"
: isTestMode ? "test.json"
: "config.json";
export const config: SBSConfig = JSON.parse(fs.readFileSync(configFile).toString("utf8"));
addDefaults(config, {
port: 80,
@@ -54,8 +54,8 @@ addDefaults(config, {
dumpDatabase: {
enabled: false,
minTimeBetweenMs: 60000,
appExportPath: './docker/database-export',
postgresExportPath: '/opt/exports',
appExportPath: "./docker/database-export",
postgresExportPath: "/opt/exports",
tables: [{
name: "sponsorTimes",
order: "timeSubmitted"

View File

@@ -8,60 +8,60 @@ import { DBSegment } from "../types/segments.model";
const jobConfig = serverConfig?.crons?.downvoteSegmentArchive;
export const archiveDownvoteSegment = async (dayLimit: number, voteLimit: number, runTime?: number): Promise<number> => {
const timeNow = runTime || new Date().getTime();
const threshold = dayLimit * 86400000;
const timeNow = runTime || new Date().getTime();
const threshold = dayLimit * 86400000;
Logger.info(`DownvoteSegmentArchiveJob starts at ${timeNow}`);
try {
Logger.info(`DownvoteSegmentArchiveJob starts at ${timeNow}`);
try {
// insert into archive sponsorTime
await db.prepare(
'run',
`INSERT INTO "archivedSponsorTimes"
"run",
`INSERT INTO "archivedSponsorTimes"
SELECT *
FROM "sponsorTimes"
WHERE "votes" < ? AND (? - "timeSubmitted") > ?`,
[
voteLimit,
timeNow,
threshold
]
[
voteLimit,
timeNow,
threshold
]
) as DBSegment[];
} catch (err) {
Logger.error('Execption when insert segment in archivedSponsorTimes');
Logger.error(err);
return 1;
}
} catch (err) {
Logger.error("Execption when insert segment in archivedSponsorTimes");
Logger.error(err);
return 1;
}
// remove from sponsorTime
try {
// remove from sponsorTime
try {
await db.prepare(
'run',
'DELETE FROM "sponsorTimes" WHERE "votes" < ? AND (? - "timeSubmitted") > ?',
[
voteLimit,
timeNow,
threshold
]
"run",
'DELETE FROM "sponsorTimes" WHERE "votes" < ? AND (? - "timeSubmitted") > ?',
[
voteLimit,
timeNow,
threshold
]
) as DBSegment[];
} catch (err) {
Logger.error('Execption when deleting segment in sponsorTimes');
Logger.error(err);
return 1;
}
} catch (err) {
Logger.error("Execption when deleting segment in sponsorTimes");
Logger.error(err);
return 1;
}
Logger.info('DownvoteSegmentArchiveJob finished');
return 0;
Logger.info("DownvoteSegmentArchiveJob finished");
return 0;
};
const DownvoteSegmentArchiveJob = new CronJob(
jobConfig?.schedule || "0 0 * * * 0",
() => archiveDownvoteSegment(jobConfig?.timeThresholdInDays, jobConfig?.voteThreshold)
jobConfig?.schedule || "0 0 * * * 0",
() => archiveDownvoteSegment(jobConfig?.timeThresholdInDays, jobConfig?.voteThreshold)
);
if (serverConfig?.crons?.enabled && jobConfig && !jobConfig.schedule) {
Logger.error("Invalid cron schedule for downvoteSegmentArchive");
Logger.error("Invalid cron schedule for downvoteSegmentArchive");
}
export default DownvoteSegmentArchiveJob;

View File

@@ -3,11 +3,11 @@ import { config } from "../config";
import DownvoteSegmentArchiveJob from "./downvoteSegmentArchiveJob";
export function startAllCrons (): void {
if (config?.crons?.enabled) {
Logger.info("Crons started");
if (config?.crons?.enabled) {
Logger.info("Crons started");
DownvoteSegmentArchiveJob.start();
} else {
Logger.info("Crons dissabled");
}
DownvoteSegmentArchiveJob.start();
} else {
Logger.info("Crons dissabled");
}
}

View File

@@ -4,4 +4,4 @@ export interface IDatabase {
prepare(type: QueryType, query: string, params?: any[]): Promise<any | any[] | void>;
}
export type QueryType = 'get' | 'all' | 'run';
export type QueryType = "get" | "all" | "run";

View File

@@ -1,8 +1,8 @@
import {Logger} from '../utils/logger';
import {IDatabase, QueryType} from './IDatabase';
import {Logger} from "../utils/logger";
import {IDatabase, QueryType} from "./IDatabase";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import MysqlInterface from 'sync-mysql';
import MysqlInterface from "sync-mysql";
export class Mysql implements IDatabase {
private connection: any;
@@ -19,17 +19,16 @@ export class Mysql implements IDatabase {
const queryResult = this.connection.query(query, params);
switch (type) {
case 'get': {
return queryResult[0];
}
case 'all': {
return queryResult;
}
case 'run': {
break;
}
case "get": {
return queryResult[0];
}
case "all": {
return queryResult;
}
case "run": {
break;
}
}
}
}

View File

@@ -1,6 +1,6 @@
import { Logger } from '../utils/logger';
import { IDatabase, QueryType } from './IDatabase';
import { Client, Pool, types } from 'pg';
import { Logger } from "../utils/logger";
import { IDatabase, QueryType } from "./IDatabase";
import { Client, Pool, types } from "pg";
import fs from "fs";
@@ -11,7 +11,7 @@ types.setTypeParser(1700, function(val) {
// return int8 (pg_type oid=20) as int
types.setTypeParser(20, function(val) {
return parseInt(val, 10);
return parseInt(val, 10);
});
export class Postgres implements IDatabase {
@@ -47,8 +47,8 @@ export class Postgres implements IDatabase {
// Convert query to use numbered parameters
let count = 1;
for (let char = 0; char < query.length; char++) {
if (query.charAt(char) === '?') {
query = query.slice(0, char) + "$" + count + query.slice(char + 1);
if (query.charAt(char) === "?") {
query = `${query.slice(0, char)}$${count}${query.slice(char + 1)}`;
count++;
}
}
@@ -58,19 +58,19 @@ export class Postgres implements IDatabase {
const queryResult = await this.pool.query({text: query, values: params});
switch (type) {
case 'get': {
const value = queryResult.rows[0];
Logger.debug(`result (postgres): ${JSON.stringify(value)}`);
return value;
}
case 'all': {
const values = queryResult.rows;
Logger.debug(`result (postgres): ${values}`);
return values;
}
case 'run': {
break;
}
case "get": {
const value = queryResult.rows[0];
Logger.debug(`result (postgres): ${JSON.stringify(value)}`);
return value;
}
case "all": {
const values = queryResult.rows;
Logger.debug(`result (postgres): ${values}`);
return values;
}
case "run": {
break;
}
}
}
@@ -81,7 +81,7 @@ export class Postgres implements IDatabase {
});
await client.connect();
if ((await client.query(`SELECT * FROM pg_database WHERE datname = '${this.config.postgres.database}'`)).rowCount == 0) {
await client.query(`CREATE DATABASE "${this.config.postgres.database}"
WITH
@@ -101,25 +101,25 @@ export class Postgres implements IDatabase {
const versionCodeInfo = await this.pool.query("SELECT value FROM config WHERE key = 'version'");
let versionCode = versionCodeInfo.rows[0] ? versionCodeInfo.rows[0].value : 0;
let path = schemaFolder + "/_upgrade_" + fileNamePrefix + "_" + (parseInt(versionCode) + 1) + ".sql";
Logger.debug('db update: trying ' + path);
let path = `${schemaFolder}/_upgrade_${fileNamePrefix}_${(parseInt(versionCode) + 1)}.sql`;
Logger.debug(`db update: trying ${path}`);
while (fs.existsSync(path)) {
Logger.debug('db update: updating ' + path);
Logger.debug(`db update: updating ${path}`);
await this.pool.query(this.processUpgradeQuery(fs.readFileSync(path).toString()));
versionCode = (await this.pool.query("SELECT value FROM config WHERE key = 'version'"))?.rows[0]?.value;
path = schemaFolder + "/_upgrade_" + fileNamePrefix + "_" + (parseInt(versionCode) + 1) + ".sql";
Logger.debug('db update: trying ' + path);
path = `${schemaFolder}/_upgrade_${fileNamePrefix}_${(parseInt(versionCode) + 1)}.sql`;
Logger.debug(`db update: trying ${path}`);
}
Logger.debug('db update: no file ' + path);
Logger.debug(`db update: no file ${path}`);
}
private async applyIndexes(fileNamePrefix: string, schemaFolder: string) {
const path = schemaFolder + "/_" + fileNamePrefix + "_indexes.sql";
const path = `${schemaFolder}/_${fileNamePrefix}_indexes.sql`;
if (fs.existsSync(path)) {
await this.pool.query(fs.readFileSync(path).toString());
} else {
Logger.debug('failed to apply indexes to ' + fileNamePrefix);
Logger.debug(`failed to apply indexes to ${fileNamePrefix}`);
}
}
@@ -131,4 +131,3 @@ export class Postgres implements IDatabase {
return result;
}
}

View File

@@ -1,9 +1,9 @@
import {IDatabase, QueryType} from './IDatabase';
import Sqlite3, {Database, Database as SQLiteDatabase} from 'better-sqlite3';
import {IDatabase, QueryType} from "./IDatabase";
import Sqlite3, {Database, Database as SQLiteDatabase} from "better-sqlite3";
import fs from "fs";
import path from "path";
import {getHash} from '../utils/getHash';
import {Logger} from '../utils/logger';
import {getHash} from "../utils/getHash";
import {Logger} from "../utils/logger";
export class Sqlite implements IDatabase {
private db: SQLiteDatabase;
@@ -17,16 +17,16 @@ export class Sqlite implements IDatabase {
const preparedQuery = this.db.prepare(query);
switch (type) {
case 'get': {
return preparedQuery.get(...params);
}
case 'all': {
return preparedQuery.all(...params);
}
case 'run': {
preparedQuery.run(...params);
break;
}
case "get": {
return preparedQuery.get(...params);
}
case "all": {
return preparedQuery.all(...params);
}
case "run": {
preparedQuery.run(...params);
break;
}
}
}
@@ -69,17 +69,17 @@ export class Sqlite implements IDatabase {
const versionCodeInfo = db.prepare("SELECT value FROM config WHERE key = ?").get("version");
let versionCode = versionCodeInfo ? versionCodeInfo.value : 0;
let path = schemaFolder + "/_upgrade_" + fileNamePrefix + "_" + (parseInt(versionCode) + 1) + ".sql";
Logger.debug('db update: trying ' + path);
let path = `${schemaFolder}/_upgrade_${fileNamePrefix}_${(parseInt(versionCode) + 1)}.sql`;
Logger.debug(`db update: trying ${path}`);
while (fs.existsSync(path)) {
Logger.debug('db update: updating ' + path);
Logger.debug(`db update: updating ${path}`);
db.exec(this.processUpgradeQuery(fs.readFileSync(path).toString()));
versionCode = db.prepare("SELECT value FROM config WHERE key = ?").get("version").value;
path = schemaFolder + "/_upgrade_" + fileNamePrefix + "_" + (parseInt(versionCode) + 1) + ".sql";
Logger.debug('db update: trying ' + path);
path = `${schemaFolder}/_upgrade_${fileNamePrefix}_${(parseInt(versionCode) + 1)}.sql`;
Logger.debug(`db update: trying ${path}`);
}
Logger.debug('db update: no file ' + path);
Logger.debug(`db update: no file ${path}`);
}
private static processUpgradeQuery(query: string): string {

View File

@@ -1,8 +1,8 @@
import {config} from '../config';
import {Sqlite} from './Sqlite';
import {Mysql} from './Mysql';
import {Postgres} from './Postgres';
import {IDatabase} from './IDatabase';
import {config} from "../config";
import {Sqlite} from "./Sqlite";
import {Mysql} from "./Mysql";
import {Postgres} from "./Postgres";
import {IDatabase} from "./IDatabase";
let db: IDatabase;
@@ -14,7 +14,7 @@ if (config.mysql) {
db = new Postgres({
dbSchemaFileName: config.dbSchema,
dbSchemaFolder: config.schemaFolder,
fileNamePrefix: 'sponsorTimes',
fileNamePrefix: "sponsorTimes",
readOnly: config.readOnly,
createDbIfNotExists: config.createDatabaseIfNotExist,
postgres: {
@@ -29,7 +29,7 @@ if (config.mysql) {
privateDB = new Postgres({
dbSchemaFileName: config.privateDBSchema,
dbSchemaFolder: config.schemaFolder,
fileNamePrefix: 'private',
fileNamePrefix: "private",
readOnly: config.readOnly,
createDbIfNotExists: config.createDatabaseIfNotExist,
postgres: {
@@ -45,7 +45,7 @@ if (config.mysql) {
dbPath: config.db,
dbSchemaFileName: config.dbSchema,
dbSchemaFolder: config.schemaFolder,
fileNamePrefix: 'sponsorTimes',
fileNamePrefix: "sponsorTimes",
readOnly: config.readOnly,
createDbIfNotExists: config.createDatabaseIfNotExist,
enableWalCheckpointNumber: !config.readOnly && config.mode === "production"
@@ -54,7 +54,7 @@ if (config.mysql) {
dbPath: config.privateDB,
dbSchemaFileName: config.privateDBSchema,
dbSchemaFolder: config.schemaFolder,
fileNamePrefix: 'private',
fileNamePrefix: "private",
readOnly: config.readOnly,
createDbIfNotExists: config.createDatabaseIfNotExist,
enableWalCheckpointNumber: false
@@ -66,7 +66,7 @@ async function initDb(): Promise<void> {
if (db instanceof Sqlite) {
// Attach private db to main db
(db as Sqlite).attachDatabase(config.privateDB, 'privateDB');
(db as Sqlite).attachDatabase(config.privateDB, "privateDB");
}
}

View File

@@ -1,5 +1,5 @@
import {config} from "./config";
import {initDb} from './databases/databases';
import {initDb} from "./databases/databases";
import {createServer} from "./app";
import {Logger} from "./utils/logger";
import {startAllCrons} from "./cronjob";
@@ -8,7 +8,7 @@ async function init() {
await initDb();
createServer(() => {
Logger.info("Server started on port " + config.port + ".");
Logger.info(`Server started on port ${config.port}.`);
// ignite cron job after server created
startAllCrons();

View File

@@ -1,4 +1,4 @@
import {NextFunction, Request, Response} from 'express';
import {NextFunction, Request, Response} from "express";
export function apiCspMiddleware(req: Request, res: Response, next: NextFunction): void {
res.header("Content-Security-Policy", "script-src 'none'; object-src 'none'");

View File

@@ -1,4 +1,4 @@
import {NextFunction, Request, Response} from 'express';
import {NextFunction, Request, Response} from "express";
export function corsMiddleware(req: Request, res: Response, next: NextFunction): void {
res.header("Access-Control-Allow-Origin", "*");

View File

@@ -1,5 +1,5 @@
import {Logger} from '../utils/logger';
import {NextFunction, Request, Response} from 'express';
import {Logger} from "../utils/logger";
import {NextFunction, Request, Response} from "express";
export function loggerMiddleware(req: Request, res: Response, next: NextFunction): void {
Logger.info(`Request received: ${req.method} ${req.url}`);

View File

@@ -1,10 +1,10 @@
import {getIP} from '../utils/getIP';
import {getHash} from '../utils/getHash';
import rateLimit from 'express-rate-limit';
import {RateLimitConfig} from '../types/config.model';
import {Request} from 'express';
import { isUserVIP } from '../utils/isUserVIP';
import { UserID } from '../types/user.model';
import {getIP} from "../utils/getIP";
import {getHash} from "../utils/getHash";
import rateLimit from "express-rate-limit";
import {RateLimitConfig} from "../types/config.model";
import {Request} from "express";
import { isUserVIP } from "../utils/isUserVIP";
import { UserID } from "../types/user.model";
export function rateLimitMiddleware(limitConfig: RateLimitConfig, getUserID?: (req: Request) => UserID): rateLimit.RateLimit {
return rateLimit({

View File

@@ -1,13 +1,13 @@
import fetch from 'node-fetch';
import {Logger} from '../utils/logger';
import {config} from '../config';
import {getIP} from '../utils/getIP';
import {getHash} from '../utils/getHash';
import {NextFunction, Request, Response} from 'express';
import fetch from "node-fetch";
import {Logger} from "../utils/logger";
import {config} from "../config";
import {getIP} from "../utils/getIP";
import {getHash} from "../utils/getHash";
import {NextFunction, Request, Response} from "express";
export function userCounter(req: Request, res: Response, next: NextFunction): void {
fetch(config.userCounterURL + "/api/v1/addIP?hashedIP=" + getHash(getIP(req), 1), {method: "POST"})
.catch(() => Logger.debug("Failing to connect to user counter at: " + config.userCounterURL));
fetch(`${config.userCounterURL}/api/v1/addIP?hashedIP=${getHash(getIP(req), 1)}`, {method: "POST"})
.catch(() => Logger.debug(`Failing to connect to user counter at: ${config.userCounterURL}`));
next();
}

View File

@@ -1,11 +1,11 @@
import {Request, Response} from 'express';
import { db } from '../databases/databases';
import { Logger } from '../utils/logger';
import {Request, Response} from "express";
import { db } from "../databases/databases";
import { Logger } from "../utils/logger";
/**
* Optional API method that will be used temporarily to help collect
* unlisted videos created before 2017
*
*
* https://support.google.com/youtube/answer/9230970
*/
@@ -21,7 +21,7 @@ export function addUnlistedVideo(req: Request, res: Response): Response {
try {
const timeSubmitted = Date.now();
db.prepare('run', `INSERT INTO "unlistedVideos" ("videoID", "year", "views", "channelID", "timeSubmitted") values (?, ?, ?, ?, ?)`, [videoID, year, views, channelID, timeSubmitted]);
db.prepare("run", `INSERT INTO "unlistedVideos" ("videoID", "year", "views", "channelID", "timeSubmitted") values (?, ?, ?, ?, ?)`, [videoID, year, views, channelID, timeSubmitted]);
} catch (err) {
Logger.error(err);
return res.sendStatus(500);

View File

@@ -1,7 +1,7 @@
import {getHash} from '../utils/getHash';
import {db} from '../databases/databases';
import {config} from '../config';
import {Request, Response} from 'express';
import {getHash} from "../utils/getHash";
import {db} from "../databases/databases";
import {config} from "../config";
import {Request, Response} from "express";
export async function addUserAsVIP(req: Request, res: Response): Promise<Response> {
const userID = req.query.userID as string;
@@ -9,7 +9,7 @@ export async function addUserAsVIP(req: Request, res: Response): Promise<Respons
const enabled = req.query.enabled === undefined
? false
: req.query.enabled === 'true';
: req.query.enabled === "true";
if (userID == undefined || adminUserIDInput == undefined) {
//invalid request
@@ -25,14 +25,14 @@ export async function addUserAsVIP(req: Request, res: Response): Promise<Respons
}
//check to see if this user is already a vip
const row = await db.prepare('get', 'SELECT count(*) as "userCount" FROM "vipUsers" WHERE "userID" = ?', [userID]);
const row = await db.prepare("get", 'SELECT count(*) as "userCount" FROM "vipUsers" WHERE "userID" = ?', [userID]);
if (enabled && row.userCount == 0) {
//add them to the vip list
await db.prepare('run', 'INSERT INTO "vipUsers" VALUES(?)', [userID]);
await db.prepare("run", 'INSERT INTO "vipUsers" VALUES(?)', [userID]);
} else if (!enabled && row.userCount > 0) {
//remove them from the shadow ban list
await db.prepare('run', 'DELETE FROM "vipUsers" WHERE "userID" = ?', [userID]);
await db.prepare("run", 'DELETE FROM "vipUsers" WHERE "userID" = ?', [userID]);
}
return res.sendStatus(200);

View File

@@ -1,9 +1,9 @@
import {Request, Response} from 'express';
import {isUserVIP} from '../utils/isUserVIP';
import {getHash} from '../utils/getHash';
import {db} from '../databases/databases';
import { Category, VideoID } from '../types/segments.model';
import { UserID } from '../types/user.model';
import {Request, Response} from "express";
import {isUserVIP} from "../utils/isUserVIP";
import {getHash} from "../utils/getHash";
import {db} from "../databases/databases";
import { Category, VideoID } from "../types/segments.model";
import { UserID } from "../types/user.model";
export async function deleteLockCategoriesEndpoint(req: Request, res: Response): Promise<Response> {
// Collect user input data
@@ -19,7 +19,7 @@ export async function deleteLockCategoriesEndpoint(req: Request, res: Response):
|| categories.length === 0
) {
return res.status(400).json({
message: 'Bad Format',
message: "Bad Format",
});
}
@@ -29,18 +29,18 @@ export async function deleteLockCategoriesEndpoint(req: Request, res: Response):
if (!userIsVIP) {
return res.status(403).json({
message: 'Must be a VIP to mark videos.',
message: "Must be a VIP to mark videos.",
});
}
await deleteLockCategories(videoID, categories);
await deleteLockCategories(videoID, categories);
return res.status(200).json({message: 'Removed lock categories entrys for video ' + videoID});
return res.status(200).json({message: `Removed lock categories entrys for video ${videoID}`});
}
/**
*
* @param videoID
*
* @param videoID
* @param categories If null, will remove all
*/
export async function deleteLockCategories(videoID: VideoID, categories: Category[]): Promise<void> {
@@ -49,6 +49,6 @@ export async function deleteLockCategories(videoID: VideoID, categories: Categor
});
for (const entry of entries) {
await db.prepare('run', 'DELETE FROM "lockCategories" WHERE "videoID" = ? AND "category" = ?', [videoID, entry.category]);
await db.prepare("run", 'DELETE FROM "lockCategories" WHERE "videoID" = ? AND "category" = ?', [videoID, entry.category]);
}
}

View File

@@ -1,10 +1,10 @@
import {db} from '../databases/databases';
import {Logger} from '../utils/logger';
import {Request, Response} from 'express';
import { config } from '../config';
import util from 'util';
import fs from 'fs';
import path from 'path';
import {db} from "../databases/databases";
import {Logger} from "../utils/logger";
import {Request, Response} from "express";
import { config } from "../config";
import util from "util";
import fs from "fs";
import path from "path";
const unlink = util.promisify(fs.unlink);
const ONE_MINUTE = 1000 * 60;
@@ -31,8 +31,8 @@ const licenseHeader = `<p>The API and database follow <a href="https://creativec
const tables = config?.dumpDatabase?.tables ?? [];
const MILLISECONDS_BETWEEN_DUMPS = config?.dumpDatabase?.minTimeBetweenMs ?? ONE_MINUTE;
const appExportPath = config?.dumpDatabase?.appExportPath ?? './docker/database-export';
const postgresExportPath = config?.dumpDatabase?.postgresExportPath ?? '/opt/exports';
const appExportPath = config?.dumpDatabase?.appExportPath ?? "./docker/database-export";
const postgresExportPath = config?.dumpDatabase?.postgresExportPath ?? "/opt/exports";
const tableNames = tables.map(table => table.name);
interface TableDumpList {
@@ -47,7 +47,7 @@ interface TableFile {
}
if (tables.length === 0) {
Logger.warn('[dumpDatabase] No tables configured');
Logger.warn("[dumpDatabase] No tables configured");
}
let lastUpdate = 0;
@@ -71,7 +71,7 @@ function removeOutdatedDumps(exportPath: string): Promise<void> {
files.forEach(file => {
// we only care about files that start with "<tablename>_" and ends with .csv
tableNames.forEach(tableName => {
if (file.startsWith(`${tableName}`) && file.endsWith('.csv')) {
if (file.startsWith(`${tableName}`) && file.endsWith(".csv")) {
const filePath = path.join(exportPath, file);
tableFiles[tableName].push({
file: filePath,
@@ -108,7 +108,7 @@ export default async function dumpDatabase(req: Request, res: Response, showPage
updateQueueTime();
res.status(200);
if (showPage) {
res.send(`${styleHeader}
<h1>SponsorBlock database dumps</h1>${licenseHeader}
@@ -127,16 +127,16 @@ export default async function dumpDatabase(req: Request, res: Response, showPage
</tr>
</thead>
<tbody>
${latestDumpFiles.map((item:any) => {
return `
<tr>
<td>${item.tableName}</td>
<td><a href="/database/${item.tableName}.csv">${item.tableName}.csv</a></td>
</tr>
`;
}).join('')}
${latestDumpFiles.length === 0 ? '<tr><td colspan="2">Please wait: Generating files</td></tr>' : ''}
</tbody>
${latestDumpFiles.map((item:any) => {
return `
<tr>
<td>${item.tableName}</td>
<td><a href="/database/${item.tableName}.csv">${item.tableName}.csv</a></td>
</tr>
`;
}).join("")}
${latestDumpFiles.length === 0 ? '<tr><td colspan="2">Please wait: Generating files</td></tr>' : ""}
</tbody>
</table>
<hr/>
${updateQueued ? `Update queued.` : ``} Last updated: ${lastUpdate ? new Date(lastUpdate).toUTCString() : `Unknown`}`);
@@ -159,7 +159,7 @@ export default async function dumpDatabase(req: Request, res: Response, showPage
}
async function getDbVersion(): Promise<number> {
const row = await db.prepare('get', `SELECT "value" FROM "config" WHERE "key" = 'version'`);
const row = await db.prepare("get", `SELECT "value" FROM "config" WHERE "key" = 'version'`);
if (row === undefined) return 0;
return row.value;
}
@@ -173,13 +173,13 @@ export async function redirectLink(req: Request, res: Response): Promise<void> {
res.status(404).send("Not supported on this instance");
return;
}
const file = latestDumpFiles.find((value) => `/database/${value.tableName}.csv` === req.path);
updateQueueTime();
if (file) {
res.redirect("/download/" + file.fileName);
res.redirect(`/download/${file.fileName}`);
} else {
res.sendStatus(404);
}
@@ -198,13 +198,13 @@ async function queueDump(): Promise<void> {
try {
await removeOutdatedDumps(appExportPath);
const dumpFiles = [];
for (const table of tables) {
const fileName = `${table.name}_${startTime}.csv`;
const file = `${postgresExportPath}/${fileName}`;
await db.prepare('run', `COPY (SELECT * FROM "${table.name}"${table.order ? ` ORDER BY "${table.order}"` : ``})
await db.prepare("run", `COPY (SELECT * FROM "${table.name}"${table.order ? ` ORDER BY "${table.order}"` : ``})
TO '${file}' WITH (FORMAT CSV, HEADER true);`);
dumpFiles.push({
fileName,

View File

@@ -1,8 +1,8 @@
import {db} from '../databases/databases';
import {Request, Response} from 'express';
import {db} from "../databases/databases";
import {Request, Response} from "express";
export async function getDaysSavedFormatted(req: Request, res: Response): Promise<Response> {
const row = await db.prepare('get', 'SELECT SUM(("endTime" - "startTime") / 60 / 60 / 24 * "views") as "daysSaved" from "sponsorTimes" where "shadowHidden" != 1', []);
const row = await db.prepare("get", 'SELECT SUM(("endTime" - "startTime") / 60 / 60 / 24 * "views") as "daysSaved" from "sponsorTimes" where "shadowHidden" != 1', []);
if (row !== undefined) {
//send this result

View File

@@ -1,8 +1,8 @@
import {Logger} from '../utils/logger';
import {getHash} from '../utils/getHash';
import {isUserVIP} from '../utils/isUserVIP';
import {Request, Response} from 'express';
import { HashedUserID, UserID } from '../types/user.model';
import {Logger} from "../utils/logger";
import {getHash} from "../utils/getHash";
import {isUserVIP} from "../utils/isUserVIP";
import {Request, Response} from "express";
import { HashedUserID, UserID } from "../types/user.model";
export async function getIsUserVIP(req: Request, res: Response): Promise<Response> {
const userID = req.query.userID as UserID;

View File

@@ -1,6 +1,6 @@
import {db} from '../databases/databases';
import {Logger} from '../utils/logger';
import {Request, Response} from 'express';
import {db} from "../databases/databases";
import {Logger} from "../utils/logger";
import {Request, Response} from "express";
import { Category, VideoID } from "../types/segments.model";
export async function getLockCategories(req: Request, res: Response): Promise<Response> {
@@ -13,13 +13,13 @@ export async function getLockCategories(req: Request, res: Response): Promise<Re
try {
// Get existing lock categories markers
const row = await db.prepare('all', 'SELECT "category", "reason" from "lockCategories" where "videoID" = ?', [videoID]) as {category: Category, reason: string}[];
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);
.reduce((a,b) => (a.length > b.length) ? a : b);
return res.send({
reason,
categories

View File

@@ -1,7 +1,7 @@
import {db} from '../databases/databases';
import {Logger} from '../utils/logger';
import {Request, Response} from 'express';
import {hashPrefixTester} from '../utils/hashPrefixTester';
import {db} from "../databases/databases";
import {Logger} from "../utils/logger";
import {Request, Response} from "express";
import {hashPrefixTester} from "../utils/hashPrefixTester";
import { Category, VideoID, VideoIDHash } from "../types/segments.model";
interface LockResultByHash {
@@ -25,7 +25,7 @@ const mergeLocks = (source: DBLock[]) => {
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;
if (obj.reason?.length > destMatch.reason?.length) destMatch.reason = obj.reason;
// push to categories
destMatch.categories.push(obj.category);
} else {
@@ -40,7 +40,6 @@ const mergeLocks = (source: DBLock[]) => {
return dest;
};
export async function getLockCategoriesByHash(req: Request, res: Response): Promise<Response> {
let hashPrefix = req.params.prefix as VideoIDHash;
if (!hashPrefixTester(req.params.prefix)) {
@@ -50,7 +49,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", "reason" 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));

View File

@@ -1,8 +1,8 @@
import {db} from '../databases/databases';
import {Request, Response} from 'express';
import {getHash} from '../utils/getHash';
import {config} from '../config';
import { Logger } from '../utils/logger';
import {db} from "../databases/databases";
import {Request, Response} from "express";
import {getHash} from "../utils/getHash";
import {config} from "../config";
import { Logger } from "../utils/logger";
const maxRewardTimePerSegmentInSeconds = config.maxRewardTimePerSegmentInSeconds ?? 86400;
@@ -28,7 +28,7 @@ export async function getSavedTimeForUser(req: Request, res: Response): Promise<
return res.sendStatus(404);
}
} catch (err) {
Logger.error("getSavedTimeForUser " + err);
Logger.error(`getSavedTimeForUser ${err}`);
return res.sendStatus(500);
}
}

View File

@@ -1,12 +1,12 @@
import { Request, Response } from 'express';
import { db } from '../databases/databases';
import { Request, Response } from "express";
import { db } from "../databases/databases";
import { DBSegment, SegmentUUID } from "../types/segments.model";
const isValidSegmentUUID = (str: string): boolean => /^([a-f0-9]{64}|[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/.test(str);
async function getSegmentFromDBByUUID(UUID: SegmentUUID): Promise<DBSegment> {
try {
return await db.prepare('get',
return await db.prepare("get",
`SELECT "videoID", "startTime", "endTime", "votes", "locked",
"UUID", "userID", "timeSubmitted", "views", "category",
"service", "videoDuration", "hidden", "reputation", "shadowHidden" FROM "sponsorTimes"

View File

@@ -1,15 +1,15 @@
import { Request, Response } from 'express';
import { config } from '../config';
import { db, privateDB } from '../databases/databases';
import { skipSegmentsHashKey, skipSegmentsKey } from '../utils/redisKeys';
import { SBRecord } from '../types/lib.model';
import { Request, Response } from "express";
import { config } from "../config";
import { db, privateDB } from "../databases/databases";
import { skipSegmentsHashKey, skipSegmentsKey } from "../utils/redisKeys";
import { SBRecord } from "../types/lib.model";
import { ActionType, Category, CategoryActionType, DBSegment, HashedIP, IPAddress, OverlappingSegmentGroup, Segment, SegmentCache, SegmentUUID, Service, VideoData, VideoID, VideoIDHash, Visibility, VotableObject } from "../types/segments.model";
import { getCategoryActionType } from '../utils/categoryInfo';
import { getHash } from '../utils/getHash';
import { getIP } from '../utils/getIP';
import { Logger } from '../utils/logger';
import { QueryCacher } from '../utils/queryCacher';
import { getReputation } from '../utils/reputation';
import { getCategoryActionType } from "../utils/categoryInfo";
import { getHash } from "../utils/getHash";
import { getIP } from "../utils/getIP";
import { Logger } from "../utils/logger";
import { QueryCacher } from "../utils/queryCacher";
import { getReputation } from "../utils/reputation";
async function prepareCategorySegments(req: Request, videoID: VideoID, category: Category, segments: DBSegment[],cache: SegmentCache = {shadowHiddenSegmentIPs: {}}): Promise<Segment[]> {
@@ -25,7 +25,7 @@ async function prepareCategorySegments(req: Request, videoID: VideoID, category:
}
if (cache.shadowHiddenSegmentIPs[videoID] === undefined) {
cache.shadowHiddenSegmentIPs[videoID] = await privateDB.prepare('all', 'SELECT "hashedIP" FROM "sponsorTimes" WHERE "videoID" = ?', [videoID]) as { hashedIP: HashedIP }[];
cache.shadowHiddenSegmentIPs[videoID] = await privateDB.prepare("all", 'SELECT "hashedIP" FROM "sponsorTimes" WHERE "videoID" = ?', [videoID]) as { hashedIP: HashedIP }[];
}
//if this isn't their ip, don't send it to them
@@ -38,7 +38,7 @@ async function prepareCategorySegments(req: Request, videoID: VideoID, category:
return shadowHiddenSegment.hashedIP === cache.userHashedIP;
});
}));
const filteredSegments = segments.filter((_, index) => shouldFilter[index]);
const maxSegments = getCategoryActionType(category) === CategoryActionType.Skippable ? 32 : 1;
@@ -51,8 +51,8 @@ async function prepareCategorySegments(req: Request, videoID: VideoID, category:
}));
}
async function getSegmentsByVideoID(req: Request, videoID: VideoID, categories: Category[],
actionTypes: ActionType[], requiredSegments: SegmentUUID[], service: Service): Promise<Segment[]> {
async function getSegmentsByVideoID(req: Request, videoID: VideoID, categories: Category[],
actionTypes: ActionType[], requiredSegments: SegmentUUID[], service: Service): Promise<Segment[]> {
const cache: SegmentCache = {shadowHiddenSegmentIPs: {}};
const segments: Segment[] = [];
@@ -84,8 +84,8 @@ async function getSegmentsByVideoID(req: Request, videoID: VideoID, categories:
}
}
async function getSegmentsByHash(req: Request, hashedVideoIDPrefix: VideoIDHash, categories: Category[],
actionTypes: ActionType[], requiredSegments: SegmentUUID[], service: Service): Promise<SBRecord<VideoID, VideoData>> {
async function getSegmentsByHash(req: Request, hashedVideoIDPrefix: VideoIDHash, categories: Category[],
actionTypes: ActionType[], requiredSegments: SegmentUUID[], service: Service): Promise<SBRecord<VideoID, VideoData>> {
const cache: SegmentCache = {shadowHiddenSegmentIPs: {}};
const segments: SBRecord<VideoID, VideoData> = {};
@@ -133,10 +133,10 @@ async function getSegmentsByHash(req: Request, hashedVideoIDPrefix: VideoIDHash,
async function getSegmentsFromDBByHash(hashedVideoIDPrefix: VideoIDHash, service: Service): Promise<DBSegment[]> {
const fetchFromDB = () => db
.prepare(
'all',
"all",
`SELECT "videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "category", "actionType", "videoDuration", "reputation", "shadowHidden", "hashedVideoID" FROM "sponsorTimes"
WHERE "hashedVideoID" LIKE ? AND "service" = ? AND "hidden" = 0 ORDER BY "startTime"`,
[hashedVideoIDPrefix + '%', service]
[`${hashedVideoIDPrefix}%`, service]
) as Promise<DBSegment[]>;
if (hashedVideoIDPrefix.length === 4) {
@@ -149,7 +149,7 @@ async function getSegmentsFromDBByHash(hashedVideoIDPrefix: VideoIDHash, service
async function getSegmentsFromDBByVideoID(videoID: VideoID, service: Service): Promise<DBSegment[]> {
const fetchFromDB = () => db
.prepare(
'all',
"all",
`SELECT "startTime", "endTime", "votes", "locked", "UUID", "userID", "category", "actionType", "videoDuration", "reputation", "shadowHidden" FROM "sponsorTimes"
WHERE "videoID" = ? AND "service" = ? AND "hidden" = 0 ORDER BY "startTime"`,
[videoID, service]
@@ -287,7 +287,7 @@ async function handleGetSegments(req: Request, res: Response): Promise<Segment[]
? Array.isArray(req.query.category)
? req.query.category
: [req.query.category]
: ['sponsor'];
: ["sponsor"];
if (!Array.isArray(categories)) {
res.status(400).send("Categories parameter does not match format requirements.");
return false;
@@ -316,7 +316,7 @@ async function handleGetSegments(req: Request, res: Response): Promise<Segment[]
res.status(400).send("requiredSegments parameter does not match format requirements.");
return false;
}
let service: Service = req.query.service ?? req.body.service ?? Service.YouTube;
if (!Object.values(Service).some((val) => val == service)) {
service = Service.YouTube;
@@ -359,4 +359,3 @@ export {
endpoint,
handleGetSegments
};

View File

@@ -1,7 +1,7 @@
import {hashPrefixTester} from '../utils/hashPrefixTester';
import {getSegmentsByHash} from './getSkipSegments';
import {Request, Response} from 'express';
import { ActionType, Category, SegmentUUID, Service, VideoIDHash } from '../types/segments.model';
import {hashPrefixTester} from "../utils/hashPrefixTester";
import {getSegmentsByHash} from "./getSkipSegments";
import {Request, Response} from "express";
import { ActionType, Category, SegmentUUID, Service, VideoIDHash } from "../types/segments.model";
export async function getSkipSegmentsByHash(req: Request, res: Response): Promise<Response> {
let hashPrefix = req.params.prefix as VideoIDHash;
@@ -18,7 +18,7 @@ export async function getSkipSegmentsByHash(req: Request, res: Response): Promis
? Array.isArray(req.query.category)
? req.query.category
: [req.query.category]
: ['sponsor'];
: ["sponsor"];
if (!Array.isArray(categories)) {
return res.status(400).send("Categories parameter does not match format requirements.");
}
@@ -45,12 +45,12 @@ export async function getSkipSegmentsByHash(req: Request, res: Response): Promis
let requiredSegments: SegmentUUID[] = [];
try {
requiredSegments = req.query.requiredSegments
? JSON.parse(req.query.requiredSegments as string)
: req.query.requiredSegment
? Array.isArray(req.query.requiredSegment)
? req.query.requiredSegment
: [req.query.requiredSegment]
: [];
? JSON.parse(req.query.requiredSegments as string)
: req.query.requiredSegment
? Array.isArray(req.query.requiredSegment)
? req.query.requiredSegment
: [req.query.requiredSegment]
: [];
if (!Array.isArray(requiredSegments)) {
return res.status(400).send("requiredSegments parameter does not match format requirements.");
}
@@ -62,7 +62,7 @@ export async function getSkipSegmentsByHash(req: Request, res: Response): Promis
if (!Object.values(Service).some((val) => val == service)) {
service = Service.YouTube;
}
// filter out none string elements, only flat array with strings is valid
categories = categories.filter((item: any) => typeof item === "string");

View File

@@ -1,7 +1,7 @@
import {db} from '../databases/databases';
import {createMemoryCache} from '../utils/createMemoryCache';
import {config} from '../config';
import {Request, Response} from 'express';
import {db} from "../databases/databases";
import {createMemoryCache} from "../utils/createMemoryCache";
import {config} from "../config";
import {Request, Response} from "express";
const MILLISECONDS_IN_MINUTE = 60000;
const getTopUsersWithCache = createMemoryCache(generateTopUsersStats, config.getTopUsersCacheTimeMinutes * MILLISECONDS_IN_MINUTE);
@@ -14,7 +14,7 @@ async function generateTopUsersStats(sortBy: string, categoryStatsEnabled = fals
const minutesSaved = [];
const categoryStats: any[] = categoryStatsEnabled ? [] : undefined;
let additionalFields = '';
let additionalFields = "";
if (categoryStatsEnabled) {
additionalFields += `SUM(CASE WHEN category = 'sponsor' THEN 1 ELSE 0 END) as "categorySponsor",
SUM(CASE WHEN category = 'intro' THEN 1 ELSE 0 END) as "categorySumIntro",
@@ -25,11 +25,9 @@ async function generateTopUsersStats(sortBy: string, categoryStatsEnabled = fals
SUM(CASE WHEN category = 'preview' THEN 1 ELSE 0 END) as "categorySumPreview", `;
}
const rows = await db.prepare('all', `SELECT COUNT(*) as "totalSubmissions", SUM(views) as "viewCount",
const rows = await db.prepare("all", `SELECT COUNT(*) as "totalSubmissions", SUM(views) as "viewCount",
SUM(((CASE WHEN "sponsorTimes"."endTime" - "sponsorTimes"."startTime" > ? THEN ? ELSE "sponsorTimes"."endTime" - "sponsorTimes"."startTime" END) / 60) * "sponsorTimes"."views") as "minutesSaved",
SUM("votes") as "userVotes", ` +
additionalFields +
`COALESCE("userNames"."userName", "sponsorTimes"."userID") as "userName" FROM "sponsorTimes" LEFT JOIN "userNames" ON "sponsorTimes"."userID"="userNames"."userID"
SUM("votes") as "userVotes", ${additionalFields} COALESCE("userNames"."userName", "sponsorTimes"."userID") as "userName" FROM "sponsorTimes" LEFT JOIN "userNames" ON "sponsorTimes"."userID"="userNames"."userID"
LEFT JOIN "shadowBannedUsers" ON "sponsorTimes"."userID"="shadowBannedUsers"."userID"
WHERE "sponsorTimes"."votes" > -1 AND "sponsorTimes"."shadowHidden" != 1 AND "shadowBannedUsers"."userID" IS NULL
GROUP BY COALESCE("userName", "sponsorTimes"."userID") HAVING SUM("votes") > 20
@@ -73,13 +71,13 @@ export async function getTopUsers(req: Request, res: Response): Promise<Response
}
//setup which sort type to use
let sortBy = '';
let sortBy = "";
if (sortType == 0) {
sortBy = 'minutesSaved';
sortBy = "minutesSaved";
} else if (sortType == 1) {
sortBy = 'viewCount';
sortBy = "viewCount";
} else if (sortType == 2) {
sortBy = 'totalSubmissions';
sortBy = "totalSubmissions";
} else {
//invalid request
return res.sendStatus(400);

View File

@@ -1,8 +1,8 @@
import {db} from '../databases/databases';
import {config} from '../config';
import {Request, Response} from 'express';
import fetch from 'node-fetch';
import {Logger} from '../utils/logger';
import {db} from "../databases/databases";
import {config} from "../config";
import {Request, Response} from "express";
import fetch from "node-fetch";
import {Logger} from "../utils/logger";
// A cache of the number of chrome web store users
let chromeUsersCache = 0;
@@ -16,7 +16,7 @@ let lastUserCountCheck = 0;
export async function getTotalStats(req: Request, res: Response): Promise<void> {
const userCountQuery = `(SELECT COUNT(*) FROM (SELECT DISTINCT "userID" from "sponsorTimes") t) "userCount",`;
const row = await db.prepare('get', `SELECT ${req.query.countContributingUsers ? userCountQuery : ""} COUNT(*) as "totalSubmissions",
const row = await db.prepare("get", `SELECT ${req.query.countContributingUsers ? userCountQuery : ""} COUNT(*) as "totalSubmissions",
SUM("views") as "viewCount", SUM(("endTime" - "startTime") / 60 * "views") as "minutesSaved" FROM "sponsorTimes" WHERE "shadowHidden" != 1 AND "votes" >= 0`, []);
if (row !== undefined) {
@@ -44,42 +44,41 @@ export async function getTotalStats(req: Request, res: Response): Promise<void>
function updateExtensionUsers() {
if (config.userCounterURL) {
fetch(config.userCounterURL + "/api/v1/userCount")
.then(res => res.json())
.then(data => {
apiUsersCache = Math.max(apiUsersCache, data.userCount);
})
.catch(() => Logger.debug("Failing to connect to user counter at: " + config.userCounterURL));
fetch(`${config.userCounterURL}/api/v1/userCount`)
.then(res => res.json())
.then(data => {
apiUsersCache = Math.max(apiUsersCache, data.userCount);
})
.catch(() => Logger.debug(`Failing to connect to user counter at: ${config.userCounterURL}`));
}
const mozillaAddonsUrl = "https://addons.mozilla.org/api/v3/addons/addon/sponsorblock/";
const chromeExtensionUrl = "https://chrome.google.com/webstore/detail/sponsorblock-for-youtube/mnjggcdmjocbbbhaepdhchncahnbgone";
fetch(mozillaAddonsUrl)
.then(res => res.json())
.then(data => {
firefoxUsersCache = data.average_daily_users;
fetch(chromeExtensionUrl)
.then(res => res.text())
.then(body => {
// 2021-01-05
// [...]<span><meta itemprop="interactionCount" content="UserDownloads:100.000+"/><meta itemprop="opera[...]
const matchingString = '"UserDownloads:';
const matchingStringLen = matchingString.length;
const userDownloadsStartIndex = body.indexOf(matchingString);
if (userDownloadsStartIndex >= 0) {
const closingQuoteIndex = body.indexOf('"', userDownloadsStartIndex + matchingStringLen);
const userDownloadsStr = body.substr(userDownloadsStartIndex + matchingStringLen, closingQuoteIndex - userDownloadsStartIndex).replace(',','').replace('.','');
chromeUsersCache = parseInt(userDownloadsStr);
}
else {
lastUserCountCheck = 0;
}
.then(res => res.json())
.then(data => {
firefoxUsersCache = data.average_daily_users;
fetch(chromeExtensionUrl)
.then(res => res.text())
.then(body => {
// 2021-01-05
// [...]<span><meta itemprop="interactionCount" content="UserDownloads:100.000+"/><meta itemprop="opera[...]
const matchingString = '"UserDownloads:';
const matchingStringLen = matchingString.length;
const userDownloadsStartIndex = body.indexOf(matchingString);
if (userDownloadsStartIndex >= 0) {
const closingQuoteIndex = body.indexOf('"', userDownloadsStartIndex + matchingStringLen);
const userDownloadsStr = body.substr(userDownloadsStartIndex + matchingStringLen, closingQuoteIndex - userDownloadsStartIndex).replace(",","").replace(".","");
chromeUsersCache = parseInt(userDownloadsStr);
}
else {
lastUserCountCheck = 0;
}
})
.catch(() => Logger.debug(`Failing to connect to ${chromeExtensionUrl}`));
})
.catch(() => Logger.debug("Failing to connect to " + chromeExtensionUrl));
})
.catch(() => {
Logger.debug("Failing to connect to " + mozillaAddonsUrl);
});
.catch(() => {
Logger.debug(`Failing to connect to ${mozillaAddonsUrl}`);
});
}

View File

@@ -1,16 +1,16 @@
import {db} from '../databases/databases';
import {Request, Response} from 'express';
import {UserID} from '../types/user.model';
import {db} from "../databases/databases";
import {Request, Response} from "express";
import {UserID} from "../types/user.model";
function getFuzzyUserID(userName: string): Promise<{userName: string, userID: UserID }[]> {
// escape [_ % \] to avoid ReDOS
userName = userName.replace(/\\/g, '\\\\')
.replace(/_/g, '\\_')
.replace(/%/g, '\\%');
userName = userName.replace(/\\/g, "\\\\")
.replace(/_/g, "\\_")
.replace(/%/g, "\\%");
userName = `%${userName}%`; // add wildcard to username
// LIMIT to reduce overhead | ESCAPE to escape LIKE wildcards
try {
return db.prepare('all', `SELECT "userName", "userID" FROM "userNames" WHERE "userName"
return db.prepare("all", `SELECT "userName", "userID" FROM "userNames" WHERE "userName"
LIKE ? ESCAPE '\\' LIMIT 10`, [userName]);
} catch (err) {
return null;
@@ -19,7 +19,7 @@ function getFuzzyUserID(userName: string): Promise<{userName: string, userID: Us
function getExactUserID(userName: string): Promise<{userName: string, userID: UserID }[]> {
try {
return db.prepare('all', `SELECT "userName", "userID" from "userNames" WHERE "userName" = ? LIMIT 10`, [userName]);
return db.prepare("all", `SELECT "userName", "userID" from "userNames" WHERE "userName" = ? LIMIT 10`, [userName]);
} catch (err) {
return null;
}
@@ -30,7 +30,7 @@ export async function getUserID(req: Request, res: Response): Promise<Response>
const exactSearch = req.query.exact
? req.query.exact == "true"
: false as boolean;
// if not exact and length is 1, also skip
if (userName == undefined || userName.length > 64 ||
(!exactSearch && userName.length < 3)) {

View File

@@ -1,10 +1,10 @@
import {db} from '../databases/databases';
import {getHash} from '../utils/getHash';
import {isUserVIP} from '../utils/isUserVIP';
import {Request, Response} from 'express';
import {Logger} from '../utils/logger';
import { HashedUserID, UserID } from '../types/user.model';
import { getReputation } from '../utils/reputation';
import {db} from "../databases/databases";
import {getHash} from "../utils/getHash";
import {isUserVIP} from "../utils/isUserVIP";
import {Request, Response} from "express";
import {Logger} from "../utils/logger";
import { HashedUserID, UserID } from "../types/user.model";
import { getReputation } from "../utils/reputation";
import { SegmentUUID } from "../types/segments.model";
async function dbGetSubmittedSegmentSummary(userID: HashedUserID): Promise<{ minutesSaved: number, segmentCount: number }> {
@@ -39,7 +39,7 @@ async function dbGetIgnoredSegmentCount(userID: HashedUserID): Promise<number> {
async function dbGetUsername(userID: HashedUserID) {
try {
const row = await db.prepare('get', `SELECT "userName" FROM "userNames" WHERE "userID" = ?`, [userID]);
const row = await db.prepare("get", `SELECT "userName" FROM "userNames" WHERE "userID" = ?`, [userID]);
if (row !== undefined) {
return row.userName;
} else {
@@ -53,7 +53,7 @@ async function dbGetUsername(userID: HashedUserID) {
async function dbGetViewsForUser(userID: HashedUserID) {
try {
const row = await db.prepare('get', `SELECT SUM("views") as "viewCount" FROM "sponsorTimes" WHERE "userID" = ? AND "votes" > -2 AND "shadowHidden" != 1`, [userID]);
const row = await db.prepare("get", `SELECT SUM("views") as "viewCount" FROM "sponsorTimes" WHERE "userID" = ? AND "votes" > -2 AND "shadowHidden" != 1`, [userID]);
return row?.viewCount ?? 0;
} catch (err) {
return false;
@@ -62,7 +62,7 @@ async function dbGetViewsForUser(userID: HashedUserID) {
async function dbGetIgnoredViewsForUser(userID: HashedUserID) {
try {
const row = await db.prepare('get', `SELECT SUM("views") as "ignoredViewCount" FROM "sponsorTimes" WHERE "userID" = ? AND ( "votes" <= -2 OR "shadowHidden" = 1 )`, [userID]);
const row = await db.prepare("get", `SELECT SUM("views") as "ignoredViewCount" FROM "sponsorTimes" WHERE "userID" = ? AND ( "votes" <= -2 OR "shadowHidden" = 1 )`, [userID]);
return row?.ignoredViewCount ?? 0;
} catch (err) {
return false;
@@ -71,17 +71,17 @@ async function dbGetIgnoredViewsForUser(userID: HashedUserID) {
async function dbGetWarningsForUser(userID: HashedUserID): Promise<number> {
try {
const row = await db.prepare('get', `SELECT COUNT(*) as total FROM "warnings" WHERE "userID" = ? AND "enabled" = 1`, [userID]);
const row = await db.prepare("get", `SELECT COUNT(*) as total FROM "warnings" WHERE "userID" = ? AND "enabled" = 1`, [userID]);
return row?.total ?? 0;
} catch (err) {
Logger.error('Couldn\'t get warnings for user ' + userID + '. returning 0');
Logger.error(`Couldn't get warnings for user ${userID}. returning 0`);
return 0;
}
}
async function dbGetLastSegmentForUser(userID: HashedUserID): Promise<SegmentUUID> {
try {
const row = await db.prepare('get', `SELECT "UUID" FROM "sponsorTimes" WHERE "userID" = ? ORDER BY "timeSubmitted" DESC LIMIT 1`, [userID]);
const row = await db.prepare("get", `SELECT "UUID" FROM "sponsorTimes" WHERE "userID" = ? ORDER BY "timeSubmitted" DESC LIMIT 1`, [userID]);
return row?.UUID ?? null;
} catch (err) {
return null;
@@ -90,24 +90,24 @@ async function dbGetLastSegmentForUser(userID: HashedUserID): Promise<SegmentUUI
async function dbGetActiveWarningReasonForUser(userID: HashedUserID): Promise<string> {
try {
const row = await db.prepare('get', `SELECT reason FROM "warnings" WHERE "userID" = ? AND "enabled" = 1 ORDER BY "issueTime" DESC LIMIT 1`, [userID]);
return row?.reason ?? '';
const row = await db.prepare("get", `SELECT reason FROM "warnings" WHERE "userID" = ? AND "enabled" = 1 ORDER BY "issueTime" DESC LIMIT 1`, [userID]);
return row?.reason ?? "";
} catch (err) {
Logger.error('Couldn\'t get reason for user ' + userID + '. returning blank');
return '';
Logger.error(`Couldn't get reason for user ${userID}. returning blank`);
return "";
}
}
type cases = Record<string, any>
const executeIfFunction = (f: any) =>
typeof f === 'function' ? f() : f;
typeof f === "function" ? f() : f;
const objSwitch = (cases: cases) => (defaultCase: string) => (key: string) =>
Object.prototype.hasOwnProperty.call(cases, key) ? cases[key] : defaultCase;
const functionSwitch = (cases: cases) => (defaultCase: string) => (key: string) =>
executeIfFunction(objSwitch(cases)(defaultCase)(key));
executeIfFunction(objSwitch(cases)(defaultCase)(key));
const dbGetValue = async (userID: HashedUserID, property: string): Promise<string|SegmentUUID|number> => {
return functionSwitch({
@@ -149,7 +149,7 @@ export async function getUserInfo(req: Request, res: Response): Promise<Response
if (hashedUserID == undefined) {
//invalid request
return res.status(400).send('Invalid userID or publicUserID parameter');
return res.status(400).send("Invalid userID or publicUserID parameter");
}
const segmentsSummary = await dbGetSubmittedSegmentSummary(hashedUserID);

View File

@@ -1,7 +1,7 @@
import {db} from '../databases/databases';
import {getHash} from '../utils/getHash';
import {Logger} from '../utils/logger';
import {Request, Response} from 'express';
import {db} from "../databases/databases";
import {getHash} from "../utils/getHash";
import {Logger} from "../utils/logger";
import {Request, Response} from "express";
export async function getUsername(req: Request, res: Response): Promise<Response> {
let userID = req.query.userID as string;
@@ -15,7 +15,7 @@ export async function getUsername(req: Request, res: Response): Promise<Response
userID = getHash(userID);
try {
const row = await db.prepare('get', `SELECT "userName" FROM "userNames" WHERE "userID" = ?`, [userID]);
const row = await db.prepare("get", `SELECT "userName" FROM "userNames" WHERE "userID" = ?`, [userID]);
if (row !== undefined) {
return res.send({

View File

@@ -1,7 +1,7 @@
import {db} from '../databases/databases';
import {Request, Response} from 'express';
import {getHash} from '../utils/getHash';
import {Logger} from '../utils/logger';
import {db} from "../databases/databases";
import {Request, Response} from "express";
import {getHash} from "../utils/getHash";
import {Logger} from "../utils/logger";
export async function getViewsForUser(req: Request, res: Response): Promise<Response> {
let userID = req.query.userID as string;
@@ -15,7 +15,7 @@ export async function getViewsForUser(req: Request, res: Response): Promise<Resp
userID = getHash(userID);
try {
const row = await db.prepare('get', `SELECT SUM("views") as "viewCount" FROM "sponsorTimes" WHERE "userID" = ?`, [userID]);
const row = await db.prepare("get", `SELECT SUM("views") as "viewCount" FROM "sponsorTimes" WHERE "userID" = ?`, [userID]);
//increase the view count by one
if (row.viewCount != null) {

View File

@@ -1,5 +1,5 @@
import {handleGetSegments} from './getSkipSegments';
import {Request, Response} from 'express';
import {handleGetSegments} from "./getSkipSegments";
import {Request, Response} from "express";
export async function oldGetVideoSponsorTimes(req: Request, res: Response): Promise<Response> {
const segments = await handleGetSegments(req, res);

View File

@@ -1,5 +1,5 @@
import {postSkipSegments} from './postSkipSegments';
import {Request, Response} from 'express';
import {postSkipSegments} from "./postSkipSegments";
import {Request, Response} from "express";
export async function oldSubmitSponsorTimes(req: Request, res: Response): Promise<Response> {
req.query.category = "sponsor";

View File

@@ -1,10 +1,10 @@
import { Logger } from '../utils/logger';
import { HashedUserID, UserID } from '../types/user.model';
import { getHash } from '../utils/getHash';
import { Request, Response } from 'express';
import { Service, VideoID } from '../types/segments.model';
import { QueryCacher } from '../utils/queryCacher';
import { isUserVIP } from '../utils/isUserVIP';
import { Logger } from "../utils/logger";
import { HashedUserID, UserID } from "../types/user.model";
import { getHash } from "../utils/getHash";
import { Request, Response } from "express";
import { Service, VideoID } from "../types/segments.model";
import { QueryCacher } from "../utils/queryCacher";
import { isUserVIP } from "../utils/isUserVIP";
import { VideoIDHash } from "../types/segments.model";
export async function postClearCache(req: Request, res: Response): Promise<Response> {
@@ -13,17 +13,17 @@ export async function postClearCache(req: Request, res: Response): Promise<Respo
const service = req.query.service as Service ?? Service.YouTube;
const invalidFields = [];
if (typeof videoID !== 'string') {
invalidFields.push('videoID');
if (typeof videoID !== "string") {
invalidFields.push("videoID");
}
if (typeof userID !== 'string') {
invalidFields.push('userID');
if (typeof userID !== "string") {
invalidFields.push("userID");
}
if (invalidFields.length !== 0) {
// invalid request
const fields = invalidFields.reduce((p, c, i) => p + (i !== 0 ? ', ' : '') + c, '');
return res.status(400).send(`No valid ${fields} field(s) provided`);
// invalid request
const fields = invalidFields.reduce((p, c, i) => p + (i !== 0 ? ", " : "") + c, "");
return res.status(400).send(`No valid ${fields} field(s) provided`);
}
// hash the userID as early as possible
@@ -33,7 +33,7 @@ export async function postClearCache(req: Request, res: Response): Promise<Respo
// Ensure user is a VIP
if (!(await isUserVIP(hashedUserID))){
Logger.warn("Permission violation: User " + hashedUserID + " attempted to clear cache for video " + videoID + ".");
Logger.warn(`Permission violation: User ${hashedUserID} attempted to clear cache for video ${videoID}.`);
return res.status(403).json({"message": "Not a VIP"});
}
@@ -44,7 +44,7 @@ export async function postClearCache(req: Request, res: Response): Promise<Respo
service
});
return res.status(200).json({
message: "Cache cleared on video " + videoID
message: `Cache cleared on video ${videoID}`
});
} catch(err) {
return res.sendStatus(500);

View File

@@ -1,8 +1,8 @@
import {Logger} from '../utils/logger';
import {getHash} from '../utils/getHash';
import {isUserVIP} from '../utils/isUserVIP';
import {db} from '../databases/databases';
import {Request, Response} from 'express';
import {Logger} from "../utils/logger";
import {getHash} from "../utils/getHash";
import {isUserVIP} from "../utils/isUserVIP";
import {db} from "../databases/databases";
import {Request, Response} from "express";
import { VideoIDHash } from "../types/segments.model";
export async function postLockCategories(req: Request, res: Response): Promise<string[]> {
@@ -10,7 +10,7 @@ export async function postLockCategories(req: Request, res: Response): Promise<s
const videoID = req.body.videoID;
let userID = req.body.userID;
const categories = req.body.categories;
const reason: string = req.body.reason ?? '';
const reason: string = req.body.reason ?? "";
// Check input data is valid
if (!videoID
@@ -20,7 +20,7 @@ export async function postLockCategories(req: Request, res: Response): Promise<s
|| categories.length === 0
) {
res.status(400).json({
message: 'Bad Format',
message: "Bad Format",
});
return;
}
@@ -31,13 +31,13 @@ export async function postLockCategories(req: Request, res: Response): Promise<s
if (!userIsVIP) {
res.status(403).json({
message: 'Must be a VIP to mark videos.',
message: "Must be a VIP to mark videos.",
});
return;
}
// Get existing lock categories markers
let noCategoryList = await db.prepare('all', 'SELECT "category" from "lockCategories" where "videoID" = ?', [videoID]);
let noCategoryList = await db.prepare("all", 'SELECT "category" from "lockCategories" where "videoID" = ?', [videoID]);
if (!noCategoryList || noCategoryList.length === 0) {
noCategoryList = [];
} else {
@@ -65,9 +65,9 @@ export async function postLockCategories(req: Request, res: Response): Promise<s
// create database entry
for (const category of categoriesToMark) {
try {
await db.prepare('run', `INSERT INTO "lockCategories" ("videoID", "userID", "category", "hashedVideoID", "reason") VALUES(?, ?, ?, ?, ?)`, [videoID, userID, category, hashedVideoID, reason]);
await db.prepare("run", `INSERT INTO "lockCategories" ("videoID", "userID", "category", "hashedVideoID", "reason") VALUES(?, ?, ?, ?, ?)`, [videoID, userID, category, hashedVideoID, reason]);
} catch (err) {
Logger.error("Error submitting 'lockCategories' marker for category '" + category + "' for video '" + videoID + "'");
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.",
@@ -84,11 +84,11 @@ export async function postLockCategories(req: Request, res: Response): Promise<s
for (const category of overlapCategories) {
try {
await db.prepare('run',
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(`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.",

View File

@@ -1,10 +1,10 @@
import {Logger} from '../utils/logger';
import {getHash} from '../utils/getHash';
import {isUserVIP} from '../utils/isUserVIP';
import {Request, Response} from 'express';
import {HashedUserID, UserID} from '../types/user.model';
import {Logger} from "../utils/logger";
import {getHash} from "../utils/getHash";
import {isUserVIP} from "../utils/isUserVIP";
import {Request, Response} from "express";
import {HashedUserID, UserID} from "../types/user.model";
import {VideoID} from "../types/segments.model";
import {db} from '../databases/databases';
import {db} from "../databases/databases";
export async function postPurgeAllSegments(req: Request, res: Response): Promise<Response> {
const userID = req.body.userID as UserID;
@@ -22,12 +22,12 @@ export async function postPurgeAllSegments(req: Request, res: Response): Promise
const vipState = await isUserVIP(hashedUserID);
if (!vipState) {
return res.status(403).json({
message: 'Must be a VIP to perform this action.',
message: "Must be a VIP to perform this action.",
});
}
await db.prepare('run', `UPDATE "sponsorTimes" SET "hidden" = 1 WHERE "videoID" = ?`, [videoID]);
await db.prepare("run", `UPDATE "sponsorTimes" SET "hidden" = 1 WHERE "videoID" = ?`, [videoID]);
} catch (err) {
Logger.error(err);
return res.sendStatus(500);

View File

@@ -1,12 +1,12 @@
import {Request, Response} from 'express';
import {Logger} from '../utils/logger';
import {isUserVIP} from '../utils/isUserVIP';
import {getHash} from '../utils/getHash';
import {db} from '../databases/databases';
import {Request, Response} from "express";
import {Logger} from "../utils/logger";
import {isUserVIP} from "../utils/isUserVIP";
import {getHash} from "../utils/getHash";
import {db} from "../databases/databases";
const ACTION_NONE = Symbol('none');
const ACTION_UPDATE = Symbol('update');
const ACTION_REMOVE = Symbol('remove');
const ACTION_NONE = Symbol("none");
const ACTION_UPDATE = Symbol("update");
const ACTION_REMOVE = Symbol("remove");
function shiftSegment(segment: any, shift: { startTime: any; endTime: any }) {
if (segment.startTime >= segment.endTime) return {action: ACTION_NONE, segment};
@@ -59,7 +59,7 @@ export async function postSegmentShift(req: Request, res: Response): Promise<Res
|| !endTime
) {
return res.status(400).json({
message: 'Bad Format',
message: "Bad Format",
});
}
@@ -69,12 +69,12 @@ export async function postSegmentShift(req: Request, res: Response): Promise<Res
if (!userIsVIP) {
return res.status(403).json({
message: 'Must be a VIP to perform this action.',
message: "Must be a VIP to perform this action.",
});
}
try {
const segments = await db.prepare('all', 'SELECT "startTime", "endTime", "UUID" FROM "sponsorTimes" WHERE "videoID" = ?', [videoID]);
const segments = await db.prepare("all", 'SELECT "startTime", "endTime", "UUID" FROM "sponsorTimes" WHERE "videoID" = ?', [videoID]);
const shift = {
startTime,
endTime,
@@ -83,12 +83,12 @@ export async function postSegmentShift(req: Request, res: Response): Promise<Res
for (const segment of segments) {
const result = shiftSegment(segment, shift);
switch (result.action) {
case ACTION_UPDATE:
await db.prepare('run', 'UPDATE "sponsorTimes" SET "startTime" = ?, "endTime" = ? WHERE "UUID" = ?', [result.segment.startTime, result.segment.endTime, result.segment.UUID]);
break;
case ACTION_REMOVE:
await db.prepare('run', 'UPDATE "sponsorTimes" SET "startTime" = ?, "endTime" = ?, "votes" = -2 WHERE "UUID" = ?', [result.segment.startTime, result.segment.endTime, result.segment.UUID]);
break;
case ACTION_UPDATE:
await db.prepare("run", 'UPDATE "sponsorTimes" SET "startTime" = ?, "endTime" = ? WHERE "UUID" = ?', [result.segment.startTime, result.segment.endTime, result.segment.UUID]);
break;
case ACTION_REMOVE:
await db.prepare("run", 'UPDATE "sponsorTimes" SET "startTime" = ?, "endTime" = ?, "votes" = -2 WHERE "UUID" = ?', [result.segment.startTime, result.segment.endTime, result.segment.UUID]);
break;
}
}
} catch (err) {

View File

@@ -1,25 +1,25 @@
import {config} from '../config';
import {Logger} from '../utils/logger';
import {db, privateDB} from '../databases/databases';
import {getMaxResThumbnail, YouTubeAPI} from '../utils/youtubeApi';
import {getSubmissionUUID} from '../utils/getSubmissionUUID';
import fetch from 'node-fetch';
import {getHash} from '../utils/getHash';
import {getIP} from '../utils/getIP';
import {getFormattedTime} from '../utils/getFormattedTime';
import {isUserTrustworthy} from '../utils/isUserTrustworthy';
import {dispatchEvent} from '../utils/webhookUtils';
import {Request, Response} from 'express';
import { ActionType, Category, CategoryActionType, IncomingSegment, SegmentUUID, Service, VideoDuration, VideoID } from '../types/segments.model';
import { deleteLockCategories } from './deleteLockCategories';
import { getCategoryActionType } from '../utils/categoryInfo';
import { QueryCacher } from '../utils/queryCacher';
import { getReputation } from '../utils/reputation';
import { APIVideoData, APIVideoInfo } from '../types/youtubeApi.model';
import { UserID } from '../types/user.model';
import {config} from "../config";
import {Logger} from "../utils/logger";
import {db, privateDB} from "../databases/databases";
import {getMaxResThumbnail, YouTubeAPI} from "../utils/youtubeApi";
import {getSubmissionUUID} from "../utils/getSubmissionUUID";
import fetch from "node-fetch";
import {getHash} from "../utils/getHash";
import {getIP} from "../utils/getIP";
import {getFormattedTime} from "../utils/getFormattedTime";
import {isUserTrustworthy} from "../utils/isUserTrustworthy";
import {dispatchEvent} from "../utils/webhookUtils";
import {Request, Response} from "express";
import { ActionType, Category, CategoryActionType, IncomingSegment, SegmentUUID, Service, VideoDuration, VideoID } from "../types/segments.model";
import { deleteLockCategories } from "./deleteLockCategories";
import { getCategoryActionType } from "../utils/categoryInfo";
import { QueryCacher } from "../utils/queryCacher";
import { getReputation } from "../utils/reputation";
import { APIVideoData, APIVideoInfo } from "../types/youtubeApi.model";
import { UserID } from "../types/user.model";
async function sendWebhookNotification(userID: string, videoID: string, UUID: string, submissionCount: number, youtubeData: APIVideoData, {submissionStart, submissionEnd}: { submissionStart: number; submissionEnd: number; }, segmentInfo: any) {
const row = await db.prepare('get', `SELECT "userName" FROM "userNames" WHERE "userID" = ?`, [userID]);
const row = await db.prepare("get", `SELECT "userName" FROM "userNames" WHERE "userID" = ?`, [userID]);
const userName = row !== undefined ? row.userName : null;
let scopeName = "submissions.other";
@@ -32,7 +32,7 @@ async function sendWebhookNotification(userID: string, videoID: string, UUID: st
"id": videoID,
"title": youtubeData?.title,
"thumbnail": getMaxResThumbnail(youtubeData) || null,
"url": "https://www.youtube.com/watch?v=" + videoID,
"url": `https://www.youtube.com/watch?v=${videoID}`,
},
"submission": {
"UUID": UUID,
@@ -49,7 +49,7 @@ async function sendWebhookNotification(userID: string, videoID: string, UUID: st
async function sendWebhooks(apiVideoInfo: APIVideoInfo, userID: string, videoID: string, UUID: string, segmentInfo: any, service: Service) {
if (apiVideoInfo && service == Service.YouTube) {
const userSubmissionCountRow = await db.prepare('get', `SELECT count(*) as "submissionCount" FROM "sponsorTimes" WHERE "userID" = ?`, [userID]);
const userSubmissionCountRow = await db.prepare("get", `SELECT count(*) as "submissionCount" FROM "sponsorTimes" WHERE "userID" = ?`, [userID]);
const {data, err} = apiVideoInfo;
if (err) return;
@@ -64,17 +64,17 @@ async function sendWebhooks(apiVideoInfo: APIVideoInfo, userID: string, videoID:
// If it is a first time submission
// Then send a notification to discord
if (config.discordFirstTimeSubmissionsWebhookURL === null || userSubmissionCountRow.submissionCount > 1) return;
fetch(config.discordFirstTimeSubmissionsWebhookURL, {
method: 'POST',
method: "POST",
body: JSON.stringify({
"embeds": [{
"title": data?.title,
"url": "https://www.youtube.com/watch?v=" + videoID + "&t=" + (parseInt(startTime.toFixed(0)) - 2),
"description": "Submission ID: " + UUID +
"\n\nTimestamp: " +
getFormattedTime(startTime) + " to " + getFormattedTime(endTime) +
"\n\nCategory: " + segmentInfo.category,
"url": `https://www.youtube.com/watch?v=${videoID}&t=${(parseInt(startTime.toFixed(0)) - 2)}`,
"description": `Submission ID: ${UUID}\
\n\nTimestamp: \
${getFormattedTime(startTime)} to ${getFormattedTime(endTime)}\
\n\nCategory: ${segmentInfo.category}`,
"color": 10813440,
"author": {
"name": userID,
@@ -85,55 +85,55 @@ async function sendWebhooks(apiVideoInfo: APIVideoInfo, userID: string, videoID:
}],
}),
headers: {
'Content-Type': 'application/json'
"Content-Type": "application/json"
}
})
.then(res => {
if (res.status >= 400) {
Logger.error("Error sending first time submission Discord hook");
Logger.error(JSON.stringify(res));
.then(res => {
if (res.status >= 400) {
Logger.error("Error sending first time submission Discord hook");
Logger.error(JSON.stringify(res));
Logger.error("\n");
}
})
.catch(err => {
Logger.error("Failed to send first time submission Discord hook.");
Logger.error(JSON.stringify(err));
Logger.error("\n");
}
})
.catch(err => {
Logger.error("Failed to send first time submission Discord hook.");
Logger.error(JSON.stringify(err));
Logger.error("\n");
});
});
}
}
async function sendWebhooksNB(userID: string, videoID: string, UUID: string, startTime: number, endTime: number, category: string, probability: number, ytData: any) {
const submissionInfoRow = await db.prepare('get', `SELECT
const submissionInfoRow = await db.prepare("get", `SELECT
(select count(1) from "sponsorTimes" where "userID" = ?) count,
(select count(1) from "sponsorTimes" where "userID" = ? and "votes" <= -2) disregarded,
coalesce((select "userName" FROM "userNames" WHERE "userID" = ?), ?) "userName"`,
[userID, userID, userID, userID]);
[userID, userID, userID, userID]);
let submittedBy: string;
// If a userName was created then show both
if (submissionInfoRow.userName !== userID) {
submittedBy = submissionInfoRow.userName + "\n " + userID;
submittedBy = `${submissionInfoRow.userName}\n${userID}`;
} else {
submittedBy = userID;
}
// Send discord message
if (config.discordNeuralBlockRejectWebhookURL === null) return;
fetch(config.discordNeuralBlockRejectWebhookURL, {
method: 'POST',
method: "POST",
body: JSON.stringify({
"embeds": [{
"title": ytData.items[0].snippet.title,
"url": "https://www.youtube.com/watch?v=" + videoID + "&t=" + (parseFloat(startTime.toFixed(0)) - 2),
"description": "**Submission ID:** " + UUID +
"\n**Timestamp:** " + getFormattedTime(startTime) + " to " + getFormattedTime(endTime) +
"\n**Predicted Probability:** " + probability +
"\n**Category:** " + category +
"\n**Submitted by:** " + submittedBy +
"\n**Total User Submissions:** " + submissionInfoRow.count +
"\n**Ignored User Submissions:** " + submissionInfoRow.disregarded,
"url": `https://www.youtube.com/watch?v=${videoID}&t=${(parseFloat(startTime.toFixed(0)) - 2)}`,
"description": `**Submission ID:** ${UUID}\
\n**Timestamp:** ${getFormattedTime(startTime)} to ${getFormattedTime(endTime)}\
\n**Predicted Probability:** ${probability}\
\n**Category:** ${category}\
\n**Submitted by:** ${submittedBy}\
\n**Total User Submissions:** ${submissionInfoRow.count}\
\n**Ignored User Submissions:** ${submissionInfoRow.disregarded}`,
"color": 10813440,
"thumbnail": {
"url": ytData.items[0].snippet.thumbnails.maxres ? ytData.items[0].snippet.thumbnails.maxres.url : "",
@@ -141,21 +141,21 @@ async function sendWebhooksNB(userID: string, videoID: string, UUID: string, sta
}],
}),
headers: {
'Content-Type': 'application/json'
"Content-Type": "application/json"
}
})
.then(res => {
if (res.status >= 400) {
Logger.error("Error sending NeuralBlock Discord hook");
Logger.error(JSON.stringify(res));
.then(res => {
if (res.status >= 400) {
Logger.error("Error sending NeuralBlock Discord hook");
Logger.error(JSON.stringify(res));
Logger.error("\n");
}
})
.catch(err => {
Logger.error("Failed to send NeuralBlock Discord hook.");
Logger.error(JSON.stringify(err));
Logger.error("\n");
}
})
.catch(err => {
Logger.error("Failed to send NeuralBlock Discord hook.");
Logger.error(JSON.stringify(err));
Logger.error("\n");
});
});
}
// callback: function(reject: "String containing reason the submission was rejected")
@@ -164,8 +164,8 @@ async function sendWebhooksNB(userID: string, videoID: string, UUID: string, sta
// Looks like this was broken for no defined youtube key - fixed but IMO we shouldn't return
// false for a pass - it was confusing and lead to this bug - any use of this function in
// the future could have the same problem.
async function autoModerateSubmission(apiVideoInfo: APIVideoInfo,
submission: { videoID: VideoID; userID: UserID; segments: IncomingSegment[] }) {
async function autoModerateSubmission(apiVideoInfo: APIVideoInfo,
submission: { videoID: VideoID; userID: UserID; segments: IncomingSegment[] }) {
if (apiVideoInfo) {
const {err, data} = apiVideoInfo;
if (err) return false;
@@ -180,13 +180,13 @@ async function autoModerateSubmission(apiVideoInfo: APIVideoInfo,
} else {
if (segments[i].category === "sponsor") {
//Prepare timestamps to send to NB all at once
nbString = nbString + segments[i].segment[0] + "," + segments[i].segment[1] + ";";
nbString = `${nbString}${segments[i].segment[0]},${segments[i].segment[1]};`;
}
}
}
// Get all submissions for this user
const allSubmittedByUser = await db.prepare('all', `SELECT "startTime", "endTime" FROM "sponsorTimes" WHERE "userID" = ? and "videoID" = ? and "votes" > -1`, [submission.userID, submission.videoID]);
const allSubmittedByUser = await db.prepare("all", `SELECT "startTime", "endTime" FROM "sponsorTimes" WHERE "userID" = ? and "videoID" = ? and "votes" > -1`, [submission.userID, submission.videoID]);
const allSegmentTimes = [];
if (allSubmittedByUser !== undefined) {
//add segments the user has previously submitted
@@ -221,8 +221,8 @@ async function autoModerateSubmission(apiVideoInfo: APIVideoInfo,
// Check NeuralBlock
const neuralBlockURL = config.neuralBlockURL;
if (!neuralBlockURL) return false;
const response = await fetch(neuralBlockURL + "/api/checkSponsorSegments?vid=" + submission.videoID +
"&segments=" + nbString.substring(0, nbString.length - 1));
const response = await fetch(`${neuralBlockURL}/api/checkSponsorSegments?vid=${submission.videoID}
&segments=${nbString.substring(0, nbString.length - 1)}`);
if (!response.ok) return false;
const nbPredictions = await response.json();
@@ -270,7 +270,7 @@ async function getYouTubeVideoInfo(videoID: VideoID, ignoreCache = false): Promi
async function checkUserActiveWarning(userID: string): Promise<{ pass: boolean; errorMessage: string; }> {
const MILLISECONDS_IN_HOUR = 3600000;
const now = Date.now();
const warnings = await db.prepare('all',
const warnings = await db.prepare("all",
`SELECT "reason"
FROM warnings
WHERE "userID" = ? AND "issueTime" > ? AND enabled = 1
@@ -278,30 +278,30 @@ async function checkUserActiveWarning(userID: string): Promise<{ pass: boolean;
LIMIT ?`,
[
userID,
Math.floor(now - (config.hoursAfterWarningExpires * MILLISECONDS_IN_HOUR)),
Math.floor(now - (config.hoursAfterWarningExpires * MILLISECONDS_IN_HOUR)),
config.maxNumberOfActiveWarnings
],
) as {reason: string}[];
if (warnings?.length >= config.maxNumberOfActiveWarnings) {
const defaultMessage = 'Submission rejected due to a warning from a moderator. This means that we noticed you were making some common mistakes that are not malicious, and we just want to clarify the rules. Could you please send a message in Discord or Matrix so we can further help you?';
const defaultMessage = "Submission rejected due to a warning from a moderator. This means that we noticed you were making some common mistakes that are not malicious, and we just want to clarify the rules. Could you please send a message in Discord or Matrix so we can further help you?";
return {
pass: false,
pass: false,
errorMessage: warnings[0]?.reason?.length > 0 ? warnings[0].reason : defaultMessage
};
}
return {pass: true, errorMessage: ''};
return {pass: true, errorMessage: ""};
}
function proxySubmission(req: Request) {
fetch(config.proxySubmission + '/api/skipSegments?userID=' + req.query.userID + '&videoID=' + req.query.videoID, {
method: 'POST',
body: req.body,
})
fetch(`${config.proxySubmission}/api/skipSegments?userID=${req.query.userID}&videoID=${req.query.videoID}`, {
method: "POST",
body: req.body,
})
.then(async res => {
Logger.debug('Proxy Submission: ' + res.status + ' (' + (await res.text()) + ')');
Logger.debug(`Proxy Submission: ${res.status} (${(await res.text())})`);
})
.catch(() => {
Logger.error("Proxy Submission: Failed to make call");
@@ -334,27 +334,27 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
segments.forEach((segment) => {
if (!Object.values(ActionType).some((val) => val === segment.actionType)){
segment.actionType = ActionType.Skip;
}
}
});
const invalidFields = [];
const errors = [];
if (typeof videoID !== 'string') {
invalidFields.push('videoID');
if (typeof videoID !== "string") {
invalidFields.push("videoID");
}
if (typeof userID !== 'string' || userID?.length < 30) {
invalidFields.push('userID');
if (userID?.length < 30) errors.push(`userID must be at least 30 characters long`);
if (typeof userID !== "string" || userID?.length < 30) {
invalidFields.push("userID");
if (userID?.length < 30) errors.push(`userID must be at least 30 characters long`);
}
if (!Array.isArray(segments) || segments.length < 1) {
invalidFields.push('segments');
invalidFields.push("segments");
}
if (invalidFields.length !== 0) {
// invalid request
const formattedFields = invalidFields.reduce((p, c, i) => p + (i !== 0 ? ', ' : '') + c, '');
const formattedErrors = errors.reduce((p, c, i) => p + (i !== 0 ? '. ' : ' ') + c, '');
return res.status(400).send(`No valid ${formattedFields} field(s) provided.${formattedErrors}`);
// invalid request
const formattedFields = invalidFields.reduce((p, c, i) => p + (i !== 0 ? ", " : "") + c, "");
const formattedErrors = errors.reduce((p, c, i) => p + (i !== 0 ? ". " : " ") + c, "");
return res.status(400).send(`No valid ${formattedFields} field(s) provided.${formattedErrors}`);
}
//hash the userID
@@ -365,14 +365,14 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
return res.status(403).send(warningResult.errorMessage);
}
let lockedCategoryList = (await db.prepare('all', 'SELECT category from "lockCategories" where "videoID" = ?', [videoID])).map((list: any) => list.category );
let lockedCategoryList = (await db.prepare("all", 'SELECT category from "lockCategories" where "videoID" = ?', [videoID])).map((list: any) => list.category );
//check if this user is on the vip list
const isVIP = (await db.prepare("get", `SELECT count(*) as "userCount" FROM "vipUsers" WHERE "userID" = ?`, [userID])).userCount > 0;
const decreaseVotes = 0;
const previousSubmissions = await db.prepare('all',
const previousSubmissions = await db.prepare("all",
`SELECT "videoDuration", "UUID"
FROM "sponsorTimes"
WHERE "videoID" = ? AND "service" = ? AND
@@ -398,7 +398,7 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
if (videoDurationChanged(videoDuration)) {
// Hide all previous submissions
for (const submission of previousSubmissions) {
await db.prepare('run', `UPDATE "sponsorTimes" SET "hidden" = 1 WHERE "UUID" = ?`, [submission.UUID]);
await db.prepare("run", `UPDATE "sponsorTimes" SET "hidden" = 1 WHERE "UUID" = ?`, [submission.UUID]);
}
// Reset lock categories
@@ -420,13 +420,13 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
// Reject segment if it's in the locked categories list
if (!isVIP && lockedCategoryList.indexOf(segments[i].category) !== -1) {
// TODO: Do something about the fradulent submission
Logger.warn("Caught a no-segment submission. userID: '" + userID + "', videoID: '" + videoID + "', category: '" + segments[i].category + "'");
Logger.warn(`Caught a no-segment submission. userID: '${userID}', videoID: '${videoID}', category: '${segments[i].category}'`);
return res.status(403).send(
"New submissions are not allowed for the following category: '"
+ segments[i].category + "'. A moderator has decided that no new segments are needed and that all current segments of this category are timed perfectly.\n\n "
+ (segments[i].category === "sponsor" ? "Maybe the segment you are submitting is a different category that you have not enabled and is not a sponsor. " +
"Categories that aren't sponsor, such as self-promotion can be enabled in the options.\n\n" : "")
+ "If you believe this is incorrect, please contact someone on discord.gg/SponsorBlock or matrix.to/#/+sponsorblock:ajay.app",
`New submissions are not allowed for the following category: \
'${segments[i].category}'. A moderator has decided that no new segments are needed and that all current segments of this category are timed perfectly.\n\n\
${(segments[i].category === "sponsor" ? "Maybe the segment you are submitting is a different category that you have not enabled and is not a sponsor. "+
"Categories that aren't sponsor, such as self-promotion can be enabled in the options.\n\n" : "")}\
If you believe this is incorrect, please contact someone on discord.gg/SponsorBlock or matrix.to/#/+sponsorblock:ajay.app`,
);
}
@@ -436,7 +436,7 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
if (isNaN(startTime) || isNaN(endTime)
|| startTime === Infinity || endTime === Infinity || startTime < 0 || startTime > endTime
|| (getCategoryActionType(segments[i].category) === CategoryActionType.Skippable && startTime === endTime)
|| (getCategoryActionType(segments[i].category) === CategoryActionType.Skippable && startTime === endTime)
|| (getCategoryActionType(segments[i].category) === CategoryActionType.POI && startTime !== endTime)) {
//invalid request
return res.status(400).send("One of your segments times are invalid (too short, startTime before endTime, etc.)");
@@ -448,7 +448,7 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
}
//check if this info has already been submitted before
const duplicateCheck2Row = await db.prepare('get', `SELECT COUNT(*) as count FROM "sponsorTimes" WHERE "startTime" = ?
const duplicateCheck2Row = await db.prepare("get", `SELECT COUNT(*) as count FROM "sponsorTimes" WHERE "startTime" = ?
and "endTime" = ? and "category" = ? and "videoID" = ? and "service" = ?`, [startTime, endTime, segments[i].category, videoID, service]);
if (duplicateCheck2Row.count > 0) {
return res.sendStatus(409);
@@ -466,7 +466,7 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
//decreaseVotes = -2; //Disable for now
} else if (autoModerateResult) {
//Normal automod behavior
return res.status(403).send("Request rejected by auto moderator: " + autoModerateResult + " If this is an issue, send a message on Discord.");
return res.status(403).send(`Request rejected by auto moderator: ${autoModerateResult} If this is an issue, send a message on Discord.`);
}
}
// Will be filled when submitting
@@ -486,7 +486,7 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
// eslint-disable-next-line no-constant-condition
if (false) {
//check to see if this ip has submitted too many sponsors today
const rateLimitCheckRow = await privateDB.prepare('get', `SELECT COUNT(*) as count FROM "sponsorTimes" WHERE "hashedIP" = ? AND "videoID" = ? AND "timeSubmitted" > ?`, [hashedIP, videoID, yesterday]);
const rateLimitCheckRow = await privateDB.prepare("get", `SELECT COUNT(*) as count FROM "sponsorTimes" WHERE "hashedIP" = ? AND "videoID" = ? AND "timeSubmitted" > ?`, [hashedIP, videoID, yesterday]);
if (rateLimitCheckRow.count >= 10) {
//too many sponsors for the same video from the same ip address
@@ -498,7 +498,7 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
// eslint-disable-next-line no-constant-condition
if (false) {
//check to see if the user has already submitted sponsors for this video
const duplicateCheckRow = await db.prepare('get', `SELECT COUNT(*) as count FROM "sponsorTimes" WHERE "userID" = ? and "videoID" = ?`, [userID, videoID]);
const duplicateCheckRow = await db.prepare("get", `SELECT COUNT(*) as count FROM "sponsorTimes" WHERE "userID" = ? and "videoID" = ?`, [userID, videoID]);
if (duplicateCheckRow.count >= 16) {
//too many sponsors for the same video from the same user
@@ -507,7 +507,7 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
}
//check to see if this user is shadowbanned
const shadowBanRow = await db.prepare('get', `SELECT count(*) as "userCount" FROM "shadowBannedUsers" WHERE "userID" = ?`, [userID]);
const shadowBanRow = await db.prepare("get", `SELECT count(*) as "userCount" FROM "shadowBannedUsers" WHERE "userID" = ?`, [userID]);
let shadowBanned = shadowBanRow.userCount;
@@ -528,16 +528,16 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
const startingLocked = isVIP ? 1 : 0;
try {
await db.prepare('run', `INSERT INTO "sponsorTimes"
await db.prepare("run", `INSERT INTO "sponsorTimes"
("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "actionType", "service", "videoDuration", "reputation", "shadowHidden", "hashedVideoID")
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
videoID, segmentInfo.segment[0], segmentInfo.segment[1], startingVotes, startingLocked, UUID, userID, timeSubmitted, 0, segmentInfo.category, segmentInfo.actionType, service, videoDuration, reputation, shadowBanned, hashedVideoID,
],
videoID, segmentInfo.segment[0], segmentInfo.segment[1], startingVotes, startingLocked, UUID, userID, timeSubmitted, 0, segmentInfo.category, segmentInfo.actionType, service, videoDuration, reputation, shadowBanned, hashedVideoID,
],
);
//add to private db as well
await privateDB.prepare('run', `INSERT INTO "sponsorTimes" VALUES(?, ?, ?)`, [videoID, hashedIP, timeSubmitted]);
await privateDB.prepare("run", `INSERT INTO "sponsorTimes" VALUES(?, ?, ?)`, [videoID, hashedIP, timeSubmitted]);
// Clear redis cache for this video
QueryCacher.clearVideoCache({
videoID,
@@ -547,8 +547,7 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
});
} catch (err) {
//a DB change probably occurred
Logger.error("Error when putting sponsorTime in the DB: " + videoID + ", " + segmentInfo.segment[0] + ", " +
segmentInfo.segment[1] + ", " + userID + ", " + segmentInfo.category + ". " + err);
Logger.error(`Error when putting sponsorTime in the DB: ${videoID}, ${segmentInfo.segment[0]}, ${segmentInfo.segment[1]}, ${userID}, ${segmentInfo.category}. ${err}`);
return res.sendStatus(500);
}
@@ -570,18 +569,18 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
return res.json(newSegments);
}
// Takes an array of arrays:
// ex)
// Takes an array of arrays:
// ex)
// [
// [3, 40],
// [50, 70],
// [60, 80],
// [3, 40],
// [50, 70],
// [60, 80],
// [100, 150]
// ]
// ]
// => transforms to combining overlapping segments
// [
// [3, 40],
// [50, 80],
// [50, 80],
// [100, 150]
// ]
function mergeTimeSegments(ranges: number[][]) {

View File

@@ -1,9 +1,9 @@
import {Request, Response} from 'express';
import {Logger} from '../utils/logger';
import {db} from '../databases/databases';
import {isUserVIP} from '../utils/isUserVIP';
import {getHash} from '../utils/getHash';
import { HashedUserID, UserID } from '../types/user.model';
import {Request, Response} from "express";
import {Logger} from "../utils/logger";
import {db} from "../databases/databases";
import {isUserVIP} from "../utils/isUserVIP";
import {getHash} from "../utils/getHash";
import { HashedUserID, UserID } from "../types/user.model";
export async function postWarning(req: Request, res: Response): Promise<Response> {
// exit early if no body passed in
@@ -13,22 +13,22 @@ export async function postWarning(req: Request, res: Response): Promise<Response
const userID: UserID = req.body.userID;
const issueTime = new Date().getTime();
const enabled: boolean = req.body.enabled ?? true;
const reason: string = req.body.reason ?? '';
const reason: string = req.body.reason ?? "";
// Ensure user is a VIP
if (!await isUserVIP(issuerUserID)) {
Logger.warn("Permission violation: User " + issuerUserID + " attempted to warn user " + userID + ".");
Logger.warn(`Permission violation: User ${issuerUserID} attempted to warn user ${userID}.`);
return res.status(403).json({"message": "Not a VIP"});
}
let resultStatus = "";
if (enabled) {
const previousWarning = await db.prepare('get', 'SELECT * FROM "warnings" WHERE "userID" = ? AND "issuerUserID" = ?', [userID, issuerUserID]);
const previousWarning = await db.prepare("get", 'SELECT * FROM "warnings" WHERE "userID" = ? AND "issuerUserID" = ?', [userID, issuerUserID]);
if (!previousWarning) {
await db.prepare(
'run',
"run",
'INSERT INTO "warnings" ("userID", "issueTime", "issuerUserID", "enabled", "reason") VALUES (?, ?, ?, 1, ?)',
[userID, issueTime, issuerUserID, reason]
);
@@ -37,11 +37,11 @@ export async function postWarning(req: Request, res: Response): Promise<Response
return res.sendStatus(409);
}
} else {
await db.prepare('run', 'UPDATE "warnings" SET "enabled" = 0 WHERE "userID" = ?', [userID]);
await db.prepare("run", 'UPDATE "warnings" SET "enabled" = 0 WHERE "userID" = ?', [userID]);
resultStatus = "removed from";
}
return res.status(200).json({
message: "Warning " + resultStatus + " user '" + userID + "'.",
message: `Warning ${resultStatus} user '${userID}'.`,
});
}

View File

@@ -1,11 +1,11 @@
import {config} from '../config';
import {Logger} from '../utils/logger';
import {db, privateDB} from '../databases/databases';
import {getHash} from '../utils/getHash';
import {Request, Response} from 'express';
import {config} from "../config";
import {Logger} from "../utils/logger";
import {db, privateDB} from "../databases/databases";
import {getHash} from "../utils/getHash";
import {Request, Response} from "express";
async function logUserNameChange(userID: string, newUserName: string, oldUserName: string, updatedByAdmin: boolean): Promise<Response> {
return privateDB.prepare('run',
return privateDB.prepare("run",
`INSERT INTO "userNameLogs"("userID", "newUserName", "oldUserName", "updatedByAdmin", "updatedAt") VALUES(?, ?, ?, ?, ?)`,
[userID, newUserName, oldUserName, + updatedByAdmin, new Date().getTime()]
);
@@ -26,11 +26,11 @@ export async function setUsername(req: Request, res: Response): Promise<Response
// Don't allow
return res.sendStatus(200);
}
// remove unicode control characters from username (example: \n, \r, \t etc.)
// source: https://en.wikipedia.org/wiki/Control_character#In_Unicode
// eslint-disable-next-line no-control-regex
userName = userName.replace(/[\u0000-\u001F\u007F-\u009F]/g, '');
userName = userName.replace(/[\u0000-\u001F\u007F-\u009F]/g, "");
if (adminUserIDInput != undefined) {
//this is the admin controlling the other users account, don't hash the controling account's ID
@@ -46,7 +46,7 @@ export async function setUsername(req: Request, res: Response): Promise<Response
}
try {
const row = await db.prepare('get', `SELECT count(*) as count FROM "userNames" WHERE "userID" = ? AND "locked" = '1'`, [userID]);
const row = await db.prepare("get", `SELECT count(*) as count FROM "userNames" WHERE "userID" = ? AND "locked" = '1'`, [userID]);
if (adminUserIDInput === undefined && row.count > 0) {
return res.sendStatus(200);
}
@@ -58,17 +58,17 @@ export async function setUsername(req: Request, res: Response): Promise<Response
try {
//check if username is already set
const row = await db.prepare('get', `SELECT "userName" FROM "userNames" WHERE "userID" = ? LIMIT 1`, [userID]);
const row = await db.prepare("get", `SELECT "userName" FROM "userNames" WHERE "userID" = ? LIMIT 1`, [userID]);
const locked = adminUserIDInput === undefined ? 0 : 1;
let oldUserName = '';
let oldUserName = "";
if (row?.userName !== undefined) {
//already exists, update this row
oldUserName = row.userName;
await db.prepare('run', `UPDATE "userNames" SET "userName" = ?, "locked" = ? WHERE "userID" = ?`, [userName, locked, userID]);
await db.prepare("run", `UPDATE "userNames" SET "userName" = ?, "locked" = ? WHERE "userID" = ?`, [userName, locked, userID]);
} else {
//add to the db
await db.prepare('run', `INSERT INTO "userNames"("userID", "userName", "locked") VALUES(?, ?, ?)`, [userID, userName, locked]);
await db.prepare("run", `INSERT INTO "userNames"("userID", "userName", "locked") VALUES(?, ?, ?)`, [userID, userName, locked]);
}
await logUserNameChange(userID, userName, oldUserName, adminUserIDInput !== undefined);

View File

@@ -1,10 +1,10 @@
import {db} from '../databases/databases';
import {getHash} from '../utils/getHash';
import {Request, Response} from 'express';
import { config } from '../config';
import { Category, Service, VideoID, VideoIDHash } from '../types/segments.model';
import { UserID } from '../types/user.model';
import { QueryCacher } from '../utils/queryCacher';
import {db} from "../databases/databases";
import {getHash} from "../utils/getHash";
import {Request, Response} from "express";
import { config } from "../config";
import { Category, Service, VideoID, VideoIDHash } from "../types/segments.model";
import { UserID } from "../types/user.model";
import { QueryCacher } from "../utils/queryCacher";
export async function shadowBanUser(req: Request, res: Response): Promise<Response> {
const userID = req.query.userID as string;
@@ -13,7 +13,7 @@ export async function shadowBanUser(req: Request, res: Response): Promise<Respon
const enabled = req.query.enabled === undefined
? true
: req.query.enabled === 'true';
: req.query.enabled === "true";
//if enabled is false and the old submissions should be made visible again
const unHideOldSubmissions = req.query.unHideOldSubmissions !== "false";
@@ -37,50 +37,50 @@ export async function shadowBanUser(req: Request, res: Response): Promise<Respon
if (userID) {
//check to see if this user is already shadowbanned
const row = await db.prepare('get', `SELECT count(*) as "userCount" FROM "shadowBannedUsers" WHERE "userID" = ?`, [userID]);
const row = await db.prepare("get", `SELECT count(*) as "userCount" FROM "shadowBannedUsers" WHERE "userID" = ?`, [userID]);
if (enabled && row.userCount == 0) {
//add them to the shadow ban list
//add it to the table
await db.prepare('run', `INSERT INTO "shadowBannedUsers" VALUES(?)`, [userID]);
await db.prepare("run", `INSERT INTO "shadowBannedUsers" VALUES(?)`, [userID]);
//find all previous submissions and hide them
if (unHideOldSubmissions) {
await db.prepare('run', `UPDATE "sponsorTimes" SET "shadowHidden" = 1 WHERE "userID" = ? AND "category" in (${categories.map((c) => `'${c}'`).join(",")})
await db.prepare("run", `UPDATE "sponsorTimes" SET "shadowHidden" = 1 WHERE "userID" = ? AND "category" in (${categories.map((c) => `'${c}'`).join(",")})
AND NOT EXISTS ( SELECT "videoID", "category" FROM "lockCategories" WHERE
"sponsorTimes"."videoID" = "lockCategories"."videoID" AND "sponsorTimes"."category" = "lockCategories"."category")`, [userID]);
// clear cache for all old videos
(await db.prepare('all', `SELECT "videoID", "hashedVideoID", "service", "votes", "views" FROM "sponsorTimes" WHERE "userID" = ?`, [userID]))
(await db.prepare("all", `SELECT "videoID", "hashedVideoID", "service", "votes", "views" FROM "sponsorTimes" WHERE "userID" = ?`, [userID]))
.forEach((videoInfo: {category: Category, videoID: VideoID, hashedVideoID: VideoIDHash, service: Service, userID: UserID}) => {
QueryCacher.clearVideoCache(videoInfo);
}
);
);
}
} else if (!enabled && row.userCount > 0) {
//remove them from the shadow ban list
await db.prepare('run', `DELETE FROM "shadowBannedUsers" WHERE "userID" = ?`, [userID]);
await db.prepare("run", `DELETE FROM "shadowBannedUsers" WHERE "userID" = ?`, [userID]);
//find all previous submissions and unhide them
if (unHideOldSubmissions) {
const segmentsToIgnore = (await db.prepare('all', `SELECT "UUID" FROM "sponsorTimes" st
JOIN "lockCategories" ns on "st"."videoID" = "ns"."videoID" AND st.category = ns.category WHERE "st"."userID" = ?`
, [userID])).map((item: {UUID: string}) => item.UUID);
const allSegments = (await db.prepare('all', `SELECT "UUID" FROM "sponsorTimes" st WHERE "st"."userID" = ?`, [userID]))
.map((item: {UUID: string}) => item.UUID);
const segmentsToIgnore = (await db.prepare("all", `SELECT "UUID" FROM "sponsorTimes" st
JOIN "lockCategories" ns on "st"."videoID" = "ns"."videoID" AND st.category = ns.category WHERE "st"."userID" = ?`
, [userID])).map((item: {UUID: string}) => item.UUID);
const allSegments = (await db.prepare("all", `SELECT "UUID" FROM "sponsorTimes" st WHERE "st"."userID" = ?`, [userID]))
.map((item: {UUID: string}) => item.UUID);
await Promise.all(allSegments.filter((item: {uuid: string}) => {
return segmentsToIgnore.indexOf(item) === -1;
}).map(async (UUID: string) => {
// collect list for unshadowbanning
(await db.prepare('all', `SELECT "videoID", "hashedVideoID", "service", "votes", "views", "userID" FROM "sponsorTimes" WHERE "UUID" = ? AND "shadowHidden" = 1 AND "category" in (${categories.map((c) => `'${c}'`).join(",")})`, [UUID]))
(await db.prepare("all", `SELECT "videoID", "hashedVideoID", "service", "votes", "views", "userID" FROM "sponsorTimes" WHERE "UUID" = ? AND "shadowHidden" = 1 AND "category" in (${categories.map((c) => `'${c}'`).join(",")})`, [UUID]))
.forEach((videoInfo: {category: Category, videoID: VideoID, hashedVideoID: VideoIDHash, service: Service, userID: UserID}) => {
QueryCacher.clearVideoCache(videoInfo);
QueryCacher.clearVideoCache(videoInfo);
}
);
);
return db.prepare('run', `UPDATE "sponsorTimes" SET "shadowHidden" = 0 WHERE "UUID" = ? AND "category" in (${categories.map((c) => `'${c}'`).join(",")})`, [UUID]);
return db.prepare("run", `UPDATE "sponsorTimes" SET "shadowHidden" = 0 WHERE "UUID" = ? AND "category" in (${categories.map((c) => `'${c}'`).join(",")})`, [UUID]);
}));
}
}
@@ -98,7 +98,7 @@ export async function shadowBanUser(req: Request, res: Response): Promise<Respon
//find all previous submissions and hide them
if (unHideOldSubmissions) {
await db.prepare('run', `UPDATE "sponsorTimes" SET "shadowHidden" = 1 WHERE "timeSubmitted" IN
await db.prepare("run", `UPDATE "sponsorTimes" SET "shadowHidden" = 1 WHERE "timeSubmitted" IN
(SELECT "privateDB"."timeSubmitted" FROM "sponsorTimes" LEFT JOIN "privateDB"."sponsorTimes" as "privateDB" ON "sponsorTimes"."timeSubmitted"="privateDB"."timeSubmitted"
WHERE "privateDB"."hashedIP" = ?)`, [hashedIP]);
}

View File

@@ -1,5 +1,5 @@
import {db} from '../databases/databases';
import {Request, Response} from 'express';
import {db} from "../databases/databases";
import {Request, Response} from "express";
export async function viewedVideoSponsorTime(req: Request, res: Response): Promise<Response> {
const UUID = req.query.UUID;
@@ -10,7 +10,7 @@ export async function viewedVideoSponsorTime(req: Request, res: Response): Promi
}
//up the view count by one
await db.prepare('run', `UPDATE "sponsorTimes" SET views = views + 1 WHERE "UUID" = ?`, [UUID]);
await db.prepare("run", `UPDATE "sponsorTimes" SET views = views + 1 WHERE "UUID" = ?`, [UUID]);
return res.sendStatus(200);
}

View File

@@ -1,18 +1,18 @@
import {Request, Response} from 'express';
import {Logger} from '../utils/logger';
import {isUserVIP} from '../utils/isUserVIP';
import fetch from 'node-fetch';
import {getMaxResThumbnail, YouTubeAPI} from '../utils/youtubeApi';
import {db, privateDB} from '../databases/databases';
import {dispatchEvent, getVoteAuthor, getVoteAuthorRaw} from '../utils/webhookUtils';
import {getFormattedTime} from '../utils/getFormattedTime';
import {getIP} from '../utils/getIP';
import {getHash} from '../utils/getHash';
import {config} from '../config';
import { UserID } from '../types/user.model';
import { Category, CategoryActionType, HashedIP, IPAddress, SegmentUUID, Service, VideoID, VideoIDHash } from '../types/segments.model';
import { getCategoryActionType } from '../utils/categoryInfo';
import { QueryCacher } from '../utils/queryCacher';
import {Request, Response} from "express";
import {Logger} from "../utils/logger";
import {isUserVIP} from "../utils/isUserVIP";
import fetch from "node-fetch";
import {getMaxResThumbnail, YouTubeAPI} from "../utils/youtubeApi";
import {db, privateDB} from "../databases/databases";
import {dispatchEvent, getVoteAuthor, getVoteAuthorRaw} from "../utils/webhookUtils";
import {getFormattedTime} from "../utils/getFormattedTime";
import {getIP} from "../utils/getIP";
import {getHash} from "../utils/getHash";
import {config} from "../config";
import { UserID } from "../types/user.model";
import { Category, CategoryActionType, HashedIP, IPAddress, SegmentUUID, Service, VideoID, VideoIDHash } from "../types/segments.model";
import { getCategoryActionType } from "../utils/categoryInfo";
import { QueryCacher } from "../utils/queryCacher";
const voteTypes = {
normal: 0,
@@ -49,26 +49,25 @@ interface VoteData {
}
async function sendWebhooks(voteData: VoteData) {
const submissionInfoRow = await db.prepare('get', `SELECT "s"."videoID", "s"."userID", s."startTime", s."endTime", s."category", u."userName",
const submissionInfoRow = await db.prepare("get", `SELECT "s"."videoID", "s"."userID", s."startTime", s."endTime", s."category", u."userName",
(select count(1) from "sponsorTimes" where "userID" = s."userID") count,
(select count(1) from "sponsorTimes" where "userID" = s."userID" and votes <= -2) disregarded
FROM "sponsorTimes" s left join "userNames" u on s."userID" = u."userID" where s."UUID"=?`,
[voteData.UUID]);
[voteData.UUID]);
const userSubmissionCountRow = await db.prepare('get', `SELECT count(*) as "submissionCount" FROM "sponsorTimes" WHERE "userID" = ?`, [voteData.nonAnonUserID]);
const userSubmissionCountRow = await db.prepare("get", `SELECT count(*) as "submissionCount" FROM "sponsorTimes" WHERE "userID" = ?`, [voteData.nonAnonUserID]);
if (submissionInfoRow !== undefined && userSubmissionCountRow != undefined) {
let webhookURL: string = null;
if (voteData.voteTypeEnum === voteTypes.normal) {
switch (voteData.finalResponse.webhookType) {
case VoteWebhookType.Normal:
webhookURL = config.discordReportChannelWebhookURL;
break;
case VoteWebhookType.Rejected:
webhookURL = config.discordFailedReportChannelWebhookURL;
break;
case VoteWebhookType.Normal:
webhookURL = config.discordReportChannelWebhookURL;
break;
case VoteWebhookType.Rejected:
webhookURL = config.discordFailedReportChannelWebhookURL;
break;
}
} else if (voteData.voteTypeEnum === voteTypes.incorrect) {
webhookURL = config.discordCompletelyIncorrectReportWebhookURL;
}
@@ -86,7 +85,7 @@ async function sendWebhooks(voteData: VoteData) {
"video": {
"id": submissionInfoRow.videoID,
"title": data?.title,
"url": "https://www.youtube.com/watch?v=" + submissionInfoRow.videoID,
"url": `https://www.youtube.com/watch?v=${submissionInfoRow.videoID}`,
"thumbnail": getMaxResThumbnail(data) || null,
},
"submission": {
@@ -113,25 +112,24 @@ async function sendWebhooks(voteData: VoteData) {
// Send discord message
if (webhookURL !== null && !isUpvote) {
fetch(webhookURL, {
method: 'POST',
method: "POST",
body: JSON.stringify({
"embeds": [{
"title": data?.title,
"url": "https://www.youtube.com/watch?v=" + submissionInfoRow.videoID
+ "&t=" + (submissionInfoRow.startTime.toFixed(0) - 2),
"description": "**" + voteData.row.votes + " Votes Prior | " +
(voteData.row.votes + voteData.incrementAmount - voteData.oldIncrementAmount) + " Votes Now | " + voteData.row.views
+ " Views**\n\n**Submission ID:** " + voteData.UUID
+ "\n**Category:** " + submissionInfoRow.category
+ "\n\n**Submitted by:** " + submissionInfoRow.userName + "\n " + submissionInfoRow.userID
+ "\n\n**Total User Submissions:** " + submissionInfoRow.count
+ "\n**Ignored User Submissions:** " + submissionInfoRow.disregarded
+ "\n\n**Timestamp:** " +
getFormattedTime(submissionInfoRow.startTime) + " to " + getFormattedTime(submissionInfoRow.endTime),
"url": `https://www.youtube.com/watch?v=${submissionInfoRow.videoID}&t=${(submissionInfoRow.startTime.toFixed(0) - 2)}`,
"description": `**${voteData.row.votes} Votes Prior | \
${(voteData.row.votes + voteData.incrementAmount - voteData.oldIncrementAmount)} Votes Now | ${voteData.row.views} \
Views**\n\n**Submission ID:** ${voteData.UUID}\
\n**Category:** ${submissionInfoRow.category}\
\n\n**Submitted by:** ${submissionInfoRow.userName}\n${submissionInfoRow.userID}\
\n\n**Total User Submissions:** ${submissionInfoRow.count}\
\n**Ignored User Submissions:** ${submissionInfoRow.disregarded}\
\n\n**Timestamp:** \
${getFormattedTime(submissionInfoRow.startTime)} to ${getFormattedTime(submissionInfoRow.endTime)}`,
"color": 10813440,
"author": {
"name": voteData.finalResponse?.webhookMessage ??
voteData.finalResponse?.finalMessage ??
voteData.finalResponse?.finalMessage ??
getVoteAuthor(userSubmissionCountRow.submissionCount, voteData.isVIP, voteData.isOwnSubmission),
},
"thumbnail": {
@@ -140,38 +138,38 @@ async function sendWebhooks(voteData: VoteData) {
}],
}),
headers: {
'Content-Type': 'application/json'
"Content-Type": "application/json"
}
})
.then(async res => {
if (res.status >= 400) {
Logger.error("Error sending reported submission Discord hook");
Logger.error(JSON.stringify((await res.text())));
.then(async res => {
if (res.status >= 400) {
Logger.error("Error sending reported submission Discord hook");
Logger.error(JSON.stringify((await res.text())));
Logger.error("\n");
}
})
.catch(err => {
Logger.error("Failed to send reported submission Discord hook.");
Logger.error(JSON.stringify(err));
Logger.error("\n");
}
})
.catch(err => {
Logger.error("Failed to send reported submission Discord hook.");
Logger.error(JSON.stringify(err));
Logger.error("\n");
});
});
}
}
}
}
async function categoryVote(UUID: SegmentUUID, userID: UserID, isVIP: boolean, isOwnSubmission: boolean, category: Category
, hashedIP: HashedIP, finalResponse: FinalResponse, res: Response): Promise<Response> {
, hashedIP: HashedIP, finalResponse: FinalResponse, res: Response): Promise<Response> {
// Check if they've already made a vote
const usersLastVoteInfo = await privateDB.prepare('get', `select count(*) as votes, category from "categoryVotes" where "UUID" = ? and "userID" = ? group by category`, [UUID, userID]);
const usersLastVoteInfo = await privateDB.prepare("get", `select count(*) as votes, category from "categoryVotes" where "UUID" = ? and "userID" = ? group by category`, [UUID, userID]);
if (usersLastVoteInfo?.category === category) {
// Double vote, ignore
return res.sendStatus(finalResponse.finalStatus);
}
const videoInfo = (await db.prepare('get', `SELECT "category", "videoID", "hashedVideoID", "service", "userID" FROM "sponsorTimes" WHERE "UUID" = ?`,
[UUID])) as {category: Category, videoID: VideoID, hashedVideoID: VideoIDHash, service: Service, userID: UserID};
const videoInfo = (await db.prepare("get", `SELECT "category", "videoID", "hashedVideoID", "service", "userID" FROM "sponsorTimes" WHERE "UUID" = ?`,
[UUID])) as {category: Category, videoID: VideoID, hashedVideoID: VideoIDHash, service: Service, userID: UserID};
if (!videoInfo) {
// Submission doesn't exist
return res.status(400).send("Submission doesn't exist.");
@@ -193,22 +191,22 @@ async function categoryVote(UUID: SegmentUUID, userID: UserID, isVIP: boolean, i
if (ableToVote) {
// Add the vote
if ((await db.prepare('get', `select count(*) as count from "categoryVotes" where "UUID" = ? and category = ?`, [UUID, category])).count > 0) {
if ((await db.prepare("get", `select count(*) as count from "categoryVotes" where "UUID" = ? and category = ?`, [UUID, category])).count > 0) {
// Update the already existing db entry
await db.prepare('run', `update "categoryVotes" set "votes" = "votes" + ? where "UUID" = ? and "category" = ?`, [voteAmount, UUID, category]);
await db.prepare("run", `update "categoryVotes" set "votes" = "votes" + ? where "UUID" = ? and "category" = ?`, [voteAmount, UUID, category]);
} else {
// Add a db entry
await db.prepare('run', `insert into "categoryVotes" ("UUID", "category", "votes") values (?, ?, ?)`, [UUID, category, voteAmount]);
await db.prepare("run", `insert into "categoryVotes" ("UUID", "category", "votes") values (?, ?, ?)`, [UUID, category, voteAmount]);
}
// Add the info into the private db
if (usersLastVoteInfo?.votes > 0) {
// Reverse the previous vote
await db.prepare('run', `update "categoryVotes" set "votes" = "votes" - ? where "UUID" = ? and "category" = ?`, [voteAmount, UUID, usersLastVoteInfo.category]);
await db.prepare("run", `update "categoryVotes" set "votes" = "votes" - ? where "UUID" = ? and "category" = ?`, [voteAmount, UUID, usersLastVoteInfo.category]);
await privateDB.prepare('run', `update "categoryVotes" set "category" = ?, "timeSubmitted" = ?, "hashedIP" = ? where "userID" = ? and "UUID" = ?`, [category, timeSubmitted, hashedIP, userID, UUID]);
await privateDB.prepare("run", `update "categoryVotes" set "category" = ?, "timeSubmitted" = ?, "hashedIP" = ? where "userID" = ? and "UUID" = ?`, [category, timeSubmitted, hashedIP, userID, UUID]);
} else {
await privateDB.prepare('run', `insert into "categoryVotes" ("UUID", "userID", "hashedIP", "category", "timeSubmitted") values (?, ?, ?, ?, ?)`, [UUID, userID, hashedIP, category, timeSubmitted]);
await privateDB.prepare("run", `insert into "categoryVotes" ("UUID", "userID", "hashedIP", "category", "timeSubmitted") values (?, ?, ?, ?, ?)`, [UUID, userID, hashedIP, category, timeSubmitted]);
}
// See if the submissions category is ready to change
@@ -235,7 +233,7 @@ async function categoryVote(UUID: SegmentUUID, userID: UserID, isVIP: boolean, i
// VIPs change it every time
if (nextCategoryCount - currentCategoryCount >= Math.max(Math.ceil(submissionInfo?.votes / 2), 2) || isVIP || isOwnSubmission) {
// Replace the category
await db.prepare('run', `update "sponsorTimes" set "category" = ? where "UUID" = ?`, [category, UUID]);
await db.prepare("run", `update "sponsorTimes" set "category" = ? where "UUID" = ?`, [category, UUID]);
}
}
@@ -283,7 +281,7 @@ export async function voteOnSponsorTime(req: Request, res: Response): Promise<Re
const hashedIP: HashedIP = getHash((ip + config.globalSalt) as IPAddress);
//check if this user is on the vip list
const isVIP = (await db.prepare('get', `SELECT count(*) as "userCount" FROM "vipUsers" WHERE "userID" = ?`, [nonAnonUserID])).userCount > 0;
const isVIP = (await db.prepare("get", `SELECT count(*) as "userCount" FROM "vipUsers" WHERE "userID" = ?`, [nonAnonUserID])).userCount > 0;
//check if user voting on own submission
const isOwnSubmission = (await db.prepare("get", `SELECT "UUID" as "submissionCount" FROM "sponsorTimes" where "userID" = ? AND "UUID" = ?`, [nonAnonUserID, UUID])) !== undefined;
@@ -293,13 +291,13 @@ export async function voteOnSponsorTime(req: Request, res: Response): Promise<Re
// no longer allow type 10/11 alternative votes
return res.sendStatus(400);
}
// If not upvote
if (!isVIP && type !== 1) {
const isSegmentLocked = async () => !!(await db.prepare('get', `SELECT "locked" FROM "sponsorTimes" WHERE "UUID" = ?`, [UUID]))?.locked;
const isVideoLocked = async () => !!(await db.prepare('get', 'SELECT "lockCategories".category from "lockCategories" left join "sponsorTimes"' +
' on ("lockCategories"."videoID" = "sponsorTimes"."videoID" and "lockCategories".category = "sponsorTimes".category)' +
' where "UUID" = ?', [UUID]));
const isSegmentLocked = async () => !!(await db.prepare("get", `SELECT "locked" FROM "sponsorTimes" WHERE "UUID" = ?`, [UUID]))?.locked;
const isVideoLocked = async () => !!(await db.prepare("get", `SELECT "lockCategories".category from "lockCategories" left join "sponsorTimes"
on ("lockCategories"."videoID" = "sponsorTimes"."videoID" and "lockCategories".category = "sponsorTimes".category)
where "UUID" = ?`, [UUID]));
if (await isSegmentLocked() || await isVideoLocked()) {
finalResponse.blockVote = true;
@@ -314,7 +312,7 @@ export async function voteOnSponsorTime(req: Request, res: Response): Promise<Re
if (type !== undefined && !isVIP && !isOwnSubmission) {
// Check if upvoting hidden segment
const voteInfo = await db.prepare('get', `SELECT votes FROM "sponsorTimes" WHERE "UUID" = ?`, [UUID]);
const voteInfo = await db.prepare("get", `SELECT votes FROM "sponsorTimes" WHERE "UUID" = ?`, [UUID]);
if (voteInfo && voteInfo.votes <= -2) {
if (type == 1) {
@@ -328,19 +326,19 @@ export async function voteOnSponsorTime(req: Request, res: Response): Promise<Re
const MILLISECONDS_IN_HOUR = 3600000;
const now = Date.now();
const warningsCount = (await db.prepare('get', `SELECT count(*) as count FROM warnings WHERE "userID" = ? AND "issueTime" > ? AND enabled = 1`,
const warningsCount = (await db.prepare("get", `SELECT count(*) as count FROM warnings WHERE "userID" = ? AND "issueTime" > ? AND enabled = 1`,
[nonAnonUserID, Math.floor(now - (config.hoursAfterWarningExpires * MILLISECONDS_IN_HOUR))],
)).count;
if (warningsCount >= config.maxNumberOfActiveWarnings) {
return res.status(403).send('Vote rejected due to a warning from a moderator. This means that we noticed you were making some common mistakes that are not malicious, and we just want to clarify the rules. Could you please send a message in Discord or Matrix so we can further help you?');
return res.status(403).send("Vote rejected due to a warning from a moderator. This means that we noticed you were making some common mistakes that are not malicious, and we just want to clarify the rules. Could you please send a message in Discord or Matrix so we can further help you?");
}
const voteTypeEnum = (type == 0 || type == 1 || type == 20) ? voteTypes.normal : voteTypes.incorrect;
try {
//check if vote has already happened
const votesRow = await privateDB.prepare('get', `SELECT "type" FROM "votes" WHERE "userID" = ? AND "UUID" = ?`, [userID, UUID]);
const votesRow = await privateDB.prepare("get", `SELECT "type" FROM "votes" WHERE "userID" = ? AND "UUID" = ?`, [userID, UUID]);
//-1 for downvote, 1 for upvote. Maybe more depending on reputation in the future
let incrementAmount = 0;
@@ -385,7 +383,7 @@ export async function voteOnSponsorTime(req: Request, res: Response): Promise<Re
}
//check if the increment amount should be multiplied (downvotes have more power if there have been many views)
const videoInfo = await db.prepare('get', `SELECT "videoID", "hashedVideoID", "service", "votes", "views", "userID" FROM "sponsorTimes" WHERE "UUID" = ?`, [UUID]) as
const videoInfo = await db.prepare("get", `SELECT "videoID", "hashedVideoID", "service", "votes", "views", "userID" FROM "sponsorTimes" WHERE "UUID" = ?`, [UUID]) as
{videoID: VideoID, hashedVideoID: VideoIDHash, service: Service, votes: number, views: number, userID: UserID};
if (voteTypeEnum === voteTypes.normal) {
@@ -414,9 +412,9 @@ export async function voteOnSponsorTime(req: Request, res: Response): Promise<Re
if (ableToVote) {
//update the votes table
if (votesRow != undefined) {
await privateDB.prepare('run', `UPDATE "votes" SET "type" = ? WHERE "userID" = ? AND "UUID" = ?`, [type, userID, UUID]);
await privateDB.prepare("run", `UPDATE "votes" SET "type" = ? WHERE "userID" = ? AND "UUID" = ?`, [type, userID, UUID]);
} else {
await privateDB.prepare('run', `INSERT INTO "votes" VALUES(?, ?, ?, ?)`, [UUID, userID, hashedIP, type]);
await privateDB.prepare("run", `INSERT INTO "votes" VALUES(?, ?, ?, ?)`, [UUID, userID, hashedIP, type]);
}
let columnName = "";
@@ -428,13 +426,13 @@ export async function voteOnSponsorTime(req: Request, res: Response): Promise<Re
//update the vote count on this sponsorTime
//oldIncrementAmount will be zero is row is null
await db.prepare('run', 'UPDATE "sponsorTimes" SET "' + columnName + '" = "' + columnName + '" + ? WHERE "UUID" = ?', [incrementAmount - oldIncrementAmount, UUID]);
await db.prepare("run", `UPDATE "sponsorTimes" SET "${columnName}" = "${columnName}" + ? WHERE "UUID" = ?`, [incrementAmount - oldIncrementAmount, UUID]);
if (isVIP && incrementAmount > 0 && voteTypeEnum === voteTypes.normal) {
// Unide and Lock this submission
await db.prepare('run', 'UPDATE "sponsorTimes" SET locked = 1, hidden = 0 WHERE "UUID" = ?', [UUID]);
await db.prepare("run", 'UPDATE "sponsorTimes" SET locked = 1, hidden = 0 WHERE "UUID" = ?', [UUID]);
} else if (isVIP && incrementAmount <= 0 && voteTypeEnum === voteTypes.normal) {
// Unlock if a VIP downvotes it
await db.prepare('run', 'UPDATE "sponsorTimes" SET locked = 0 WHERE "UUID" = ?', [UUID]);
// Unlock if a VIP downvotes it
await db.prepare("run", 'UPDATE "sponsorTimes" SET locked = 0 WHERE "UUID" = ?', [UUID]);
}
QueryCacher.clearVideoCache(videoInfo);
@@ -456,6 +454,6 @@ export async function voteOnSponsorTime(req: Request, res: Response): Promise<Re
return res.status(finalResponse.finalStatus).send(finalResponse.finalMessage ?? undefined);
} catch (err) {
Logger.error(err);
return res.status(500).json({error: 'Internal error creating segment vote'});
return res.status(500).json({error: "Internal error creating segment vote"});
}
}

View File

@@ -1,5 +1,5 @@
import { PoolConfig } from 'pg';
import * as redis from 'redis';
import { PoolConfig } from "pg";
import * as redis from "redis";
import { CacheOptions } from "@ajayyy/lru-diskcache";
export interface SBSConfig {

View File

@@ -17,8 +17,8 @@ export enum ActionType {
// Uncomment as needed
export enum Service {
YouTube = 'YouTube',
PeerTube = 'PeerTube',
YouTube = "YouTube",
PeerTube = "PeerTube",
// Twitch = 'Twitch',
// Nebula = 'Nebula',
// RSS = 'RSS',
@@ -26,16 +26,16 @@ export enum Service {
// Lbry = 'Lbry'
}
export interface IncomingSegment {
category: Category;
export interface IncomingSegment {
category: Category;
actionType: ActionType;
segment: string[];
segment: string[];
}
export interface Segment {
category: Category;
export interface Segment {
category: Category;
actionType: ActionType;
segment: number[];
segment: number[];
UUID: SegmentUUID;
videoDuration: VideoDuration;
}
@@ -45,8 +45,8 @@ export enum Visibility {
HIDDEN = 1
}
export interface DBSegment {
category: Category;
export interface DBSegment {
category: Category;
actionType: ActionType;
startTime: number;
endTime: number;

View File

@@ -10,24 +10,24 @@ export interface APIVideoData {
"height": number
}
],
"description": string,
"descriptionHtml": string,
"published": number,
"publishedText": string,
"keywords": string[],
"viewCount": number,
"likeCount": number,
"dislikeCount": number,
"paid": boolean,
"premium": boolean,
"isFamilyFriendly": boolean,
"allowedRegions": string[],
"genre": string,
"genreUrl": string,
"author": string,
"authorId": string,
"authorUrl": string,
@@ -38,7 +38,7 @@ export interface APIVideoData {
"height": number
}
],
"subCountText": string,
"lengthSeconds": number,
"allowRatings": boolean,
@@ -47,7 +47,7 @@ export interface APIVideoData {
"liveNow": boolean,
"isUpcoming": boolean,
"premiereTimestamp"?: number,
"hlsUrl"?: string,
"adaptiveFormats": [
{

View File

@@ -2,9 +2,9 @@ import { Category, CategoryActionType } from "../types/segments.model";
export function getCategoryActionType(category: Category): CategoryActionType {
switch (category) {
case "highlight":
return CategoryActionType.POI;
default:
return CategoryActionType.Skippable;
case "highlight":
return CategoryActionType.POI;
default:
return CategoryActionType.Skippable;
}
}

View File

@@ -7,7 +7,7 @@ export function createMemoryCache(memoryFn: (...args: any[]) => void, cacheTimeM
const promiseMemory = new Map();
return (...args: any[]) => {
// create cacheKey by joining arguments as string
const cacheKey = args.join('.');
const cacheKey = args.join(".");
// check if promising is already running
if (promiseMemory.has(cacheKey)) {
return promiseMemory.get(cacheKey);

View File

@@ -4,7 +4,7 @@ import { config } from "../config";
let DiskCache: LRU<string, string>;
if (config.diskCache) {
DiskCache = new LRU('./databases/cache', config.diskCache);
DiskCache = new LRU("./databases/cache", config.diskCache);
DiskCache.init();
} else {
DiskCache = {

View File

@@ -7,8 +7,8 @@ export function getFormattedTime(totalSeconds: number): string {
let secondsDisplay = seconds.toFixed(3);
if (seconds < 10) {
//add a zero
secondsDisplay = '0' + secondsDisplay;
secondsDisplay = `0${secondsDisplay}`;
}
return minutes + ':' + secondsDisplay;
return `${minutes}:${secondsDisplay}`;
}

View File

@@ -1,12 +1,12 @@
import crypto from 'crypto';
import { HashedValue } from '../types/hash.model';
import crypto from "crypto";
import { HashedValue } from "../types/hash.model";
export function getHash<T extends string>(value: T, times = 5000): T & HashedValue {
if (times <= 0) return "" as T & HashedValue;
for (let i = 0; i < times; i++) {
const hashCreator = crypto.createHash('sha256');
value = hashCreator.update(value).digest('hex') as T;
const hashCreator = crypto.createHash("sha256");
value = hashCreator.update(value).digest("hex") as T;
}
return value as T & HashedValue;

View File

@@ -1,6 +1,6 @@
import {config} from '../config';
import {Request} from 'express';
import { IPAddress } from '../types/segments.model';
import {config} from "../config";
import {Request} from "express";
import { IPAddress } from "../types/segments.model";
export function getIP(req: Request): IPAddress {
if (config.behindProxy === true || config.behindProxy === "true") {
@@ -8,14 +8,13 @@ export function getIP(req: Request): IPAddress {
}
switch (config.behindProxy as string) {
case "X-Forwarded-For":
return req.headers['x-forwarded-for'] as IPAddress;
case "Cloudflare":
return req.headers['cf-connecting-ip'] as IPAddress;
case "X-Real-IP":
return req.headers['x-real-ip'] as IPAddress;
default:
return req.connection.remoteAddress as IPAddress;
case "X-Forwarded-For":
return req.headers["x-forwarded-for"] as IPAddress;
case "Cloudflare":
return req.headers["cf-connecting-ip"] as IPAddress;
case "X-Real-IP":
return req.headers["x-real-ip"] as IPAddress;
default:
return req.connection.remoteAddress as IPAddress;
}
}

View File

@@ -1,8 +1,8 @@
import {getHash} from './getHash';
import { HashedValue } from '../types/hash.model';
import { ActionType, Category, VideoID } from '../types/segments.model';
import { UserID } from '../types/user.model';
import {getHash} from "./getHash";
import { HashedValue } from "../types/hash.model";
import { ActionType, VideoID } from "../types/segments.model";
import { UserID } from "../types/user.model";
export function getSubmissionUUID(videoID: VideoID, actionType: ActionType, userID: UserID, startTime: number, endTime: number): HashedValue{
return `3${getHash('v3' + videoID + startTime + endTime + userID, 1)}` as HashedValue;
return `3${getHash(`v3${videoID}${startTime}${endTime}${userID}`, 1)}` as HashedValue;
}

View File

@@ -1,9 +1,9 @@
import {config} from '../config';
import {config} from "../config";
const minimumPrefix = config.minimumPrefix || '3';
const maximumPrefix = config.maximumPrefix || '32'; // Half the hash.
const minimumPrefix = config.minimumPrefix || "3";
const maximumPrefix = config.maximumPrefix || "32"; // Half the hash.
const prefixChecker = new RegExp('^[\\da-f]{' + minimumPrefix + ',' + maximumPrefix + '}$', 'i');
const prefixChecker = new RegExp(`^[\\da-f]{${minimumPrefix},${maximumPrefix}}$`, "i");
export function hashPrefixTester(prefix: string): boolean {
return prefixChecker.test(prefix);

View File

@@ -1,4 +1,4 @@
import {db} from '../databases/databases';
import {db} from "../databases/databases";
/**
* Returns true if the user is considered trustworthy. This happens after a user has made 5 submissions and has less than 60% downvoted submissions
@@ -6,11 +6,11 @@ import {db} from '../databases/databases';
*/
export async function isUserTrustworthy(userID: string): Promise<boolean> {
//check to see if this user how many submissions this user has submitted
const totalSubmissionsRow = await db.prepare('get', `SELECT count(*) as "totalSubmissions", sum(votes) as "voteSum" FROM "sponsorTimes" WHERE "userID" = ?`, [userID]);
const totalSubmissionsRow = await db.prepare("get", `SELECT count(*) as "totalSubmissions", sum(votes) as "voteSum" FROM "sponsorTimes" WHERE "userID" = ?`, [userID]);
if (totalSubmissionsRow.totalSubmissions > 5) {
//check if they have a high downvote ratio
const downvotedSubmissionsRow = await db.prepare('get', `SELECT count(*) as "downvotedSubmissions" FROM "sponsorTimes" WHERE "userID" = ? AND (votes < 0 OR "shadowHidden" > 0)`, [userID]);
const downvotedSubmissionsRow = await db.prepare("get", `SELECT count(*) as "downvotedSubmissions" FROM "sponsorTimes" WHERE "userID" = ? AND (votes < 0 OR "shadowHidden" > 0)`, [userID]);
return (downvotedSubmissionsRow.downvotedSubmissions / totalSubmissionsRow.totalSubmissions) < 0.6 ||
(totalSubmissionsRow.voteSum > downvotedSubmissionsRow.downvotedSubmissions);

View File

@@ -1,8 +1,6 @@
import {db} from '../databases/databases';
import { HashedUserID } from '../types/user.model';
import {db} from "../databases/databases";
import { HashedUserID } from "../types/user.model";
export async function isUserVIP(userID: HashedUserID): Promise<boolean> {
return (await db.prepare('get', `SELECT count(*) as "userCount" FROM "vipUsers" WHERE "userID" = ?`, [userID])).userCount > 0;
return (await db.prepare("get", `SELECT count(*) as "userCount" FROM "vipUsers" WHERE "userID" = ?`, [userID])).userCount > 0;
}

View File

@@ -1,4 +1,4 @@
import {config} from '../config';
import {config} from "../config";
const enum LogLevel {
ERROR = "ERROR",
@@ -45,10 +45,10 @@ class Logger {
};
constructor() {
if (config.mode === 'development') {
if (config.mode === "development") {
this._settings.INFO = true;
this._settings.DEBUG = true;
} else if (config.mode === 'test') {
} else if (config.mode === "test") {
this._settings.WARN = false;
}
}

View File

@@ -9,7 +9,7 @@ async function get<T>(fetchFromDB: () => Promise<T>, key: string): Promise<T> {
if (!err && reply) {
try {
Logger.debug("Got data from redis: " + reply);
Logger.debug(`Got data from redis: ${reply}`);
return JSON.parse(reply);
} catch (e) {
// If all else, continue on to fetching from the database

View File

@@ -1,6 +1,6 @@
import {config} from '../config';
import {Logger} from './logger';
import redis, {Callback} from 'redis';
import {config} from "../config";
import {Logger} from "./logger";
import redis, {Callback} from "redis";
interface RedisSB {
get(key: string, callback?: Callback<string | null>): void;
@@ -12,17 +12,17 @@ interface RedisSB {
let exportObject: RedisSB = {
get: (key, callback?) => callback(null, undefined),
getAsync: () =>
getAsync: () =>
new Promise((resolve) => resolve({err: null, reply: undefined})),
set: (key, value, callback) => callback(null, undefined),
setAsync: () =>
setAsync: () =>
new Promise((resolve) => resolve({err: null, reply: undefined})),
delAsync: () =>
delAsync: () =>
new Promise((resolve) => resolve(null)),
};
if (config.redis) {
Logger.info('Connected to redis');
Logger.info("Connected to redis");
const client = redis.createClient(config.redis);
exportObject = client;

View File

@@ -3,16 +3,16 @@ import { UserID } from "../types/user.model";
import { Logger } from "./logger";
export function skipSegmentsKey(videoID: VideoID, service: Service): string {
return "segments.v2." + service + ".videoID." + videoID;
}
return `segments.v2.${service}.videoID.${videoID}`;
}
export function skipSegmentsHashKey(hashedVideoIDPrefix: VideoIDHash, service: Service): string {
hashedVideoIDPrefix = hashedVideoIDPrefix.substring(0, 4) as VideoIDHash;
if (hashedVideoIDPrefix.length !== 4) Logger.warn("Redis skip segment hash-prefix key is not length 4! " + hashedVideoIDPrefix);
return "segments.v2." + service + "." + hashedVideoIDPrefix;
}
if (hashedVideoIDPrefix.length !== 4) Logger.warn(`Redis skip segment hash-prefix key is not length 4! ${hashedVideoIDPrefix}`);
return `segments.v2.${service}.${hashedVideoIDPrefix}`;
}
export function reputationKey(userID: UserID): string {
return "reputation.user.v2." + userID;
}
return `reputation.user.${userID}`;
}

View File

@@ -17,22 +17,22 @@ export async function getReputation(userID: UserID): Promise<number> {
const weekAgo = Date.now() - 1000 * 60 * 60 * 24 * 45; // 45 days ago
const pastDate = Date.now() - 1000 * 60 * 60 * 24 * 45; // 45 days ago
// 1596240000000 is August 1st 2020, a little after auto upvote was disabled
const fetchFromDB = () => db.prepare("get",
`SELECT COUNT(*) AS "totalSubmissions",
SUM(CASE WHEN "votes" < 0 THEN 1 ELSE 0 END) AS "downvotedSubmissions",
SUM(CASE WHEN "votes" < 0 AND "videoID" NOT IN
(SELECT b."videoID" FROM "sponsorTimes" as b
WHERE b."userID" = ?
AND b."votes" > 0 AND b."category" = "a"."category" AND b."videoID" = "a"."videoID" LIMIT 1)
THEN 1 ELSE 0 END) AS "nonSelfDownvotedSubmissions",
SUM(CASE WHEN "timeSubmitted" > 1596240000000 THEN "votes" ELSE 0 END) AS "votedSum",
SUM(locked) AS "lockedSum",
SUM(CASE WHEN "timeSubmitted" < ? AND "timeSubmitted" > 1596240000000 AND "votes" > 0 THEN 1 ELSE 0 END) AS "semiOldUpvotedSubmissions",
SUM(CASE WHEN "timeSubmitted" < ? AND "timeSubmitted" > 1596240000000 AND "votes" > 0 THEN 1 ELSE 0 END) AS "oldUpvotedSubmissions"
FROM "sponsorTimes" as "a" WHERE "userID" = ?`, [userID, weekAgo, pastDate, userID]) as Promise<ReputationDBResult>;
const fetchFromDB = () => db.prepare("get",
`SELECT COUNT(*) AS "totalSubmissions",
SUM(CASE WHEN "votes" < 0 THEN 1 ELSE 0 END) AS "downvotedSubmissions",
SUM(CASE WHEN "votes" < 0 AND "videoID" NOT IN
(SELECT b."videoID" FROM "sponsorTimes" as b
WHERE b."userID" = ?
AND b."votes" > 0 AND b."category" = "a"."category" AND b."videoID" = "a"."videoID" LIMIT 1)
THEN 1 ELSE 0 END) AS "nonSelfDownvotedSubmissions",
SUM(CASE WHEN "timeSubmitted" > 1596240000000 THEN "votes" ELSE 0 END) AS "votedSum",
SUM(locked) AS "lockedSum",
SUM(CASE WHEN "timeSubmitted" < ? AND "timeSubmitted" > 1596240000000 AND "votes" > 0 THEN 1 ELSE 0 END) AS "semiOldUpvotedSubmissions",
SUM(CASE WHEN "timeSubmitted" < ? AND "timeSubmitted" > 1596240000000 AND "votes" > 0 THEN 1 ELSE 0 END) AS "oldUpvotedSubmissions"
FROM "sponsorTimes" as "a" WHERE "userID" = ?`, [userID, weekAgo, pastDate, userID]) as Promise<ReputationDBResult>;
const result = await QueryCacher.get(fetchFromDB, reputationKey(userID));
// Grace period
if (result.totalSubmissions < 5) {
return 0;
@@ -64,7 +64,7 @@ export async function getReputation(userID: UserID): Promise<number> {
}
function convertRange(value: number, currentMin: number, currentMax: number, targetMin: number, targetMax: number): number {
const currentRange = currentMax - currentMin;
const currentRange = currentMax - currentMin;
const targetRange = targetMax - targetMin;
return ((value - currentMin) / currentRange) * targetRange + targetMin;
}
}

View File

@@ -1,6 +1,6 @@
import {config} from '../config';
import {Logger} from '../utils/logger';
import fetch from 'node-fetch';
import {config} from "../config";
import {Logger} from "../utils/logger";
import fetch from "node-fetch";
function getVoteAuthorRaw(submissionCount: number, isVIP: boolean, isOwnSubmission: boolean): string {
if (isOwnSubmission) {
@@ -38,16 +38,15 @@ function dispatchEvent(scope: string, data: Record<string, unknown>): void {
if (!scopes.includes(scope.toLowerCase())) return;
fetch(webhookURL, {
method: 'POST',
method: "POST",
body: JSON.stringify(data),
headers: {
"Authorization": authKey,
"Event-Type": scope, // Maybe change this in the future?
'Content-Type': 'application/json'
"Content-Type": "application/json"
}
})
.catch(err => {
Logger.warn('Couldn\'t send webhook to ' + webhook.url);
}).catch(err => {
Logger.warn(`Couldn't send webhook to ${webhook.url}`);
Logger.warn(err);
});
}

View File

@@ -1,8 +1,8 @@
import fetch from 'node-fetch';
import {config} from '../config';
import {Logger} from './logger';
import { APIVideoData, APIVideoInfo } from '../types/youtubeApi.model';
import DiskCache from './diskCache';
import fetch from "node-fetch";
import {config} from "../config";
import {Logger} from "./logger";
import { APIVideoData, APIVideoInfo } from "../types/youtubeApi.model";
import DiskCache from "./diskCache";
export class YouTubeAPI {
static async listVideos(videoID: string, ignoreCache = false): Promise<APIVideoInfo> {
@@ -10,13 +10,13 @@ export class YouTubeAPI {
return { err: "Invalid video ID" };
}
const cacheKey = "yt.newleaf.video." + videoID;
const cacheKey = `yt.newleaf.video.$[videoID}`;
if (!ignoreCache) {
try {
const data = await DiskCache.get(cacheKey);
if (data) {
Logger.debug("YouTube API: cache used for video information: " + videoID);
Logger.debug(`YouTube API: cache used for video information: ${videoID}`);
return { err: null, data: JSON.parse(data) };
}
} catch (err) {
@@ -27,26 +27,26 @@ export class YouTubeAPI {
if (!config.newLeafURLs || config.newLeafURLs.length <= 0) return {err: "NewLeaf URL not found", data: null};
try {
const result = await fetch(config.newLeafURLs[Math.floor(Math.random() * config.newLeafURLs.length)] + "/api/v1/videos/" + videoID, { method: "GET" });
const result = await fetch(`${config.newLeafURLs[Math.floor(Math.random() * config.newLeafURLs.length)]}/api/v1/videos/${videoID}`, { method: "GET" });
if (result.ok) {
const data = await result.json();
if (data.error) {
Logger.warn("NewLeaf API Error for " + videoID + ": " + data.error);
Logger.warn(`NewLeaf API Error for ${videoID}: ${data.error}`);
return { err: data.error, data: null };
}
DiskCache.set(cacheKey, JSON.stringify(data))
.catch((err: any) => Logger.warn(err))
.then(() => Logger.debug("YouTube API: video information cache set for: " + videoID));
.catch((err: any) => Logger.warn(err))
.then(() => Logger.debug(`YouTube API: video information cache set for: ${videoID}`));
return { err: false, data };
} else {
return { err: result.statusText, data: null };
}
} catch (err) {
return {err, data: null};
}
}
}
}

View File

@@ -1,10 +1,10 @@
import {db, privateDB} from '../../src/databases/databases';
import {db, privateDB} from "../../src/databases/databases";
describe('dbUpgrade', () => {
it('Should update the database version when starting the application', async () => {
const dbVersion = (await db.prepare('get', 'SELECT key, value FROM config where key = ?', ['version'])).value;
const privateVersion = (await privateDB.prepare('get', 'SELECT key, value FROM config where key = ?', ['version'])).value;
describe("dbUpgrade", () => {
it("Should update the database version when starting the application", async () => {
const dbVersion = (await db.prepare("get", "SELECT key, value FROM config where key = ?", ["version"])).value;
const privateVersion = (await privateDB.prepare("get", "SELECT key, value FROM config where key = ?", ["version"])).value;
if (dbVersion >= 1 && privateVersion >= 1) return;
else return 'Versions are not at least 1. db is ' + dbVersion + ', private is ' + privateVersion;
else return `Versions are not at least 1. db is ${dbVersion}, private is ${privateVersion}`;
});
});

View File

@@ -1,62 +1,62 @@
import assert from 'assert';
import assert from "assert";
import { db } from '../../src/databases/databases';
import { getHash } from '../../src/utils/getHash';
import { archiveDownvoteSegment } from '../../src/cronjob/downvoteSegmentArchiveJob';
import { DBSegment } from '../../src/types/segments.model';
import { db } from "../../src/databases/databases";
import { getHash } from "../../src/utils/getHash";
import { archiveDownvoteSegment } from "../../src/cronjob/downvoteSegmentArchiveJob";
import { DBSegment } from "../../src/types/segments.model";
const records = [
['testtesttest', 1, 11, 2, 0, '1-uuid-0', 'testman', new Date('December 17, 2021').getTime(), 50, 'sponsor', 'skip', 'ytb', 100, 0, 0, getHash('testtesttest', 1)],
['testtesttest2', 1, 11, 2, 0, '1-uuid-0-1', 'testman', new Date('December 17, 2021').getTime(), 50, 'sponsor', 'skip', 'ytb', 120, 0, 0, getHash('testtesttest2', 1)],
['testtesttest', 12, 14, 2, 0, '1-uuid-0-2', 'testman', new Date('December 17, 2021').getTime(), 50, 'sponsor', 'mute', 'ytb', 100, 0, 0, getHash('testtesttest', 1)],
['testtesttest', 20, 33, 2, 0, '1-uuid-2', 'testman', new Date('December 17, 2021').getTime(), 50, 'intro', 'skip', 'ytb', 101, 0, 0, getHash('testtesttest', 1)],
['testtesttest,test', 1, 11, 2, 0, '1-uuid-1', 'testman', new Date('December 17, 2021').getTime(), 50, 'sponsor', 'skip', 'ytb', 140, 0, 0, getHash('testtesttest,test', 1)],
["testtesttest", 1, 11, 2, 0, "1-uuid-0", "testman", new Date("December 17, 2021").getTime(), 50, "sponsor", "skip", "ytb", 100, 0, 0, getHash("testtesttest", 1)],
["testtesttest2", 1, 11, 2, 0, "1-uuid-0-1", "testman", new Date("December 17, 2021").getTime(), 50, "sponsor", "skip", "ytb", 120, 0, 0, getHash("testtesttest2", 1)],
["testtesttest", 12, 14, 2, 0, "1-uuid-0-2", "testman", new Date("December 17, 2021").getTime(), 50, "sponsor", "mute", "ytb", 100, 0, 0, getHash("testtesttest", 1)],
["testtesttest", 20, 33, 2, 0, "1-uuid-2", "testman", new Date("December 17, 2021").getTime(), 50, "intro", "skip", "ytb", 101, 0, 0, getHash("testtesttest", 1)],
["testtesttest,test", 1, 11, 2, 0, "1-uuid-1", "testman", new Date("December 17, 2021").getTime(), 50, "sponsor", "skip", "ytb", 140, 0, 0, getHash("testtesttest,test", 1)],
['test3', 1, 11, 2, 0, '1-uuid-4', 'testman', new Date('December 17, 2021').getTime(), 50, 'sponsor', 'skip', 'ytb', 200, 0, 0, getHash('test3', 1)],
['test3', 7, 22, -3, 0, '1-uuid-5', 'testman', new Date('December 17, 2021').getTime(), 50, 'sponsor', 'skip', 'ytb', 300, 0, 0, getHash('test3', 1)],
["test3", 1, 11, 2, 0, "1-uuid-4", "testman", new Date("December 17, 2021").getTime(), 50, "sponsor", "skip", "ytb", 200, 0, 0, getHash("test3", 1)],
["test3", 7, 22, -3, 0, "1-uuid-5", "testman", new Date("December 17, 2021").getTime(), 50, "sponsor", "skip", "ytb", 300, 0, 0, getHash("test3", 1)],
['multiple', 1, 11, 2, 0, '1-uuid-6', 'testman', new Date('December 17, 2021').getTime(), 50, 'intro', 'skip', 'ytb', 400, 0, 0, getHash('multiple', 1)],
['multiple', 20, 33, -4, 0, '1-uuid-7', 'testman', new Date('October 1, 2021').getTime(), 50, 'intro', 'skip', 'ytb', 500, 0, 0, getHash('multiple', 1)],
["multiple", 1, 11, 2, 0, "1-uuid-6", "testman", new Date("December 17, 2021").getTime(), 50, "intro", "skip", "ytb", 400, 0, 0, getHash("multiple", 1)],
["multiple", 20, 33, -4, 0, "1-uuid-7", "testman", new Date("October 1, 2021").getTime(), 50, "intro", "skip", "ytb", 500, 0, 0, getHash("multiple", 1)],
['locked', 20, 33, 2, 1, '1-uuid-locked-8', 'testman', new Date('December 17, 2021').getTime(), 50, 'intro', 'skip', 'ytb', 230, 0, 0, getHash('locked', 1)],
['locked', 20, 34, 100000, 0, '1-uuid-9', 'testman', new Date('December 17, 2021').getTime(), 50, 'intro', 'skip', 'ytb', 190, 0, 0, getHash('locked', 1)],
["locked", 20, 33, 2, 1, "1-uuid-locked-8", "testman", new Date("December 17, 2021").getTime(), 50, "intro", "skip", "ytb", 230, 0, 0, getHash("locked", 1)],
["locked", 20, 34, 100000, 0, "1-uuid-9", "testman", new Date("December 17, 2021").getTime(), 50, "intro", "skip", "ytb", 190, 0, 0, getHash("locked", 1)],
['onlyHiddenSegments', 20, 34, 100000, 0, 'onlyHiddenSegments', 'testman', new Date('December 17, 2021').getTime(), 50, 'sponsor', 'skip', 'ytb', 190, 1, 0, getHash('onlyHiddenSegments', 1)],
["onlyHiddenSegments", 20, 34, 100000, 0, "onlyHiddenSegments", "testman", new Date("December 17, 2021").getTime(), 50, "sponsor", "skip", "ytb", 190, 1, 0, getHash("onlyHiddenSegments", 1)],
['requiredSegmentVid-raw', 60, 70, 2, 0, 'requiredSegmentVid-raw-1', 'testman', new Date('December 17, 2021').getTime(), 50, 'sponsor', 'skip', 'ytb', 0, 0, 0, getHash('requiredSegmentVid-raw', 1)],
['requiredSegmentVid-raw', 60, 70, -1, 0, 'requiredSegmentVid-raw-2', 'testman', new Date('December 17, 2021').getTime(), 50, 'sponsor', 'skip', 'ytb', 0, 0, 0, getHash('requiredSegmentVid-raw', 1)],
['requiredSegmentVid-raw', 80, 90, -2, 0, 'requiredSegmentVid-raw-3', 'testman', new Date('November 17, 2021').getTime(), 50, 'sponsor', 'skip', 'ytb', 0, 0, 0, getHash('requiredSegmentVid-raw', 1)],
['requiredSegmentVid-raw', 80, 90, 2, 0, 'requiredSegmentVid-raw-4', 'testman', new Date('December 17, 2021').getTime(), 50, 'sponsor', 'skip', 'ytb', 0, 0, 0, getHash('requiredSegmentVid-raw', 1)]
["requiredSegmentVid-raw", 60, 70, 2, 0, "requiredSegmentVid-raw-1", "testman", new Date("December 17, 2021").getTime(), 50, "sponsor", "skip", "ytb", 0, 0, 0, getHash("requiredSegmentVid-raw", 1)],
["requiredSegmentVid-raw", 60, 70, -1, 0, "requiredSegmentVid-raw-2", "testman", new Date("December 17, 2021").getTime(), 50, "sponsor", "skip", "ytb", 0, 0, 0, getHash("requiredSegmentVid-raw", 1)],
["requiredSegmentVid-raw", 80, 90, -2, 0, "requiredSegmentVid-raw-3", "testman", new Date("November 17, 2021").getTime(), 50, "sponsor", "skip", "ytb", 0, 0, 0, getHash("requiredSegmentVid-raw", 1)],
["requiredSegmentVid-raw", 80, 90, 2, 0, "requiredSegmentVid-raw-4", "testman", new Date("December 17, 2021").getTime(), 50, "sponsor", "skip", "ytb", 0, 0, 0, getHash("requiredSegmentVid-raw", 1)]
];
describe('downvoteSegmentArchiveJob', () => {
describe("downvoteSegmentArchiveJob", () => {
beforeEach(async () => {
const query = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", views, category, "actionType", "service", "videoDuration", "hidden", "shadowHidden", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
for (let i = 0; i < records.length; i += 1) {
await db.prepare('run', query, records[i]);
await db.prepare("run", query, records[i]);
}
return;
});
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;
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;
assert.ok(version >= 21, "version should be greater or equal to 21");
});
afterEach(async () => {
await db.prepare('run', 'DELETE FROM "sponsorTimes"');
await db.prepare('run', 'DELETE FROM "archivedSponsorTimes"');
await db.prepare("run", 'DELETE FROM "sponsorTimes"');
await db.prepare("run", 'DELETE FROM "archivedSponsorTimes"');
});
const getArchivedSegment = (): Promise<DBSegment[]> => {
return db.prepare('all', 'SELECT * FROM "archivedSponsorTimes"');
return db.prepare("all", 'SELECT * FROM "archivedSponsorTimes"');
};
const getSegmentsInMainTable = (dayLimit: number, voteLimit: number, now: number): Promise<DBSegment[]> => {
return db.prepare(
'all',
"all",
'SELECT * FROM "sponsorTimes" WHERE "votes" < ? AND (? - "timeSubmitted") > ?',
[
voteLimit,
@@ -68,17 +68,17 @@ describe('downvoteSegmentArchiveJob', () => {
const countSegmentInMainTable = (): Promise<number> => {
return db.prepare(
'get',
"get",
'SELECT COUNT(*) as count FROM "sponsorTimes"'
).then(res => res.count);
};
it('Should archive all records match', async () => {
it("Should archive all records match", async () => {
const dayLimit = 20;
const voteLimit = 0;
const time = new Date('December 17, 2022').getTime();
const time = new Date("December 17, 2022").getTime();
const res = await archiveDownvoteSegment(dayLimit, voteLimit, time);
assert.strictEqual(res, 0, 'Expection in archiveDownvoteSegment');
assert.strictEqual(res, 0, "Expection in archiveDownvoteSegment");
// check segments in archived table
const archivedSegment = await getArchivedSegment();
@@ -89,15 +89,15 @@ describe('downvoteSegmentArchiveJob', () => {
assert.strictEqual(segments.length, 0, `Incorrect segment in main table: ${segments.length} instead of 0`);
// check number segments remain in main table
assert.strictEqual(await countSegmentInMainTable(), records.length - archivedSegment.length ,'Incorrect segment remain in main table');
assert.strictEqual(await countSegmentInMainTable(), records.length - archivedSegment.length ,"Incorrect segment remain in main table");
});
it('Should archive records with vote < -1 match', async () => {
it("Should archive records with vote < -1 match", async () => {
const dayLimit = 20;
const voteLimit = -1;
const time = new Date('December 17, 2022').getTime();
const time = new Date("December 17, 2022").getTime();
const res = await archiveDownvoteSegment(dayLimit, voteLimit, time);
assert.strictEqual(res, 0, '');
assert.strictEqual(res, 0, "");
// check segments in archived table
const archivedSegment = await getArchivedSegment();
@@ -108,15 +108,15 @@ describe('downvoteSegmentArchiveJob', () => {
assert.strictEqual(segments.length, 0, `Incorrect segment in main table: ${segments.length} instead of 0`);
// check number segments remain in main table
assert.strictEqual(await countSegmentInMainTable(), records.length - archivedSegment.length ,'Incorrect segment remain in main table');
assert.strictEqual(await countSegmentInMainTable(), records.length - archivedSegment.length ,"Incorrect segment remain in main table");
});
it('Should archive records with vote < -2 and day < 30 match', async () => {
it("Should archive records with vote < -2 and day < 30 match", async () => {
const dayLimit = 30;
const voteLimit = -2;
const time = new Date('December 17, 2021').getTime();
const time = new Date("December 17, 2021").getTime();
const res = await archiveDownvoteSegment(dayLimit, voteLimit, time);
assert.strictEqual(res, 0, '');
assert.strictEqual(res, 0, "");
// check segments in archived table
const archivedSegment = await getArchivedSegment();
@@ -129,15 +129,15 @@ describe('downvoteSegmentArchiveJob', () => {
assert.strictEqual(segments.length, 0, `Incorrect segment in main table: ${segments.length} instead of 0`);
// check number segments remain in main table
assert.strictEqual(await countSegmentInMainTable(), records.length - archivedSegment.length ,'Incorrect segment remain in main table');
assert.strictEqual(await countSegmentInMainTable(), records.length - archivedSegment.length ,"Incorrect segment remain in main table");
});
it('Should archive records with vote < -2 and day < 300 match', async () => {
it("Should archive records with vote < -2 and day < 300 match", async () => {
const dayLimit = 300;
const voteLimit = -2;
const time = new Date('December 17, 2022').getTime();
const time = new Date("December 17, 2022").getTime();
const res = await archiveDownvoteSegment(dayLimit, voteLimit, time);
assert.strictEqual(res, 0, '');
assert.strictEqual(res, 0, "");
// check segments in archived table
const archivedSegment = await getArchivedSegment();
@@ -148,15 +148,15 @@ describe('downvoteSegmentArchiveJob', () => {
assert.strictEqual(segments.length, 0, `Incorrect segment in main table: ${segments.length} instead of 0`);
// check number segments remain in main table
assert.strictEqual(await countSegmentInMainTable(), records.length - archivedSegment.length ,'Incorrect segment remain in main table');
assert.strictEqual(await countSegmentInMainTable(), records.length - archivedSegment.length ,"Incorrect segment remain in main table");
});
it('Should not archive any', async () => {
it("Should not archive any", async () => {
const dayLimit = 300;
const voteLimit = -2;
const time = new Date('December 17, 2021').getTime();
const time = new Date("December 17, 2021").getTime();
const res = await archiveDownvoteSegment(dayLimit, voteLimit, time);
assert.strictEqual(res, 0, '');
assert.strictEqual(res, 0, "");
// check segments in archived table
const archivedSegment = await getArchivedSegment();
@@ -167,6 +167,6 @@ describe('downvoteSegmentArchiveJob', () => {
assert.strictEqual(segments.length, 0, `Incorrect segment in main table: ${segments.length} instead of 0`);
// check number segments remain in main table
assert.strictEqual(await countSegmentInMainTable(), records.length - archivedSegment.length ,'Incorrect segment remain in main table');
assert.strictEqual(await countSegmentInMainTable(), records.length - archivedSegment.length ,"Incorrect segment remain in main table");
});
});

View File

@@ -1,33 +1,33 @@
import {getHash} from '../../src/utils/getHash';
import assert from 'assert';
import {getHash} from "../../src/utils/getHash";
import assert from "assert";
describe('getHash', () => {
it('Should not output the input string', () => {
describe("getHash", () => {
it("Should not output the input string", () => {
assert(getHash("test") !== "test");
assert(getHash("test", -1) !== "test");
assert(getHash("test", 0) !== "test");
assert(getHash("test", null) !== "test");
});
it('Should return a hashed value', () => {
it("Should return a hashed value", () => {
assert.strictEqual(getHash("test"), "2f327ef967ade1ebf4319163f7debbda9cc17bb0c8c834b00b30ca1cf1c256ee");
});
it('Should be able to output the same has the DB upgrade script will output', () => {
it("Should be able to output the same has the DB upgrade script will output", () => {
assert.strictEqual(getHash("vid", 1), "1ff838dc6ca9680d88455341118157d59a055fe6d0e3870f9c002847bebe4663");
});
it('Should take a variable number of passes', () => {
it("Should take a variable number of passes", () => {
assert.strictEqual(getHash("test", 1), "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08");
assert.strictEqual(getHash("test", 2), "7b3d979ca8330a94fa7e9e1b466d8b99e0bcdea1ec90596c0dcc8d7ef6b4300c");
assert.strictEqual(getHash("test", 3), "5b24f7aa99f1e1da5698a4f91ae0f4b45651a1b625c61ed669dd25ff5b937972");
});
it('Should default to 5000 passes', () => {
it("Should default to 5000 passes", () => {
assert.strictEqual(getHash("test"), getHash("test", 5000));
});
it('Should not take a negative number of passes', () => {
it("Should not take a negative number of passes", () => {
assert.strictEqual(getHash("test", -1), "");
});
});

View File

@@ -1,56 +1,52 @@
import fetch from 'node-fetch';
import {getbaseURL, Done} from '../utils';
import {db} from '../../src/databases/databases';
import {getHash} from '../../src/utils/getHash';
import assert from 'assert';
import fetch from "node-fetch";
import {getbaseURL, Done} from "../utils";
import {db} from "../../src/databases/databases";
import {getHash} from "../../src/utils/getHash";
import assert from "assert";
describe('getIsUserVIP', () => {
describe("getIsUserVIP", () => {
before((done: Done) => {
db.prepare("run", 'INSERT INTO "vipUsers" ("userID") VALUES (?)', [getHash("supertestman")]).then(done);
});
it('Should be able to get a 200', (done: Done) => {
fetch(getbaseURL() + "/api/isUserVIP?userID=supertestman")
.then(res => {
assert.strictEqual(res.status, 200, "response should be 200");
done();
})
.catch(err => done(err));
it("Should be able to get a 200", (done: Done) => {
fetch(`${getbaseURL()}/api/isUserVIP?userID=supertestman`)
.then(res => {
assert.strictEqual(res.status, 200, "response should be 200");
done();
})
.catch(err => done(err));
});
it('Should get a 400 if no userID', (done: Done) => {
fetch(getbaseURL() + "/api/isUserVIP")
.then(res => {
assert.strictEqual(res.status, 400, "response should be 400");
done();
})
.catch(err => done(err));
it("Should get a 400 if no userID", (done: Done) => {
fetch(`${getbaseURL()}/api/isUserVIP`)
.then(res => {
assert.strictEqual(res.status, 400, "response should be 400");
done();
})
.catch(err => done(err));
});
it('Should say a VIP is a VIP', (done: Done) => {
fetch(getbaseURL() + "/api/isUserVIP?userID=supertestman")
.then(async res => {
if (res.status !== 200) done("non 200: " + res.status);
else {
it("Should say a VIP is a VIP", (done: Done) => {
fetch(`${getbaseURL()}/api/isUserVIP?userID=supertestman`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.vip, true);
done();
}
})
.catch(err => done(err));
})
.catch(err => done(err));
});
it('Should say a normal user is not a VIP', (done: Done) => {
fetch(getbaseURL() + "/api/isUserVIP?userID=regulartestman")
.then(async res => {
if (res.status !== 200) done("non 200: " + res.status);
else {
it("Should say a normal user is not a VIP", (done: Done) => {
fetch(`${getbaseURL()}/api/isUserVIP?userID=regulartestman`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.vip, false);
done();
}
})
.catch(err => done(err));
})
.catch(err => done(err));
});
});

View File

@@ -1,80 +1,80 @@
import fetch from 'node-fetch';
import {Done, getbaseURL} from '../utils';
import {getHash} from '../../src/utils/getHash';
import {db} from '../../src/databases/databases';
import assert from 'assert';
import fetch from "node-fetch";
import {Done, getbaseURL} from "../utils";
import {getHash} from "../../src/utils/getHash";
import {db} from "../../src/databases/databases";
import assert from "assert";
describe('getLockCategories', () => {
describe("getLockCategories", () => {
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", "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', '2-reason']);
await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'getLock-3', 'nonmusic', '3-reason']);
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", "2-reason"]);
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;
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 > 20) return;
else return 'Version isn\'t greater than 20. Version is ' + version;
else return `Version isn't greater than 20. Version is ${version}`;
});
it('Should be able to get multiple locks', (done: Done) => {
fetch(getbaseURL() + '/api/lockCategories?videoID=getLock-1')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
const expected = {
categories: [
"sponsor",
"interaction"
],
reason: "1-longer-reason"
};
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
it("Should be able to get multiple locks", (done: Done) => {
fetch(`${getbaseURL()}/api/lockCategories?videoID=getLock-1`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
const expected = {
categories: [
"sponsor",
"interaction"
],
reason: "1-longer-reason"
};
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('Should be able to get single locks', (done: Done) => {
fetch(getbaseURL() + '/api/lockCategories?videoID=getLock-2')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
const expected = {
categories: [
"preview"
],
reason: "2-reason"
};
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
it("Should be able to get single locks", (done: Done) => {
fetch(`${getbaseURL()}/api/lockCategories?videoID=getLock-2`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
const expected = {
categories: [
"preview"
],
reason: "2-reason"
};
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('should return 404 if no lock exists', (done: Done) => {
fetch(getbaseURL() + '/api/lockCategories?videoID=getLock-0')
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
it("should return 404 if no lock exists", (done: Done) => {
fetch(`${getbaseURL()}/api/lockCategories?videoID=getLock-0`)
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
});
it('should return 400 if no videoID specified', (done: Done) => {
fetch(getbaseURL() + '/api/lockCategories')
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
it("should return 400 if no videoID specified", (done: Done) => {
fetch(`${getbaseURL()}/api/lockCategories`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
});

View File

@@ -1,169 +1,169 @@
import fetch from 'node-fetch';
import {Done, getbaseURL} from '../utils';
import {getHash} from '../../src/utils/getHash';
import {db} from '../../src/databases/databases';
import assert from 'assert';
import fetch from "node-fetch";
import {Done, getbaseURL} from "../utils";
import {getHash} from "../../src/utils/getHash";
import {db} from "../../src/databases/databases";
import assert from "assert";
describe('getLockCategoriesByHash', () => {
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", "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', '2-reason', 'dff09120437b4bd594dffae5f3cde3cfc5f6099fb01d0ef4051919b2908d9a50']);
await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), 'getLockHash-3', 'nonmusic', '3-reason', 'bf1b122fd5630e0df8626d00c4a95c58954ad715e5595b0f75a19ac131e28928']);
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"), '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']);
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", "3-reason", "bf1b122fd5630e0df8626d00c4a95c58954ad715e5595b0f75a19ac131e28928"]);
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 20', async () => {
const version = (await db.prepare('get', 'SELECT key, value FROM config where key = ?', ['version'])).value;
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 >= 20) return;
else return 'Version isn\'t greater than 20. Version is ' + version;
else return `Version isn't greater than 20. Version is ${version}`;
});
it('Should be able to get multiple locks in one object', (done: Done) => {
fetch(getbaseURL() + '/api/lockCategories/67a65')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
const expected = [{
videoID: "getLockHash-1",
hash: getHash("getLockHash-1", 1),
categories: [
"sponsor",
"interaction"
],
reason: "1-reason-longer"
}];
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
it("Should be able to get multiple locks in one object", (done: Done) => {
fetch(`${getbaseURL()}/api/lockCategories/67a65`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
const expected = [{
videoID: "getLockHash-1",
hash: getHash("getLockHash-1", 1),
categories: [
"sponsor",
"interaction"
],
reason: "1-reason-longer"
}];
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('Should be able to get single lock', (done: Done) => {
fetch(getbaseURL() + '/api/lockCategories/dff09')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
const expected = [{
videoID: "getLockHash-2",
hash: getHash("getLockHash-2", 1),
categories: [
"preview"
],
reason: "2-reason"
}];
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('Should be able to get by half full hash', (done: Done) => {
fetch(getbaseURL() + '/api/lockCategories/bf1b122fd5630e0df8626d00c4a95c58')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
const expected = [{
videoID: "getLockHash-3",
hash: getHash("getLockHash-3", 1),
categories: [
"nonmusic"
],
reason: "3-reason"
}];
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
it("Should be able to get single lock", (done: Done) => {
fetch(`${getbaseURL()}/api/lockCategories/dff09`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
const expected = [{
videoID: "getLockHash-2",
hash: getHash("getLockHash-2", 1),
categories: [
"preview"
],
reason: "2-reason"
}];
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('Should be able to get multiple by similar hash with multiple categories', (done: Done) => {
fetch(getbaseURL() + '/api/lockCategories/b05a')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
const expected = [{
videoID: "fakehash-1",
hash: "b05a20424f24a53dac1b059fb78d861ba9723645026be2174c93a94f9106bb35",
categories: [
"outro"
],
reason: "fake1-reason"
}, {
videoID: "fakehash-2",
hash: "b05acd1cd6ec7dffe5ffea64ada91ae7469d6db2ce21c7e30ad7fa62075d450",
categories: [
"intro",
"preview"
],
reason: "fake2-longer-reason"
}];
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
it("Should be able to get by half full hash", (done: Done) => {
fetch(`${getbaseURL()}/api/lockCategories/bf1b122fd5630e0df8626d00c4a95c58`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
const expected = [{
videoID: "getLockHash-3",
hash: getHash("getLockHash-3", 1),
categories: [
"nonmusic"
],
reason: "3-reason"
}];
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('should return 404 once hash prefix varies', (done: Done) => {
fetch(getbaseURL() + '/api/lockCategories/b05aa')
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
it("Should be able to get multiple by similar hash with multiple categories", (done: Done) => {
fetch(`${getbaseURL()}/api/lockCategories/b05a`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
const expected = [{
videoID: "fakehash-1",
hash: "b05a20424f24a53dac1b059fb78d861ba9723645026be2174c93a94f9106bb35",
categories: [
"outro"
],
reason: "fake1-reason"
}, {
videoID: "fakehash-2",
hash: "b05acd1cd6ec7dffe5ffea64ada91ae7469d6db2ce21c7e30ad7fa62075d450",
categories: [
"intro",
"preview"
],
reason: "fake2-longer-reason"
}];
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('should return 404 if no lock exists', (done: Done) => {
fetch(getbaseURL() + '/api/lockCategories/aaaaaa')
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
it("should return 404 once hash prefix varies", (done: Done) => {
fetch(`${getbaseURL()}/api/lockCategories/b05aa`)
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
});
it('should return 400 if no videoID specified', (done: Done) => {
fetch(getbaseURL() + '/api/lockCategories/')
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
it("should return 404 if no lock exists", (done: Done) => {
fetch(`${getbaseURL()}/api/lockCategories/aaaaaa`)
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
});
it('should return 400 if full hash sent', (done: Done) => {
fetch(getbaseURL() + '/api/lockCategories/b05a20424f24a53dac1b059fb78d861ba9723645026be2174c93a94f9106bb35')
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
it("should return 400 if no videoID specified", (done: Done) => {
fetch(`${getbaseURL()}/api/lockCategories/`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.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 full hash sent", (done: Done) => {
fetch(`${getbaseURL()}/api/lockCategories/b05a20424f24a53dac1b059fb78d861ba9723645026be2174c93a94f9106bb35`)
.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));
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));
});
});

View File

@@ -1,29 +1,29 @@
import fetch from 'node-fetch';
import {Done, getbaseURL} from '../utils';
import {db} from '../../src/databases/databases';
import {getHash} from '../../src/utils/getHash';
import assert from 'assert';
import fetch from "node-fetch";
import {Done, getbaseURL} from "../utils";
import {db} from "../../src/databases/databases";
import {getHash} from "../../src/utils/getHash";
import assert from "assert";
describe('getSavedTimeForUser', () => {
describe("getSavedTimeForUser", () => {
before(async () => {
const startOfQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "shadowHidden", "hashedVideoID") VALUES';
await db.prepare("run", startOfQuery + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
['getSavedTimeForUser', 1, 11, 2, 'abc1239999', getHash("testman"), 0, 50, 'sponsor', 0, getHash('getSavedTimeForUser', 0)]);
await db.prepare("run", `${startOfQuery}(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
["getSavedTimeForUser", 1, 11, 2, "abc1239999", getHash("testman"), 0, 50, "sponsor", 0, getHash("getSavedTimeForUser", 0)]);
return;
});
it('Should be able to get a 200', (done: Done) => {
fetch(getbaseURL() + "/api/getSavedTimeForUser?userID=testman")
.then(async res => {
const data = await res.json();
// (end-start)*minute * views
const savedMinutes = ((11-1)/60) * 50;
const expected = {
timeSaved: savedMinutes
};
assert.deepStrictEqual(data, expected);
done();
})
.catch((err) => done(err));
it("Should be able to get a 200", (done: Done) => {
fetch(`${getbaseURL()}/api/getSavedTimeForUser?userID=testman`)
.then(async res => {
const data = await res.json();
// (end-start)*minute * views
const savedMinutes = ((11-1)/60) * 50;
const expected = {
timeSaved: savedMinutes
};
assert.deepStrictEqual(data, expected);
done();
})
.catch((err) => done(err));
});
});

View File

@@ -1,298 +1,298 @@
import fetch from 'node-fetch';
import {db} from '../../src/databases/databases';
import {Done, getbaseURL} from '../utils';
import {getHash} from '../../src/utils/getHash';
import assert from 'assert';
import fetch from "node-fetch";
import {db} from "../../src/databases/databases";
import {Done, getbaseURL} from "../utils";
import {getHash} from "../../src/utils/getHash";
import assert from "assert";
const ENOENTID = "0".repeat(64);
const upvotedID = "a"+"0".repeat(63);
const downvotedID = "b"+"0".repeat(63);
const lockedupID = "c"+"0".repeat(63);
const infvotesID = "d"+"0".repeat(63);
const shadowhiddenID = "e"+"0".repeat(63);
const lockeddownID = "f"+"0".repeat(63);
const hiddenID = "1"+"0".repeat(63);
const fillerID1 = "11"+"0".repeat(62);
const fillerID2 = "12"+"0".repeat(62);
const fillerID3 = "13"+"0".repeat(62);
const fillerID4 = "14"+"0".repeat(62);
const fillerID5 = "15"+"0".repeat(62);
const oldID = `${'0'.repeat(8)}-${'0000-'.repeat(3)}${'0'.repeat(12)}`;
const upvotedID = `a${"0".repeat(63)}`;
const downvotedID = `b${"0".repeat(63)}`;
const lockedupID = `c${"0".repeat(63)}`;
const infvotesID = `d${"0".repeat(63)}`;
const shadowhiddenID = `e${"0".repeat(63)}`;
const lockeddownID = `f${"0".repeat(63)}`;
const hiddenID = `1${"0".repeat(63)}`;
const fillerID1 = `11${"0".repeat(62)}`;
const fillerID2 = `12${"0".repeat(62)}`;
const fillerID3 = `13${"0".repeat(62)}`;
const fillerID4 = `14${"0".repeat(62)}`;
const fillerID5 = `15${"0".repeat(62)}`;
const oldID = `${"0".repeat(8)}-${"0000-".repeat(3)}${"0".repeat(12)}`;
describe('getSegmentInfo', () => {
describe("getSegmentInfo", () => {
before(async () => {
const insertQuery = `INSERT INTO
"sponsorTimes"("videoID", "startTime", "endTime", "votes", "locked",
"UUID", "userID", "timeSubmitted", "views", "category", "service",
"videoDuration", "hidden", "shadowHidden", "hashedVideoID")
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
await db.prepare("run", insertQuery, ['upvoted', 1, 10, 2, 0, upvotedID, 'testman', 0, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash('upvoted', 1)]);
await db.prepare("run", insertQuery, ['downvoted', 1, 10, -2, 0, downvotedID, 'testman', 0, 50, 'sponsor', 'YouTube', 120, 0, 0, getHash('downvoted', 1)]);
await db.prepare("run", insertQuery, ['locked-up', 1, 10, 2, 1, lockedupID, 'testman', 0, 50, 'sponsor', 'YouTube', 101, 0, 0, getHash('locked-up', 1)]);
await db.prepare("run", insertQuery, ['infvotes', 1, 10, 100000, 0, infvotesID, 'testman', 0, 50, 'sponsor', 'YouTube', 101, 0, 0, getHash('infvotes', 1)]);
await db.prepare("run", insertQuery, ['hidden', 1, 10, 2, 0, hiddenID, 'testman', 0, 50, 'sponsor', 'YouTube', 140, 1, 0, getHash('hidden', 1)]);
await db.prepare("run", insertQuery, ['shadowhidden', 1, 10, 2, 0, shadowhiddenID, 'testman', 0, 50, 'sponsor', 'YouTube', 140, 0, 1, getHash('shadowhidden', 1)]);
await db.prepare("run", insertQuery, ['locked-down', 1, 10, -2, 1, lockeddownID, 'testman', 0, 50, 'sponsor', 'YouTube', 200, 0, 0, getHash('locked-down', 1)]);
await db.prepare("run", insertQuery, ['oldID', 1, 10, 1, 0, oldID, 'testman', 0, 50, 'sponsor', 'YouTube', 300, 0, 0, getHash('oldID', 1)]);
await db.prepare("run", insertQuery, ['filler', 1, 2, 1, 0, fillerID1, 'testman', 0, 50, 'sponsor', 'YouTube', 300, 0, 0, getHash('filler', 1)]);
await db.prepare("run", insertQuery, ['filler', 2, 3, 1, 0, fillerID2, 'testman', 0, 50, 'sponsor', 'YouTube', 300, 0, 0, getHash('filler', 1)]);
await db.prepare("run", insertQuery, ['filler', 3, 4, 1, 0, fillerID3, 'testman', 0, 50, 'sponsor', 'YouTube', 300, 0, 0, getHash('filler', 1)]);
await db.prepare("run", insertQuery, ['filler', 4, 5, 1, 0, fillerID4, 'testman', 0, 50, 'sponsor', 'YouTube', 300, 0, 0, getHash('filler', 1)]);
await db.prepare("run", insertQuery, ['filler', 5, 6, 1, 0, fillerID5, 'testman', 0, 50, 'sponsor', 'YouTube', 300, 0, 0, getHash('filler', 1)]);
await db.prepare("run", insertQuery, ["upvoted", 1, 10, 2, 0, upvotedID, "testman", 0, 50, "sponsor", "YouTube", 100, 0, 0, getHash("upvoted", 1)]);
await db.prepare("run", insertQuery, ["downvoted", 1, 10, -2, 0, downvotedID, "testman", 0, 50, "sponsor", "YouTube", 120, 0, 0, getHash("downvoted", 1)]);
await db.prepare("run", insertQuery, ["locked-up", 1, 10, 2, 1, lockedupID, "testman", 0, 50, "sponsor", "YouTube", 101, 0, 0, getHash("locked-up", 1)]);
await db.prepare("run", insertQuery, ["infvotes", 1, 10, 100000, 0, infvotesID, "testman", 0, 50, "sponsor", "YouTube", 101, 0, 0, getHash("infvotes", 1)]);
await db.prepare("run", insertQuery, ["hidden", 1, 10, 2, 0, hiddenID, "testman", 0, 50, "sponsor", "YouTube", 140, 1, 0, getHash("hidden", 1)]);
await db.prepare("run", insertQuery, ["shadowhidden", 1, 10, 2, 0, shadowhiddenID, "testman", 0, 50, "sponsor", "YouTube", 140, 0, 1, getHash("shadowhidden", 1)]);
await db.prepare("run", insertQuery, ["locked-down", 1, 10, -2, 1, lockeddownID, "testman", 0, 50, "sponsor", "YouTube", 200, 0, 0, getHash("locked-down", 1)]);
await db.prepare("run", insertQuery, ["oldID", 1, 10, 1, 0, oldID, "testman", 0, 50, "sponsor", "YouTube", 300, 0, 0, getHash("oldID", 1)]);
await db.prepare("run", insertQuery, ["filler", 1, 2, 1, 0, fillerID1, "testman", 0, 50, "sponsor", "YouTube", 300, 0, 0, getHash("filler", 1)]);
await db.prepare("run", insertQuery, ["filler", 2, 3, 1, 0, fillerID2, "testman", 0, 50, "sponsor", "YouTube", 300, 0, 0, getHash("filler", 1)]);
await db.prepare("run", insertQuery, ["filler", 3, 4, 1, 0, fillerID3, "testman", 0, 50, "sponsor", "YouTube", 300, 0, 0, getHash("filler", 1)]);
await db.prepare("run", insertQuery, ["filler", 4, 5, 1, 0, fillerID4, "testman", 0, 50, "sponsor", "YouTube", 300, 0, 0, getHash("filler", 1)]);
await db.prepare("run", insertQuery, ["filler", 5, 6, 1, 0, fillerID5, "testman", 0, 50, "sponsor", "YouTube", 300, 0, 0, getHash("filler", 1)]);
});
it('Should be able to retreive upvoted segment', (done: Done) => {
fetch(getbaseURL() + `/api/segmentInfo?UUID=${upvotedID}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "upvoted");
assert.strictEqual(data[0].votes, 2);
done();
})
.catch(err => done(err));
it("Should be able to retreive upvoted segment", (done: Done) => {
fetch(`${getbaseURL()}/api/segmentInfo?UUID=${upvotedID}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "upvoted");
assert.strictEqual(data[0].votes, 2);
done();
})
.catch(err => done(err));
});
it('Should be able to retreive downvoted segment', (done: Done) => {
fetch(getbaseURL() + `/api/segmentInfo?UUID=${downvotedID}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "downvoted");
assert.strictEqual(data[0].votes, -2);
done();
})
.catch(err => done(err));
it("Should be able to retreive downvoted segment", (done: Done) => {
fetch(`${getbaseURL()}/api/segmentInfo?UUID=${downvotedID}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "downvoted");
assert.strictEqual(data[0].votes, -2);
done();
})
.catch(err => done(err));
});
it('Should be able to retreive locked up segment', (done: Done) => {
fetch(getbaseURL() + `/api/segmentInfo?UUID=${lockedupID}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "locked-up");
assert.strictEqual(data[0].locked, 1);
assert.strictEqual(data[0].votes, 2);
done();
})
.catch(err => done(err));
it("Should be able to retreive locked up segment", (done: Done) => {
fetch(`${getbaseURL()}/api/segmentInfo?UUID=${lockedupID}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "locked-up");
assert.strictEqual(data[0].locked, 1);
assert.strictEqual(data[0].votes, 2);
done();
})
.catch(err => done(err));
});
it('Should be able to retreive infinite vote segment', (done: Done) => {
fetch(getbaseURL() + `/api/segmentInfo?UUID=${infvotesID}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "infvotes");
assert.strictEqual(data[0].votes, 100000);
done();
})
.catch(err => done(err));
it("Should be able to retreive infinite vote segment", (done: Done) => {
fetch(`${getbaseURL()}/api/segmentInfo?UUID=${infvotesID}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "infvotes");
assert.strictEqual(data[0].votes, 100000);
done();
})
.catch(err => done(err));
});
it('Should be able to retreive shadowhidden segment', (done: Done) => {
fetch(getbaseURL() + `/api/segmentInfo?UUID=${shadowhiddenID}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "shadowhidden");
assert.strictEqual(data[0].shadowHidden, 1);
done();
})
.catch(err => done(err));
it("Should be able to retreive shadowhidden segment", (done: Done) => {
fetch(`${getbaseURL()}/api/segmentInfo?UUID=${shadowhiddenID}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "shadowhidden");
assert.strictEqual(data[0].shadowHidden, 1);
done();
})
.catch(err => done(err));
});
it('Should be able to retreive locked down segment', (done: Done) => {
fetch(getbaseURL() + `/api/segmentInfo?UUID=${lockeddownID}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "locked-down");
assert.strictEqual(data[0].votes, -2);
assert.strictEqual(data[0].locked, 1);
done();
})
.catch(err => done(err));
it("Should be able to retreive locked down segment", (done: Done) => {
fetch(`${getbaseURL()}/api/segmentInfo?UUID=${lockeddownID}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "locked-down");
assert.strictEqual(data[0].votes, -2);
assert.strictEqual(data[0].locked, 1);
done();
})
.catch(err => done(err));
});
it('Should be able to retreive hidden segment', (done: Done) => {
fetch(getbaseURL() + `/api/segmentInfo?UUID=${hiddenID}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "hidden");
assert.strictEqual(data[0].hidden, 1);
done();
})
.catch(err => done(err));
it("Should be able to retreive hidden segment", (done: Done) => {
fetch(`${getbaseURL() }/api/segmentInfo?UUID=${hiddenID}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "hidden");
assert.strictEqual(data[0].hidden, 1);
done();
})
.catch(err => done(err));
});
it('Should be able to retreive segment with old ID', (done: Done) => {
fetch(getbaseURL() + `/api/segmentInfo?UUID=${oldID}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "oldID");
assert.strictEqual(data[0].votes, 1);
done();
})
.catch(err => done(err));
it("Should be able to retreive segment with old ID", (done: Done) => {
fetch(`${getbaseURL()}/api/segmentInfo?UUID=${oldID}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "oldID");
assert.strictEqual(data[0].votes, 1);
done();
})
.catch(err => done(err));
});
it('Should be able to retreive single segment in array', (done: Done) => {
fetch(getbaseURL() + `/api/segmentInfo?UUIDs=["${upvotedID}"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].videoID, "upvoted");
assert.strictEqual(data[0].votes, 2);
done();
})
.catch(err => done(err));
it("Should be able to retreive single segment in array", (done: Done) => {
fetch(`${getbaseURL()}/api/segmentInfo?UUIDs=["${upvotedID}"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].videoID, "upvoted");
assert.strictEqual(data[0].votes, 2);
done();
})
.catch(err => done(err));
});
it('Should be able to retreive multiple segments in array', (done: Done) => {
fetch(getbaseURL() + `/api/segmentInfo?UUIDs=["${upvotedID}", "${downvotedID}"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].videoID, "upvoted");
assert.strictEqual(data[0].votes, 2);
assert.strictEqual(data[1].videoID, "downvoted");
assert.strictEqual(data[1].votes, -2);
done();
})
.catch(err => done(err));
it("Should be able to retreive multiple segments in array", (done: Done) => {
fetch(`${getbaseURL()}/api/segmentInfo?UUIDs=["${upvotedID}", "${downvotedID}"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].videoID, "upvoted");
assert.strictEqual(data[0].votes, 2);
assert.strictEqual(data[1].videoID, "downvoted");
assert.strictEqual(data[1].votes, -2);
done();
})
.catch(err => done(err));
});
it('Should be possible to send unexpected query parameters', (done: Done) => {
fetch(getbaseURL() + `/api/segmentInfo?UUID=${upvotedID}&fakeparam=hello&category=sponsor`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "upvoted");
assert.strictEqual(data[0].votes, 2);
done();
})
.catch(err => done(err));
it("Should be possible to send unexpected query parameters", (done: Done) => {
fetch(`${getbaseURL()}/api/segmentInfo?UUID=${upvotedID}&fakeparam=hello&category=sponsor`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "upvoted");
assert.strictEqual(data[0].votes, 2);
done();
})
.catch(err => done(err));
});
it('Should return 400 if array passed to UUID', (done: Done) => {
fetch(getbaseURL() + `/api/segmentInfo?UUID=["${upvotedID}", "${downvotedID}"]`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
it("Should return 400 if array passed to UUID", (done: Done) => {
fetch(`${getbaseURL()}/api/segmentInfo?UUID=["${upvotedID}", "${downvotedID}"]`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Should return 400 if bad array passed to UUIDs', (done: Done) => {
fetch(getbaseURL() + "/api/segmentInfo?UUIDs=[not-quoted,not-quoted]")
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
it("Should return 400 if bad array passed to UUIDs", (done: Done) => {
fetch(`${getbaseURL()}/api/segmentInfo?UUIDs=[not-quoted,not-quoted]`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Should return 400 if bad UUID passed', (done: Done) => {
fetch(getbaseURL() + "/api/segmentInfo?UUID=notarealuuid")
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
it("Should return 400 if bad UUID passed", (done: Done) => {
fetch(`${getbaseURL()}/api/segmentInfo?UUID=notarealuuid`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Should return 400 if bad UUIDs passed in array', (done: Done) => {
fetch(getbaseURL() + `/api/segmentInfo?UUIDs=["notarealuuid", "anotherfakeuuid"]`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
it("Should return 400 if bad UUIDs passed in array", (done: Done) => {
fetch(`${getbaseURL()}/api/segmentInfo?UUIDs=["notarealuuid", "anotherfakeuuid"]`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Should return good UUID when mixed with bad UUIDs', (done: Done) => {
fetch(getbaseURL() + `/api/segmentInfo?UUIDs=["${upvotedID}", "anotherfakeuuid"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].videoID, "upvoted");
assert.strictEqual(data[0].votes, 2);
done();
})
.catch(err => done(err));
it("Should return good UUID when mixed with bad UUIDs", (done: Done) => {
fetch(`${getbaseURL()}/api/segmentInfo?UUIDs=["${upvotedID}", "anotherfakeuuid"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].videoID, "upvoted");
assert.strictEqual(data[0].votes, 2);
done();
})
.catch(err => done(err));
});
it('Should cut off array at 10', function(done: Done) {
it("Should cut off array at 10", function(done: Done) {
this.timeout(10000);
const filledIDArray = `["${upvotedID}", "${downvotedID}", "${lockedupID}", "${shadowhiddenID}", "${lockeddownID}", "${hiddenID}", "${fillerID1}", "${fillerID2}", "${fillerID3}", "${fillerID4}", "${fillerID5}"]`;
fetch(getbaseURL() + `/api/segmentInfo?UUIDs=${filledIDArray}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 10);
assert.strictEqual(data[0].videoID, "upvoted");
assert.strictEqual(data[0].votes, 2);
assert.strictEqual(data[9].videoID, "filler");
assert.strictEqual(data[9].UUID, fillerID4);
done();
})
.catch(err => done(err));
fetch(`${getbaseURL()}/api/segmentInfo?UUIDs=${filledIDArray}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 10);
assert.strictEqual(data[0].videoID, "upvoted");
assert.strictEqual(data[0].votes, 2);
assert.strictEqual(data[9].videoID, "filler");
assert.strictEqual(data[9].UUID, fillerID4);
done();
})
.catch(err => done(err));
});
it('Should not duplicate reponses', (done: Done) => {
fetch(getbaseURL() + `/api/segmentInfo?UUIDs=["${upvotedID}", "${upvotedID}", "${upvotedID}", "${upvotedID}", "${upvotedID}", "${upvotedID}", "${upvotedID}", "${upvotedID}", "${upvotedID}", "${upvotedID}", "${downvotedID}"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].videoID, "upvoted");
assert.strictEqual(data[0].votes, 2);
assert.strictEqual(data[1].videoID, "downvoted");
assert.strictEqual(data[1].votes, -2);
done();
})
.catch(err => done(err));
it("Should not duplicate reponses", (done: Done) => {
fetch(`${getbaseURL()}/api/segmentInfo?UUIDs=["${upvotedID}", "${upvotedID}", "${upvotedID}", "${upvotedID}", "${upvotedID}", "${upvotedID}", "${upvotedID}", "${upvotedID}", "${upvotedID}", "${upvotedID}", "${downvotedID}"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].videoID, "upvoted");
assert.strictEqual(data[0].votes, 2);
assert.strictEqual(data[1].videoID, "downvoted");
assert.strictEqual(data[1].votes, -2);
done();
})
.catch(err => done(err));
});
it('Should return 400 if UUID not found', (done: Done) => {
fetch(getbaseURL() + `/api/segmentInfo?UUID=${ENOENTID}`)
.then(res => {
if (res.status !== 400) done("non 400 respone code: " + res.status);
else done(); // pass
})
.catch(err => done(err));
it("Should return 400 if UUID not found", (done: Done) => {
fetch(`${getbaseURL()}/api/segmentInfo?UUID=${ENOENTID}`)
.then(res => {
if (res.status !== 400) done(`non 400 respone code: ${res.status}`);
else done(); // pass
})
.catch(err => done(err));
});
it('Should be able to retreive multiple segments with multiple parameters', (done: Done) => {
fetch(getbaseURL() + `/api/segmentInfo?UUID=${upvotedID}&UUID=${downvotedID}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].videoID, "upvoted");
assert.strictEqual(data[1].videoID, "downvoted");
assert.strictEqual(data[0].votes, 2);
assert.strictEqual(data[1].votes, -2);
done();
})
.catch(err => done(err));
it("Should be able to retreive multiple segments with multiple parameters", (done: Done) => {
fetch(`${getbaseURL()}/api/segmentInfo?UUID=${upvotedID}&UUID=${downvotedID}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].videoID, "upvoted");
assert.strictEqual(data[1].videoID, "downvoted");
assert.strictEqual(data[0].votes, 2);
assert.strictEqual(data[1].votes, -2);
done();
})
.catch(err => done(err));
});
it('Should not parse repeated UUID if UUIDs present', (done: Done) => {
fetch(getbaseURL() + `/api/segmentInfo?UUID=${downvotedID}&UUID=${lockedupID}&UUIDs=["${upvotedID}"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "upvoted");
assert.strictEqual(data[0].votes, 2);
done();
})
.catch(err => done(err));
it("Should not parse repeated UUID if UUIDs present", (done: Done) => {
fetch(`${getbaseURL()}/api/segmentInfo?UUID=${downvotedID}&UUID=${lockedupID}&UUIDs=["${upvotedID}"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data[0].videoID, "upvoted");
assert.strictEqual(data[0].votes, 2);
done();
})
.catch(err => done(err));
});
});

View File

@@ -1,344 +1,344 @@
import fetch from 'node-fetch';
import {db} from '../../src/databases/databases';
import {Done, getbaseURL} from '../utils';
import {getHash} from '../../src/utils/getHash';
import assert from 'assert';
import fetch from "node-fetch";
import {db} from "../../src/databases/databases";
import {Done, getbaseURL} from "../utils";
import {getHash} from "../../src/utils/getHash";
import assert from "assert";
describe('getSkipSegments', () => {
describe("getSkipSegments", () => {
before(async () => {
const query = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", views, category, "actionType", "service", "videoDuration", "hidden", "shadowHidden", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
await db.prepare("run", query, ['testtesttest', 1, 11, 2, 0, '1-uuid-0', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 100, 0, 0, getHash('testtesttest', 1)]);
await db.prepare("run", query, ['testtesttest2', 1, 11, 2, 0, '1-uuid-0-1', 'testman', 0, 50, 'sponsor', 'skip', 'PeerTube', 120, 0, 0, getHash('testtesttest2', 1)]);
await db.prepare("run", query, ['testtesttest', 12, 14, 2, 0, '1-uuid-0-2', 'testman', 0, 50, 'sponsor', 'mute', 'YouTube', 100, 0, 0, getHash('testtesttest', 1)]);
await db.prepare("run", query, ['testtesttest', 20, 33, 2, 0, '1-uuid-2', 'testman', 0, 50, 'intro', 'skip', 'YouTube', 101, 0, 0, getHash('testtesttest', 1)]);
await db.prepare("run", query, ['testtesttest,test', 1, 11, 2, 0, '1-uuid-1', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 140, 0, 0, getHash('testtesttest,test', 1)]);
await db.prepare("run", query, ['test3', 1, 11, 2, 0, '1-uuid-4', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 200, 0, 0, getHash('test3', 1)]);
await db.prepare("run", query, ['test3', 7, 22, -3, 0, '1-uuid-5', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 300, 0, 0, getHash('test3', 1)]);
await db.prepare("run", query, ['multiple', 1, 11, 2, 0, '1-uuid-6', 'testman', 0, 50, 'intro', 'skip', 'YouTube', 400, 0, 0, getHash('multiple', 1)]);
await db.prepare("run", query, ['multiple', 20, 33, 2, 0, '1-uuid-7', 'testman', 0, 50, 'intro', 'skip', 'YouTube', 500, 0, 0, getHash('multiple', 1)]);
await db.prepare("run", query, ['locked', 20, 33, 2, 1, '1-uuid-locked-8', 'testman', 0, 50, 'intro', 'skip', 'YouTube', 230, 0, 0, getHash('locked', 1)]);
await db.prepare("run", query, ['locked', 20, 34, 100000, 0, '1-uuid-9', 'testman', 0, 50, 'intro', 'skip', 'YouTube', 190, 0, 0, getHash('locked', 1)]);
await db.prepare("run", query, ['onlyHiddenSegments', 20, 34, 100000, 0, 'onlyHiddenSegments', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 190, 1, 0, getHash('onlyHiddenSegments', 1)]);
await db.prepare("run", query, ['requiredSegmentVid-raw', 60, 70, 2, 0, 'requiredSegmentVid-raw-1', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 0, getHash('requiredSegmentVid-raw', 1)]);
await db.prepare("run", query, ['requiredSegmentVid-raw', 60, 70, -2, 0, 'requiredSegmentVid-raw-2', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 0, getHash('requiredSegmentVid-raw', 1)]);
await db.prepare("run", query, ['requiredSegmentVid-raw', 80, 90, -2, 0, 'requiredSegmentVid-raw-3', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 0, getHash('requiredSegmentVid-raw', 1)]);
await db.prepare("run", query, ['requiredSegmentVid-raw', 80, 90, 2, 0, 'requiredSegmentVid-raw-4', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 0, getHash('requiredSegmentVid-raw', 1)]);
await db.prepare("run", query, ["testtesttest", 1, 11, 2, 0, "1-uuid-0", "testman", 0, 50, "sponsor", "skip", "YouTube", 100, 0, 0, getHash("testtesttest", 1)]);
await db.prepare("run", query, ["testtesttest2", 1, 11, 2, 0, "1-uuid-0-1", "testman", 0, 50, "sponsor", "skip", "PeerTube", 120, 0, 0, getHash("testtesttest2", 1)]);
await db.prepare("run", query, ["testtesttest", 12, 14, 2, 0, "1-uuid-0-2", "testman", 0, 50, "sponsor", "mute", "YouTube", 100, 0, 0, getHash("testtesttest", 1)]);
await db.prepare("run", query, ["testtesttest", 20, 33, 2, 0, "1-uuid-2", "testman", 0, 50, "intro", "skip", "YouTube", 101, 0, 0, getHash("testtesttest", 1)]);
await db.prepare("run", query, ["testtesttest,test", 1, 11, 2, 0, "1-uuid-1", "testman", 0, 50, "sponsor", "skip", "YouTube", 140, 0, 0, getHash("testtesttest,test", 1)]);
await db.prepare("run", query, ["test3", 1, 11, 2, 0, "1-uuid-4", "testman", 0, 50, "sponsor", "skip", "YouTube", 200, 0, 0, getHash("test3", 1)]);
await db.prepare("run", query, ["test3", 7, 22, -3, 0, "1-uuid-5", "testman", 0, 50, "sponsor", "skip", "YouTube", 300, 0, 0, getHash("test3", 1)]);
await db.prepare("run", query, ["multiple", 1, 11, 2, 0, "1-uuid-6", "testman", 0, 50, "intro", "skip", "YouTube", 400, 0, 0, getHash("multiple", 1)]);
await db.prepare("run", query, ["multiple", 20, 33, 2, 0, "1-uuid-7", "testman", 0, 50, "intro", "skip", "YouTube", 500, 0, 0, getHash("multiple", 1)]);
await db.prepare("run", query, ["locked", 20, 33, 2, 1, "1-uuid-locked-8", "testman", 0, 50, "intro", "skip", "YouTube", 230, 0, 0, getHash("locked", 1)]);
await db.prepare("run", query, ["locked", 20, 34, 100000, 0, "1-uuid-9", "testman", 0, 50, "intro", "skip", "YouTube", 190, 0, 0, getHash("locked", 1)]);
await db.prepare("run", query, ["onlyHiddenSegments", 20, 34, 100000, 0, "onlyHiddenSegments", "testman", 0, 50, "sponsor", "skip", "YouTube", 190, 1, 0, getHash("onlyHiddenSegments", 1)]);
await db.prepare("run", query, ["requiredSegmentVid-raw", 60, 70, 2, 0, "requiredSegmentVid-raw-1", "testman", 0, 50, "sponsor", "skip", "YouTube", 0, 0, 0, getHash("requiredSegmentVid-raw", 1)]);
await db.prepare("run", query, ["requiredSegmentVid-raw", 60, 70, -2, 0, "requiredSegmentVid-raw-2", "testman", 0, 50, "sponsor", "skip", "YouTube", 0, 0, 0, getHash("requiredSegmentVid-raw", 1)]);
await db.prepare("run", query, ["requiredSegmentVid-raw", 80, 90, -2, 0, "requiredSegmentVid-raw-3", "testman", 0, 50, "sponsor", "skip", "YouTube", 0, 0, 0, getHash("requiredSegmentVid-raw", 1)]);
await db.prepare("run", query, ["requiredSegmentVid-raw", 80, 90, 2, 0, "requiredSegmentVid-raw-4", "testman", 0, 50, "sponsor", "skip", "YouTube", 0, 0, 0, getHash("requiredSegmentVid-raw", 1)]);
return;
});
it('Should be able to get a time by category 1', (done: Done) => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&category=sponsor")
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0");
assert.strictEqual(data[0].videoDuration, 100);
done();
})
.catch(err => done(err));
it("Should be able to get a time by category 1", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=testtesttest&category=sponsor`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0");
assert.strictEqual(data[0].videoDuration, 100);
done();
})
.catch(err => done(err));
});
it('Should be able to get a time by category and action type', (done: Done) => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&category=sponsor&actionType=mute")
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 12);
assert.strictEqual(data[0].segment[1], 14);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0-2");
assert.strictEqual(data[0].videoDuration, 100);
done();
})
.catch(err => done(err));
it("Should be able to get a time by category and action type", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=testtesttest&category=sponsor&actionType=mute`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 12);
assert.strictEqual(data[0].segment[1], 14);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0-2");
assert.strictEqual(data[0].videoDuration, 100);
done();
})
.catch(err => done(err));
});
it('Should be able to get a time by category and multiple action types', (done: Done) => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&category=sponsor&actionType=mute&actionType=skip")
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0");
assert.strictEqual(data[1].UUID, "1-uuid-0-2");
assert.strictEqual(data[0].videoDuration, 100);
done();
})
.catch(err => done(err));
it("Should be able to get a time by category and multiple action types", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=testtesttest&category=sponsor&actionType=mute&actionType=skip`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0");
assert.strictEqual(data[1].UUID, "1-uuid-0-2");
assert.strictEqual(data[0].videoDuration, 100);
done();
})
.catch(err => done(err));
});
it('Should be able to get a time by category and multiple action types (JSON array)', (done: Done) => {
fetch(getbaseURL() + '/api/skipSegments?videoID=testtesttest&category=sponsor&actionTypes=["mute","skip"]')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0");
assert.strictEqual(data[1].UUID, "1-uuid-0-2");
assert.strictEqual(data[0].videoDuration, 100);
done();
})
.catch(err => done(err));
it("Should be able to get a time by category and multiple action types (JSON array)", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=testtesttest&category=sponsor&actionTypes=["mute","skip"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0");
assert.strictEqual(data[1].UUID, "1-uuid-0-2");
assert.strictEqual(data[0].videoDuration, 100);
done();
})
.catch(err => done(err));
});
it('Should be able to get a time by category for a different service 1', (done: Done) => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest2&category=sponsor&service=PeerTube")
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0-1");
assert.strictEqual(data[0].videoDuration, 120);
done();
})
.catch(err => done(err));
it("Should be able to get a time by category for a different service 1", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=testtesttest2&category=sponsor&service=PeerTube`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0-1");
assert.strictEqual(data[0].videoDuration, 120);
done();
})
.catch(err => done(err));
});
it('Should be able to get a time by category 2', (done: Done) => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&category=intro")
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 20);
assert.strictEqual(data[0].segment[1], 33);
assert.strictEqual(data[0].category, "intro");
assert.strictEqual(data[0].UUID, "1-uuid-2");
done();
})
.catch(err => done(err));
it("Should be able to get a time by category 2", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=testtesttest&category=intro`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 20);
assert.strictEqual(data[0].segment[1], 33);
assert.strictEqual(data[0].category, "intro");
assert.strictEqual(data[0].UUID, "1-uuid-2");
done();
})
.catch(err => done(err));
});
it('Should be able to get a time by categories array', (done: Done) => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&categories=[\"sponsor\"]")
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0");
assert.strictEqual(data[0].videoDuration, 100);
done();
})
.catch(err => done(err));
it("Should be able to get a time by categories array", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=testtesttest&categories=["sponsor"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0");
assert.strictEqual(data[0].videoDuration, 100);
done();
})
.catch(err => done(err));
});
it('Should be able to get a time by categories array 2', (done: Done) => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&categories=[\"intro\"]")
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 20);
assert.strictEqual(data[0].segment[1], 33);
assert.strictEqual(data[0].category, "intro");
assert.strictEqual(data[0].UUID, "1-uuid-2");
assert.strictEqual(data[0].videoDuration, 101);
done();
})
.catch(err => done(err));
it("Should be able to get a time by categories array 2", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=testtesttest&categories=["intro"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 20);
assert.strictEqual(data[0].segment[1], 33);
assert.strictEqual(data[0].category, "intro");
assert.strictEqual(data[0].UUID, "1-uuid-2");
assert.strictEqual(data[0].videoDuration, 101);
done();
})
.catch(err => done(err));
});
it('Should return 404 if all submissions are hidden', (done: Done) => {
fetch(getbaseURL() + "/api/skipSegments?videoID=onlyHiddenSegments")
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
it("Should return 404 if all submissions are hidden", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=onlyHiddenSegments`)
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
});
it('Should be able to get multiple times by category', (done: Done) => {
fetch(getbaseURL() + "/api/skipSegments?videoID=multiple&categories=[\"intro\"]")
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "intro");
assert.strictEqual(data[0].UUID, "1-uuid-6");
assert.strictEqual(data[1].segment[0], 20);
assert.strictEqual(data[1].segment[1], 33);
assert.strictEqual(data[1].category, "intro");
assert.strictEqual(data[1].UUID, "1-uuid-7");
done();
})
.catch(err => done(err));
it("Should be able to get multiple times by category", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=multiple&categories=["intro"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "intro");
assert.strictEqual(data[0].UUID, "1-uuid-6");
assert.strictEqual(data[1].segment[0], 20);
assert.strictEqual(data[1].segment[1], 33);
assert.strictEqual(data[1].category, "intro");
assert.strictEqual(data[1].UUID, "1-uuid-7");
done();
})
.catch(err => done(err));
});
it('Should be able to get multiple times by multiple categories', (done: Done) => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&categories=[\"sponsor\", \"intro\"]")
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0");
assert.strictEqual(data[1].segment[0], 20);
assert.strictEqual(data[1].segment[1], 33);
assert.strictEqual(data[1].category, "intro");
assert.strictEqual(data[1].UUID, "1-uuid-2");
done();
})
.catch(err => done(err));
it("Should be able to get multiple times by multiple categories", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=testtesttest&categories=["sponsor", "intro"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0");
assert.strictEqual(data[1].segment[0], 20);
assert.strictEqual(data[1].segment[1], 33);
assert.strictEqual(data[1].category, "intro");
assert.strictEqual(data[1].UUID, "1-uuid-2");
done();
})
.catch(err => done(err));
});
it('Should be possible to send unexpected query parameters', (done: Done) => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&fakeparam=hello&category=sponsor")
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0");
done();
})
.catch(err => done(err));
it("Should be possible to send unexpected query parameters", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=testtesttest&fakeparam=hello&category=sponsor`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0");
done();
})
.catch(err => done(err));
});
it('Low voted submissions should be hidden', (done: Done) => {
fetch(getbaseURL() + "/api/skipSegments?videoID=test3&category=sponsor")
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-4");
done();
})
.catch(err => done(err));
it("Low voted submissions should be hidden", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=test3&category=sponsor`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-4");
done();
})
.catch(err => done(err));
});
it('Should return 404 if no segment found', (done: Done) => {
fetch(getbaseURL() + "/api/skipSegments?videoID=notarealvideo")
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
it("Should return 404 if no segment found", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=notarealvideo`)
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
});
it('Should return 400 if bad categories argument', (done: Done) => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&categories=[not-quoted,not-quoted]")
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
it("Should return 400 if bad categories argument", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=testtesttest&categories=[not-quoted,not-quoted]`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Should be able send a comma in a query param', (done: Done) => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest,test&category=sponsor")
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-1");
done();
})
.catch(err => done(err));
it("Should be able send a comma in a query param", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=testtesttest,test&category=sponsor`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-1");
done();
})
.catch(err => done(err));
});
it('Should always get locked segment', (done: Done) => {
fetch(getbaseURL() + "/api/skipSegments?videoID=locked&category=intro")
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 20);
assert.strictEqual(data[0].segment[1], 33);
assert.strictEqual(data[0].category, "intro");
assert.strictEqual(data[0].UUID, "1-uuid-locked-8");
done();
})
.catch(err => done(err));
it("Should always get locked segment", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=locked&category=intro`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 20);
assert.strictEqual(data[0].segment[1], 33);
assert.strictEqual(data[0].category, "intro");
assert.strictEqual(data[0].UUID, "1-uuid-locked-8");
done();
})
.catch(err => done(err));
});
it('Should be able to get multiple categories with repeating parameters', (done: Done) => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&category=sponsor&category=intro")
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0");
assert.strictEqual(data[1].segment[0], 20);
assert.strictEqual(data[1].segment[1], 33);
assert.strictEqual(data[1].category, "intro");
assert.strictEqual(data[1].UUID, "1-uuid-2");
done();
})
.catch(err => done(err));
it("Should be able to get multiple categories with repeating parameters", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=testtesttest&category=sponsor&category=intro`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0");
assert.strictEqual(data[1].segment[0], 20);
assert.strictEqual(data[1].segment[1], 33);
assert.strictEqual(data[1].category, "intro");
assert.strictEqual(data[1].UUID, "1-uuid-2");
done();
})
.catch(err => done(err));
});
it('Should be able to get, categories param overriding repeating category', (done: Done) => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&categories=[\"sponsor\"]&category=intro")
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0");
done();
})
.catch(err => done(err));
it("Should be able to get, categories param overriding repeating category", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=testtesttest&categories=["sponsor"]&category=intro`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segment[0], 1);
assert.strictEqual(data[0].segment[1], 11);
assert.strictEqual(data[0].category, "sponsor");
assert.strictEqual(data[0].UUID, "1-uuid-0");
done();
})
.catch(err => done(err));
});
it('Should be able to get specific segments with requiredSegments', (done: Done) => {
fetch(getbaseURL() + '/api/skipSegments?videoID=requiredSegmentVid-raw&requiredSegments=["requiredSegmentVid-raw-2","requiredSegmentVid-raw-3"]')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].UUID, "requiredSegmentVid-raw-2");
assert.strictEqual(data[1].UUID, "requiredSegmentVid-raw-3");
done();
})
.catch(err => done(err));
it("Should be able to get specific segments with requiredSegments", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=requiredSegmentVid-raw&requiredSegments=["requiredSegmentVid-raw-2","requiredSegmentVid-raw-3"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].UUID, "requiredSegmentVid-raw-2");
assert.strictEqual(data[1].UUID, "requiredSegmentVid-raw-3");
done();
})
.catch(err => done(err));
});
it('Should be able to get specific segments with repeating requiredSegment', (done: Done) => {
fetch(getbaseURL() + '/api/skipSegments?videoID=requiredSegmentVid-raw&requiredSegment=requiredSegmentVid-raw-2&requiredSegment=requiredSegmentVid-raw-3')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].UUID, 'requiredSegmentVid-raw-2');
assert.strictEqual(data[1].UUID, 'requiredSegmentVid-raw-3');
done();
})
.catch(err => done(err));
it("Should be able to get specific segments with repeating requiredSegment", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments?videoID=requiredSegmentVid-raw&requiredSegment=requiredSegmentVid-raw-2&requiredSegment=requiredSegmentVid-raw-3`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].UUID, "requiredSegmentVid-raw-2");
assert.strictEqual(data[1].UUID, "requiredSegmentVid-raw-3");
done();
})
.catch(err => done(err));
});
it('Should get 400 if no videoID passed in', (done: Done) => {

View File

@@ -1,239 +1,239 @@
import fetch from 'node-fetch';
import {db} from '../../src/databases/databases';
import {Done, getbaseURL} from '../utils';
import {getHash} from '../../src/utils/getHash';
import {ImportMock,} from 'ts-mock-imports';
import * as YouTubeAPIModule from '../../src/utils/youtubeApi';
import {YouTubeApiMock} from '../youtubeMock';
import assert from 'assert';
import fetch from "node-fetch";
import {db} from "../../src/databases/databases";
import {Done, getbaseURL} from "../utils";
import {getHash} from "../../src/utils/getHash";
import {ImportMock,} from "ts-mock-imports";
import * as YouTubeAPIModule from "../../src/utils/youtubeApi";
import {YouTubeApiMock} from "../youtubeMock";
import assert from "assert";
const mockManager = ImportMock.mockStaticClass(YouTubeAPIModule, 'YouTubeAPI');
const sinonStub = mockManager.mock('listVideos');
const mockManager = ImportMock.mockStaticClass(YouTubeAPIModule, "YouTubeAPI");
const sinonStub = mockManager.mock("listVideos");
sinonStub.callsFake(YouTubeApiMock.listVideos);
describe('getSkipSegmentsByHash', () => {
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']);
await db.prepare("run", query, ['getSegmentsByHash-0', 1, 10, 2, 'getSegmentsByHash-0-0-1', 'testman', 0, 50, 'sponsor', 'skip', 'PeerTube', 0, 0, 'fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910']);
await db.prepare("run", query, ['getSegmentsByHash-0', 20, 30, 2, 'getSegmentsByHash-0-1', 'testman', 100, 150, 'intro', 'skip', 'YouTube', 0, 0, 'fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910']);
await db.prepare("run", query, ['getSegmentsByHash-0', 40, 50, 2, 'getSegmentsByHash-0-2', 'testman', 0, 50, 'sponsor', 'mute', 'YouTube', 0, 0, 'fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910']);
await db.prepare("run", query, ['getSegmentsByHash-noMatchHash', 40, 50, 2, 'getSegmentsByHash-noMatchHash', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 'fdaffnoMatchHash']);
await db.prepare("run", query, ['getSegmentsByHash-1', 60, 70, 2, 'getSegmentsByHash-1', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, '3272fa85ee0927f6073ef6f07ad5f3146047c1abba794cfa364d65ab9921692b']);
await db.prepare("run", query, ['onlyHidden', 60, 70, 2, 'onlyHidden', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 1, 0, 'f3a199e1af001d716cdc6599360e2b062c2d2b3fa2885f6d9d2fd741166cbbd3']);
await db.prepare("run", query, ['highlightVid', 60, 60, 2, 'highlightVid-1', 'testman', 0, 50, 'highlight', 'skip', 'YouTube', 0, 0, getHash('highlightVid', 1)]);
await db.prepare("run", query, ['highlightVid', 70, 70, 2, 'highlightVid-2', 'testman', 0, 50, 'highlight', 'skip', 'YouTube', 0, 0, getHash('highlightVid', 1)]);
await db.prepare("run", query, ['requiredSegmentVid', 60, 70, 2, 'requiredSegmentVid-1', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 'd51822c3f681e07aef15a8855f52ad12db9eb9cf059e65b16b64c43359557f61']);
await db.prepare("run", query, ['requiredSegmentVid', 60, 70, -2, 'requiredSegmentVid-2', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 'd51822c3f681e07aef15a8855f52ad12db9eb9cf059e65b16b64c43359557f61']);
await db.prepare("run", query, ['requiredSegmentVid', 80, 90, -2, 'requiredSegmentVid-3', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 'd51822c3f681e07aef15a8855f52ad12db9eb9cf059e65b16b64c43359557f61']);
await db.prepare("run", query, ['requiredSegmentVid', 80, 90, 2, 'requiredSegmentVid-4', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 'd51822c3f681e07aef15a8855f52ad12db9eb9cf059e65b16b64c43359557f61']);
await db.prepare("run", query, ["getSegmentsByHash-0", 1, 10, 2, "getSegmentsByHash-0-0", "testman", 0, 50, "sponsor", "skip", "YouTube", 0, 0, "fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910"]);
await db.prepare("run", query, ["getSegmentsByHash-0", 1, 10, 2, "getSegmentsByHash-0-0-1", "testman", 0, 50, "sponsor", "skip", "PeerTube", 0, 0, "fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910"]);
await db.prepare("run", query, ["getSegmentsByHash-0", 20, 30, 2, "getSegmentsByHash-0-1", "testman", 100, 150, "intro", "skip", "YouTube", 0, 0, "fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910"]);
await db.prepare("run", query, ["getSegmentsByHash-0", 40, 50, 2, "getSegmentsByHash-0-2", "testman", 0, 50, "sponsor", "mute", "YouTube", 0, 0, "fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910"]);
await db.prepare("run", query, ["getSegmentsByHash-noMatchHash", 40, 50, 2, "getSegmentsByHash-noMatchHash", "testman", 0, 50, "sponsor", "skip", "YouTube", 0, 0, "fdaffnoMatchHash"]);
await db.prepare("run", query, ["getSegmentsByHash-1", 60, 70, 2, "getSegmentsByHash-1", "testman", 0, 50, "sponsor", "skip", "YouTube", 0, 0, "3272fa85ee0927f6073ef6f07ad5f3146047c1abba794cfa364d65ab9921692b"]);
await db.prepare("run", query, ["onlyHidden", 60, 70, 2, "onlyHidden", "testman", 0, 50, "sponsor", "skip", "YouTube", 1, 0, "f3a199e1af001d716cdc6599360e2b062c2d2b3fa2885f6d9d2fd741166cbbd3"]);
await db.prepare("run", query, ["highlightVid", 60, 60, 2, "highlightVid-1", "testman", 0, 50, "highlight", "skip", "YouTube", 0, 0, getHash("highlightVid", 1)]);
await db.prepare("run", query, ["highlightVid", 70, 70, 2, "highlightVid-2", "testman", 0, 50, "highlight", "skip", "YouTube", 0, 0, getHash("highlightVid", 1)]);
await db.prepare("run", query, ["requiredSegmentVid", 60, 70, 2, "requiredSegmentVid-1", "testman", 0, 50, "sponsor", "skip", "YouTube", 0, 0, "d51822c3f681e07aef15a8855f52ad12db9eb9cf059e65b16b64c43359557f61"]);
await db.prepare("run", query, ["requiredSegmentVid", 60, 70, -2, "requiredSegmentVid-2", "testman", 0, 50, "sponsor", "skip", "YouTube", 0, 0, "d51822c3f681e07aef15a8855f52ad12db9eb9cf059e65b16b64c43359557f61"]);
await db.prepare("run", query, ["requiredSegmentVid", 80, 90, -2, "requiredSegmentVid-3", "testman", 0, 50, "sponsor", "skip", "YouTube", 0, 0, "d51822c3f681e07aef15a8855f52ad12db9eb9cf059e65b16b64c43359557f61"]);
await db.prepare("run", query, ["requiredSegmentVid", 80, 90, 2, "requiredSegmentVid-4", "testman", 0, 50, "sponsor", "skip", "YouTube", 0, 0, "d51822c3f681e07aef15a8855f52ad12db9eb9cf059e65b16b64c43359557f61"]);
});
it('Should be able to get a 200', (done: Done) => {
fetch(getbaseURL() + '/api/skipSegments/3272f?categories=["sponsor", "intro"]')
.then(res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
it("Should be able to get a 200", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments/3272f?categories=["sponsor", "intro"]`)
.then(res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
});
it('Should return 404 if no segments are found even if a video for the given hash is known', (done: Done) => {
fetch(getbaseURL() + '/api/skipSegments/3272f?categories=["shilling"]')
.then(async res => {
assert.strictEqual(res.status, 404);
const expected = '[]';
const body = await res.text();
assert.strictEqual(body, expected);
done();
})
.catch(err => done(err));
});
it('Should be able to get an empty array if no videos', (done: Done) => {
fetch(getbaseURL() + '/api/skipSegments/11111?categories=["shilling"]')
.then(async res => {
assert.strictEqual(res.status, 404);
const body = await res.text();
const expected = '[]';
assert.strictEqual(JSON.parse(body).length, 0);
assert.strictEqual(body, expected);
done();
})
.catch(err => done(err));
});
it('Should be able to get an empty array if only hidden videos', (done: Done) => {
fetch(getbaseURL() + '/api/skipSegments/f3a1?categories=["sponsor"]')
.then(async res => {
if (res.status !== 404) done("non 404 status code, was " + res.status);
else {
it("Should return 404 if no segments are found even if a video for the given hash is known", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments/3272f?categories=["shilling"]`)
.then(async res => {
assert.strictEqual(res.status, 404);
const expected = "[]";
const body = await res.text();
if (JSON.parse(body).length === 0 && body === '[]') done(); // pass
else done("non empty array returned");
}
})
.catch(err => done(err));
assert.strictEqual(body, expected);
done();
})
.catch(err => done(err));
});
it('Should return 400 prefix too short', (done: Done) => {
fetch(getbaseURL() + '/api/skipSegments/11?categories=["shilling"]')
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
it("Should be able to get an empty array if no videos", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments/11111?categories=["shilling"]`)
.then(async res => {
assert.strictEqual(res.status, 404);
const body = await res.text();
const expected = "[]";
assert.strictEqual(JSON.parse(body).length, 0);
assert.strictEqual(body, expected);
done();
})
.catch(err => done(err));
});
it('Should return 400 prefix too long', (done: Done) => {
const prefix = '1'.repeat(50);
it("Should be able to get an empty array if only hidden videos", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments/f3a1?categories=["sponsor"]`)
.then(async res => {
if (res.status !== 404) done(`non 404 status code, was ${res.status}`);
else {
const body = await res.text();
if (JSON.parse(body).length === 0 && body === "[]") done(); // pass
else done("non empty array returned");
}
})
.catch(err => done(err));
});
it("Should return 400 prefix too short", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments/11?categories=["shilling"]`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it("Should return 400 prefix too long", (done: Done) => {
const prefix = "1".repeat(50);
assert.ok(prefix.length > 33, "failed to generate long enough string");
fetch(getbaseURL() + '/api/skipSegments/' + prefix + '?categories=["shilling"]')
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
fetch(`${getbaseURL()}/api/skipSegments/${prefix}?categories=["shilling"]`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Should return 404 prefix in range', (done: Done) => {
const prefix = '1'.repeat(5);
fetch(getbaseURL() + '/api/skipSegments/'+prefix+'?categories=["shilling"]')
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
it("Should return 404 prefix in range", (done: Done) => {
const prefix = "1".repeat(5);
fetch(`${getbaseURL()}/api/skipSegments/${prefix}?categories=["shilling"]`)
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
});
it('Should return 400 for no hash', (done: Done) => {
fetch(getbaseURL() + '/api/skipSegments/?categories=["shilling"]')
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
it("Should return 400 for no hash", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments/?categories=["shilling"]`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Should return 400 for bad format categories', (done: Done) => {
fetch(getbaseURL() + '/api/skipSegments/fdaf?categories=shilling')
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
it("Should return 400 for bad format categories", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments/fdaf?categories=shilling`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Should be able to get multiple videos', (done: Done) => {
fetch(getbaseURL() + '/api/skipSegments/fdaf?categories=["sponsor","intro"]')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segments.length, 2);
assert.strictEqual(data[1].segments.length, 1);
done();
})
.catch(err => done(err));
it("Should be able to get multiple videos", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments/fdaf?categories=["sponsor","intro"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segments.length, 2);
assert.strictEqual(data[1].segments.length, 1);
done();
})
.catch(err => done(err));
});
it('Should be able to get 200 for no categories (default sponsor)', (done: Done) => {
fetch(getbaseURL() + '/api/skipSegments/fdaf')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segments.length, 1);
assert.strictEqual(data[1].segments.length, 1);
assert.strictEqual(data[0].segments[0].category, 'sponsor');
assert.strictEqual(data[0].segments[0].UUID, 'getSegmentsByHash-0-0');
assert.strictEqual(data[1].segments[0].category, 'sponsor');
done();
})
.catch(err => done(err));
it("Should be able to get 200 for no categories (default sponsor)", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments/fdaf`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segments.length, 1);
assert.strictEqual(data[1].segments.length, 1);
assert.strictEqual(data[0].segments[0].category, "sponsor");
assert.strictEqual(data[0].segments[0].UUID, "getSegmentsByHash-0-0");
assert.strictEqual(data[1].segments[0].category, "sponsor");
done();
})
.catch(err => done(err));
});
it('Should be able to get 200 for no categories (default sponsor) with action type', (done: Done) => {
fetch(getbaseURL() + '/api/skipSegments/fdaf?actionType=skip')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segments.length, 1);
assert.strictEqual(data[1].segments.length, 1);
assert.strictEqual(data[0].segments[0].category, 'sponsor');
assert.strictEqual(data[0].segments[0].UUID, 'getSegmentsByHash-0-0');
assert.strictEqual(data[1].segments[0].category, 'sponsor');
done();
})
.catch(err => done(err));
it("Should be able to get 200 for no categories (default sponsor) with action type", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments/fdaf?actionType=skip`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segments.length, 1);
assert.strictEqual(data[1].segments.length, 1);
assert.strictEqual(data[0].segments[0].category, "sponsor");
assert.strictEqual(data[0].segments[0].UUID, "getSegmentsByHash-0-0");
assert.strictEqual(data[1].segments[0].category, "sponsor");
done();
})
.catch(err => done(err));
});
it('Should be able to get 200 for no categories (default sponsor) with multiple action types', (done: Done) => {
fetch(getbaseURL() + '/api/skipSegments/fdaf?actionType=skip&actionType=mute')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segments.length, 2);
assert.strictEqual(data[1].segments.length, 1);
assert.strictEqual(data[0].segments[0].category, 'sponsor');
assert.strictEqual(data[0].segments[0].UUID, 'getSegmentsByHash-0-0');
assert.strictEqual(data[0].segments[1].UUID, 'getSegmentsByHash-0-2');
assert.strictEqual(data[1].segments[0].category, 'sponsor');
done();
})
.catch(err => done(err));
it("Should be able to get 200 for no categories (default sponsor) with multiple action types", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments/fdaf?actionType=skip&actionType=mute`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segments.length, 2);
assert.strictEqual(data[1].segments.length, 1);
assert.strictEqual(data[0].segments[0].category, "sponsor");
assert.strictEqual(data[0].segments[0].UUID, "getSegmentsByHash-0-0");
assert.strictEqual(data[0].segments[1].UUID, "getSegmentsByHash-0-2");
assert.strictEqual(data[1].segments[0].category, "sponsor");
done();
})
.catch(err => done(err));
});
it('Should be able to get 200 for no categories (default sponsor) with multiple action types (JSON array)', (done: Done) => {
fetch(getbaseURL() + '/api/skipSegments/fdaf?actionTypes=["skip","mute"]')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segments.length, 2);
assert.strictEqual(data[1].segments.length, 1);
assert.strictEqual(data[0].segments[0].category, 'sponsor');
assert.strictEqual(data[0].segments[0].UUID, 'getSegmentsByHash-0-0');
assert.strictEqual(data[0].segments[1].UUID, 'getSegmentsByHash-0-2');
assert.strictEqual(data[1].segments[0].category, 'sponsor');
done();
})
.catch(err => done(err));
it("Should be able to get 200 for no categories (default sponsor) with multiple action types (JSON array)", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments/fdaf?actionTypes=["skip","mute"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 2);
assert.strictEqual(data[0].segments.length, 2);
assert.strictEqual(data[1].segments.length, 1);
assert.strictEqual(data[0].segments[0].category, "sponsor");
assert.strictEqual(data[0].segments[0].UUID, "getSegmentsByHash-0-0");
assert.strictEqual(data[0].segments[1].UUID, "getSegmentsByHash-0-2");
assert.strictEqual(data[1].segments[0].category, "sponsor");
done();
})
.catch(err => done(err));
});
it('Should be able to get 200 for no categories (default sponsor) for a non YouTube service', (done: Done) => {
fetch(getbaseURL() + '/api/skipSegments/fdaf?service=PeerTube')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segments.length, 1);
assert.strictEqual(data[0].segments[0].UUID, 'getSegmentsByHash-0-0-1');
done();
})
.catch(err => done(err));
it("Should be able to get 200 for no categories (default sponsor) for a non YouTube service", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments/fdaf?service=PeerTube`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segments.length, 1);
assert.strictEqual(data[0].segments[0].UUID, "getSegmentsByHash-0-0-1");
done();
})
.catch(err => done(err));
});
it('Should only return one segment when fetching highlight segments', (done: Done) => {
fetch(getbaseURL() + '/api/skipSegments/c962?category=highlight')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segments.length, 1);
done();
})
.catch(err => done(err));
it("Should only return one segment when fetching highlight segments", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments/c962?category=highlight`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segments.length, 1);
done();
})
.catch(err => done(err));
});
it('Should be able to post a segment and get it using endpoint', (done: Done) => {
const testID = 'abc123goodVideo';
fetch(getbaseURL() + "/api/postVideoSponsorTimes", {
method: 'POST',
it("Should be able to post a segment and get it using endpoint", (done: Done) => {
const testID = "abc123goodVideo";
fetch(`${getbaseURL()}/api/postVideoSponsorTimes`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({
userID: "test-qwertyuiopasdfghjklzxcvbnm",
@@ -244,66 +244,65 @@ describe('getSkipSegmentsByHash', () => {
}],
}),
})
.then(async () => {
fetch(getbaseURL() + '/api/skipSegments/' + getHash(testID, 1).substring(0, 3))
.then(async () => {
fetch(`${getbaseURL()}/api/skipSegments/${getHash(testID, 1).substring(0, 3)}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segments.length, 1);
assert.strictEqual(data[0].segments[0].category, "sponsor");
done();
})
.catch(err => done(`(get) ${err}`));
})
.catch(err => done(`(post) ${err}`));
});
it("Should be able to get multiple categories with repeating parameters", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments/fdaff4?&category=sponsor&category=intro`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segments.length, 1);
assert.strictEqual(data[0].segments[0].category, 'sponsor');
assert.strictEqual(data[0].segments[0].segment[0], 1);
assert.strictEqual(data[0].segments[0].segment[1], 10);
assert.strictEqual(data[0].segments[0].category, "sponsor");
assert.strictEqual(data[0].segments[0].UUID, "getSegmentsByHash-0-0");
assert.strictEqual(data[0].segments[1].segment[0], 20);
assert.strictEqual(data[0].segments[1].segment[1], 30);
assert.strictEqual(data[0].segments[1].category, "intro");
assert.strictEqual(data[0].segments[1].UUID, "getSegmentsByHash-0-1");
done();
})
.catch(err => done('(get) ' + err));
})
.catch(err => done('(post) ' + err));
.catch(err => done(err));
});
it('Should be able to get multiple categories with repeating parameters', (done: Done) => {
fetch(getbaseURL() + "/api/skipSegments/fdaff4?&category=sponsor&category=intro")
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segments[0].segment[0], 1);
assert.strictEqual(data[0].segments[0].segment[1], 10);
assert.strictEqual(data[0].segments[0].category, "sponsor");
assert.strictEqual(data[0].segments[0].UUID, "getSegmentsByHash-0-0");
assert.strictEqual(data[0].segments[1].segment[0], 20);
assert.strictEqual(data[0].segments[1].segment[1], 30);
assert.strictEqual(data[0].segments[1].category, "intro");
assert.strictEqual(data[0].segments[1].UUID, "getSegmentsByHash-0-1");
done();
})
.catch(err => done(err));
it("Should be able to get specific segments with requiredSegments", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments/d518?requiredSegments=["requiredSegmentVid-2","requiredSegmentVid-3"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segments.length, 2);
assert.strictEqual(data[0].segments[0].UUID, "requiredSegmentVid-2");
assert.strictEqual(data[0].segments[0].UUID, "requiredSegmentVid-2");
done();
})
.catch(err => done(err));
});
it('Should be able to get specific segments with requiredSegments', (done: Done) => {
fetch(getbaseURL() + '/api/skipSegments/d518?requiredSegments=["requiredSegmentVid-2","requiredSegmentVid-3"]')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segments.length, 2);
assert.strictEqual(data[0].segments[0].UUID, 'requiredSegmentVid-2');
assert.strictEqual(data[0].segments[0].UUID, 'requiredSegmentVid-2');
done();
})
.catch(err => done(err));
});
it('Should be able to get specific segments with repeating requiredSegment', (done: Done) => {
fetch(getbaseURL() + '/api/skipSegments/d518?requiredSegment=requiredSegmentVid-2&requiredSegment=requiredSegmentVid-3')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segments.length, 2);
assert.strictEqual(data[0].segments[0].UUID, 'requiredSegmentVid-2');
assert.strictEqual(data[0].segments[1].UUID, 'requiredSegmentVid-3');
done();
})
.catch(err => done(err));
it("Should be able to get specific segments with repeating requiredSegment", (done: Done) => {
fetch(`${getbaseURL()}/api/skipSegments/d518?requiredSegment=requiredSegmentVid-2&requiredSegment=requiredSegmentVid-3`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.length, 1);
assert.strictEqual(data[0].segments.length, 2);
assert.strictEqual(data[0].segments[0].UUID, "requiredSegmentVid-2");
assert.strictEqual(data[0].segments[1].UUID, "requiredSegmentVid-3");
done();
})
.catch(err => done(err));
});
});

View File

@@ -1,10 +1,10 @@
import {getSubmissionUUID} from '../../src/utils/getSubmissionUUID';
import assert from 'assert';
import { ActionType, VideoID } from '../../src/types/segments.model';
import { UserID } from '../../src/types/user.model';
import {getSubmissionUUID} from "../../src/utils/getSubmissionUUID";
import assert from "assert";
import { ActionType, VideoID } from "../../src/types/segments.model";
import { UserID } from "../../src/types/user.model";
describe('getSubmissionUUID', () => {
it('Should return the hashed value', () => {
assert.strictEqual(getSubmissionUUID('video001' as VideoID, 'skip' as ActionType, 'testuser001' as UserID, 13.33337, 42.000001), '3572aa64e0a2d6352c3de14ca45f8a83d193c32635669a7ae0b40c9eb36395872');
describe("getSubmissionUUID", () => {
it("Should return the hashed value", () => {
assert.strictEqual(getSubmissionUUID("video001" as VideoID, "skip" as ActionType, "testuser001" as UserID, 13.33337, 42.000001), "3572aa64e0a2d6352c3de14ca45f8a83d193c32635669a7ae0b40c9eb36395872");
});
});

View File

@@ -1,317 +1,317 @@
import fetch from 'node-fetch';
import {Done, getbaseURL} from '../utils';
import {db} from '../../src/databases/databases';
import {getHash} from '../../src/utils/getHash';
import assert from 'assert';
import fetch from "node-fetch";
import {Done, getbaseURL} from "../utils";
import {db} from "../../src/databases/databases";
import {getHash} from "../../src/utils/getHash";
import assert from "assert";
describe('getUserID', () => {
describe("getUserID", () => {
before(async () => {
const insertUserNameQuery = 'INSERT INTO "userNames" ("userID", "userName") VALUES(?, ?)';
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_01"), 'fuzzy user 01']);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_02"), 'fuzzy user 02']);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_03"), 'specific user 03']);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_04"), 'repeating']);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_05"), 'repeating']);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_01"), "fuzzy user 01"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_02"), "fuzzy user 02"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_03"), "specific user 03"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_04"), "repeating"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_05"), "repeating"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_06"), getHash("getuserid_user_06")]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_07"), '0redos0']);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_08"), '%redos%']);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_09"), '_redos_']);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_10"), 'redos\\%']);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_11"), '\\\\\\']);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_12"), 'a']);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_07"), "0redos0"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_08"), "%redos%"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_09"), "_redos_"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_10"), "redos\\%"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_11"), "\\\\\\"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_12"), "a"]);
});
it('Should be able to get a 200', (done: Done) => {
fetch(getbaseURL() + '/api/userID?username=fuzzy+user+01')
.then(async res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
it("Should be able to get a 200", (done: Done) => {
fetch(`${getbaseURL()}/api/userID?username=fuzzy+user+01`)
.then(async res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
});
it('Should be able to get a 400 (No username parameter)', (done: Done) => {
fetch(getbaseURL() + '/api/userID')
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
it("Should be able to get a 400 (No username parameter)", (done: Done) => {
fetch(`${getbaseURL()}/api/userID`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Should be able to get a 200 (username is public id)', (done: Done) => {
fetch(getbaseURL() + '/api/userID?username='+getHash("getuserid_user_06"))
.then(async res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
it("Should be able to get a 200 (username is public id)", (done: Done) => {
fetch(`${getbaseURL()}/api/userID?username=${getHash("getuserid_user_06")}`)
.then(async res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
});
it('Should be able to get a 400 (username longer than 64 chars)', (done: Done) => {
fetch(getbaseURL() + '/api/userID?username='+getHash("getuserid_user_06")+'0')
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
it("Should be able to get a 400 (username longer than 64 chars)", (done: Done) => {
fetch(`${getbaseURL()}/api/userID?username=${getHash("getuserid_user_06")}0`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Should be able to get single username', (done: Done) => {
fetch(getbaseURL() + '/api/userID?username=fuzzy+user+01')
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "fuzzy user 01",
userID: getHash("getuserid_user_01")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
it("Should be able to get single username", (done: Done) => {
fetch(`${getbaseURL()}/api/userID?username=fuzzy+user+01`)
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "fuzzy user 01",
userID: getHash("getuserid_user_01")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('Should be able to get multiple fuzzy user info from start', (done: Done) => {
fetch(getbaseURL() + '/api/userID?username=fuzzy+user')
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "fuzzy user 01",
userID: getHash("getuserid_user_01")
}, {
userName: "fuzzy user 02",
userID: getHash("getuserid_user_02")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
it("Should be able to get multiple fuzzy user info from start", (done: Done) => {
fetch(`${getbaseURL()}/api/userID?username=fuzzy+user`)
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "fuzzy user 01",
userID: getHash("getuserid_user_01")
}, {
userName: "fuzzy user 02",
userID: getHash("getuserid_user_02")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('Should be able to get multiple fuzzy user info from middle', (done: Done) => {
fetch(getbaseURL() + '/api/userID?username=user')
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "fuzzy user 01",
userID: getHash("getuserid_user_01")
}, {
userName: "fuzzy user 02",
userID: getHash("getuserid_user_02")
}, {
userName: "specific user 03",
userID: getHash("getuserid_user_03")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
it("Should be able to get multiple fuzzy user info from middle", (done: Done) => {
fetch(`${getbaseURL()}/api/userID?username=user`)
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "fuzzy user 01",
userID: getHash("getuserid_user_01")
}, {
userName: "fuzzy user 02",
userID: getHash("getuserid_user_02")
}, {
userName: "specific user 03",
userID: getHash("getuserid_user_03")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('Should be able to get with public ID', (done: Done) => {
it("Should be able to get with public ID", (done: Done) => {
const userID = getHash("getuserid_user_06");
fetch(getbaseURL() + '/api/userID?username='+userID)
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: userID,
userID
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
fetch(`${getbaseURL()}/api/userID?username=${userID}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: userID,
userID
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('Should be able to get with fuzzy public ID', (done: Done) => {
it("Should be able to get with fuzzy public ID", (done: Done) => {
const userID = getHash("getuserid_user_06");
fetch(getbaseURL() + '/api/userID?username='+userID.substr(10,60))
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: userID,
userID
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
fetch(`${getbaseURL()}/api/userID?username=${userID.substr(10,60)}`)
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: userID,
userID
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('Should be able to get repeating username', (done: Done) => {
fetch(getbaseURL() + '/api/userID?username=repeating')
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "repeating",
userID: getHash("getuserid_user_04")
}, {
userName: "repeating",
userID: getHash("getuserid_user_05")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
it("Should be able to get repeating username", (done: Done) => {
fetch(`${getbaseURL()}/api/userID?username=repeating`)
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "repeating",
userID: getHash("getuserid_user_04")
}, {
userName: "repeating",
userID: getHash("getuserid_user_05")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('Should be able to get repeating fuzzy username', (done: Done) => {
fetch(getbaseURL() + '/api/userID?username=peat')
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "repeating",
userID: getHash("getuserid_user_04")
}, {
userName: "repeating",
userID: getHash("getuserid_user_05")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
it("Should be able to get repeating fuzzy username", (done: Done) => {
fetch(`${getbaseURL()}/api/userID?username=peat`)
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "repeating",
userID: getHash("getuserid_user_04")
}, {
userName: "repeating",
userID: getHash("getuserid_user_05")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('should avoid ReDOS with _', (done: Done) => {
fetch(getbaseURL() + '/api/userID?username=_redos_')
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "_redos_",
userID: getHash("getuserid_user_09")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
it("should avoid ReDOS with _", (done: Done) => {
fetch(`${getbaseURL()}/api/userID?username=_redos_`)
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "_redos_",
userID: getHash("getuserid_user_09")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('should avoid ReDOS with %', (done: Done) => {
fetch(getbaseURL() + '/api/userID?username=%redos%')
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "%redos%",
userID: getHash("getuserid_user_08")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
it("should avoid ReDOS with %", (done: Done) => {
fetch(`${getbaseURL()}/api/userID?username=%redos%`)
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "%redos%",
userID: getHash("getuserid_user_08")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('should return 404 if escaped backslashes present', (done: Done) => {
fetch(getbaseURL() + '/api/userID?username=%redos\\\\_')
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
it("should return 404 if escaped backslashes present", (done: Done) => {
fetch(`${getbaseURL()}/api/userID?username=%redos\\\\_`)
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
});
it('should return 404 if backslashes present', (done: Done) => {
fetch(getbaseURL() + '/api/userID?username=\\%redos\\_')
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
it("should return 404 if backslashes present", (done: Done) => {
fetch(`${getbaseURL()}/api/userID?username=\\%redos\\_`)
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
});
it('should return user if just backslashes', (done: Done) => {
fetch(getbaseURL() + '/api/userID?username=\\\\\\')
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "\\\\\\",
userID: getHash("getuserid_user_11")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
it("should return user if just backslashes", (done: Done) => {
fetch(`${getbaseURL()}/api/userID?username=\\\\\\`)
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "\\\\\\",
userID: getHash("getuserid_user_11")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('should not allow usernames more than 64 characters', (done: Done) => {
fetch(getbaseURL() + '/api/userID?username='+'0'.repeat(65))
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
it("should not allow usernames more than 64 characters", (done: Done) => {
fetch(`${getbaseURL()}/api/userID?username=${"0".repeat(65)}`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('should not allow usernames less than 3 characters', (done: Done) => {
fetch(getbaseURL() + '/api/userID?username=aa')
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
it("should not allow usernames less than 3 characters", (done: Done) => {
fetch(`${getbaseURL()}/api/userID?username=aa`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('should allow exact match', (done: Done) => {
fetch(getbaseURL() + '/api/userID?username=a&exact=true')
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "a",
userID: getHash("getuserid_user_12")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
it("should allow exact match", (done: Done) => {
fetch(`${getbaseURL()}/api/userID?username=a&exact=true`)
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "a",
userID: getHash("getuserid_user_12")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('Should be able to get repeating username with exact username', (done: Done) => {
fetch(getbaseURL() + '/api/userID?username=repeating&exact=true')
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "repeating",
userID: getHash("getuserid_user_04")
}, {
userName: "repeating",
userID: getHash("getuserid_user_05")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
it("Should be able to get repeating username with exact username", (done: Done) => {
fetch(`${getbaseURL()}/api/userID?username=repeating&exact=true`)
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "repeating",
userID: getHash("getuserid_user_04")
}, {
userName: "repeating",
userID: getHash("getuserid_user_05")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('Should not get exact unless explicitly set to true', (done: Done) => {
fetch(getbaseURL() + '/api/userID?username=user&exact=1')
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "fuzzy user 01",
userID: getHash("getuserid_user_01")
}, {
userName: "fuzzy user 02",
userID: getHash("getuserid_user_02")
}, {
userName: "specific user 03",
userID: getHash("getuserid_user_03")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
it("Should not get exact unless explicitly set to true", (done: Done) => {
fetch(`${getbaseURL()}/api/userID?username=user&exact=1`)
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "fuzzy user 01",
userID: getHash("getuserid_user_01")
}, {
userName: "fuzzy user 02",
userID: getHash("getuserid_user_02")
}, {
userName: "specific user 03",
userID: getHash("getuserid_user_03")
}];
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('should return 400 if no username parameter specified', (done: Done) => {

View File

@@ -1,208 +1,208 @@
import fetch from 'node-fetch';
import {Done, getbaseURL} from '../utils';
import {db} from '../../src/databases/databases';
import {getHash} from '../../src/utils/getHash';
import assert from 'assert';
import fetch from "node-fetch";
import {Done, getbaseURL} from "../utils";
import {db} from "../../src/databases/databases";
import {getHash} from "../../src/utils/getHash";
import assert from "assert";
describe('getUserInfo', () => {
describe("getUserInfo", () => {
before(async () => {
const insertUserNameQuery = 'INSERT INTO "userNames" ("userID", "userName") VALUES(?, ?)';
await db.prepare("run", insertUserNameQuery, [getHash("getuserinfo_user_01"), 'Username user 01']);
await db.prepare("run", insertUserNameQuery, [getHash("getuserinfo_user_01"), "Username user 01"]);
const sponsorTimesQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "shadowHidden") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
await db.prepare("run", sponsorTimesQuery, ['xxxyyyzzz', 1, 11, 2, 'uuid000001', getHash("getuserinfo_user_01"), 1, 10, 'sponsor', 0]);
await db.prepare("run", sponsorTimesQuery, ['xxxyyyzzz', 1, 11, 2, 'uuid000002', getHash("getuserinfo_user_01"), 2, 10, 'sponsor', 0]);
await db.prepare("run", sponsorTimesQuery, ['yyyxxxzzz', 1, 11, -1, 'uuid000003', getHash("getuserinfo_user_01"), 3, 10, 'sponsor', 0]);
await db.prepare("run", sponsorTimesQuery, ['yyyxxxzzz', 1, 11, -2, 'uuid000004', getHash("getuserinfo_user_01"), 4, 10, 'sponsor', 1]);
await db.prepare("run", sponsorTimesQuery, ['xzzzxxyyy', 1, 11, -5, 'uuid000005', getHash("getuserinfo_user_01"), 5, 10, 'sponsor', 1]);
await db.prepare("run", sponsorTimesQuery, ['zzzxxxyyy', 1, 11, 2, 'uuid000006', getHash("getuserinfo_user_02"), 6, 10, 'sponsor', 0]);
await db.prepare("run", sponsorTimesQuery, ['xxxyyyzzz', 1, 11, 2, 'uuid000007', getHash("getuserinfo_user_02"), 7, 10, 'sponsor', 1]);
await db.prepare("run", sponsorTimesQuery, ['xxxyyyzzz', 1, 11, 2, 'uuid000008', getHash("getuserinfo_user_02"), 8, 10, 'sponsor', 1]);
await db.prepare("run", sponsorTimesQuery, ["xxxyyyzzz", 1, 11, 2, "uuid000001", getHash("getuserinfo_user_01"), 1, 10, "sponsor", 0]);
await db.prepare("run", sponsorTimesQuery, ["xxxyyyzzz", 1, 11, 2, "uuid000002", getHash("getuserinfo_user_01"), 2, 10, "sponsor", 0]);
await db.prepare("run", sponsorTimesQuery, ["yyyxxxzzz", 1, 11, -1, "uuid000003", getHash("getuserinfo_user_01"), 3, 10, "sponsor", 0]);
await db.prepare("run", sponsorTimesQuery, ["yyyxxxzzz", 1, 11, -2, "uuid000004", getHash("getuserinfo_user_01"), 4, 10, "sponsor", 1]);
await db.prepare("run", sponsorTimesQuery, ["xzzzxxyyy", 1, 11, -5, "uuid000005", getHash("getuserinfo_user_01"), 5, 10, "sponsor", 1]);
await db.prepare("run", sponsorTimesQuery, ["zzzxxxyyy", 1, 11, 2, "uuid000006", getHash("getuserinfo_user_02"), 6, 10, "sponsor", 0]);
await db.prepare("run", sponsorTimesQuery, ["xxxyyyzzz", 1, 11, 2, "uuid000007", getHash("getuserinfo_user_02"), 7, 10, "sponsor", 1]);
await db.prepare("run", sponsorTimesQuery, ["xxxyyyzzz", 1, 11, 2, "uuid000008", getHash("getuserinfo_user_02"), 8, 10, "sponsor", 1]);
const insertWarningQuery = 'INSERT INTO warnings ("userID", "issueTime", "issuerUserID", "enabled", "reason") VALUES (?, ?, ?, ?, ?)';
await db.prepare("run", insertWarningQuery, [getHash('getuserinfo_warning_0'), 10, 'getuserinfo_vip', 1, "warning0-0"]);
await db.prepare("run", insertWarningQuery, [getHash('getuserinfo_warning_1'), 20, 'getuserinfo_vip', 1, "warning1-0"]);
await db.prepare("run", insertWarningQuery, [getHash('getuserinfo_warning_1'), 30, 'getuserinfo_vip', 1, "warning1-1"]);
await db.prepare("run", insertWarningQuery, [getHash('getuserinfo_warning_2'), 40, 'getuserinfo_vip', 0, "warning2-0"]);
await db.prepare("run", insertWarningQuery, [getHash('getuserinfo_warning_3'), 50, 'getuserinfo_vip', 1, "warning3-0"]);
await db.prepare("run", insertWarningQuery, [getHash('getuserinfo_warning_3'), 60, 'getuserinfo_vip', 0, "warning3-1"]);
await db.prepare("run", insertWarningQuery, [getHash("getuserinfo_warning_0"), 10, "getuserinfo_vip", 1, "warning0-0"]);
await db.prepare("run", insertWarningQuery, [getHash("getuserinfo_warning_1"), 20, "getuserinfo_vip", 1, "warning1-0"]);
await db.prepare("run", insertWarningQuery, [getHash("getuserinfo_warning_1"), 30, "getuserinfo_vip", 1, "warning1-1"]);
await db.prepare("run", insertWarningQuery, [getHash("getuserinfo_warning_2"), 40, "getuserinfo_vip", 0, "warning2-0"]);
await db.prepare("run", insertWarningQuery, [getHash("getuserinfo_warning_3"), 50, "getuserinfo_vip", 1, "warning3-0"]);
await db.prepare("run", insertWarningQuery, [getHash("getuserinfo_warning_3"), 60, "getuserinfo_vip", 0, "warning3-1"]);
});
it('Should be able to get a 200', (done: Done) => {
fetch(getbaseURL() + '/api/userInfo?userID=getuserinfo_user_01')
.then(res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
it("Should be able to get a 200", (done: Done) => {
fetch(`${getbaseURL()}/api/userInfo?userID=getuserinfo_user_01`)
.then(res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
});
it('Should be able to get a 400 (No userID parameter)', (done: Done) => {
fetch(getbaseURL() + '/api/userInfo')
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
it("Should be able to get a 400 (No userID parameter)", (done: Done) => {
fetch(`${getbaseURL()}/api/userInfo`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Should be able to get user info', (done: Done) => {
fetch(getbaseURL() + '/api/userInfo?userID=getuserinfo_user_01')
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = {
userName: 'Username user 01',
userID: "66e7c974039ffb870a500a33eca3a3989861018909b938c313cf1a8a366800b8",
minutesSaved: 5,
viewCount: 30,
ignoredViewCount: 20,
segmentCount: 3,
ignoredSegmentCount: 2,
reputation: -2,
lastSegmentID: "uuid000005",
vip: false,
warnings: 0,
warningReason: ""
};
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
it("Should be able to get user info", (done: Done) => {
fetch(`${getbaseURL()}/api/userInfo?userID=getuserinfo_user_01`)
.then(async res => {
assert.strictEqual(res.status, 200);
const expected = {
userName: "Username user 01",
userID: "66e7c974039ffb870a500a33eca3a3989861018909b938c313cf1a8a366800b8",
minutesSaved: 5,
viewCount: 30,
ignoredViewCount: 20,
segmentCount: 3,
ignoredSegmentCount: 2,
reputation: -2,
lastSegmentID: "uuid000005",
vip: false,
warnings: 0,
warningReason: ""
};
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('Should get warning data', (done: Done) => {
fetch(getbaseURL() + '/api/userInfo?userID=getuserinfo_warning_0&value=warnings')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.warnings, 1);
done();
})
.catch(err => done(err));
it("Should get warning data", (done: Done) => {
fetch(`${getbaseURL()}/api/userInfo?userID=getuserinfo_warning_0&value=warnings`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.warnings, 1);
done();
})
.catch(err => done(err));
});
it('Should get warning data with public ID', (done: Done) => {
fetch(getbaseURL() + `/api/userInfo?publicUserID=${getHash("getuserinfo_warning_0")}&values=["warnings"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.warnings, 1);
done();
})
.catch(err => done(err));
it("Should get warning data with public ID", (done: Done) => {
fetch(`${getbaseURL()}/api/userInfo?publicUserID=${getHash("getuserinfo_warning_0")}&values=["warnings"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.warnings, 1);
done();
})
.catch(err => done(err));
});
it('Should get multiple warnings', (done: Done) => {
fetch(getbaseURL() + '/api/userInfo?userID=getuserinfo_warning_1&value=warnings')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.warnings, 2);
done();
})
.catch(err => done(err));
it("Should get multiple warnings", (done: Done) => {
fetch(`${getbaseURL()}/api/userInfo?userID=getuserinfo_warning_1&value=warnings`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.warnings, 2);
done();
})
.catch(err => done(err));
});
it('Should not get warnings if none', (done: Done) => {
fetch(getbaseURL() + '/api/userInfo?userID=getuserinfo_warning_2&value=warnings')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.warnings, 0);
done();
})
.catch(err => done(err));
it("Should not get warnings if none", (done: Done) => {
fetch(`${getbaseURL()}/api/userInfo?userID=getuserinfo_warning_2&value=warnings`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.warnings, 0);
done();
})
.catch(err => done(err));
});
it('Should done(userID for userName (No userName set)', (done: Done) => {
fetch(getbaseURL() + '/api/userInfo?userID=getuserinfo_user_02&value=userName')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.userName, 'c2a28fd225e88f74945794ae85aef96001d4a1aaa1022c656f0dd48ac0a3ea0f');
done();
})
.catch(err => done(err));
it("Should done(userID for userName (No userName set)", (done: Done) => {
fetch(`${getbaseURL()}/api/userInfo?userID=getuserinfo_user_02&value=userName`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.userName, "c2a28fd225e88f74945794ae85aef96001d4a1aaa1022c656f0dd48ac0a3ea0f");
done();
})
.catch(err => done(err));
});
it('Should return null segment if none', (done: Done) => {
fetch(getbaseURL() + '/api/userInfo?userID=getuserinfo_null&value=lastSegmentID')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.lastSegmentID, null);
done();
})
.catch(err => done(err));
it("Should return null segment if none", (done: Done) => {
fetch(`${getbaseURL()}/api/userInfo?userID=getuserinfo_null&value=lastSegmentID`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.lastSegmentID, null);
done();
})
.catch(err => done(err));
});
it('Should return zeroes if userid does not exist', (done: Done) => {
fetch(getbaseURL() + '/api/userInfo?userID=getuserinfo_null&value=lastSegmentID')
.then(async res => {
const data = await res.json();
for (const value in data) {
if (data[value] === null && value !== "lastSegmentID") {
done(`returned null for ${value}`);
it("Should return zeroes if userid does not exist", (done: Done) => {
fetch(`${getbaseURL()}/api/userInfo?userID=getuserinfo_null&value=lastSegmentID`)
.then(async res => {
const data = await res.json();
for (const value in data) {
if (data[value] === null && value !== "lastSegmentID") {
done(`returned null for ${value}`);
}
done(); // pass
}
}
done(); // pass
})
.catch(err => done(err));
})
.catch(err => done(err));
});
it('Should get warning reason from from single enabled warning', (done: Done) => {
fetch(getbaseURL() + '/api/userInfo?userID=getuserinfo_warning_0&values=["warningReason"]')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.warningReason, "warning0-0");
done(); // pass
})
.catch(err => done(err));
it("Should get warning reason from from single enabled warning", (done: Done) => {
fetch(`${getbaseURL()}/api/userInfo?userID=getuserinfo_warning_0&values=["warningReason"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.warningReason, "warning0-0");
done(); // pass
})
.catch(err => done(err));
});
it('Should get most recent warning from two enabled warnings', (done: Done) => {
fetch(getbaseURL() + '/api/userInfo?userID=getuserinfo_warning_1&value=warningReason')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.warningReason, "warning1-1");
done(); // pass
})
.catch(err => done(err));
it("Should get most recent warning from two enabled warnings", (done: Done) => {
fetch(`${getbaseURL()}/api/userInfo?userID=getuserinfo_warning_1&value=warningReason`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.warningReason, "warning1-1");
done(); // pass
})
.catch(err => done(err));
});
it('Should not get disabled warning', (done: Done) => {
fetch(getbaseURL() + '/api/userInfo?userID=getuserinfo_warning_2&values=["warnings","warningReason"]')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.warnings, 0);
assert.strictEqual(data.warningReason, "");
done(); // pass
})
.catch(err => done(err));
it("Should not get disabled warning", (done: Done) => {
fetch(`${getbaseURL()}/api/userInfo?userID=getuserinfo_warning_2&values=["warnings","warningReason"]`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.warnings, 0);
assert.strictEqual(data.warningReason, "");
done(); // pass
})
.catch(err => done(err));
});
it('Should not get newer disabled warning', (done: Done) => {
fetch(getbaseURL() + '/api/userInfo?userID=getuserinfo_warning_3&value=warnings&value=warningReason')
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.warnings, 1);
assert.strictEqual(data.warningReason, "warning3-0");
done(); // pass
})
.catch(err => done(err));
it("Should not get newer disabled warning", (done: Done) => {
fetch(`${getbaseURL()}/api/userInfo?userID=getuserinfo_warning_3&value=warnings&value=warningReason`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.warnings, 1);
assert.strictEqual(data.warningReason, "warning3-0");
done(); // pass
})
.catch(err => done(err));
});
it('Should get 400 if bad values specified', (done: Done) => {
fetch(getbaseURL() + '/api/userInfo?userID=getuserinfo_warning_3&value=invalid-value')
.then(async res => {
assert.strictEqual(res.status, 400);
done(); // pass
})
.catch(err => done(err));
it("Should get 400 if bad values specified", (done: Done) => {
fetch(`${getbaseURL()}/api/userInfo?userID=getuserinfo_warning_3&value=invalid-value`)
.then(async res => {
assert.strictEqual(res.status, 400);
done(); // pass
})
.catch(err => done(err));
});
});

View File

@@ -1,462 +1,464 @@
import fetch from 'node-fetch';
import {Done, getbaseURL} from '../utils';
import {getHash} from '../../src/utils/getHash';
import {db} from '../../src/databases/databases';
import assert from 'assert';
import {LockCategory} from '../../src/types/segments.model';
import fetch from "node-fetch";
import {Done, getbaseURL} from "../utils";
import {getHash} from "../../src/utils/getHash";
import {db} from "../../src/databases/databases";
import assert from "assert";
import {LockCategory} from "../../src/types/segments.model";
const deepStringEqual = (a: string[], b: string[]): boolean => {
if (a.length !== b.length) return false;
a.forEach((e) => { if (!b.includes(e)) return false; });
return true;
const stringDeepEquals = (a: string[] ,b: string[]): boolean => {
let result = true;
b.forEach((e) => {
if (!a.includes(e)) result = false;
});
return result;
};
describe('lockCategoriesRecords', () => {
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", "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", "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"), "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", "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']);
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 () => {
const version = (await db.prepare('get', 'SELECT key, value FROM config where key = ?', ['version'])).value;
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;
assert.ok(version > 1);
});
it('Should be able to submit categories not in video (http response)', (done: Done) => {
it("Should be able to submit categories not in video (http response)", (done: Done) => {
const json = {
videoID: 'no-segments-video-id',
userID: 'VIPUser-lockCategories',
videoID: "no-segments-video-id",
userID: "VIPUser-lockCategories",
categories: [
'outro',
'shilling',
'shilling',
'shil ling',
'',
'intro',
"outro",
"shilling",
"shilling",
"shil ling",
"",
"intro",
],
};
const expected = {
submitted: [
'outro',
'shilling',
"outro",
"shilling",
],
};
fetch(getbaseURL() + "/api/lockCategories", {
method: 'POST',
fetch(`${getbaseURL()}/api/lockCategories`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify(json)
})
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.deepStrictEqual(data, expected);
done();
})
.catch(err => done(err));
});
it('Should be able to submit categories not in video (sql check)', (done: Done) => {
it("Should be able to submit categories not in video (sql check)", (done: Done) => {
const json = {
videoID: 'no-segments-video-id-1',
userID: 'VIPUser-lockCategories',
videoID: "no-segments-video-id-1",
userID: "VIPUser-lockCategories",
categories: [
'outro',
'shilling',
'shilling',
'shil ling',
'',
'intro',
"outro",
"shilling",
"shilling",
"shil ling",
"",
"intro",
],
};
fetch(getbaseURL() + "/api/lockCategories", {
method: 'POST',
fetch(`${getbaseURL()}/api/lockCategories`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify(json)
})
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['no-segments-video-id-1']) as LockCategory[];
assert.strictEqual(result.length, 4);
const oldRecordNotChangeReason = result.filter(item =>
item.reason === 'reason-2' && ['sponsor', 'intro'].includes(item.category)
);
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare("all", 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ["no-segments-video-id-1"]) as LockCategory[];
assert.strictEqual(result.length, 4);
const oldRecordNotChangeReason = result.filter(item =>
item.reason === "reason-2" && ["sponsor", "intro"].includes(item.category)
);
const newRecordWithEmptyReason = result.filter(item =>
item.reason === '' && ['outro', 'shilling'].includes(item.category)
);
const newRecordWithEmptyReason = result.filter(item =>
item.reason === "" && ["outro", "shilling"].includes(item.category)
);
assert.strictEqual(newRecordWithEmptyReason.length, 2);
assert.strictEqual(oldRecordNotChangeReason.length, 2);
done();
})
.catch(err => done(err));
assert.strictEqual(newRecordWithEmptyReason.length, 2);
assert.strictEqual(oldRecordNotChangeReason.length, 2);
done();
})
.catch(err => done(err));
});
it('Should be able to submit categories not in video with reason (http response)', (done: Done) => {
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',
videoID: "no-segments-video-id",
userID: "VIPUser-lockCategories",
categories: [
'outro',
'shilling',
'shilling',
'shil ling',
'',
'intro',
"outro",
"shilling",
"shilling",
"shil ling",
"",
"intro",
],
reason: 'new reason'
reason: "new reason"
};
const expected = {
submitted: [
'outro',
'shilling',
'intro'
"outro",
"shilling",
"intro"
],
};
fetch(getbaseURL() + "/api/lockCategories", {
method: 'POST',
fetch(`${getbaseURL()}/api/lockCategories`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify(json)
})
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.deepStrictEqual(data.submitted, expected.submitted);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.deepStrictEqual(data.submitted, expected.submitted);
done();
})
.catch(err => done(err));
});
it('Should be able to submit categories not in video with reason (sql check)', (done: Done) => {
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',
videoID: "no-segments-video-id-1",
userID: "VIPUser-lockCategories",
categories: [
'outro',
'shilling',
'shilling',
'shil ling',
'',
'intro',
"outro",
"shilling",
"shilling",
"shil ling",
"",
"intro",
],
reason: 'new reason'
reason: "new reason"
};
const expectedWithNewReason = [
'outro',
'shilling',
'intro'
"outro",
"shilling",
"intro"
];
fetch(getbaseURL() + "/api/lockCategories", {
method: 'POST',
fetch(`${getbaseURL()}/api/lockCategories`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify(json)
})
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['no-segments-video-id-1']) as LockCategory[];
assert.strictEqual(result.length, 4);
const newRecordWithNewReason = result.filter(item =>
expectedWithNewReason.includes(item.category) && item.reason === 'new reason'
);
const oldRecordNotChangeReason = result.filter(item =>
item.reason === 'reason-2'
);
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare("all", 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ["no-segments-video-id-1"]) as LockCategory[];
assert.strictEqual(result.length, 4);
const newRecordWithNewReason = result.filter(item =>
expectedWithNewReason.includes(item.category) && item.reason === "new reason"
);
const oldRecordNotChangeReason = result.filter(item =>
item.reason === "reason-2"
);
assert.strictEqual(newRecordWithNewReason.length, 3);
assert.strictEqual(oldRecordNotChangeReason.length, 1);
done();
})
.catch(err => done(err));
assert.strictEqual(newRecordWithNewReason.length, 3);
assert.strictEqual(oldRecordNotChangeReason.length, 1);
done();
})
.catch(err => done(err));
});
it('Should be able to submit categories with _ in the category', (done: Done) => {
it("Should be able to submit categories with _ in the category", (done: Done) => {
const json = {
videoID: 'underscore',
userID: 'VIPUser-lockCategories',
videoID: "underscore",
userID: "VIPUser-lockCategories",
categories: [
'word_word',
"word_word",
],
};
fetch(getbaseURL() + "/api/lockCategories", {
method: 'POST',
fetch(`${getbaseURL()}/api/lockCategories`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify(json),
})
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['underscore']);
assert.strictEqual(result.length, 1);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare("all", 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ["underscore"]);
assert.strictEqual(result.length, 1);
done();
})
.catch(err => done(err));
});
it('Should be able to submit categories with upper and lower case in the category', (done: Done) => {
it("Should be able to submit categories with upper and lower case in the category", (done: Done) => {
const json = {
videoID: 'bothCases',
userID: 'VIPUser-lockCategories',
videoID: "bothCases",
userID: "VIPUser-lockCategories",
categories: [
'wordWord',
"wordWord",
],
};
fetch(getbaseURL() + "/api/lockCategories", {
method: 'POST',
fetch(`${getbaseURL()}/api/lockCategories`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify(json),
})
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['bothCases']);
assert.strictEqual(result.length, 1);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare("all", 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ["bothCases"]);
assert.strictEqual(result.length, 1);
done();
})
.catch(err => done(err));
});
it('Should not be able to submit categories with $ in the category', (done: Done) => {
it("Should not be able to submit categories with $ in the category", (done: Done) => {
const json = {
videoID: 'specialChar',
userID: 'VIPUser-lockCategories',
videoID: "specialChar",
userID: "VIPUser-lockCategories",
categories: [
'word&word',
"word&word",
],
};
fetch(getbaseURL() + "/api/lockCategories", {
method: 'POST',
fetch(`${getbaseURL()}/api/lockCategories`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify(json),
})
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['specialChar']);
assert.strictEqual(result.length, 0);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare("all", 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ["specialChar"]);
assert.strictEqual(result.length, 0);
done();
})
.catch(err => done(err));
});
it('Should return 400 for missing params', (done: Done) => {
fetch(getbaseURL() + "/api/lockCategories", {
method: 'POST',
it("Should return 400 for missing params", (done: Done) => {
fetch(`${getbaseURL()}/api/lockCategories`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({}),
})
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Should return 400 for no categories', (done: Done) => {
it("Should return 400 for no categories", (done: Done) => {
const json: any = {
videoID: 'test',
userID: 'test',
videoID: "test",
userID: "test",
categories: [],
};
fetch(getbaseURL() + "/api/lockCategories", {
method: 'POST',
fetch(`${getbaseURL()}/api/lockCategories`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify(json),
})
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Should return 400 for no userID', (done: Done) => {
it("Should return 400 for no userID", (done: Done) => {
const json: any = {
videoID: 'test',
videoID: "test",
userID: null,
categories: ['sponsor'],
categories: ["sponsor"],
};
fetch(getbaseURL() + "/api/lockCategories", {
method: 'POST',
fetch(`${getbaseURL()}/api/lockCategories`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify(json),
})
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Should return 400 for no videoID', (done: Done) => {
it("Should return 400 for no videoID", (done: Done) => {
const json: any = {
videoID: null,
userID: 'test',
categories: ['sponsor'],
userID: "test",
categories: ["sponsor"],
};
fetch(getbaseURL() + "/api/lockCategories", {
method: 'POST',
fetch(`${getbaseURL()}/api/lockCategories`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify(json),
})
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Should return 400 object categories', (done: Done) => {
it("Should return 400 object categories", (done: Done) => {
const json = {
videoID: 'test',
userID: 'test',
videoID: "test",
userID: "test",
categories: {},
};
fetch(getbaseURL() + "/api/lockCategories", {
method: 'POST',
fetch(`${getbaseURL()}/api/lockCategories`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify(json),
})
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Should return 400 bad format categories', (done: Done) => {
it("Should return 400 bad format categories", (done: Done) => {
const json = {
videoID: 'test',
userID: 'test',
categories: 'sponsor',
videoID: "test",
userID: "test",
categories: "sponsor",
};
fetch(getbaseURL() + "/api/lockCategories", {
method: 'POST',
fetch(`${getbaseURL()}/api/lockCategories`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify(json),
})
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Should return 403 if user is not VIP', (done: Done) => {
it("Should return 403 if user is not VIP", (done: Done) => {
const json = {
videoID: 'test',
userID: 'test',
videoID: "test",
userID: "test",
categories: [
'sponsor',
"sponsor",
],
};
fetch(getbaseURL() + "/api/lockCategories", {
method: 'POST',
fetch(`${getbaseURL()}/api/lockCategories`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify(json),
})
.then(res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
.then(res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
});
it('Should be able to delete a lockCategories record', (done: Done) => {
it("Should be able to delete a lockCategories record", (done: Done) => {
const json = {
videoID: 'delete-record',
userID: 'VIPUser-lockCategories',
videoID: "delete-record",
userID: "VIPUser-lockCategories",
categories: [
'sponsor',
"sponsor",
],
};
fetch(getbaseURL() + "/api/lockCategories", {
method: 'DELETE',
fetch(`${getbaseURL()}/api/lockCategories`, {
method: "DELETE",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify(json),
})
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['delete-record']);
assert.strictEqual(result.length, 0);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare("all", 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ["delete-record"]);
assert.strictEqual(result.length, 0);
done();
})
.catch(err => done(err));
});
it('Should be able to delete one lockCategories record without removing another', (done: Done) => {
it("Should be able to delete one lockCategories record without removing another", (done: Done) => {
const json = {
videoID: 'delete-record-1',
userID: 'VIPUser-lockCategories',
videoID: "delete-record-1",
userID: "VIPUser-lockCategories",
categories: [
'sponsor',
"sponsor",
],
};
fetch(getbaseURL() + "/api/lockCategories", {
method: 'DELETE',
fetch(`${getbaseURL()}/api/lockCategories`, {
method: "DELETE",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify(json),
})
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['delete-record-1']);
assert.strictEqual(result.length, 1);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare("all", 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ["delete-record-1"]);
assert.strictEqual(result.length, 1);
done();
})
.catch(err => done(err));
});
@@ -465,11 +467,11 @@ describe('lockCategoriesRecords', () => {
* To test the submission code properly see ./test/cases/postSkipSegments.js
*/
it('Should not be able to submit a segment to a video with a lock-category record (single submission)', (done: Done) => {
fetch(getbaseURL() + "/api/postVideoSponsorTimes", {
method: 'POST',
it("Should not be able to submit a segment to a video with a lock-category record (single submission)", (done: Done) => {
fetch(`${getbaseURL()}/api/postVideoSponsorTimes`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({
userID: "testman42-qwertyuiopasdfghjklzxcvbnm",
@@ -480,44 +482,44 @@ describe('lockCategoriesRecords', () => {
}],
}),
})
.then(async res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
});
it('Should not be able to submit segments to a video where any of the submissions with a no-segment record', (done: Done) => {
fetch(getbaseURL() + "/api/postVideoSponsorTimes", {
method: 'POST',
it("Should not be able to submit segments to a video where any of the submissions with a no-segment record", (done: Done) => {
fetch(`${getbaseURL()}/api/postVideoSponsorTimes`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({
userID: "testman42-qwertyuiopasdfghjklzxcvbnm",
videoID: "lockCategoryVideo",
segments: [{
segment: [20, 40],
category: "sponsor",
}, {
segment: [50, 60],
category: "intro",
}],
},),
userID: "testman42-qwertyuiopasdfghjklzxcvbnm",
videoID: "lockCategoryVideo",
segments: [{
segment: [20, 40],
category: "sponsor",
}, {
segment: [50, 60],
category: "intro",
}],
},),
})
.then(async res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
});
it('Should be able to submit a segment to a video with a different no-segment record', (done: Done) => {
fetch(getbaseURL() + "/api/postVideoSponsorTimes", {
method: 'POST',
it("Should be able to submit a segment to a video with a different no-segment record", (done: Done) => {
fetch(`${getbaseURL()}/api/postVideoSponsorTimes`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({
userID: "testman42-qwertyuiopasdfghjklzxcvbnm",
@@ -528,52 +530,52 @@ describe('lockCategoriesRecords', () => {
}],
}),
})
.then(async res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
});
it('Should be able to submit a segment to a video with no no-segment records', (done: Done) => {
fetch(getbaseURL() + "/api/postVideoSponsorTimes", {
method: 'POST',
it("Should be able to submit a segment to a video with no no-segment records", (done: Done) => {
fetch(`${getbaseURL()}/api/postVideoSponsorTimes`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({
userID: "testman42-qwertyuiopasdfghjklzxcvbnm",
videoID: "normalVideo",
segments: [{
segment: [20, 40],
category: "intro",
}],
}),
userID: "testman42-qwertyuiopasdfghjklzxcvbnm",
videoID: "normalVideo",
segments: [{
segment: [20, 40],
category: "intro",
}],
}),
})
.then(async res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
});
it('should be able to get existing category lock', (done: Done) => {
it("should be able to get existing category lock", (done: Done) => {
const expected = {
categories: [
'sponsor',
'intro',
'outro',
'shilling'
"sponsor",
"intro",
"outro",
"shilling"
],
};
fetch(getbaseURL() + "/api/lockCategories?videoID=" + "no-segments-video-id")
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.ok(deepStringEqual(data.categories, expected.categories));
done();
})
.catch(err => done(err));
fetch(`${getbaseURL()}/api/lockCategories?videoID=` + `no-segments-video-id`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.ok(stringDeepEquals(data.categories, expected.categories));
done();
})
.catch(err => done(err));
});
});

View File

@@ -1,65 +1,65 @@
import fetch from 'node-fetch';
import {db} from '../../src/databases/databases';
import {Done, getbaseURL} from '../utils';
import {getHash} from '../../src/utils/getHash';
import assert from 'assert';
import fetch from "node-fetch";
import {db} from "../../src/databases/databases";
import {Done, getbaseURL} from "../utils";
import {getHash} from "../../src/utils/getHash";
import assert from "assert";
describe('getVideoSponsorTime (Old get method)', () => {
describe("getVideoSponsorTime (Old get method)", () => {
before(async () => {
const insertSponsorTimes = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "shadowHidden", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
await db.prepare("run", insertSponsorTimes, ['old-testtesttest', 1, 11, 2, 'uuid-0', 'testman', 0, 50, 'sponsor', 0, getHash('old-testtesttest', 1)]);
await db.prepare("run", insertSponsorTimes, ['old-testtesttest,test', 1, 11, 2, 'uuid-1', 'testman', 0, 50, 'sponsor', 0, getHash('old-testtesttest,test', 1)]);
await db.prepare("run", insertSponsorTimes, ["old-testtesttest", 1, 11, 2, "uuid-0", "testman", 0, 50, "sponsor", 0, getHash("old-testtesttest", 1)]);
await db.prepare("run", insertSponsorTimes, ["old-testtesttest,test", 1, 11, 2, "uuid-1", "testman", 0, 50, "sponsor", 0, getHash("old-testtesttest,test", 1)]);
});
it('Should be able to get a time', (done: Done) => {
fetch(getbaseURL() + "/api/getVideoSponsorTimes?videoID=old-testtesttest")
.then(res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
it("Should be able to get a time", (done: Done) => {
fetch(`${getbaseURL()}/api/getVideoSponsorTimes?videoID=old-testtesttest`)
.then(res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
});
it('Should return 404 if no segment found', (done: Done) => {
fetch(getbaseURL() + "/api/getVideoSponsorTimes?videoID=notarealvideo")
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
it("Should return 404 if no segment found", (done: Done) => {
fetch(`${getbaseURL()}/api/getVideoSponsorTimes?videoID=notarealvideo`)
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
});
it('Should be possible to send unexpected query parameters', (done: Done) => {
fetch(getbaseURL() + "/api/getVideoSponsorTimes?videoID=old-testtesttest&fakeparam=hello")
.then(res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(() => done("couldn't callendpoint"));
it("Should be possible to send unexpected query parameters", (done: Done) => {
fetch(`${getbaseURL()}/api/getVideoSponsorTimes?videoID=old-testtesttest&fakeparam=hello`)
.then(res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(() => done("couldn't callendpoint"));
});
it('Should be able send a comma in a query param', (done: Done) => {
fetch(getbaseURL() + "/api/getVideoSponsorTimes?videoID=old-testtesttest,test")
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.UUIDs[0], "uuid-1");
done();
})
.catch(err => done(err));
it("Should be able send a comma in a query param", (done: Done) => {
fetch(`${getbaseURL()}/api/getVideoSponsorTimes?videoID=old-testtesttest,test`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.UUIDs[0], "uuid-1");
done();
})
.catch(err => done(err));
});
it('Should be able to get the correct time', (done: Done) => {
fetch(getbaseURL() + "/api/getVideoSponsorTimes?videoID=old-testtesttest")
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.sponsorTimes[0][0], 1);
assert.strictEqual(data.sponsorTimes[0][1], 11);
assert.strictEqual(data.UUIDs[0], 'uuid-0');
done();
})
.catch(err => done(err));
it("Should be able to get the correct time", (done: Done) => {
fetch(`${getbaseURL()}/api/getVideoSponsorTimes?videoID=old-testtesttest`)
.then(async res => {
assert.strictEqual(res.status, 200);
const data = await res.json();
assert.strictEqual(data.sponsorTimes[0][0], 1);
assert.strictEqual(data.sponsorTimes[0][1], 11);
assert.strictEqual(data.UUIDs[0], "uuid-0");
done();
})
.catch(err => done(err));
});
});

View File

@@ -1,49 +1,49 @@
import fetch from 'node-fetch';
import {Done, getbaseURL} from '../utils';
import {db} from '../../src/databases/databases';
import assert from 'assert';
import fetch from "node-fetch";
import {Done, getbaseURL} from "../utils";
import {db} from "../../src/databases/databases";
import assert from "assert";
describe('postVideoSponsorTime (Old submission method)', () => {
it('Should be able to submit a time (GET)', (done: Done) => {
fetch(getbaseURL()
+ "/api/postVideoSponsorTimes?videoID=dQw4w9WgXcQ&startTime=1&endTime=10&userID=testtesttesttesttesttesttesttesttest")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "startTime", "endTime", "category" FROM "sponsorTimes" WHERE "videoID" = ?`, ["dQw4w9WgXcQ"]);
assert.strictEqual(row.startTime, 1);
assert.strictEqual(row.endTime, 10);
assert.strictEqual(row.category, "sponsor");
done();
})
.catch(err => done(err));
});
it('Should be able to submit a time (POST)', (done: Done) => {
fetch(getbaseURL()
+ "/api/postVideoSponsorTimes?videoID=dQw4w9WgXcE&startTime=1&endTime=11&userID=testtesttesttesttesttesttesttesttest", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
describe("postVideoSponsorTime (Old submission method)", () => {
it("Should be able to submit a time (GET)", (done: Done) => {
fetch(`${getbaseURL()
}/api/postVideoSponsorTimes?videoID=dQw4w9WgXcQ&startTime=1&endTime=10&userID=testtesttesttesttesttesttesttesttest`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "startTime", "endTime", "category" FROM "sponsorTimes" WHERE "videoID" = ?`, ["dQw4w9WgXcQ"]);
assert.strictEqual(row.startTime, 1);
assert.strictEqual(row.endTime, 10);
assert.strictEqual(row.category, "sponsor");
done();
})
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "startTime", "endTime", "category" FROM "sponsorTimes" WHERE "videoID" = ?`, ["dQw4w9WgXcE"]);
assert.strictEqual(row.startTime, 1);
assert.strictEqual(row.endTime, 11);
assert.strictEqual(row.category, "sponsor");
done();
})
.catch(err => done(err));
.catch(err => done(err));
});
it('Should return 400 for missing params', (done: Done) => {
fetch(getbaseURL()
+ "/api/postVideoSponsorTimes?startTime=1&endTime=10&userID=testtesttesttesttesttesttesttesttest")
.then(async res => {
assert.strictEqual(res.status, 400);
done();
it("Should be able to submit a time (POST)", (done: Done) => {
fetch(`${getbaseURL()
}/api/postVideoSponsorTimes?videoID=dQw4w9WgXcE&startTime=1&endTime=11&userID=testtesttesttesttesttesttesttesttest`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "startTime", "endTime", "category" FROM "sponsorTimes" WHERE "videoID" = ?`, ["dQw4w9WgXcE"]);
assert.strictEqual(row.startTime, 1);
assert.strictEqual(row.endTime, 11);
assert.strictEqual(row.category, "sponsor");
done();
})
.catch(err => done(err));
});
it("Should return 400 for missing params", (done: Done) => {
fetch(`${getbaseURL()
}/api/postVideoSponsorTimes?startTime=1&endTime=10&userID=testtesttesttesttesttesttesttesttest`)
.then(async res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
});

View File

@@ -1,73 +1,73 @@
import fetch from 'node-fetch';
import {Done, getbaseURL} from '../utils';
import {db} from '../../src/databases/databases';
import {getHash} from '../../src/utils/getHash';
import assert from 'assert';
import fetch from "node-fetch";
import {Done, getbaseURL} from "../utils";
import {db} from "../../src/databases/databases";
import {getHash} from "../../src/utils/getHash";
import assert from "assert";
describe('postClearCache', () => {
describe("postClearCache", () => {
before(async () => {
await db.prepare("run", `INSERT INTO "vipUsers" ("userID") VALUES ('` + getHash("clearing-vip") + "')");
await db.prepare("run", `INSERT INTO "vipUsers" ("userID") VALUES ('${getHash("clearing-vip")}')`);
const startOfQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "shadowHidden", "hashedVideoID") VALUES';
await db.prepare("run", startOfQuery + "('clear-test', 0, 1, 2, 'clear-uuid', 'testman', 0, 50, 'sponsor', 0, '" + getHash('clear-test', 1) + "')");
await db.prepare("run", `${startOfQuery}('clear-test', 0, 1, 2, 'clear-uuid', 'testman', 0, 50, 'sponsor', 0, '" + getHash("clear-test", 1) + "')`);
});
it('Should be able to clear cache for existing video', (done: Done) => {
fetch(getbaseURL()
+ "/api/clearCache?userID=clearing-vip&videoID=clear-test", {
method: 'POST'
it("Should be able to clear cache for existing video", (done: Done) => {
fetch(`${getbaseURL()
}/api/clearCache?userID=clearing-vip&videoID=clear-test`, {
method: "POST"
})
.then(res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
.then(res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
});
it('Should be able to clear cache for nonexistent video', (done: Done) => {
fetch(getbaseURL()
+ "/api/clearCache?userID=clearing-vip&videoID=dne-video", {
method: 'POST'
it("Should be able to clear cache for nonexistent video", (done: Done) => {
fetch(`${getbaseURL()
}/api/clearCache?userID=clearing-vip&videoID=dne-video`, {
method: "POST"
})
.then(res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
.then(res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
});
it('Should get 403 as non-vip', (done: Done) => {
fetch(getbaseURL()
+ "/api/clearCache?userID=regular-user&videoID=clear-tes", {
method: 'POST'
it("Should get 403 as non-vip", (done: Done) => {
fetch(`${getbaseURL()
}/api/clearCache?userID=regular-user&videoID=clear-tes`, {
method: "POST"
})
.then(async res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
});
it('Should give 400 with missing videoID', (done: Done) => {
fetch(getbaseURL()
+ "/api/clearCache?userID=clearing-vip", {
method: 'POST'
it("Should give 400 with missing videoID", (done: Done) => {
fetch(`${getbaseURL()
}/api/clearCache?userID=clearing-vip`, {
method: "POST"
})
.then(async res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Should give 400 with missing userID', (done: Done) => {
fetch(getbaseURL()
+ "/api/clearCache?userID=clearing-vip", {
method: 'POST'
it("Should give 400 with missing userID", (done: Done) => {
fetch(`${getbaseURL()
}/api/clearCache?userID=clearing-vip`, {
method: "POST"
})
.then(async res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
});

View File

@@ -1,9 +1,9 @@
import fetch from 'node-fetch';
import {Done, getbaseURL} from '../utils';
import {db} from '../../src/databases/databases';
import {getHash} from '../../src/utils/getHash';
import {IDatabase} from '../../src/databases/IDatabase';
import assert from 'assert';
import fetch from "node-fetch";
import {Done, getbaseURL} from "../utils";
import {db} from "../../src/databases/databases";
import {getHash} from "../../src/utils/getHash";
import {IDatabase} from "../../src/databases/IDatabase";
import assert from "assert";
async function dbSponsorTimesAdd(db: IDatabase, videoID: string, startTime: number, endTime: number, UUID: string, category: string) {
const votes = 0,
@@ -21,7 +21,7 @@ async function dbSponsorTimesAdd(db: IDatabase, videoID: string, startTime: numb
}
async function dbSponsorTimesCompareExpect(db: IDatabase, videoId: string, expectdHidden: number) {
const seg = await db.prepare('get', `SELECT "hidden", "UUID" FROM "sponsorTimes" WHERE "videoID" = ?`, [videoId]);
const seg = await db.prepare("get", `SELECT "hidden", "UUID" FROM "sponsorTimes" WHERE "videoID" = ?`, [videoId]);
for (let i = 0, len = seg.length; i < len; i++) {
if (seg.hidden !== expectdHidden) {
return `${seg.UUID} hidden expected to be ${expectdHidden} but found ${seg.hidden}`;
@@ -30,56 +30,56 @@ async function dbSponsorTimesCompareExpect(db: IDatabase, videoId: string, expec
return;
}
describe('postPurgeAllSegments', function () {
const privateVipUserID = 'VIPUser-purgeAll';
const route = '/api/purgeAllSegments';
describe("postPurgeAllSegments", function () {
const privateVipUserID = "VIPUser-purgeAll";
const route = "/api/purgeAllSegments";
const vipUserID = getHash(privateVipUserID);
const baseURL = getbaseURL();
before(async function () {
// startTime and endTime get set in beforeEach for consistency
await dbSponsorTimesAdd(db, 'vsegpurge01', 0, 1, 'vsegpurgetest01uuid01', 'intro');
await dbSponsorTimesAdd(db, 'vsegpurge01', 0, 2, 'vsegpurgetest01uuid02', 'sponsor');
await dbSponsorTimesAdd(db, 'vsegpurge01', 0, 3, 'vsegpurgetest01uuid03', 'interaction');
await dbSponsorTimesAdd(db, 'vsegpurge01', 0, 4, 'vsegpurgetest01uuid04', 'outro');
await dbSponsorTimesAdd(db, 'vseg-not-purged01', 0, 5, 'vsegpurgetest01uuid05', 'outro');
await dbSponsorTimesAdd(db, "vsegpurge01", 0, 1, "vsegpurgetest01uuid01", "intro");
await dbSponsorTimesAdd(db, "vsegpurge01", 0, 2, "vsegpurgetest01uuid02", "sponsor");
await dbSponsorTimesAdd(db, "vsegpurge01", 0, 3, "vsegpurgetest01uuid03", "interaction");
await dbSponsorTimesAdd(db, "vsegpurge01", 0, 4, "vsegpurgetest01uuid04", "outro");
await dbSponsorTimesAdd(db, "vseg-not-purged01", 0, 5, "vsegpurgetest01uuid05", "outro");
await db.prepare("run", `INSERT INTO "vipUsers" ("userID") VALUES (?)`, [vipUserID]);
});
it('Reject non-VIP user', function (done: Done) {
it("Reject non-VIP user", function (done: Done) {
fetch(`${baseURL}${route}`, {
method: 'POST',
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({
videoID: 'vsegpurge01',
userID: 'segshift_randomuser001',
videoID: "vsegpurge01",
userID: "segshift_randomuser001",
}),
})
.then(async res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
});
it('Purge all segments success', function (done: Done) {
it("Purge all segments success", function (done: Done) {
fetch(`${baseURL}${route}`, {
method: 'POST',
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({
videoID: 'vsegpurge01',
videoID: "vsegpurge01",
userID: privateVipUserID,
}),
})
.then(async res => {
assert.strictEqual(res.status, 200);
done(await dbSponsorTimesCompareExpect(db, 'vsegpurge01', 1) || await dbSponsorTimesCompareExpect(db, 'vseg-not-purged01', 0));
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
done(await dbSponsorTimesCompareExpect(db, "vsegpurge01", 1) || await dbSponsorTimesCompareExpect(db, "vseg-not-purged01", 0));
})
.catch(err => done(err));
});
it('Should return 400 if missing body', function (done: Done) {

File diff suppressed because it is too large Load Diff

View File

@@ -1,106 +1,102 @@
import fetch from 'node-fetch';
import {Done, getbaseURL} from '../utils';
import {db} from '../../src/databases/databases';
import {getHash} from '../../src/utils/getHash';
import assert from 'assert';
import fetch from "node-fetch";
import {Done, getbaseURL} from "../utils";
import {db} from "../../src/databases/databases";
import {getHash} from "../../src/utils/getHash";
import assert from "assert";
describe('postWarning', () => {
describe("postWarning", () => {
before(async () => {
await db.prepare("run", `INSERT INTO "vipUsers" ("userID") VALUES (?)`, [getHash("warning-vip")]);
});
it('Should be able to create warning if vip (exp 200)', (done: Done) => {
it("Should be able to create warning if vip (exp 200)", (done: Done) => {
const json = {
issuerUserID: 'warning-vip',
userID: 'warning-0',
reason: 'warning-reason-0'
issuerUserID: "warning-vip",
userID: "warning-0",
reason: "warning-reason-0"
};
fetch(getbaseURL()
+ "/api/warnUser", {
method: 'POST',
fetch(`${getbaseURL()}/api/warnUser`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify(json),
})
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "userID", "issueTime", "issuerUserID", enabled, "reason" FROM warnings WHERE "userID" = ?`, [json.userID]);
assert.strictEqual(row.enabled, 1);
assert.strictEqual(row.issuerUserID, getHash(json.issuerUserID));
assert.strictEqual(row.reason, json.reason);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "userID", "issueTime", "issuerUserID", enabled, "reason" FROM warnings WHERE "userID" = ?`, [json.userID]);
assert.strictEqual(row.enabled, 1);
assert.strictEqual(row.issuerUserID, getHash(json.issuerUserID));
assert.strictEqual(row.reason, json.reason);
done();
})
.catch(err => done(err));
});
it('Should be not be able to create a duplicate warning if vip', (done: Done) => {
it("Should be not be able to create a duplicate warning if vip", (done: Done) => {
const json = {
issuerUserID: 'warning-vip',
userID: 'warning-0',
issuerUserID: "warning-vip",
userID: "warning-0",
};
fetch(getbaseURL()
+ "/api/warnUser", {
method: 'POST',
fetch(`${getbaseURL()}/api/warnUser`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify(json),
})
.then(async res => {
assert.strictEqual(res.status, 409);
const row = await db.prepare('get', `SELECT "userID", "issueTime", "issuerUserID", enabled FROM warnings WHERE "userID" = ?`, [json.userID]);
assert.strictEqual(row.enabled, 1);
assert.strictEqual(row.issuerUserID, getHash(json.issuerUserID));
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 409);
const row = await db.prepare("get", `SELECT "userID", "issueTime", "issuerUserID", enabled FROM warnings WHERE "userID" = ?`, [json.userID]);
assert.strictEqual(row.enabled, 1);
assert.strictEqual(row.issuerUserID, getHash(json.issuerUserID));
done();
})
.catch(err => done(err));
});
it('Should be able to remove warning if vip', (done: Done) => {
it("Should be able to remove warning if vip", (done: Done) => {
const json = {
issuerUserID: 'warning-vip',
userID: 'warning-0',
issuerUserID: "warning-vip",
userID: "warning-0",
enabled: false
};
fetch(getbaseURL()
+ "/api/warnUser", {
method: 'POST',
fetch(`${getbaseURL()}/api/warnUser`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify(json),
})
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "userID", "issueTime", "issuerUserID", enabled FROM warnings WHERE "userID" = ?`, [json.userID]);
assert.strictEqual(row.enabled, 0);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "userID", "issueTime", "issuerUserID", enabled FROM warnings WHERE "userID" = ?`, [json.userID]);
assert.strictEqual(row.enabled, 0);
done();
})
.catch(err => done(err));
});
it('Should not be able to create warning if not vip (exp 403)', (done: Done) => {
it("Should not be able to create warning if not vip (exp 403)", (done: Done) => {
const json = {
issuerUserID: 'warning-not-vip',
userID: 'warning-1',
issuerUserID: "warning-not-vip",
userID: "warning-1",
};
fetch(getbaseURL()
+ "/api/warnUser", {
method: 'POST',
fetch(`${getbaseURL()}/api/warnUser`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify(json),
})
.then(res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
.then(res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
});
it('Should return 400 if missing body', (done: Done) => {

View File

@@ -1,8 +1,8 @@
import assert from 'assert';
import { db } from '../../src/databases/databases';
import { UserID } from '../../src/types/user.model';
import { getHash } from '../../src/utils/getHash';
import { getReputation } from '../../src/utils/reputation';
import assert from "assert";
import { db } from "../../src/databases/databases";
import { UserID } from "../../src/types/user.model";
import { getHash } from "../../src/utils/getHash";
import { getReputation } from "../../src/utils/reputation";
const userIDLowSubmissions = "reputation-lowsubmissions" as UserID;
const userIDHighDownvotes = "reputation-highdownvotes" as UserID;
@@ -13,80 +13,80 @@ const userIDHighRepBeforeManualVote = "reputation-oldhighrep" as UserID;
const userIDHighRep = "reputation-highrep" as UserID;
const userIDHighRepAndLocked = "reputation-highlockedrep" as UserID;
describe('reputation', () => {
describe("reputation", () => {
before(async function() {
this.timeout(5000); // this preparation takes longer then usual
const videoID = "reputation-videoID";
const sponsorTimesInsertQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "service", "videoDuration", "hidden", "shadowHidden", "hashedVideoID") VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)';
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-0-uuid-0', getHash(userIDLowSubmissions), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-0-uuid-1', getHash(userIDLowSubmissions), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 100, 0, 'reputation-0-uuid-2', getHash(userIDLowSubmissions), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-1-uuid-0', getHash(userIDHighDownvotes), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -2, 0, 'reputation-1-uuid-1', getHash(userIDHighDownvotes), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -2, 0, 'reputation-1-uuid-2', getHash(userIDHighDownvotes), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -2, 0, 'reputation-1-uuid-3', getHash(userIDHighDownvotes), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -2, 0, 'reputation-1-uuid-4', getHash(userIDHighDownvotes), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, 'reputation-1-uuid-5', getHash(userIDHighDownvotes), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, 'reputation-1-uuid-6', getHash(userIDHighDownvotes), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, 'reputation-1-uuid-7', getHash(userIDHighDownvotes), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-0-uuid-0", getHash(userIDLowSubmissions), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-0-uuid-1", getHash(userIDLowSubmissions), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 100, 0, "reputation-0-uuid-2", getHash(userIDLowSubmissions), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-1-uuid-0", getHash(userIDHighDownvotes), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -2, 0, "reputation-1-uuid-1", getHash(userIDHighDownvotes), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -2, 0, "reputation-1-uuid-2", getHash(userIDHighDownvotes), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -2, 0, "reputation-1-uuid-3", getHash(userIDHighDownvotes), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -2, 0, "reputation-1-uuid-4", getHash(userIDHighDownvotes), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-1-uuid-5", getHash(userIDHighDownvotes), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-uuid-6", getHash(userIDHighDownvotes), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-uuid-7", getHash(userIDHighDownvotes), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
// First video is considered a normal downvote, second is considered a self-downvote (ie. they didn't resubmit to fix their downvote)
await db.prepare("run", sponsorTimesInsertQuery, [videoID+'A', 1, 11, 2, 0, 'reputation-1-1-uuid-0', getHash(userIDHighNonSelfDownvotes), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [`${videoID}A`, 1, 11, 2, 0, "reputation-1-1-uuid-0", getHash(userIDHighNonSelfDownvotes), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
// Different category, same video
await db.prepare("run", sponsorTimesInsertQuery, [videoID+'A', 1, 11, -2, 0, 'reputation-1-1-uuid-1', getHash(userIDHighNonSelfDownvotes), 1606240000000, 50, 'intro', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, 'reputation-1-1-uuid-2', getHash(userIDHighNonSelfDownvotes), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, 'reputation-1-1-uuid-3', getHash(userIDHighNonSelfDownvotes), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, 'reputation-1-1-uuid-4', getHash(userIDHighNonSelfDownvotes), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, 'reputation-1-1-uuid-5', getHash(userIDHighNonSelfDownvotes), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, 'reputation-1-1-uuid-6', getHash(userIDHighNonSelfDownvotes), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, 'reputation-1-1-uuid-7', getHash(userIDHighNonSelfDownvotes), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-2-uuid-0', getHash(userIDNewSubmissions), Date.now(), 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-2-uuid-1', getHash(userIDNewSubmissions), Date.now(), 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-2-uuid-2', getHash(userIDNewSubmissions), Date.now(), 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-2-uuid-3', getHash(userIDNewSubmissions), Date.now(), 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-2-uuid-4', getHash(userIDNewSubmissions), Date.now(), 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, 'reputation-2-uuid-5', getHash(userIDNewSubmissions), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, 'reputation-2-uuid-6', getHash(userIDNewSubmissions), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, 'reputation-2-uuid-7', getHash(userIDNewSubmissions), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [`${videoID}A`, 1, 11, -2, 0, "reputation-1-1-uuid-1", getHash(userIDHighNonSelfDownvotes), 1606240000000, 50, "intro", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-uuid-2", getHash(userIDHighNonSelfDownvotes), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-uuid-3", getHash(userIDHighNonSelfDownvotes), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-uuid-4", getHash(userIDHighNonSelfDownvotes), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-1-1-uuid-5", getHash(userIDHighNonSelfDownvotes), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-uuid-6", getHash(userIDHighNonSelfDownvotes), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-uuid-7", getHash(userIDHighNonSelfDownvotes), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-3-uuid-0', getHash(userIDLowSum), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 1, 0, 'reputation-3-uuid-1', getHash(userIDLowSum), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, 'reputation-3-uuid-2', getHash(userIDLowSum), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, 'reputation-3-uuid-3', getHash(userIDLowSum), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 1, 0, 'reputation-3-uuid-4', getHash(userIDLowSum), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, 'reputation-3-uuid-5', getHash(userIDLowSum), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, 'reputation-3-uuid-6', getHash(userIDLowSum), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, 'reputation-3-uuid-7', getHash(userIDLowSum), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-2-uuid-0", getHash(userIDNewSubmissions), Date.now(), 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-2-uuid-1", getHash(userIDNewSubmissions), Date.now(), 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-2-uuid-2", getHash(userIDNewSubmissions), Date.now(), 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-2-uuid-3", getHash(userIDNewSubmissions), Date.now(), 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-2-uuid-4", getHash(userIDNewSubmissions), Date.now(), 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-2-uuid-5", getHash(userIDNewSubmissions), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-2-uuid-6", getHash(userIDNewSubmissions), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-2-uuid-7", getHash(userIDNewSubmissions), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-4-uuid-0', getHash(userIDHighRepBeforeManualVote), 0, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-4-uuid-1', getHash(userIDHighRepBeforeManualVote), 0, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-4-uuid-2', getHash(userIDHighRepBeforeManualVote), 0, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-4-uuid-3', getHash(userIDHighRepBeforeManualVote), 0, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-4-uuid-4', getHash(userIDHighRepBeforeManualVote), 0, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, 'reputation-4-uuid-5', getHash(userIDHighRepBeforeManualVote), 0, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, 'reputation-4-uuid-6', getHash(userIDHighRepBeforeManualVote), 0, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, 'reputation-4-uuid-7', getHash(userIDHighRepBeforeManualVote), 0, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-3-uuid-0", getHash(userIDLowSum), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 1, 0, "reputation-3-uuid-1", getHash(userIDLowSum), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-3-uuid-2", getHash(userIDLowSum), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-3-uuid-3", getHash(userIDLowSum), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 1, 0, "reputation-3-uuid-4", getHash(userIDLowSum), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-3-uuid-5", getHash(userIDLowSum), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-3-uuid-6", getHash(userIDLowSum), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-3-uuid-7", getHash(userIDLowSum), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-5-uuid-0', getHash(userIDHighRep), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-5-uuid-1', getHash(userIDHighRep), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-5-uuid-2', getHash(userIDHighRep), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-5-uuid-3', getHash(userIDHighRep), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-5-uuid-4', getHash(userIDHighRep), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, 'reputation-5-uuid-5', getHash(userIDHighRep), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, 'reputation-5-uuid-6', getHash(userIDHighRep), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, 'reputation-5-uuid-7', getHash(userIDHighRep), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 1, 'reputation-6-uuid-0', getHash(userIDHighRepAndLocked), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 1, 'reputation-6-uuid-1', getHash(userIDHighRepAndLocked), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 1, 'reputation-6-uuid-2', getHash(userIDHighRepAndLocked), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 1, 'reputation-6-uuid-3', getHash(userIDHighRepAndLocked), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-6-uuid-4', getHash(userIDHighRepAndLocked), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, 'reputation-6-uuid-5', getHash(userIDHighRepAndLocked), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, 'reputation-6-uuid-6', getHash(userIDHighRepAndLocked), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, 'reputation-6-uuid-7', getHash(userIDHighRepAndLocked), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-4-uuid-0", getHash(userIDHighRepBeforeManualVote), 0, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-4-uuid-1", getHash(userIDHighRepBeforeManualVote), 0, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-4-uuid-2", getHash(userIDHighRepBeforeManualVote), 0, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-4-uuid-3", getHash(userIDHighRepBeforeManualVote), 0, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-4-uuid-4", getHash(userIDHighRepBeforeManualVote), 0, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-4-uuid-5", getHash(userIDHighRepBeforeManualVote), 0, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-4-uuid-6", getHash(userIDHighRepBeforeManualVote), 0, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-4-uuid-7", getHash(userIDHighRepBeforeManualVote), 0, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-5-uuid-0", getHash(userIDHighRep), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-5-uuid-1", getHash(userIDHighRep), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-5-uuid-2", getHash(userIDHighRep), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-5-uuid-3", getHash(userIDHighRep), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-5-uuid-4", getHash(userIDHighRep), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-5-uuid-5", getHash(userIDHighRep), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-5-uuid-6", getHash(userIDHighRep), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-5-uuid-7", getHash(userIDHighRep), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 1, "reputation-6-uuid-0", getHash(userIDHighRepAndLocked), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 1, "reputation-6-uuid-1", getHash(userIDHighRepAndLocked), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 1, "reputation-6-uuid-2", getHash(userIDHighRepAndLocked), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 1, "reputation-6-uuid-3", getHash(userIDHighRepAndLocked), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-6-uuid-4", getHash(userIDHighRepAndLocked), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-6-uuid-5", getHash(userIDHighRepAndLocked), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-6-uuid-6", getHash(userIDHighRepAndLocked), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-6-uuid-7", getHash(userIDHighRepAndLocked), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]);
});
it("user in grace period", async () => {

View File

@@ -1,9 +1,9 @@
import fetch from 'node-fetch';
import {Done, getbaseURL} from '../utils';
import {db} from '../../src/databases/databases';
import {getHash} from '../../src/utils/getHash';
import {IDatabase} from '../../src/databases/IDatabase';
import assert from 'assert';
import fetch from "node-fetch";
import {Done, getbaseURL} from "../utils";
import {db} from "../../src/databases/databases";
import {getHash} from "../../src/utils/getHash";
import {IDatabase} from "../../src/databases/IDatabase";
import assert from "assert";
async function dbSponsorTimesAdd(db: IDatabase, videoID: string, startTime: number, endTime: number, UUID: string, category: string) {
const votes = 0,
@@ -16,18 +16,18 @@ async function dbSponsorTimesAdd(db: IDatabase, videoID: string, startTime: numb
"sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID",
"userID", "timeSubmitted", "views", "category", "shadowHidden", "hashedVideoID")
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[videoID, startTime, endTime, votes, UUID, userID, timeSubmitted, views, category, shadowHidden, hashedVideoID]);
[videoID, startTime, endTime, votes, UUID, userID, timeSubmitted, views, category, shadowHidden, hashedVideoID]);
}
async function dbSponsorTimesSetByUUID(db: IDatabase, UUID: string, startTime: number, endTime: number) {
await db.prepare('run', `UPDATE "sponsorTimes" SET "startTime" = ?, "endTime" = ? WHERE "UUID" = ?`, [startTime, endTime, UUID]);
await db.prepare("run", `UPDATE "sponsorTimes" SET "startTime" = ?, "endTime" = ? WHERE "UUID" = ?`, [startTime, endTime, UUID]);
}
async function dbSponsorTimesCompareExpect(db: IDatabase, expect: any): Promise<void> {
for (let i = 0, len = expect.length; i < len; i++) {
const expectSeg = expect[i];
const seg = await db.prepare('get', `SELECT "startTime", "endTime" FROM "sponsorTimes" WHERE "UUID" = ?`, [expectSeg.UUID]);
if ('removed' in expect) {
const seg = await db.prepare("get", `SELECT "startTime", "endTime" FROM "sponsorTimes" WHERE "UUID" = ?`, [expectSeg.UUID]);
if ("removed" in expect) {
assert.ok(expect.removed);
assert.strictEqual(seg.votes, -2);
assert.deepStrictEqual(seg, expectSeg);
@@ -37,256 +37,256 @@ async function dbSponsorTimesCompareExpect(db: IDatabase, expect: any): Promise<
}
}
describe('segmentShift', function () {
const privateVipUserID = 'VIPUser-segmentShift';
describe("segmentShift", function () {
const privateVipUserID = "VIPUser-segmentShift";
const vipUserID = getHash(privateVipUserID);
const baseURL = getbaseURL();
before(async function () {
// startTime and endTime get set in beforeEach for consistency
await dbSponsorTimesAdd(db, 'vsegshift01', 0, 0, 'vsegshifttest01uuid01', 'intro');
await dbSponsorTimesAdd(db, 'vsegshift01', 0, 0, 'vsegshifttest01uuid02', 'sponsor');
await dbSponsorTimesAdd(db, 'vsegshift01', 0, 0, 'vsegshifttest01uuid03', 'interaction');
await dbSponsorTimesAdd(db, 'vsegshift01', 0, 0, 'vsegshifttest01uuid04', 'outro');
await dbSponsorTimesAdd(db, "vsegshift01", 0, 0, "vsegshifttest01uuid01", "intro");
await dbSponsorTimesAdd(db, "vsegshift01", 0, 0, "vsegshifttest01uuid02", "sponsor");
await dbSponsorTimesAdd(db, "vsegshift01", 0, 0, "vsegshifttest01uuid03", "interaction");
await dbSponsorTimesAdd(db, "vsegshift01", 0, 0, "vsegshifttest01uuid04", "outro");
await db.prepare("run", `INSERT INTO "vipUsers" ("userID") VALUES (?)`, [vipUserID]);
});
beforeEach(async function () {
// resetting startTime and endTime to reuse them
await dbSponsorTimesSetByUUID(db, 'vsegshifttest01uuid01', 0, 10);
await dbSponsorTimesSetByUUID(db, 'vsegshifttest01uuid02', 60, 90);
await dbSponsorTimesSetByUUID(db, 'vsegshifttest01uuid03', 40, 45);
await dbSponsorTimesSetByUUID(db, 'vsegshifttest01uuid04', 120, 140);
await dbSponsorTimesSetByUUID(db, "vsegshifttest01uuid01", 0, 10);
await dbSponsorTimesSetByUUID(db, "vsegshifttest01uuid02", 60, 90);
await dbSponsorTimesSetByUUID(db, "vsegshifttest01uuid03", 40, 45);
await dbSponsorTimesSetByUUID(db, "vsegshifttest01uuid04", 120, 140);
});
it('Reject none VIP user', function (done: Done) {
it("Reject none VIP user", function (done: Done) {
fetch(`${baseURL}/api/segmentShift`, {
method: 'POST',
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({
videoID: 'vsegshift01',
userID: 'segshift_randomuser001',
videoID: "vsegshift01",
userID: "segshift_randomuser001",
startTime: 20,
endTime: 30,
}),
})
.then(async res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
});
it('Shift is outside segments', function (done: Done) {
it("Shift is outside segments", function (done: Done) {
fetch(`${baseURL}/api/segmentShift`, {
method: 'POST',
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({
videoID: 'vsegshift01',
videoID: "vsegshift01",
userID: privateVipUserID,
startTime: 20,
endTime: 30,
}),
})
.then(async res => {
assert.strictEqual(res.status, 200);
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(await dbSponsorTimesCompareExpect(db, expect));
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
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(await dbSponsorTimesCompareExpect(db, expect));
})
.catch(err => done(err));
});
it('Shift is inside segment', function (done: Done) {
it("Shift is inside segment", function (done: Done) {
fetch(`${baseURL}/api/segmentShift`, {
method: 'POST',
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({
videoID: 'vsegshift01',
videoID: "vsegshift01",
userID: privateVipUserID,
startTime: 65,
endTime: 75,
}),
})
.then(async res => {
assert.strictEqual(res.status, 200);
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(await dbSponsorTimesCompareExpect(db, expect));
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
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(await dbSponsorTimesCompareExpect(db, expect));
})
.catch(err => done(err));
});
it('Shift is overlaping startTime of segment', function (done: Done) {
it("Shift is overlaping startTime of segment", function (done: Done) {
fetch(`${baseURL}/api/segmentShift`, {
method: 'POST',
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({
videoID: 'vsegshift01',
videoID: "vsegshift01",
userID: privateVipUserID,
startTime: 32,
endTime: 42,
}),
})
.then(async res => {
assert.strictEqual(res.status, 200);
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(await dbSponsorTimesCompareExpect(db, expect));
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
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(await dbSponsorTimesCompareExpect(db, expect));
})
.catch(err => done(err));
});
it('Shift is overlaping endTime of segment', function (done: Done) {
it("Shift is overlaping endTime of segment", function (done: Done) {
fetch(`${baseURL}/api/segmentShift`, {
method: 'POST',
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({
videoID: 'vsegshift01',
videoID: "vsegshift01",
userID: privateVipUserID,
startTime: 85,
endTime: 95,
}),
})
.then(async res => {
assert.strictEqual(res.status, 200);
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(await dbSponsorTimesCompareExpect(db, expect));
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
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(await dbSponsorTimesCompareExpect(db, expect));
})
.catch(err => done(err));
});
it('Shift is overlaping segment', function (done: Done) {
it("Shift is overlaping segment", function (done: Done) {
fetch(`${baseURL}/api/segmentShift`, {
method: 'POST',
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({
videoID: 'vsegshift01',
videoID: "vsegshift01",
userID: privateVipUserID,
startTime: 35,
endTime: 55,
}),
})
.then(async res => {
assert.strictEqual(res.status, 200);
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(await dbSponsorTimesCompareExpect(db, expect));
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
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(await dbSponsorTimesCompareExpect(db, expect));
})
.catch(err => done(err));
});
});

View File

@@ -1,54 +1,54 @@
import fetch from 'node-fetch';
import { Done, getbaseURL } from '../utils';
import { db, privateDB } from '../../src/databases/databases';
import { getHash } from '../../src/utils/getHash';
import assert from 'assert';
import fetch from "node-fetch";
import { Done, getbaseURL } from "../utils";
import { db, privateDB } from "../../src/databases/databases";
import { getHash } from "../../src/utils/getHash";
import assert from "assert";
const adminPrivateUserID = 'testUserId';
const user00PrivateUserID = 'setUsername_00';
const username00 = 'Username 00';
const user01PrivateUserID = 'setUsername_01';
const username01 = 'Username 01';
const user02PrivateUserID = 'setUsername_02';
const username02 = 'Username 02';
const user03PrivateUserID = 'setUsername_03';
const username03 = 'Username 03';
const user04PrivateUserID = 'setUsername_04';
const username04 = 'Username 04';
const user05PrivateUserID = 'setUsername_05';
const username05 = 'Username 05';
const user06PrivateUserID = 'setUsername_06';
const username06 = 'Username 06';
const user07PrivateUserID = 'setUsername_07';
const username07 = 'Username 07';
const adminPrivateUserID = "testUserId";
const user00PrivateUserID = "setUsername_00";
const username00 = "Username 00";
const user01PrivateUserID = "setUsername_01";
const username01 = "Username 01";
const user02PrivateUserID = "setUsername_02";
const username02 = "Username 02";
const user03PrivateUserID = "setUsername_03";
const username03 = "Username 03";
const user04PrivateUserID = "setUsername_04";
const username04 = "Username 04";
const user05PrivateUserID = "setUsername_05";
const username05 = "Username 05";
const user06PrivateUserID = "setUsername_06";
const username06 = "Username 06";
const user07PrivateUserID = "setUsername_07";
const username07 = "Username 07";
async function addUsername(userID: string, userName: string, locked = 0) {
await db.prepare('run', 'INSERT INTO "userNames" ("userID", "userName", "locked") VALUES(?, ?, ?)', [userID, userName, locked]);
await db.prepare("run", 'INSERT INTO "userNames" ("userID", "userName", "locked") VALUES(?, ?, ?)', [userID, userName, locked]);
await addLogUserNameChange(userID, userName);
}
async function getUsernameInfo(userID: string): Promise<{ userName: string, locked: string }> {
const row = await db.prepare('get', 'SELECT "userName", "locked" FROM "userNames" WHERE "userID" = ?', [userID]);
const row = await db.prepare("get", 'SELECT "userName", "locked" FROM "userNames" WHERE "userID" = ?', [userID]);
if (!row) {
return null;
}
return row;
}
async function addLogUserNameChange(userID: string, newUserName: string, oldUserName = '') {
privateDB.prepare('run',
async function addLogUserNameChange(userID: string, newUserName: string, oldUserName = "") {
privateDB.prepare("run",
`INSERT INTO "userNameLogs"("userID", "newUserName", "oldUserName", "updatedAt", "updatedByAdmin") VALUES(?, ?, ?, ?, ?)`,
[getHash(userID), newUserName, oldUserName, new Date().getTime(), + true]
);
}
async function getLastLogUserNameChange(userID: string) {
return privateDB.prepare('get', `SELECT * FROM "userNameLogs" WHERE "userID" = ? ORDER BY "updatedAt" DESC LIMIT 1`, [getHash(userID)]);
return privateDB.prepare("get", `SELECT * FROM "userNameLogs" WHERE "userID" = ? ORDER BY "updatedAt" DESC LIMIT 1`, [getHash(userID)]);
}
function wellFormatUserName(userName: string) {
// eslint-disable-next-line no-control-regex
return userName.replace(/[\u0000-\u001F\u007F-\u009F]/g, '');
return userName.replace(/[\u0000-\u001F\u007F-\u009F]/g, "");
}
async function testUserNameChangelog(userID: string, newUserName: string, oldUserName: string, byAdmin: boolean, done: Done) {
@@ -59,7 +59,7 @@ async function testUserNameChangelog(userID: string, newUserName: string, oldUse
return done();
}
describe('setUsername', () => {
describe("setUsername", () => {
before(async () => {
await addUsername(getHash(user01PrivateUserID), username01, 0);
await addUsername(getHash(user02PrivateUserID), username02, 0);
@@ -70,157 +70,157 @@ describe('setUsername', () => {
await addUsername(getHash(user07PrivateUserID), username07, 1);
});
it('Should be able to set username that has never been set', (done: Done) => {
it("Should be able to set username that has never been set", (done: Done) => {
fetch(`${getbaseURL()}/api/setUsername?userID=${user00PrivateUserID}&username=${username00}`, {
method: 'POST',
method: "POST",
})
.then(async res => {
const usernameInfo = await getUsernameInfo(getHash(user00PrivateUserID));
assert.strictEqual(res.status, 200);
assert.strictEqual(usernameInfo.userName, username00);
assert.notStrictEqual(usernameInfo.locked, 1, "username should not be locked");
done();
})
.catch(() => done(`couldn't call endpoint`));
.then(async res => {
const usernameInfo = await getUsernameInfo(getHash(user00PrivateUserID));
assert.strictEqual(res.status, 200);
assert.strictEqual(usernameInfo.userName, username00);
assert.notStrictEqual(usernameInfo.locked, 1, "username should not be locked");
done();
})
.catch(() => done(`couldn't call endpoint`));
});
it('Should return 200', (done: Done) => {
it("Should return 200", (done: Done) => {
fetch(`${getbaseURL()}/api/setUsername?userID=${user01PrivateUserID}&username=Changed%20Username`, {
method: 'POST',
method: "POST",
})
.then(async res => {
assert.strictEqual(res.status, 200);
testUserNameChangelog(user01PrivateUserID, decodeURIComponent('Changed%20Username'), username01, false, done);
})
.catch(() => done(`couldn't call endpoint`));
.then(async res => {
assert.strictEqual(res.status, 200);
testUserNameChangelog(user01PrivateUserID, decodeURIComponent("Changed%20Username"), username01, false, done);
})
.catch(() => done(`couldn't call endpoint`));
});
it('Should return 400 for missing param "userID"', (done: Done) => {
fetch(`${getbaseURL()}/api/setUsername?username=MyUsername`, {
method: 'POST',
method: "POST",
})
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(() => done(`couldn't call endpoint`));
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(() => done(`couldn't call endpoint`));
});
it('Should return 400 for missing param "username"', (done: Done) => {
fetch(`${getbaseURL()}/api/setUsername?userID=test`, {
method: 'POST',
method: "POST",
})
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(() => done(`couldn't call endpoint`));
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(() => done(`couldn't call endpoint`));
});
it('Should return 400 for "username" longer then 64 characters', (done: Done) => {
const username65 = '0000000000000000000000000000000000000000000000000000000000000000X';
const username65 = "0000000000000000000000000000000000000000000000000000000000000000X";
fetch(`${getbaseURL()}/api/setUsername?userID=test&username=${encodeURIComponent(username65)}`, {
method: 'POST',
method: "POST",
})
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(() => done(`couldn't call endpoint`));
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(() => done(`couldn't call endpoint`));
});
it('Should not change username if it contains "discord"', (done: Done) => {
const newUsername = 'discord.me';
const newUsername = "discord.me";
fetch(`${getbaseURL()}/api/setUsername?userID=${user02PrivateUserID}&username=${encodeURIComponent(newUsername)}`, {
method: 'POST',
method: "POST",
})
.then(async res => {
assert.strictEqual(res.status, 200);
const userNameInfo = await getUsernameInfo(getHash(user02PrivateUserID));
assert.notStrictEqual(userNameInfo.userName, newUsername);
done();
})
.catch(() => done(`couldn't call endpoint`));
.then(async res => {
assert.strictEqual(res.status, 200);
const userNameInfo = await getUsernameInfo(getHash(user02PrivateUserID));
assert.notStrictEqual(userNameInfo.userName, newUsername);
done();
})
.catch(() => done(`couldn't call endpoint`));
});
it('Should be able to change username', (done: Done) => {
const newUsername = 'newUsername';
it("Should be able to change username", (done: Done) => {
const newUsername = "newUsername";
fetch(`${getbaseURL()}/api/setUsername?userID=${user03PrivateUserID}&username=${encodeURIComponent(newUsername)}`, {
method: 'POST',
method: "POST",
})
.then(async () => {
const usernameInfo = await getUsernameInfo(getHash(user03PrivateUserID));
assert.strictEqual(usernameInfo.userName, newUsername, "Username should change");
assert.notStrictEqual(usernameInfo.locked, 1, "Username should not be locked");
testUserNameChangelog(user03PrivateUserID, newUsername, username03, false, done);
})
.catch(() => done(`couldn't call endpoint`));
.then(async () => {
const usernameInfo = await getUsernameInfo(getHash(user03PrivateUserID));
assert.strictEqual(usernameInfo.userName, newUsername, "Username should change");
assert.notStrictEqual(usernameInfo.locked, 1, "Username should not be locked");
testUserNameChangelog(user03PrivateUserID, newUsername, username03, false, done);
})
.catch(() => done(`couldn't call endpoint`));
});
it('Should not be able to change locked username', (done: Done) => {
const newUsername = 'newUsername';
it("Should not be able to change locked username", (done: Done) => {
const newUsername = "newUsername";
fetch(`${getbaseURL()}/api/setUsername?userID=${user04PrivateUserID}&username=${encodeURIComponent(newUsername)}`, {
method: 'POST',
method: "POST",
})
.then(async () => {
const usernameInfo = await getUsernameInfo(getHash(user04PrivateUserID));
assert.notStrictEqual(usernameInfo.userName, newUsername, "Username should not be changed");
assert.strictEqual(usernameInfo.locked, 1, "username should be locked");
done();
})
.catch(() => done(`couldn't call endpoint`));
.then(async () => {
const usernameInfo = await getUsernameInfo(getHash(user04PrivateUserID));
assert.notStrictEqual(usernameInfo.userName, newUsername, "Username should not be changed");
assert.strictEqual(usernameInfo.locked, 1, "username should be locked");
done();
})
.catch(() => done(`couldn't call endpoint`));
});
it('Should filter out unicode control characters', (done: Done) => {
const newUsername = 'This\nUsername+has\tInvalid+Characters';
it("Should filter out unicode control characters", (done: Done) => {
const newUsername = "This\nUsername+has\tInvalid+Characters";
fetch(`${getbaseURL()}/api/setUsername?userID=${user05PrivateUserID}&username=${encodeURIComponent(newUsername)}`, {
method: 'POST',
method: "POST",
})
.then(async () => {
const usernameInfo = await getUsernameInfo(getHash(user05PrivateUserID));
assert.notStrictEqual(usernameInfo.userName, newUsername, "Username should not contain control characters");
testUserNameChangelog(user05PrivateUserID, wellFormatUserName(newUsername), username05, false, done);
})
.catch(() => done(`couldn't call endpoint`));
.then(async () => {
const usernameInfo = await getUsernameInfo(getHash(user05PrivateUserID));
assert.notStrictEqual(usernameInfo.userName, newUsername, "Username should not contain control characters");
testUserNameChangelog(user05PrivateUserID, wellFormatUserName(newUsername), username05, false, done);
})
.catch(() => done(`couldn't call endpoint`));
});
it('Incorrect adminUserID should return 403', (done: Done) => {
const newUsername = 'New Username';
it("Incorrect adminUserID should return 403", (done: Done) => {
const newUsername = "New Username";
fetch(`${getbaseURL()}/api/setUsername?adminUserID=invalidAdminID&userID=${getHash(user06PrivateUserID)}&username=${encodeURIComponent(newUsername)}`, {
method: 'POST',
method: "POST",
})
.then(async res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(() => done(`couldn't call endpoint`));
.then(async res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(() => done(`couldn't call endpoint`));
});
it('Admin should be able to change username', (done: Done) => {
const newUsername = 'New Username';
it("Admin should be able to change username", (done: Done) => {
const newUsername = "New Username";
fetch(`${getbaseURL()}/api/setUsername?adminUserID=${adminPrivateUserID}&userID=${getHash(user06PrivateUserID)}&username=${encodeURIComponent(newUsername)}`, {
method: 'POST',
method: "POST",
})
.then(async () => {
const usernameInfo = await getUsernameInfo(getHash(user06PrivateUserID));
assert.strictEqual(usernameInfo.userName, newUsername, "username should be changed");
assert.strictEqual(usernameInfo.locked, 1, "Username should be locked");
testUserNameChangelog(user06PrivateUserID, newUsername, username06, true, done);
})
.catch(() => done(`couldn't call endpoint`));
.then(async () => {
const usernameInfo = await getUsernameInfo(getHash(user06PrivateUserID));
assert.strictEqual(usernameInfo.userName, newUsername, "username should be changed");
assert.strictEqual(usernameInfo.locked, 1, "Username should be locked");
testUserNameChangelog(user06PrivateUserID, newUsername, username06, true, done);
})
.catch(() => done(`couldn't call endpoint`));
});
it('Admin should be able to change locked username', (done: Done) => {
const newUsername = 'New Username';
it("Admin should be able to change locked username", (done: Done) => {
const newUsername = "New Username";
fetch(`${getbaseURL()}/api/setUsername?adminUserID=${adminPrivateUserID}&userID=${getHash(user07PrivateUserID)}&username=${encodeURIComponent(newUsername)}`, {
method: 'POST',
method: "POST",
})
.then(async () => {
const usernameInfo = await getUsernameInfo(getHash(user06PrivateUserID));
assert.strictEqual(usernameInfo.userName, newUsername, "Username should be changed");
assert.strictEqual(usernameInfo.locked, 1, "Username should be locked");
testUserNameChangelog(user07PrivateUserID, newUsername, username07, true, done);
})
.catch(() => done(`couldn't call endpoint`));
.then(async () => {
const usernameInfo = await getUsernameInfo(getHash(user06PrivateUserID));
assert.strictEqual(usernameInfo.userName, newUsername, "Username should be changed");
assert.strictEqual(usernameInfo.locked, 1, "Username should be locked");
testUserNameChangelog(user07PrivateUserID, newUsername, username07, true, done);
})
.catch(() => done(`couldn't call endpoint`));
});
});

View File

@@ -1,104 +1,109 @@
import fetch from 'node-fetch';
import {db} from '../../src/databases/databases';
import {Done, getbaseURL} from '../utils';
import {getHash} from '../../src/utils/getHash';
import assert from 'assert';
import fetch from "node-fetch";
import {db} from "../../src/databases/databases";
import {Done, getbaseURL} from "../utils";
import {getHash} from "../../src/utils/getHash";
import assert from "assert";
describe('shadowBanUser', () => {
describe("shadowBanUser", () => {
before(async () => {
const insertQuery = `INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "service", "videoDuration", "hidden", "shadowHidden", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
await db.prepare("run", insertQuery, ['testtesttest', 1, 11, 2, 0, 'shadow-1-uuid-0', 'shadowBanned', 0, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash('testtesttest', 1)]);
await db.prepare("run", insertQuery, ['testtesttest2', 1, 11, 2, 0, 'shadow-1-uuid-0-1', 'shadowBanned', 0, 50, 'sponsor', 'PeerTube', 120, 0, 0, getHash('testtesttest2', 1)]);
await db.prepare("run", insertQuery, ['testtesttest', 20, 33, 2, 0, 'shadow-1-uuid-2', 'shadowBanned', 0, 50, 'intro', 'YouTube', 101, 0, 0, getHash('testtesttest', 1)]);
await db.prepare("run", insertQuery, ["testtesttest", 1, 11, 2, 0, "shadow-1-uuid-0", "shadowBanned", 0, 50, "sponsor", "YouTube", 100, 0, 0, getHash("testtesttest", 1)]);
await db.prepare("run", insertQuery, ["testtesttest2", 1, 11, 2, 0, "shadow-1-uuid-0-1", "shadowBanned", 0, 50, "sponsor", "PeerTube", 120, 0, 0, getHash("testtesttest2", 1)]);
await db.prepare("run", insertQuery, ["testtesttest", 20, 33, 2, 0, "shadow-1-uuid-2", "shadowBanned", 0, 50, "intro", "YouTube", 101, 0, 0, getHash("testtesttest", 1)]);
await db.prepare("run", insertQuery, ['testtesttest', 1, 11, 2, 0, 'shadow-2-uuid-0', 'shadowBanned2', 0, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash('testtesttest', 1)]);
await db.prepare("run", insertQuery, ['testtesttest2', 1, 11, 2, 0, 'shadow-2-uuid-0-1', 'shadowBanned2', 0, 50, 'sponsor', 'PeerTube', 120, 0, 0, getHash('testtesttest2', 1)]);
await db.prepare("run", insertQuery, ['testtesttest', 20, 33, 2, 0, 'shadow-2-uuid-2', 'shadowBanned2', 0, 50, 'intro', 'YouTube', 101, 0, 0, getHash('testtesttest', 1)]);
await db.prepare("run", insertQuery, ["testtesttest", 1, 11, 2, 0, "shadow-2-uuid-0", "shadowBanned2", 0, 50, "sponsor", "YouTube", 100, 0, 0, getHash("testtesttest", 1)]);
await db.prepare("run", insertQuery, ["testtesttest2", 1, 11, 2, 0, "shadow-2-uuid-0-1", "shadowBanned2", 0, 50, "sponsor", "PeerTube", 120, 0, 0, getHash("testtesttest2", 1)]);
await db.prepare("run", insertQuery, ["testtesttest", 20, 33, 2, 0, "shadow-2-uuid-2", "shadowBanned2", 0, 50, "intro", "YouTube", 101, 0, 0, getHash("testtesttest", 1)]);
await db.prepare("run", insertQuery, ['testtesttest', 1, 11, 2, 0, 'shadow-3-uuid-0', 'shadowBanned3', 0, 50, 'sponsor', 'YouTube', 100, 0, 1, getHash('testtesttest', 1)]);
await db.prepare("run", insertQuery, ['testtesttest2', 1, 11, 2, 0, 'shadow-3-uuid-0-1', 'shadowBanned3', 0, 50, 'sponsor', 'PeerTube', 120, 0, 1, getHash('testtesttest2', 1)]);
await db.prepare("run", insertQuery, ['testtesttest', 20, 33, 2, 0, 'shadow-3-uuid-2', 'shadowBanned3', 0, 50, 'intro', 'YouTube', 101, 0, 1, getHash('testtesttest', 1)]);
await db.prepare("run", `INSERT INTO "shadowBannedUsers" ("userID") VALUES(?)`, ['shadowBanned3']);
await db.prepare("run", insertQuery, ["testtesttest", 1, 11, 2, 0, "shadow-3-uuid-0", "shadowBanned3", 0, 50, "sponsor", "YouTube", 100, 0, 1, getHash("testtesttest", 1)]);
await db.prepare("run", insertQuery, ["testtesttest2", 1, 11, 2, 0, "shadow-3-uuid-0-1", "shadowBanned3", 0, 50, "sponsor", "PeerTube", 120, 0, 1, getHash("testtesttest2", 1)]);
await db.prepare("run", insertQuery, ["testtesttest", 20, 33, 2, 0, "shadow-3-uuid-2", "shadowBanned3", 0, 50, "intro", "YouTube", 101, 0, 1, getHash("testtesttest", 1)]);
await db.prepare("run", `INSERT INTO "shadowBannedUsers" ("userID") VALUES(?)`, ["shadowBanned3"]);
await db.prepare("run", `INSERT INTO "vipUsers" ("userID") VALUES(?)`, [getHash("shadow-ban-vip")]);
});
it('Should be able to ban user and hide submissions', (done: Done) => {
fetch(getbaseURL() + "/api/shadowBanUser?userID=shadowBanned&adminUserID=shadow-ban-vip", {
method: 'POST'
it("Should be able to ban user and hide submissions", (done: Done) => {
fetch(`${getbaseURL()
}/api/shadowBanUser?userID=shadowBanned&adminUserID=shadow-ban-vip`, {
method: "POST"
})
.then(async res => {
assert.strictEqual(res.status, 200);
const videoRow = await db.prepare('all', `SELECT "shadowHidden" FROM "sponsorTimes" WHERE "userID" = ? AND "shadowHidden" = ?`, ["shadowBanned", 1]);
const shadowRow = await db.prepare('get', `SELECT * FROM "shadowBannedUsers" WHERE "userID" = ?`, ["shadowBanned"]);
assert.ok(shadowRow);
assert.strictEqual(videoRow.length, 3);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
const videoRow = await db.prepare("all", `SELECT "shadowHidden" FROM "sponsorTimes" WHERE "userID" = ? AND "shadowHidden" = ?`, ["shadowBanned", 1]);
const shadowRow = await db.prepare("get", `SELECT * FROM "shadowBannedUsers" WHERE "userID" = ?`, ["shadowBanned"]);
assert.ok(shadowRow);
assert.strictEqual(videoRow.length, 3);
done();
})
.catch(err => done(err));
});
it('Should be able to unban user without unhiding submissions', (done: Done) => {
fetch(getbaseURL() + "/api/shadowBanUser?userID=shadowBanned&adminUserID=shadow-ban-vip&enabled=false&unHideOldSubmissions=false", {
method: 'POST'
it("Should be able to unban user without unhiding submissions", (done: Done) => {
fetch(`${getbaseURL()
}/api/shadowBanUser?userID=shadowBanned&adminUserID=shadow-ban-vip&enabled=false&unHideOldSubmissions=false`, {
method: "POST"
})
.then(async res => {
assert.strictEqual(res.status, 200);
const videoRow = await db.prepare('all', `SELECT "shadowHidden" FROM "sponsorTimes" WHERE "userID" = ? AND "shadowHidden" = ?`, ["shadowBanned", 1]);
const shadowRow = await db.prepare('get', `SELECT * FROM "shadowBannedUsers" WHERE "userID" = ?`, ["shadowBanned"]);
assert.ok(!shadowRow);
assert.strictEqual(videoRow.length, 3);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
const videoRow = await db.prepare("all", `SELECT "shadowHidden" FROM "sponsorTimes" WHERE "userID" = ? AND "shadowHidden" = ?`, ["shadowBanned", 1]);
const shadowRow = await db.prepare("get", `SELECT * FROM "shadowBannedUsers" WHERE "userID" = ?`, ["shadowBanned"]);
assert.ok(!shadowRow);
assert.strictEqual(videoRow.length, 3);
done();
})
.catch(err => done(err));
});
it('Should be able to ban user and hide submissions from only some categories', (done: Done) => {
fetch(getbaseURL() + '/api/shadowBanUser?userID=shadowBanned2&adminUserID=shadow-ban-vip&categories=["sponsor"]', {
method: 'POST'
it("Should be able to ban user and hide submissions from only some categories", (done: Done) => {
fetch(`${getbaseURL()
}/api/shadowBanUser?userID=shadowBanned2&adminUserID=shadow-ban-vip&categories=["sponsor"]`, {
method: "POST"
})
.then(async res => {
assert.strictEqual(res.status, 200);
const videoRow: {category: string, shadowHidden: number}[] = (await db.prepare('all', `SELECT "shadowHidden", "category" FROM "sponsorTimes" WHERE "userID" = ? AND "shadowHidden" = ?`, ["shadowBanned2", 1]));
const shadowRow = await db.prepare('get', `SELECT * FROM "shadowBannedUsers" WHERE "userID" = ?`, ["shadowBanned2"]);
assert.ok(shadowRow);
assert.strictEqual(videoRow.length, 2);
assert.strictEqual(videoRow.filter((elem) => elem.category === "sponsor").length, 2);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
const videoRow: {category: string, shadowHidden: number}[] = (await db.prepare("all", `SELECT "shadowHidden", "category" FROM "sponsorTimes" WHERE "userID" = ? AND "shadowHidden" = ?`, ["shadowBanned2", 1]));
const shadowRow = await db.prepare("get", `SELECT * FROM "shadowBannedUsers" WHERE "userID" = ?`, ["shadowBanned2"]);
assert.ok(shadowRow);
assert.strictEqual(videoRow.length, 2);
assert.strictEqual(videoRow.filter((elem) => elem.category === "sponsor").length, 2);
done();
})
.catch(err => done(err));
});
it('Should be able to unban user and unhide submissions', (done: Done) => {
fetch(getbaseURL() + "/api/shadowBanUser?userID=shadowBanned2&adminUserID=shadow-ban-vip&enabled=false", {
method: 'POST'
it("Should be able to unban user and unhide submissions", (done: Done) => {
fetch(`${getbaseURL()
}/api/shadowBanUser?userID=shadowBanned2&adminUserID=shadow-ban-vip&enabled=false`, {
method: "POST"
})
.then(async res => {
assert.strictEqual(res.status, 200);
const videoRow = await db.prepare('all', `SELECT "shadowHidden" FROM "sponsorTimes" WHERE "userID" = ? AND "shadowHidden" = ?`, ["shadowBanned2", 1]);
const shadowRow = await db.prepare('get', `SELECT * FROM "shadowBannedUsers" WHERE "userID" = ?`, ["shadowBanned2"]);
assert.ok(!shadowRow);
assert.strictEqual(videoRow?.length, 0);
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
const videoRow = await db.prepare("all", `SELECT "shadowHidden" FROM "sponsorTimes" WHERE "userID" = ? AND "shadowHidden" = ?`, ["shadowBanned2", 1]);
const shadowRow = await db.prepare("get", `SELECT * FROM "shadowBannedUsers" WHERE "userID" = ?`, ["shadowBanned2"]);
assert.ok(!shadowRow);
assert.strictEqual(videoRow?.length, 0);
done();
})
.catch(err => done(err));
});
it('Should be able to unban user and unhide some submissions', (done: Done) => {
fetch(getbaseURL() + `/api/shadowBanUser?userID=shadowBanned3&adminUserID=shadow-ban-vip&enabled=false&categories=["sponsor"]`, {
method: 'POST'
it("Should be able to unban user and unhide some submissions", (done: Done) => {
fetch(`${getbaseURL()
}/api/shadowBanUser?userID=shadowBanned3&adminUserID=shadow-ban-vip&enabled=false&categories=["sponsor"]`, {
method: "POST"
})
.then(async res => {
assert.strictEqual(res.status, 200);
const videoRow = await db.prepare('all', `SELECT "shadowHidden", "category" FROM "sponsorTimes" WHERE "userID" = ? AND "shadowHidden" = ?`, ["shadowBanned3", 1]);
const shadowRow = await db.prepare('get', `SELECT * FROM "shadowBannedUsers" WHERE "userID" = ?`, ["shadowBanned3"]);
assert.ok(!shadowRow);
assert.strictEqual(videoRow.length, 1);
assert.strictEqual(videoRow[0].category, "intro");
done();
})
.catch(err => done(err));
.then(async res => {
assert.strictEqual(res.status, 200);
const videoRow = await db.prepare("all", `SELECT "shadowHidden", "category" FROM "sponsorTimes" WHERE "userID" = ? AND "shadowHidden" = ?`, ["shadowBanned3", 1]);
const shadowRow = await db.prepare("get", `SELECT * FROM "shadowBannedUsers" WHERE "userID" = ?`, ["shadowBanned3"]);
assert.ok(!shadowRow);
assert.strictEqual(videoRow.length, 1);
assert.strictEqual(videoRow[0].category, "intro");
done();
})
.catch(err => done(err));
});
});

View File

@@ -1,74 +1,77 @@
import fetch from 'node-fetch';
import * as utils from '../utils';
import { getHash } from '../../src/utils/getHash';
import { db } from '../../src/databases/databases';
import assert from 'assert';
import fetch from "node-fetch";
import * as utils from "../utils";
import { getHash } from "../../src/utils/getHash";
import { db } from "../../src/databases/databases";
import assert from "assert";
describe('unBan', () => {
before(async () => {
const insertShadowBannedUserQuery = 'INSERT INTO "shadowBannedUsers" VALUES(?)';
await db.prepare("run", insertShadowBannedUserQuery, ['testMan-unBan']);
await db.prepare("run", insertShadowBannedUserQuery, ['testWoman-unBan']);
await db.prepare("run", insertShadowBannedUserQuery, ['testEntity-unBan']);
describe("unBan", () => {
before(async () => {
const insertShadowBannedUserQuery = 'INSERT INTO "shadowBannedUsers" VALUES(?)';
await db.prepare("run", insertShadowBannedUserQuery, ["testMan-unBan"]);
await db.prepare("run", insertShadowBannedUserQuery, ["testWoman-unBan"]);
await db.prepare("run", insertShadowBannedUserQuery, ["testEntity-unBan"]);
const insertVipUserQuery = 'INSERT INTO "vipUsers" ("userID") VALUES (?)';
await db.prepare("run", insertVipUserQuery, [getHash("VIPUser-unBan")]);
const insertVipUserQuery = 'INSERT INTO "vipUsers" ("userID") VALUES (?)';
await db.prepare("run", insertVipUserQuery, [getHash("VIPUser-unBan")]);
const insertLockCategoryQuery = 'INSERT INTO "lockCategories" ("userID", "videoID", "category") VALUES(?, ?, ?)';
await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-unBan"), 'unBan-videoID-1', 'sponsor']);
const insertLockCategoryQuery = 'INSERT INTO "lockCategories" ("userID", "videoID", "category") VALUES(?, ?, ?)';
await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-unBan"), "unBan-videoID-1", "sponsor"]);
const insertSponsorTimeQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "shadowHidden", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
await db.prepare("run", insertSponsorTimeQuery, ['unBan-videoID-0', 1, 11, 2, 'unBan-uuid-0', 'testMan-unBan', 0, 50, 'sponsor', 1, getHash('unBan-videoID-0', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['unBan-videoID-1', 1, 11, 2, 'unBan-uuid-1', 'testWoman-unBan', 0, 50, 'sponsor', 1, getHash('unBan-videoID-1', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['unBan-videoID-1', 1, 11, 2, 'unBan-uuid-2', 'testEntity-unBan', 0, 60, 'sponsor', 1, getHash('unBan-videoID-1', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['unBan-videoID-2', 1, 11, 2, 'unBan-uuid-3', 'testEntity-unBan', 0, 60, 'sponsor', 1, getHash('unBan-videoID-2', 1)]);
});
const insertSponsorTimeQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "shadowHidden", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
await db.prepare("run", insertSponsorTimeQuery, ["unBan-videoID-0", 1, 11, 2, "unBan-uuid-0", "testMan-unBan", 0, 50, "sponsor", 1, getHash("unBan-videoID-0", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["unBan-videoID-1", 1, 11, 2, "unBan-uuid-1", "testWoman-unBan", 0, 50, "sponsor", 1, getHash("unBan-videoID-1", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["unBan-videoID-1", 1, 11, 2, "unBan-uuid-2", "testEntity-unBan", 0, 60, "sponsor", 1, getHash("unBan-videoID-1", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["unBan-videoID-2", 1, 11, 2, "unBan-uuid-3", "testEntity-unBan", 0, 60, "sponsor", 1, getHash("unBan-videoID-2", 1)]);
});
it('Should be able to unban a user and re-enable shadow banned segments', (done) => {
fetch(utils.getbaseURL() + "/api/shadowBanUser?userID=testMan-unBan&adminUserID=VIPUser-unBan&enabled=false", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
})
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare('all', 'SELECT * FROM "sponsorTimes" WHERE "videoID" = ? AND "userID" = ? AND "shadowHidden" = ?', ['unBan-videoID-0', 'testMan-unBan', 1]);
assert.strictEqual(result.length, 0);
done();
})
.catch(err => done(err));
});
it("Should be able to unban a user and re-enable shadow banned segments", (done) => {
fetch(`${utils.getbaseURL()
}/api/shadowBanUser?userID=testMan-unBan&adminUserID=VIPUser-unBan&enabled=false`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare("all", 'SELECT * FROM "sponsorTimes" WHERE "videoID" = ? AND "userID" = ? AND "shadowHidden" = ?', ["unBan-videoID-0", "testMan-unBan", 1]);
assert.strictEqual(result.length, 0);
done();
})
.catch(err => done(err));
});
it('Should be able to unban a user and re-enable shadow banned segments without lockCategories entrys', (done) => {
fetch(utils.getbaseURL() + "/api/shadowBanUser?userID=testWoman-unBan&adminUserID=VIPUser-unBan&enabled=false", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
})
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare('all', 'SELECT * FROM "sponsorTimes" WHERE "videoID" = ? AND "userID" = ? AND "shadowHidden" = ?', ['unBan-videoID-1', 'testWoman-unBan', 1]);
assert.strictEqual(result.length, 1);
done();
})
.catch(err => done(err));
});
it("Should be able to unban a user and re-enable shadow banned segments without lockCategories entrys", (done) => {
fetch(`${utils.getbaseURL()
}/api/shadowBanUser?userID=testWoman-unBan&adminUserID=VIPUser-unBan&enabled=false`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare("all", 'SELECT * FROM "sponsorTimes" WHERE "videoID" = ? AND "userID" = ? AND "shadowHidden" = ?', ["unBan-videoID-1", "testWoman-unBan", 1]);
assert.strictEqual(result.length, 1);
done();
})
.catch(err => done(err));
});
it('Should be able to unban a user and re-enable shadow banned segments with a mix of lockCategories entrys', (done) => {
fetch(utils.getbaseURL() + "/api/shadowBanUser?userID=testEntity-unBan&adminUserID=VIPUser-unBan&enabled=false", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
})
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare('all', 'SELECT * FROM "sponsorTimes" WHERE "userID" = ? AND "shadowHidden" = ?', ['testEntity-unBan', 1]);
assert.strictEqual(result.length, 1);
done();
})
.catch(err => done(err));
});
it("Should be able to unban a user and re-enable shadow banned segments with a mix of lockCategories entrys", (done) => {
fetch(`${utils.getbaseURL()
}/api/shadowBanUser?userID=testEntity-unBan&adminUserID=VIPUser-unBan&enabled=false`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
})
.then(async res => {
assert.strictEqual(res.status, 200);
const result = await db.prepare("all", 'SELECT * FROM "sponsorTimes" WHERE "userID" = ? AND "shadowHidden" = ?', ["testEntity-unBan", 1]);
assert.strictEqual(result.length, 1);
done();
})
.catch(err => done(err));
});
});

View File

@@ -1,18 +1,18 @@
import fetch from 'node-fetch';
import {config} from '../../src/config';
import {db} from '../../src/databases/databases';
import {Done, getbaseURL} from '../utils';
import {getHash} from '../../src/utils/getHash';
import {ImportMock} from 'ts-mock-imports';
import * as YouTubeAPIModule from '../../src/utils/youtubeApi';
import {YouTubeApiMock} from '../youtubeMock';
import assert from 'assert';
import fetch from "node-fetch";
import {config} from "../../src/config";
import {db} from "../../src/databases/databases";
import {Done, getbaseURL} from "../utils";
import {getHash} from "../../src/utils/getHash";
import {ImportMock} from "ts-mock-imports";
import * as YouTubeAPIModule from "../../src/utils/youtubeApi";
import {YouTubeApiMock} from "../youtubeMock";
import assert from "assert";
const mockManager = ImportMock.mockStaticClass(YouTubeAPIModule, 'YouTubeAPI');
const sinonStub = mockManager.mock('listVideos');
const mockManager = ImportMock.mockStaticClass(YouTubeAPIModule, "YouTubeAPI");
const sinonStub = mockManager.mock("listVideos");
sinonStub.callsFake(YouTubeApiMock.listVideos);
describe('voteOnSponsorTime', () => {
describe("voteOnSponsorTime", () => {
before(async () => {
const now = Date.now();
const warnVip01Hash = getHash("warn-vip01");
@@ -22,29 +22,29 @@ describe('voteOnSponsorTime', () => {
const warningExpireTime = MILLISECONDS_IN_HOUR * config.hoursAfterWarningExpires;
const insertSponsorTimeQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", "views", "category", "shadowHidden", "hidden", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
await db.prepare("run", insertSponsorTimeQuery, ['vote-testtesttest', 1, 11, 2, 'vote-uuid-0', 'testman', 0, 50, 'sponsor', 0, 0, getHash('vote-testtesttest', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['vote-testtesttest2', 1, 11, 2, 'vote-uuid-1', 'testman', 0, 50, 'sponsor', 0, 0, getHash('vote-testtesttest2', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['vote-testtesttest2', 1, 11, 10, 'vote-uuid-1.5', 'testman', 0, 50, 'outro', 0, 0, getHash('vote-testtesttest2', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['vote-testtesttest2', 1, 11, 10, 'vote-uuid-1.6', 'testman', 0, 50, 'interaction', 0, 0, getHash('vote-testtesttest2', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['vote-testtesttest3', 20, 33, 10, 'vote-uuid-2', 'testman', 0, 50, 'intro', 0, 0, getHash('vote-testtesttest3', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['vote-testtesttest,test', 1, 11, 100, 'vote-uuid-3', 'testman', 0, 50, 'sponsor', 0, 0, getHash('vote-testtesttest,test', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['vote-test3', 1, 11, 2, 'vote-uuid-4', 'testman', 0, 50, 'sponsor', 0, 0, getHash('vote-test3', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['vote-test3', 7, 22, -3, 'vote-uuid-5', 'testman', 0, 50, 'intro', 0, 0, getHash('vote-test3', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['vote-test3', 7, 22, -3, 'vote-uuid-5_1', 'testman', 0, 50, 'intro', 0, 0, getHash('vote-test3', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['vote-multiple', 1, 11, 2, 'vote-uuid-6', 'testman', 0, 50, 'intro', 0, 0, getHash('vote-multiple', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['vote-multiple', 20, 33, 2, 'vote-uuid-7', 'testman', 0, 50, 'intro', 0, 0, getHash('vote-multiple', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['voter-submitter', 1, 11, 2, 'vote-uuid-8', getHash("randomID"), 0, 50, 'sponsor', 0, 0, getHash('voter-submitter', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['voter-submitter2', 1, 11, 2, 'vote-uuid-9', getHash("randomID2"), 0, 50, 'sponsor', 0, 0, getHash('voter-submitter2', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['voter-submitter2', 1, 11, 2, 'vote-uuid-10', getHash("randomID3"), 0, 50, 'sponsor', 0, 0, getHash('voter-submitter2', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['voter-submitter2', 1, 11, 2, 'vote-uuid-11', getHash("randomID4"), 0, 50, 'sponsor', 0, 0, getHash('voter-submitter2', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['own-submission-video', 1, 11, 500, 'own-submission-uuid', getHash('own-submission-id'), 0, 50, 'sponsor', 0, 0, getHash('own-submission-video', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['not-own-submission-video', 1, 11, 500, 'not-own-submission-uuid', getHash('somebody-else-id'), 0, 50, 'sponsor', 0, 0, getHash('not-own-submission-video', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['incorrect-category', 1, 11, 500, 'incorrect-category', getHash('somebody-else-id'), 0, 50, 'sponsor', 0, 0, getHash('incorrect-category', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['incorrect-category-change', 1, 11, 500, 'incorrect-category-change', getHash('somebody-else-id'), 0, 50, 'sponsor', 0, 0, getHash('incorrect-category-change', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['vote-testtesttest', 1, 11, 2, 'warnvote-uuid-0', 'testman', 0, 50, 'sponsor', 0, 0, getHash('vote-testtesttest', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['no-sponsor-segments-video', 1, 11, 2, 'no-sponsor-segments-uuid-0', 'no-sponsor-segments', 0, 50, 'sponsor', 0, 0, getHash('no-sponsor-segments-video', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['no-sponsor-segments-video', 1, 11, 2, 'no-sponsor-segments-uuid-1', 'no-sponsor-segments', 0, 50, 'intro', 0, 0, getHash('no-sponsor-segments-video', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ['segment-locking-video', 1, 11, 2, 'segment-locking-uuid-1', 'segment-locking-user', 0, 50, 'intro', 0, 0, getHash('segment-locking-video', 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["vote-testtesttest", 1, 11, 2, "vote-uuid-0", "testman", 0, 50, "sponsor", 0, 0, getHash("vote-testtesttest", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["vote-testtesttest2", 1, 11, 2, "vote-uuid-1", "testman", 0, 50, "sponsor", 0, 0, getHash("vote-testtesttest2", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["vote-testtesttest2", 1, 11, 10, "vote-uuid-1.5", "testman", 0, 50, "outro", 0, 0, getHash("vote-testtesttest2", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["vote-testtesttest2", 1, 11, 10, "vote-uuid-1.6", "testman", 0, 50, "interaction", 0, 0, getHash("vote-testtesttest2", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["vote-testtesttest3", 20, 33, 10, "vote-uuid-2", "testman", 0, 50, "intro", 0, 0, getHash("vote-testtesttest3", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["vote-testtesttest,test", 1, 11, 100, "vote-uuid-3", "testman", 0, 50, "sponsor", 0, 0, getHash("vote-testtesttest,test", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["vote-test3", 1, 11, 2, "vote-uuid-4", "testman", 0, 50, "sponsor", 0, 0, getHash("vote-test3", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["vote-test3", 7, 22, -3, "vote-uuid-5", "testman", 0, 50, "intro", 0, 0, getHash("vote-test3", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["vote-test3", 7, 22, -3, "vote-uuid-5_1", "testman", 0, 50, "intro", 0, 0, getHash("vote-test3", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["vote-multiple", 1, 11, 2, "vote-uuid-6", "testman", 0, 50, "intro", 0, 0, getHash("vote-multiple", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["vote-multiple", 20, 33, 2, "vote-uuid-7", "testman", 0, 50, "intro", 0, 0, getHash("vote-multiple", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["voter-submitter", 1, 11, 2, "vote-uuid-8", getHash("randomID"), 0, 50, "sponsor", 0, 0, getHash("voter-submitter", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["voter-submitter2", 1, 11, 2, "vote-uuid-9", getHash("randomID2"), 0, 50, "sponsor", 0, 0, getHash("voter-submitter2", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["voter-submitter2", 1, 11, 2, "vote-uuid-10", getHash("randomID3"), 0, 50, "sponsor", 0, 0, getHash("voter-submitter2", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["voter-submitter2", 1, 11, 2, "vote-uuid-11", getHash("randomID4"), 0, 50, "sponsor", 0, 0, getHash("voter-submitter2", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["own-submission-video", 1, 11, 500, "own-submission-uuid", getHash("own-submission-id"), 0, 50, "sponsor", 0, 0, getHash("own-submission-video", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["not-own-submission-video", 1, 11, 500, "not-own-submission-uuid", getHash("somebody-else-id"), 0, 50, "sponsor", 0, 0, getHash("not-own-submission-video", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["incorrect-category", 1, 11, 500, "incorrect-category", getHash("somebody-else-id"), 0, 50, "sponsor", 0, 0, getHash("incorrect-category", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["incorrect-category-change", 1, 11, 500, "incorrect-category-change", getHash("somebody-else-id"), 0, 50, "sponsor", 0, 0, getHash("incorrect-category-change", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["vote-testtesttest", 1, 11, 2, "warnvote-uuid-0", "testman", 0, 50, "sponsor", 0, 0, getHash("vote-testtesttest", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["no-sponsor-segments-video", 1, 11, 2, "no-sponsor-segments-uuid-0", "no-sponsor-segments", 0, 50, "sponsor", 0, 0, getHash("no-sponsor-segments-video", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["no-sponsor-segments-video", 1, 11, 2, "no-sponsor-segments-uuid-1", "no-sponsor-segments", 0, 50, "intro", 0, 0, getHash("no-sponsor-segments-video", 1)]);
await db.prepare("run", insertSponsorTimeQuery, ["segment-locking-video", 1, 11, 2, "segment-locking-uuid-1", "segment-locking-user", 0, 50, "intro", 0, 0, getHash("segment-locking-video", 1)]);
const insertWarningQuery = 'INSERT INTO "warnings" ("userID", "issueTime", "issuerUserID", "enabled") VALUES(?, ?, ?, ?)';
await db.prepare("run", insertWarningQuery, [warnUser01Hash, now, warnVip01Hash, 1]);
@@ -60,198 +60,198 @@ describe('voteOnSponsorTime', () => {
await db.prepare("run", 'INSERT INTO "vipUsers" ("userID") VALUES (?)', [getHash("VIPUser")]);
await db.prepare("run", 'INSERT INTO "shadowBannedUsers" ("userID") VALUES (?)', [getHash("randomID4")]);
await db.prepare("run", 'INSERT INTO "lockCategories" ("videoID", "userID", "category") VALUES (?, ?, ?)', ['no-sponsor-segments-video', 'someUser', 'sponsor']);
await db.prepare("run", 'INSERT INTO "lockCategories" ("videoID", "userID", "category") VALUES (?, ?, ?)', ["no-sponsor-segments-video", "someUser", "sponsor"]);
});
it('Should be able to upvote a segment', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID&UUID=vote-uuid-0&type=1")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-0"]);
assert.strictEqual(row.votes, 3);
done();
})
.catch(err => done(err));
it("Should be able to upvote a segment", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=randomID&UUID=vote-uuid-0&type=1`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-0"]);
assert.strictEqual(row.votes, 3);
done();
})
.catch(err => done(err));
});
it('Should be able to downvote a segment', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-2&type=0")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-2"]);
assert.ok(row.votes < 10);
done();
})
.catch(err => done(err));
it("Should be able to downvote a segment", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-2&type=0`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-2"]);
assert.ok(row.votes < 10);
done();
})
.catch(err => done(err));
});
it('Should not be able to downvote the same segment when voting from a different user on the same IP', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID3&UUID=vote-uuid-2&type=0")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-2"]);
assert.strictEqual(row.votes, 9);
done();
})
.catch(err => done(err));
it("Should not be able to downvote the same segment when voting from a different user on the same IP", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=randomID3&UUID=vote-uuid-2&type=0`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-2"]);
assert.strictEqual(row.votes, 9);
done();
})
.catch(err => done(err));
});
it("Should not be able to downvote a segment if the user is shadow banned", (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID4&UUID=vote-uuid-1.6&type=0")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-1.6"]);
assert.strictEqual(row.votes, 10);
done();
})
.catch(err => done(err));
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=randomID4&UUID=vote-uuid-1.6&type=0`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-1.6"]);
assert.strictEqual(row.votes, 10);
done();
})
.catch(err => done(err));
});
it("Should not be able to upvote a segment if the user hasn't submitted yet", (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=hasNotSubmittedID&UUID=vote-uuid-1&type=1")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-1"]);
assert.strictEqual(row.votes, 2);
done();
})
.catch(err => done(err));
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=hasNotSubmittedID&UUID=vote-uuid-1&type=1`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-1"]);
assert.strictEqual(row.votes, 2);
done();
})
.catch(err => done(err));
});
it("Should not be able to downvote a segment if the user hasn't submitted yet", (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=hasNotSubmittedID&UUID=vote-uuid-1.5&type=0")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-1.5"]);
assert.strictEqual(row.votes, 10);
done();
})
.catch(err => done(err));
});
it('VIP should be able to completely downvote a segment', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=VIPUser&UUID=vote-uuid-3&type=0")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-3"]);
assert.ok(row.votes <= -2);
done();
})
.catch(err => done(err));
});
it('should be able to completely downvote your own segment', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=own-submission-id&UUID=own-submission-uuid&type=0")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["own-submission-uuid"]);
assert.ok(row.votes <= -2);
done();
})
.catch(err => done(err));
});
it('should not be able to completely downvote somebody elses segment', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID2&UUID=not-own-submission-uuid&type=0")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["not-own-submission-uuid"]);
assert.strictEqual(row.votes, 499);
done();
})
.catch(err => done(err));
});
it('Should be able to vote for a category and it should add your vote to the database', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-4&category=intro")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-4"]);
const categoryRows = await db.prepare('all', `SELECT votes, category FROM "categoryVotes" WHERE "UUID" = ?`, ["vote-uuid-4"]);
assert.strictEqual(row.category, "sponsor");
assert.strictEqual(categoryRows.length, 2);
assert.strictEqual(categoryRows[0].votes, 1);
assert.strictEqual(categoryRows[0].category, "intro");
assert.strictEqual(categoryRows[1].votes, 1);
assert.strictEqual(categoryRows[1].category, "sponsor");
done();
})
.catch(err => done(err));
});
it('Should not able to change to an invalid category', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID2&UUID=incorrect-category&category=fakecategory")
.then(async res => {
assert.strictEqual(res.status, 400);
const row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["incorrect-category"]);
assert.strictEqual(row.category, "sponsor");
done();
})
.catch(err => done(err));
});
it('Should not able to change to highlight category', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID2&UUID=incorrect-category&category=highlight")
.then(async res => {
assert.strictEqual(res.status, 400);
const row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["incorrect-category"]);
assert.strictEqual(row.category, "sponsor");
done();
})
.catch(err => done(err));
});
it('Should be able to change your vote for a category and it should add your vote to the database', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-4&category=outro")
.then(async res => {
if (res.status === 200) {
const submissionRow = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-4"]);
const categoryRows = await db.prepare('all', `SELECT votes, category FROM "categoryVotes" WHERE "UUID" = ?`, ["vote-uuid-4"]);
let introVotes = 0;
let outroVotes = 0;
let sponsorVotes = 0;
for (const row of categoryRows) {
if (row?.category === "intro") introVotes += row?.votes;
if (row?.category === "outro") outroVotes += row?.votes;
if (row?.category === "sponsor") sponsorVotes += row?.votes;
}
assert.strictEqual(submissionRow.category, "sponsor");
assert.strictEqual(categoryRows.length, 3);
assert.strictEqual(introVotes, 0);
assert.strictEqual(outroVotes, 1);
assert.strictEqual(sponsorVotes, 1);
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=hasNotSubmittedID&UUID=vote-uuid-1.5&type=0`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-1.5"]);
assert.strictEqual(row.votes, 10);
done();
} else {
done("Status code was " + res.status);
}
})
.catch(err => done(err));
});
it('Should not be able to change your vote to an invalid category', (done: Done) => {
const vote = (inputCat: string, assertCat: string, callback: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID2&UUID=incorrect-category-change&category=" + inputCat)
.then(async () => {
const row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["incorrect-category-change"]);
assert.strictEqual(row.category, assertCat);
callback();
})
.catch(err => done(err));
});
it("VIP should be able to completely downvote a segment", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=VIPUser&UUID=vote-uuid-3&type=0`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-3"]);
assert.ok(row.votes <= -2);
done();
})
.catch(err => done(err));
});
it("should be able to completely downvote your own segment", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=own-submission-id&UUID=own-submission-uuid&type=0`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["own-submission-uuid"]);
assert.ok(row.votes <= -2);
done();
})
.catch(err => done(err));
});
it("should not be able to completely downvote somebody elses segment", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=randomID2&UUID=not-own-submission-uuid&type=0`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["not-own-submission-uuid"]);
assert.strictEqual(row.votes, 499);
done();
})
.catch(err => done(err));
});
it("Should be able to vote for a category and it should add your vote to the database", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-4&category=intro`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-4"]);
const categoryRows = await db.prepare("all", `SELECT votes, category FROM "categoryVotes" WHERE "UUID" = ?`, ["vote-uuid-4"]);
assert.strictEqual(row.category, "sponsor");
assert.strictEqual(categoryRows.length, 2);
assert.strictEqual(categoryRows[0].votes, 1);
assert.strictEqual(categoryRows[0].category, "intro");
assert.strictEqual(categoryRows[1].votes, 1);
assert.strictEqual(categoryRows[1].category, "sponsor");
done();
})
.catch(err => done(err));
});
it("Should not able to change to an invalid category", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=randomID2&UUID=incorrect-category&category=fakecategory`)
.then(async res => {
assert.strictEqual(res.status, 400);
const row = await db.prepare("get", `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["incorrect-category"]);
assert.strictEqual(row.category, "sponsor");
done();
})
.catch(err => done(err));
});
it("Should not able to change to highlight category", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=randomID2&UUID=incorrect-category&category=highlight`)
.then(async res => {
assert.strictEqual(res.status, 400);
const row = await db.prepare("get", `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["incorrect-category"]);
assert.strictEqual(row.category, "sponsor");
done();
})
.catch(err => done(err));
});
it("Should be able to change your vote for a category and it should add your vote to the database", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-4&category=outro`)
.then(async res => {
if (res.status === 200) {
const submissionRow = await db.prepare("get", `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-4"]);
const categoryRows = await db.prepare("all", `SELECT votes, category FROM "categoryVotes" WHERE "UUID" = ?`, ["vote-uuid-4"]);
let introVotes = 0;
let outroVotes = 0;
let sponsorVotes = 0;
for (const row of categoryRows) {
if (row?.category === "intro") introVotes += row?.votes;
if (row?.category === "outro") outroVotes += row?.votes;
if (row?.category === "sponsor") sponsorVotes += row?.votes;
}
assert.strictEqual(submissionRow.category, "sponsor");
assert.strictEqual(categoryRows.length, 3);
assert.strictEqual(introVotes, 0);
assert.strictEqual(outroVotes, 1);
assert.strictEqual(sponsorVotes, 1);
done();
} else {
done(`Status code was ${res.status}`);
}
})
.catch(err => done(err));
});
it("Should not be able to change your vote to an invalid category", (done: Done) => {
const vote = (inputCat: string, assertCat: string, callback: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=randomID2&UUID=incorrect-category-change&category=${inputCat}`)
.then(async () => {
const row = await db.prepare("get", `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["incorrect-category-change"]);
assert.strictEqual(row.category, assertCat);
callback();
})
.catch(err => done(err));
};
vote("sponsor", "sponsor", () => {
vote("fakeCategory", "sponsor", done);
@@ -259,187 +259,187 @@ describe('voteOnSponsorTime', () => {
});
it('VIP should be able to vote for a category and it should immediately change', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=VIPUser&UUID=vote-uuid-5&category=outro")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]);
const row2 = await db.prepare('get', `SELECT votes FROM "categoryVotes" WHERE "UUID" = ? and category = ?`, ["vote-uuid-5", "outro"]);
assert.strictEqual(row.category, "outro");
assert.strictEqual(row2.votes, 500);
done();
})
.catch(err => done(err));
it("VIP should be able to vote for a category and it should immediately change", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=VIPUser&UUID=vote-uuid-5&category=outro`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]);
const row2 = await db.prepare("get", `SELECT votes FROM "categoryVotes" WHERE "UUID" = ? and category = ?`, ["vote-uuid-5", "outro"]);
assert.strictEqual(row.category, "outro");
assert.strictEqual(row2.votes, 500);
done();
})
.catch(err => done(err));
});
it('Submitter should be able to vote for a category and it should immediately change', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=testman&UUID=vote-uuid-5_1&category=outro")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]);
assert.strictEqual(row.category, "outro");
done();
})
.catch(err => done(err));
it("Submitter should be able to vote for a category and it should immediately change", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=testman&UUID=vote-uuid-5_1&category=outro`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]);
assert.strictEqual(row.category, "outro");
done();
})
.catch(err => done(err));
});
it('Should not be able to category-vote on an invalid UUID submission', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID3&UUID=invalid-uuid&category=intro")
.then(async res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
it("Should not be able to category-vote on an invalid UUID submission", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=randomID3&UUID=invalid-uuid&category=intro`)
.then(async res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Non-VIP should not be able to upvote "dead" submission', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-5&type=1")
.then(async res => {
assert.strictEqual(res.status, 403);
const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]);
assert.strictEqual(row.votes, -3);
done();
})
.catch(err => done(err));
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-5&type=1`)
.then(async res => {
assert.strictEqual(res.status, 403);
const row = await db.prepare("get", `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]);
assert.strictEqual(row.votes, -3);
done();
})
.catch(err => done(err));
});
it('Non-VIP should not be able to downvote "dead" submission', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-5&type=0")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]);
assert.strictEqual(row.votes, -3);
done();
})
.catch(err => done(err));
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-5&type=0`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]);
assert.strictEqual(row.votes, -3);
done();
})
.catch(err => done(err));
});
it('VIP should be able to upvote "dead" submission', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=VIPUser&UUID=vote-uuid-5&type=1")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]);
assert.ok(row.votes > -3);
done();
})
.catch(err => done(err));
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=VIPUser&UUID=vote-uuid-5&type=1`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]);
assert.ok(row.votes > -3);
done();
})
.catch(err => done(err));
});
it('Should not be able to upvote a segment (Too many warning)', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=warn-voteuser01&UUID=warnvote-uuid-0&type=1")
.then(async res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
it("Should not be able to upvote a segment (Too many warning)", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=warn-voteuser01&UUID=warnvote-uuid-0&type=1`)
.then(async res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
});
it('Non-VIP should not be able to downvote on a segment with no-segments category', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID&UUID=no-sponsor-segments-uuid-0&type=0")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["no-sponsor-segments-uuid-0"]);
assert.strictEqual(row.votes, 2);
done();
})
.catch(err => done(err));
it("Non-VIP should not be able to downvote on a segment with no-segments category", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=randomID&UUID=no-sponsor-segments-uuid-0&type=0`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["no-sponsor-segments-uuid-0"]);
assert.strictEqual(row.votes, 2);
done();
})
.catch(err => done(err));
});
it('Non-VIP should be able to upvote on a segment with no-segments category', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID&UUID=no-sponsor-segments-uuid-0&type=1")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["no-sponsor-segments-uuid-0"]);
assert.strictEqual(row.votes, 3);
done();
})
.catch(err => done(err));
it("Non-VIP should be able to upvote on a segment with no-segments category", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=randomID&UUID=no-sponsor-segments-uuid-0&type=1`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["no-sponsor-segments-uuid-0"]);
assert.strictEqual(row.votes, 3);
done();
})
.catch(err => done(err));
});
it('Non-VIP should not be able to category vote on a segment with no-segments category', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID&UUID=no-sponsor-segments-uuid-0&category=outro")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["no-sponsor-segments-uuid-0"]);
assert.strictEqual(row.category, "sponsor");
done();
})
.catch(err => done(err));
it("Non-VIP should not be able to category vote on a segment with no-segments category", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=randomID&UUID=no-sponsor-segments-uuid-0&category=outro`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["no-sponsor-segments-uuid-0"]);
assert.strictEqual(row.category, "sponsor");
done();
})
.catch(err => done(err));
});
it('VIP upvote should lock segment', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=VIPUser&UUID=segment-locking-uuid-1&type=1")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "locked" FROM "sponsorTimes" WHERE "UUID" = ?`, ["segment-locking-uuid-1"]);
assert.ok(row.locked);
done();
})
.catch(err => done(err));
it("VIP upvote should lock segment", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=VIPUser&UUID=segment-locking-uuid-1&type=1`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "locked" FROM "sponsorTimes" WHERE "UUID" = ?`, ["segment-locking-uuid-1"]);
assert.ok(row.locked);
done();
})
.catch(err => done(err));
});
it('VIP downvote should unlock segment', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=VIPUser&UUID=segment-locking-uuid-1&type=0")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "locked" FROM "sponsorTimes" WHERE "UUID" = ?`, ["segment-locking-uuid-1"]);
assert.ok(!row.locked);
done();
})
.catch(err => done(err));
it("VIP downvote should unlock segment", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=VIPUser&UUID=segment-locking-uuid-1&type=0`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "locked" FROM "sponsorTimes" WHERE "UUID" = ?`, ["segment-locking-uuid-1"]);
assert.ok(!row.locked);
done();
})
.catch(err => done(err));
});
it('VIP upvote should unhide segment', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=VIPUser&UUID=segment-hidden-uuid-1&type=1")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "hidden" FROM "sponsorTimes" WHERE "UUID" = ?`, ["segment-hidden-uuid-1"]);
assert.ok(!row?.hidden);
done();
})
.catch(err => done(err));
it("VIP upvote should unhide segment", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=VIPUser&UUID=segment-hidden-uuid-1&type=1`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "hidden" FROM "sponsorTimes" WHERE "UUID" = ?`, ["segment-hidden-uuid-1"]);
assert.ok(!row?.hidden);
done();
})
.catch(err => done(err));
});
it('Should be able to undo-vote a segment', (done: Done) => {
fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-2&type=20")
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-2"]);
assert.strictEqual(row.votes, 10);
done();
})
.catch(err => done(err));
it("Should be able to undo-vote a segment", (done: Done) => {
fetch(`${getbaseURL()
}/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-2&type=20`)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await db.prepare("get", `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-2"]);
assert.strictEqual(row.votes, 10);
done();
})
.catch(err => done(err));
});
it('Should not be able to vote with type 10', (done: Done) => {
fetch(getbaseURL() + "/api/voteOnSponsorTime?userID=VIPUser&UUID=segment-locking-uuid-1&type=10")
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
it("Should not be able to vote with type 10", (done: Done) => {
fetch(`${getbaseURL() }/api/voteOnSponsorTime?userID=VIPUser&UUID=segment-locking-uuid-1&type=10`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it('Should not be able to vote with type 11', (done: Done) => {
fetch(getbaseURL() + "/api/voteOnSponsorTime?userID=VIPUser&UUID=segment-locking-uuid-1&type=11")
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
it("Should not be able to vote with type 11", (done: Done) => {
fetch(`${getbaseURL() }/api/voteOnSponsorTime?userID=VIPUser&UUID=segment-locking-uuid-1&type=11`)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
});

View File

@@ -1,27 +1,27 @@
import express from 'express';
import {config} from '../src/config';
import { Server } from 'http';
import express from "express";
import {config} from "../src/config";
import { Server } from "http";
const app = express();
app.post('/ReportChannelWebhook', (req, res) => {
app.post("/ReportChannelWebhook", (req, res) => {
res.sendStatus(200);
});
app.post('/FirstTimeSubmissionsWebhook', (req, res) => {
app.post("/FirstTimeSubmissionsWebhook", (req, res) => {
res.sendStatus(200);
});
app.post('/CompletelyIncorrectReportWebhook', (req, res) => {
app.post("/CompletelyIncorrectReportWebhook", (req, res) => {
res.sendStatus(200);
});
// Testing NeuralBlock
app.post('/NeuralBlockRejectWebhook', (req, res) => {
app.post("/NeuralBlockRejectWebhook", (req, res) => {
res.sendStatus(200);
});
app.get('/NeuralBlock/api/checkSponsorSegments', (req, res) => {
app.get("/NeuralBlock/api/checkSponsorSegments", (req, res) => {
if (req.query.vid === "LevkAjUE6d4") {
res.json({
probabilities: [0.69],
@@ -32,7 +32,7 @@ app.get('/NeuralBlock/api/checkSponsorSegments', (req, res) => {
});
//getSponsorSegments is no longer being used for automod
app.get('/NeuralBlock/api/getSponsorSegments', (req, res) => {
app.get("/NeuralBlock/api/getSponsorSegments", (req, res) => {
if (req.query.vid === "LevkAjUE6d4") {
res.json({
sponsorSegments: [[0.47, 7.549], [264.023, 317.293]],
@@ -43,7 +43,7 @@ app.get('/NeuralBlock/api/getSponsorSegments', (req, res) => {
});
// Testing webhooks
app.post('/CustomWebhook', (req, res) => {
app.post("/CustomWebhook", (req, res) => {
res.sendStatus(200);
});

View File

@@ -1,17 +1,17 @@
import Mocha from 'mocha';
import fs from 'fs';
import path from 'path';
import {config} from '../src/config';
import {createServer} from '../src/app';
import {createMockServer} from './mocks';
import {Logger} from '../src/utils/logger';
import {initDb} from '../src/databases/databases';
import {ImportMock} from 'ts-mock-imports';
import * as rateLimitMiddlewareModule from '../src/middleware/requestRateLimit';
import rateLimit from 'express-rate-limit';
import Mocha from "mocha";
import fs from "fs";
import path from "path";
import {config} from "../src/config";
import {createServer} from "../src/app";
import {createMockServer} from "./mocks";
import {Logger} from "../src/utils/logger";
import {initDb} from "../src/databases/databases";
import {ImportMock} from "ts-mock-imports";
import * as rateLimitMiddlewareModule from "../src/middleware/requestRateLimit";
import rateLimit from "express-rate-limit";
async function init() {
ImportMock.mockFunction(rateLimitMiddlewareModule, 'rateLimitMiddleware', rateLimit({
ImportMock.mockFunction(rateLimitMiddlewareModule, "rateLimitMiddleware", rateLimit({
skip: () => true
}));
@@ -21,21 +21,21 @@ async function init() {
await initDb();
const dbMode = config.mysql ? 'mysql'
: config.postgres ? 'postgres'
: 'sqlite';
Logger.info('Database Mode: ' + dbMode);
const dbMode = config.mysql ? "mysql"
: config.postgres ? "postgres"
: "sqlite";
Logger.info(`Database Mode: ${dbMode}`);
// Instantiate a Mocha instance.
const mocha = new Mocha();
const testDir = './test/cases';
const testDir = "./test/cases";
// Add each .ts file to the mocha instance
fs.readdirSync(testDir)
.filter((file) =>
.filter((file) =>
// Only keep the .ts files
file.substr(-3) === '.ts'
file.substr(-3) === ".ts"
)
.forEach(function(file) {
mocha.addFile(

View File

@@ -1,7 +1,7 @@
import {config} from '../src/config';
import {config} from "../src/config";
export function getbaseURL(): string {
return "http://localhost:" + config.port;
return `http://localhost:${config.port}`;
}
/**

View File

@@ -20,11 +20,11 @@ export class YouTubeApiMock {
lengthSeconds: 0,
videoThumbnails: [
{
quality: "maxres",
url: "https://sponsor.ajay.app/LogoSponsorBlockSimple256px.png",
second__originalUrl:"https://sponsor.ajay.app/LogoSponsorBlockSimple256px.png",
width: 1280,
height: 720
quality: "maxres",
url: "https://sponsor.ajay.app/LogoSponsorBlockSimple256px.png",
second__originalUrl:"https://sponsor.ajay.app/LogoSponsorBlockSimple256px.png",
width: 1280,
height: 720
},
]
} as APIVideoData
@@ -37,11 +37,11 @@ export class YouTubeApiMock {
lengthSeconds: 4980,
videoThumbnails: [
{
quality: "maxres",
url: "https://sponsor.ajay.app/LogoSponsorBlockSimple256px.png",
second__originalUrl:"https://sponsor.ajay.app/LogoSponsorBlockSimple256px.png",
width: 1280,
height: 720
quality: "maxres",
url: "https://sponsor.ajay.app/LogoSponsorBlockSimple256px.png",
second__originalUrl:"https://sponsor.ajay.app/LogoSponsorBlockSimple256px.png",
width: 1280,
height: 720
},
]
} as APIVideoData