mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2024-11-10 01:02:30 +01:00
Add vote/submission for titles and thumbnails
This commit is contained in:
parent
2a7083b9ef
commit
07c683e8f0
8 changed files with 543 additions and 14 deletions
|
@ -26,26 +26,18 @@ CREATE TABLE IF NOT EXISTS "config" (
|
||||||
"value" TEXT NOT NULL
|
"value" TEXT NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS "titles" (
|
|
||||||
"UUID" TEXT NOT NULL PRIMARY KEY,
|
|
||||||
"hashedIP" TEXT NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS "titleVotes" (
|
CREATE TABLE IF NOT EXISTS "titleVotes" (
|
||||||
"id" SERIAL PRIMARY KEY,
|
"id" SERIAL PRIMARY KEY,
|
||||||
|
"videoID" TEXT NOT NULL,
|
||||||
"UUID" TEXT NOT NULL,
|
"UUID" TEXT NOT NULL,
|
||||||
"userID" TEXT NOT NULL,
|
"userID" TEXT NOT NULL,
|
||||||
"hashedIP" TEXT NOT NULL,
|
"hashedIP" TEXT NOT NULL,
|
||||||
"type" INTEGER NOT NULL
|
"type" INTEGER NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS "thumbnails" (
|
|
||||||
"UUID" TEXT NOT NULL PRIMARY KEY,
|
|
||||||
"hashedIP" TEXT NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS "thumbnailVotes" (
|
CREATE TABLE IF NOT EXISTS "thumbnailVotes" (
|
||||||
"id" SERIAL PRIMARY KEY,
|
"id" SERIAL PRIMARY KEY,
|
||||||
|
"videoID" TEXT NOT NULL,
|
||||||
"UUID" TEXT NOT NULL,
|
"UUID" TEXT NOT NULL,
|
||||||
"userID" TEXT NOT NULL,
|
"userID" TEXT NOT NULL,
|
||||||
"hashedIP" TEXT NOT NULL,
|
"hashedIP" TEXT NOT NULL,
|
||||||
|
|
|
@ -68,7 +68,7 @@ CREATE TABLE IF NOT EXISTS "thumbnails" (
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS "thumbnailTimestamps" (
|
CREATE TABLE IF NOT EXISTS "thumbnailTimestamps" (
|
||||||
"UUID" TEXT NOT NULL PRIMARY KEY,
|
"UUID" TEXT NOT NULL PRIMARY KEY,
|
||||||
"timestamp" INTEGER NOT NULL default 0
|
"timestamp" INTEGER NOT NULL default 0,
|
||||||
FOREIGN KEY("UUID") REFERENCES "thumbnails"("UUID")
|
FOREIGN KEY("UUID") REFERENCES "thumbnails"("UUID")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,8 @@ import { getVideoLabelsByHash } from "./routes/getVideoLabelByHash";
|
||||||
import { addFeature } from "./routes/addFeature";
|
import { addFeature } from "./routes/addFeature";
|
||||||
import { generateTokenRequest } from "./routes/generateToken";
|
import { generateTokenRequest } from "./routes/generateToken";
|
||||||
import { verifyTokenRequest } from "./routes/verifyToken";
|
import { verifyTokenRequest } from "./routes/verifyToken";
|
||||||
|
import { getBranding, getBrandingByHashEndpoint } from "./routes/getBranding";
|
||||||
|
import { postBranding } from "./routes/postBranding";
|
||||||
|
|
||||||
export function createServer(callback: () => void): Server {
|
export function createServer(callback: () => void): Server {
|
||||||
// Create a service (the app object is just a callback).
|
// Create a service (the app object is just a callback).
|
||||||
|
@ -206,6 +208,10 @@ function setupRoutes(router: Router) {
|
||||||
router.get("/api/videoLabels", getVideoLabels);
|
router.get("/api/videoLabels", getVideoLabels);
|
||||||
router.get("/api/videoLabels/:prefix", getVideoLabelsByHash);
|
router.get("/api/videoLabels/:prefix", getVideoLabelsByHash);
|
||||||
|
|
||||||
|
router.get("/api/branding", getBranding);
|
||||||
|
router.get("/api/branding/:prefix", getBrandingByHashEndpoint);
|
||||||
|
router.post("/api/branding", postBranding);
|
||||||
|
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
if (config.postgres?.enabled) {
|
if (config.postgres?.enabled) {
|
||||||
router.get("/database", (req, res) => dumpDatabase(req, res, true));
|
router.get("/database", (req, res) => dumpDatabase(req, res, true));
|
||||||
|
|
|
@ -14,6 +14,21 @@ export class Sqlite implements IDatabase {
|
||||||
|
|
||||||
// eslint-disable-next-line require-await
|
// eslint-disable-next-line require-await
|
||||||
async prepare(type: QueryType, query: string, params: any[] = []): Promise<any[]> {
|
async prepare(type: QueryType, query: string, params: any[] = []): Promise<any[]> {
|
||||||
|
if (query.includes(";")) {
|
||||||
|
const promises = [];
|
||||||
|
let paramsCount = 0;
|
||||||
|
for (const q of query.split(";")) {
|
||||||
|
if (q.trim() !== "") {
|
||||||
|
const currentParamCount = q.match(/\?/g)?.length ?? 0;
|
||||||
|
promises.push(this.prepare(type, q, params.slice(paramsCount, paramsCount + currentParamCount)));
|
||||||
|
|
||||||
|
paramsCount += currentParamCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (await Promise.all(promises)).flat();
|
||||||
|
}
|
||||||
|
|
||||||
// Logger.debug(`prepare (sqlite): type: ${type}, query: ${query}, params: ${params}`);
|
// Logger.debug(`prepare (sqlite): type: ${type}, query: ${query}, params: ${params}`);
|
||||||
const preparedQuery = this.db.prepare(Sqlite.processQuery(query));
|
const preparedQuery = this.db.prepare(Sqlite.processQuery(query));
|
||||||
|
|
||||||
|
|
|
@ -186,7 +186,7 @@ export async function getBranding(req: Request, res: Response) {
|
||||||
return res.status(status).json(result);
|
return res.status(status).json(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getBrandingByHash(req: Request, res: Response) {
|
export async function getBrandingByHashEndpoint(req: Request, res: Response) {
|
||||||
let hashPrefix = req.params.prefix as VideoIDHash;
|
let hashPrefix = req.params.prefix as VideoIDHash;
|
||||||
if (!req.params.prefix || !hashPrefixTester(req.params.prefix)) {
|
if (!req.params.prefix || !hashPrefixTester(req.params.prefix)) {
|
||||||
return res.status(400).send("Hash prefix does not match format requirements."); // Exit early on faulty prefix
|
return res.status(400).send("Hash prefix does not match format requirements."); // Exit early on faulty prefix
|
||||||
|
|
129
src/routes/postBranding.ts
Normal file
129
src/routes/postBranding.ts
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
import { Request, Response } from "express";
|
||||||
|
import { config } from "../config";
|
||||||
|
import { db, privateDB } from "../databases/databases";
|
||||||
|
|
||||||
|
import { BrandingSubmission, BrandingUUID, TimeThumbnailSubmission } from "../types/branding.model";
|
||||||
|
import { HashedIP, IPAddress, VideoID } from "../types/segments.model";
|
||||||
|
import { HashedUserID } from "../types/user.model";
|
||||||
|
import { getHashCache } from "../utils/getHashCache";
|
||||||
|
import { getIP } from "../utils/getIP";
|
||||||
|
import { getService } from "../utils/getService";
|
||||||
|
import { isUserVIP } from "../utils/isUserVIP";
|
||||||
|
import { Logger } from "../utils/logger";
|
||||||
|
|
||||||
|
enum BrandingType {
|
||||||
|
Title,
|
||||||
|
Thumbnail
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExistingVote {
|
||||||
|
UUID: BrandingUUID;
|
||||||
|
type: number;
|
||||||
|
id: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function postBranding(req: Request, res: Response) {
|
||||||
|
const { videoID, userID, title, thumbnail } = req.body as BrandingSubmission;
|
||||||
|
const service = getService(req.body.service);
|
||||||
|
|
||||||
|
if (!videoID || !userID || userID.length < 30 || !service
|
||||||
|
|| ((!title || !title.title)
|
||||||
|
&& (!thumbnail || thumbnail.original == null
|
||||||
|
|| (!thumbnail.original && !(thumbnail as TimeThumbnailSubmission).timestamp)))) {
|
||||||
|
res.status(400).send("Bad Request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const hashedUserID = await getHashCache(userID);
|
||||||
|
const isVip = await isUserVIP(hashedUserID);
|
||||||
|
const hashedVideoID = await getHashCache(videoID, 1);
|
||||||
|
const hashedIP = await getHashCache(getIP(req) + config.globalSalt as IPAddress);
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
const voteType = 1;
|
||||||
|
|
||||||
|
await Promise.all([(async () => {
|
||||||
|
if (title) {
|
||||||
|
const existingUUID = (await db.prepare("get", `SELECT "UUID" from "titles" where "videoID" = ? AND "title" = ?`, [videoID, title.title]))?.UUID;
|
||||||
|
const UUID = existingUUID || crypto.randomUUID();
|
||||||
|
|
||||||
|
const existingVote = await handleExistingVotes(BrandingType.Title, videoID, hashedUserID, UUID, hashedIP, voteType);
|
||||||
|
if (existingUUID) {
|
||||||
|
await updateVoteTotals(BrandingType.Title, existingVote, UUID, isVip);
|
||||||
|
} else {
|
||||||
|
await db.prepare("run", `INSERT INTO "titles" ("videoID", "title", "original", "userID", "service", "hashedVideoID", "timeSubmitted", "UUID") VALUES (?, ?, ?, ?, ?, ?, ?, ?);
|
||||||
|
INSERT INTO "titleVotes" ("UUID", "votes", "locked", "shadowHidden") VALUES (?, 0, ?, 0);`,
|
||||||
|
[videoID, title.title, title.original ? 1 : 0, hashedUserID, service, hashedVideoID, now, UUID, UUID, isVip ? 1 : 0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})(), (async () => {
|
||||||
|
if (thumbnail) {
|
||||||
|
const existingUUID = thumbnail.original
|
||||||
|
? (await db.prepare("get", `SELECT "UUID" from "thumbnails" where "videoID" = ? AND "original" = 1`, [videoID]))?.UUID
|
||||||
|
: (await db.prepare("get", `SELECT "thumbnails"."UUID" from "thumbnailTimestamps" JOIN "thumbnails" ON "thumbnails"."UUID" = "thumbnailTimestamps"."UUID"
|
||||||
|
WHERE "thumbnailTimestamps"."timestamp" = ? AND "thumbnails"."videoID" = ?`, [(thumbnail as TimeThumbnailSubmission).timestamp, videoID]))?.UUID;
|
||||||
|
const UUID = existingUUID || crypto.randomUUID();
|
||||||
|
|
||||||
|
const existingVote = await handleExistingVotes(BrandingType.Thumbnail, videoID, hashedUserID, UUID, hashedIP, voteType);
|
||||||
|
if (existingUUID) {
|
||||||
|
await updateVoteTotals(BrandingType.Thumbnail, existingVote, UUID, isVip);
|
||||||
|
} else {
|
||||||
|
await db.prepare("run", `INSERT INTO "thumbnails" ("videoID", "original", "userID", "service", "hashedVideoID", "timeSubmitted", "UUID") VALUES (?, ?, ?, ?, ?, ?, ?);
|
||||||
|
INSERT INTO "thumbnailVotes" ("UUID", "votes", "locked", "shadowHidden") VALUES (?, 0, ?, 0);
|
||||||
|
${thumbnail.original ? "" : `INSERT INTO "thumbnailTimestamps" ("UUID", "timestamp") VALUES (?, ?)`}`,
|
||||||
|
[videoID, thumbnail.original ? 1 : 0, hashedUserID, service, hashedVideoID, now, UUID, UUID,
|
||||||
|
isVip ? 1 : 0, thumbnail.original ? null : UUID, thumbnail.original ? null : (thumbnail as TimeThumbnailSubmission).timestamp]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
})()]);
|
||||||
|
|
||||||
|
res.status(200).send("OK");
|
||||||
|
} catch (e) {
|
||||||
|
Logger.error(e as string);
|
||||||
|
res.status(500).send("Internal Server Error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds an existing vote, if found, and it's for a different submission, it undoes it, and points to the new submission.
|
||||||
|
* If no existing vote, it adds one.
|
||||||
|
*/
|
||||||
|
async function handleExistingVotes(type: BrandingType, videoID: VideoID,
|
||||||
|
hashedUserID: HashedUserID, UUID: BrandingUUID, hashedIP: HashedIP, voteType: number): Promise<ExistingVote> {
|
||||||
|
const table = type === BrandingType.Title ? `"titleVotes"` : `"thumbnailVotes"`;
|
||||||
|
|
||||||
|
const existingVote = await privateDB.prepare("get", `SELECT "id", "UUID", "type" from ${table} where "videoID" = ? AND "userID" = ?`, [videoID, hashedUserID]);
|
||||||
|
if (existingVote && existingVote.UUID !== UUID) {
|
||||||
|
if (existingVote.type === 1) {
|
||||||
|
await db.prepare("run", `UPDATE ${table} SET "votes" = "votes" - 1 WHERE "UUID" = ?`, [existingVote.UUID]);
|
||||||
|
}
|
||||||
|
|
||||||
|
await privateDB.prepare("run", `UPDATE ${table} SET "type" = ?, "UUID" = ? WHERE "id" = ?`, [voteType, UUID, existingVote.id]);
|
||||||
|
} else if (!existingVote) {
|
||||||
|
await privateDB.prepare("run", `INSERT INTO ${table} ("videoID", "UUID", "userID", "hashedIP", "type") VALUES (?, ?, ?, ?, ?)`,
|
||||||
|
[videoID, UUID, hashedUserID, hashedIP, voteType]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return existingVote;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only called if an existing vote exists.
|
||||||
|
* Will update public vote totals and locked status.
|
||||||
|
*/
|
||||||
|
async function updateVoteTotals(type: BrandingType, existingVote: ExistingVote, UUID: BrandingUUID, isVip: boolean): Promise<void> {
|
||||||
|
if (!existingVote) return;
|
||||||
|
|
||||||
|
const table = type === BrandingType.Title ? `"titleVotes"` : `"thumbnailVotes"`;
|
||||||
|
|
||||||
|
// Don't upvote if we vote on the same submission
|
||||||
|
if (!existingVote || existingVote.UUID !== UUID) {
|
||||||
|
await db.prepare("run", `UPDATE ${table} SET "votes" = "votes" + 1 WHERE "UUID" = ?`, [UUID]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVip) {
|
||||||
|
await db.prepare("run", `UPDATE ${table} SET "locked" = 1 WHERE "UUID" = ?`, [UUID]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import { VideoID, VideoIDHash } from "./segments.model";
|
import { Service, VideoID, VideoIDHash } from "./segments.model";
|
||||||
|
import { UserID } from "./user.model";
|
||||||
|
|
||||||
export type BrandingUUID = string & { readonly __brandingUUID: unique symbol };
|
export type BrandingUUID = string & { readonly __brandingUUID: unique symbol };
|
||||||
|
|
||||||
|
@ -54,3 +55,27 @@ export interface BrandingHashDBResult {
|
||||||
export interface BrandingHashResult {
|
export interface BrandingHashResult {
|
||||||
branding: BrandingResult;
|
branding: BrandingResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OriginalThumbnailSubmission {
|
||||||
|
original: true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TimeThumbnailSubmission {
|
||||||
|
timestamp: number;
|
||||||
|
original: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ThumbnailSubmission = OriginalThumbnailSubmission | TimeThumbnailSubmission;
|
||||||
|
|
||||||
|
export interface TitleSubmission {
|
||||||
|
title: string;
|
||||||
|
original: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BrandingSubmission {
|
||||||
|
title: TitleSubmission;
|
||||||
|
thumbnail: ThumbnailSubmission;
|
||||||
|
videoID: VideoID;
|
||||||
|
userID: UserID;
|
||||||
|
service: Service;
|
||||||
|
}
|
362
test/cases/postBranding.ts
Normal file
362
test/cases/postBranding.ts
Normal file
|
@ -0,0 +1,362 @@
|
||||||
|
import { db } from "../../src/databases/databases";
|
||||||
|
import { getHash } from "../../src/utils/getHash";
|
||||||
|
import { client } from "../utils/httpClient";
|
||||||
|
import assert from "assert";
|
||||||
|
import { Service } from "../../src/types/segments.model";
|
||||||
|
|
||||||
|
describe("postBranding", () => {
|
||||||
|
|
||||||
|
const vipUser = `VIPPostBrandingUser${".".repeat(16)}`;
|
||||||
|
const userID1 = `PostBrandingUser1${".".repeat(16)}`;
|
||||||
|
const userID2 = `PostBrandingUser2${".".repeat(16)}`;
|
||||||
|
const userID3 = `PostBrandingUser3${".".repeat(16)}`;
|
||||||
|
const userID4 = `PostBrandingUser4${".".repeat(16)}`;
|
||||||
|
const userID5 = `PostBrandingUser4${".".repeat(16)}`;
|
||||||
|
|
||||||
|
const endpoint = "/api/branding";
|
||||||
|
const postBranding = (data: Record<string, any>) => client({
|
||||||
|
method: "POST",
|
||||||
|
url: endpoint,
|
||||||
|
data
|
||||||
|
});
|
||||||
|
|
||||||
|
const queryTitleByVideo = (videoID: string) => db.prepare("get", `SELECT * FROM "titles" WHERE "videoID" = ? ORDER BY "timeSubmitted" DESC`, [videoID]);
|
||||||
|
const queryThumbnailByVideo = (videoID: string) => db.prepare("get", `SELECT * FROM "thumbnails" WHERE "videoID" = ? ORDER BY "timeSubmitted" DESC`, [videoID]);
|
||||||
|
const queryThumbnailTimestampsByUUID = (UUID: string) => db.prepare("get", `SELECT * FROM "thumbnailTimestamps" WHERE "UUID" = ?`, [UUID]);
|
||||||
|
const queryTitleVotesByUUID = (UUID: string) => db.prepare("get", `SELECT * FROM "titleVotes" WHERE "UUID" = ?`, [UUID]);
|
||||||
|
const queryThumbnailVotesByUUID = (UUID: string) => db.prepare("get", `SELECT * FROM "thumbnailVotes" WHERE "UUID" = ?`, [UUID]);
|
||||||
|
|
||||||
|
before(() => {
|
||||||
|
const insertVipUserQuery = 'INSERT INTO "vipUsers" ("userID") VALUES (?)';
|
||||||
|
db.prepare("run", insertVipUserQuery, [getHash(vipUser)]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Submit only title", async () => {
|
||||||
|
const videoID = "postBrand1";
|
||||||
|
const title = {
|
||||||
|
title: "Some title",
|
||||||
|
original: false
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await postBranding({
|
||||||
|
title,
|
||||||
|
userID: userID1,
|
||||||
|
service: Service.YouTube,
|
||||||
|
videoID
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
const dbTitle = await queryTitleByVideo(videoID);
|
||||||
|
const dbVotes = await queryTitleVotesByUUID(dbTitle.UUID);
|
||||||
|
|
||||||
|
assert.strictEqual(dbTitle.title, title.title);
|
||||||
|
assert.strictEqual(dbTitle.original, title.original ? 1 : 0);
|
||||||
|
|
||||||
|
assert.strictEqual(dbVotes.votes, 0);
|
||||||
|
assert.strictEqual(dbVotes.locked, 0);
|
||||||
|
assert.strictEqual(dbVotes.shadowHidden, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Submit only original title", async () => {
|
||||||
|
const videoID = "postBrand2";
|
||||||
|
const title = {
|
||||||
|
title: "Some title",
|
||||||
|
original: true
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await postBranding({
|
||||||
|
title,
|
||||||
|
userID: userID2,
|
||||||
|
service: Service.YouTube,
|
||||||
|
videoID
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
const dbTitle = await queryTitleByVideo(videoID);
|
||||||
|
const dbVotes = await queryTitleVotesByUUID(dbTitle.UUID);
|
||||||
|
|
||||||
|
assert.strictEqual(dbTitle.title, title.title);
|
||||||
|
assert.strictEqual(dbTitle.original, title.original ? 1 : 0);
|
||||||
|
|
||||||
|
assert.strictEqual(dbVotes.votes, 0);
|
||||||
|
assert.strictEqual(dbVotes.locked, 0);
|
||||||
|
assert.strictEqual(dbVotes.shadowHidden, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Submit only original thumbnail", async () => {
|
||||||
|
const videoID = "postBrand3";
|
||||||
|
const thumbnail = {
|
||||||
|
original: true
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await postBranding({
|
||||||
|
thumbnail,
|
||||||
|
userID: userID3,
|
||||||
|
service: Service.YouTube,
|
||||||
|
videoID
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
const dbThumbnail = await queryThumbnailByVideo(videoID);
|
||||||
|
const dbVotes = await queryThumbnailVotesByUUID(dbThumbnail.UUID);
|
||||||
|
|
||||||
|
assert.strictEqual(dbThumbnail.original, thumbnail.original ? 1 : 0);
|
||||||
|
|
||||||
|
assert.strictEqual(dbVotes.votes, 0);
|
||||||
|
assert.strictEqual(dbVotes.locked, 0);
|
||||||
|
assert.strictEqual(dbVotes.shadowHidden, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Submit only custom thumbnail", async () => {
|
||||||
|
const videoID = "postBrand4";
|
||||||
|
const thumbnail = {
|
||||||
|
timestamp: 12.42,
|
||||||
|
original: false
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await postBranding({
|
||||||
|
thumbnail,
|
||||||
|
userID: userID4,
|
||||||
|
service: Service.YouTube,
|
||||||
|
videoID
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
const dbThumbnail = await queryThumbnailByVideo(videoID);
|
||||||
|
const dbThumbnailTimestamps = await queryThumbnailTimestampsByUUID(dbThumbnail.UUID);
|
||||||
|
const dbVotes = await queryThumbnailVotesByUUID(dbThumbnail.UUID);
|
||||||
|
|
||||||
|
assert.strictEqual(dbThumbnailTimestamps.timestamp, thumbnail.timestamp);
|
||||||
|
assert.strictEqual(dbThumbnail.original, thumbnail.original ? 1 : 0);
|
||||||
|
|
||||||
|
assert.strictEqual(dbVotes.votes, 0);
|
||||||
|
assert.strictEqual(dbVotes.locked, 0);
|
||||||
|
assert.strictEqual(dbVotes.shadowHidden, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Submit title and thumbnail", async () => {
|
||||||
|
const videoID = "postBrand5";
|
||||||
|
const title = {
|
||||||
|
title: "Some title",
|
||||||
|
original: false
|
||||||
|
};
|
||||||
|
const thumbnail = {
|
||||||
|
timestamp: 12.42,
|
||||||
|
original: false
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await postBranding({
|
||||||
|
title,
|
||||||
|
thumbnail,
|
||||||
|
userID: userID5,
|
||||||
|
service: Service.YouTube,
|
||||||
|
videoID
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
const dbTitle = await queryTitleByVideo(videoID);
|
||||||
|
const dbTitleVotes = await queryTitleVotesByUUID(dbTitle.UUID);
|
||||||
|
const dbThumbnail = await queryThumbnailByVideo(videoID);
|
||||||
|
const dbThumbnailTimestamps = await queryThumbnailTimestampsByUUID(dbThumbnail.UUID);
|
||||||
|
const dbThumbnailVotes = await queryThumbnailVotesByUUID(dbThumbnail.UUID);
|
||||||
|
|
||||||
|
assert.strictEqual(dbTitle.title, title.title);
|
||||||
|
assert.strictEqual(dbTitle.original, title.original ? 1 : 0);
|
||||||
|
|
||||||
|
assert.strictEqual(dbTitleVotes.votes, 0);
|
||||||
|
assert.strictEqual(dbTitleVotes.locked, 0);
|
||||||
|
assert.strictEqual(dbTitleVotes.shadowHidden, 0);
|
||||||
|
|
||||||
|
assert.strictEqual(dbThumbnailTimestamps.timestamp, thumbnail.timestamp);
|
||||||
|
assert.strictEqual(dbThumbnail.original, thumbnail.original ? 1 : 0);
|
||||||
|
|
||||||
|
assert.strictEqual(dbThumbnailVotes.votes, 0);
|
||||||
|
assert.strictEqual(dbThumbnailVotes.locked, 0);
|
||||||
|
assert.strictEqual(dbThumbnailVotes.shadowHidden, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Submit title and thumbnail as VIP", async () => {
|
||||||
|
const videoID = "postBrand6";
|
||||||
|
const title = {
|
||||||
|
title: "Some title",
|
||||||
|
original: false
|
||||||
|
};
|
||||||
|
const thumbnail = {
|
||||||
|
timestamp: 12.42,
|
||||||
|
original: false
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await postBranding({
|
||||||
|
title,
|
||||||
|
thumbnail,
|
||||||
|
userID: vipUser,
|
||||||
|
service: Service.YouTube,
|
||||||
|
videoID
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
const dbTitle = await queryTitleByVideo(videoID);
|
||||||
|
const dbTitleVotes = await queryTitleVotesByUUID(dbTitle.UUID);
|
||||||
|
const dbThumbnail = await queryThumbnailByVideo(videoID);
|
||||||
|
const dbThumbnailTimestamps = await queryThumbnailTimestampsByUUID(dbThumbnail.UUID);
|
||||||
|
const dbThumbnailVotes = await queryThumbnailVotesByUUID(dbThumbnail.UUID);
|
||||||
|
|
||||||
|
assert.strictEqual(dbTitle.title, title.title);
|
||||||
|
assert.strictEqual(dbTitle.original, title.original ? 1 : 0);
|
||||||
|
|
||||||
|
assert.strictEqual(dbTitleVotes.votes, 0);
|
||||||
|
assert.strictEqual(dbTitleVotes.locked, 1);
|
||||||
|
assert.strictEqual(dbTitleVotes.shadowHidden, 0);
|
||||||
|
|
||||||
|
assert.strictEqual(dbThumbnailTimestamps.timestamp, thumbnail.timestamp);
|
||||||
|
assert.strictEqual(dbThumbnail.original, thumbnail.original ? 1 : 0);
|
||||||
|
|
||||||
|
assert.strictEqual(dbThumbnailVotes.votes, 0);
|
||||||
|
assert.strictEqual(dbThumbnailVotes.locked, 1);
|
||||||
|
assert.strictEqual(dbThumbnailVotes.shadowHidden, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Vote the same title again", async () => {
|
||||||
|
const videoID = "postBrand1";
|
||||||
|
const title = {
|
||||||
|
title: "Some title",
|
||||||
|
original: false
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await postBranding({
|
||||||
|
title,
|
||||||
|
userID: userID1,
|
||||||
|
service: Service.YouTube,
|
||||||
|
videoID
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
const dbTitle = await queryTitleByVideo(videoID);
|
||||||
|
const dbVotes = await queryTitleVotesByUUID(dbTitle.UUID);
|
||||||
|
|
||||||
|
assert.strictEqual(dbTitle.title, title.title);
|
||||||
|
assert.strictEqual(dbTitle.original, title.original ? 1 : 0);
|
||||||
|
|
||||||
|
assert.strictEqual(dbVotes.votes, 0);
|
||||||
|
assert.strictEqual(dbVotes.locked, 0);
|
||||||
|
assert.strictEqual(dbVotes.shadowHidden, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Vote for a different title", async () => {
|
||||||
|
const videoID = "postBrand1";
|
||||||
|
const title = {
|
||||||
|
title: "Some other title",
|
||||||
|
original: false
|
||||||
|
};
|
||||||
|
|
||||||
|
const oldDbTitle = await queryTitleByVideo(videoID);
|
||||||
|
|
||||||
|
const res = await postBranding({
|
||||||
|
title,
|
||||||
|
userID: userID1,
|
||||||
|
service: Service.YouTube,
|
||||||
|
videoID
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
const dbTitle = await queryTitleByVideo(videoID);
|
||||||
|
const dbVotes = await queryTitleVotesByUUID(dbTitle.UUID);
|
||||||
|
const oldDBVotes = await queryTitleVotesByUUID(oldDbTitle.UUID);
|
||||||
|
|
||||||
|
assert.strictEqual(dbTitle.title, title.title);
|
||||||
|
assert.strictEqual(dbTitle.original, title.original ? 1 : 0);
|
||||||
|
|
||||||
|
assert.strictEqual(dbVotes.votes, 0);
|
||||||
|
assert.strictEqual(dbVotes.locked, 0);
|
||||||
|
assert.strictEqual(dbVotes.shadowHidden, 0);
|
||||||
|
|
||||||
|
assert.strictEqual(oldDBVotes.votes, -1);
|
||||||
|
assert.strictEqual(oldDBVotes.locked, 0);
|
||||||
|
assert.strictEqual(oldDBVotes.shadowHidden, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Vote for the same thumbnail again", async () => {
|
||||||
|
const videoID = "postBrand4";
|
||||||
|
const thumbnail = {
|
||||||
|
timestamp: 12.42,
|
||||||
|
original: false
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await postBranding({
|
||||||
|
thumbnail,
|
||||||
|
userID: userID4,
|
||||||
|
service: Service.YouTube,
|
||||||
|
videoID
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
const dbThumbnail = await queryThumbnailByVideo(videoID);
|
||||||
|
const dbThumbnailTimestamps = await queryThumbnailTimestampsByUUID(dbThumbnail.UUID);
|
||||||
|
const dbVotes = await queryThumbnailVotesByUUID(dbThumbnail.UUID);
|
||||||
|
|
||||||
|
assert.strictEqual(dbThumbnailTimestamps.timestamp, thumbnail.timestamp);
|
||||||
|
assert.strictEqual(dbThumbnail.original, thumbnail.original ? 1 : 0);
|
||||||
|
|
||||||
|
assert.strictEqual(dbVotes.votes, 0);
|
||||||
|
assert.strictEqual(dbVotes.locked, 0);
|
||||||
|
assert.strictEqual(dbVotes.shadowHidden, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Vote for the same thumbnail again original", async () => {
|
||||||
|
const videoID = "postBrand3";
|
||||||
|
const thumbnail = {
|
||||||
|
original: true
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await postBranding({
|
||||||
|
thumbnail,
|
||||||
|
userID: userID3,
|
||||||
|
service: Service.YouTube,
|
||||||
|
videoID
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
const dbThumbnail = await queryThumbnailByVideo(videoID);
|
||||||
|
const dbVotes = await queryThumbnailVotesByUUID(dbThumbnail.UUID);
|
||||||
|
|
||||||
|
assert.strictEqual(dbThumbnail.original, thumbnail.original ? 1 : 0);
|
||||||
|
|
||||||
|
assert.strictEqual(dbVotes.votes, 0);
|
||||||
|
assert.strictEqual(dbVotes.locked, 0);
|
||||||
|
assert.strictEqual(dbVotes.shadowHidden, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Vote for a different thumbnail", async () => {
|
||||||
|
const videoID = "postBrand4";
|
||||||
|
const thumbnail = {
|
||||||
|
timestamp: 15.34,
|
||||||
|
original: false
|
||||||
|
};
|
||||||
|
|
||||||
|
const oldDbThumbnail = await queryThumbnailByVideo(videoID);
|
||||||
|
|
||||||
|
const res = await postBranding({
|
||||||
|
thumbnail,
|
||||||
|
userID: userID4,
|
||||||
|
service: Service.YouTube,
|
||||||
|
videoID
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
const dbThumbnail = await queryThumbnailByVideo(videoID);
|
||||||
|
const dbThumbnailTimestamps = await queryThumbnailTimestampsByUUID(dbThumbnail.UUID);
|
||||||
|
const dbVotes = await queryThumbnailVotesByUUID(dbThumbnail.UUID);
|
||||||
|
const oldDBVotes = await queryThumbnailVotesByUUID(oldDbThumbnail.UUID);
|
||||||
|
|
||||||
|
assert.strictEqual(dbThumbnailTimestamps.timestamp, thumbnail.timestamp);
|
||||||
|
assert.strictEqual(dbThumbnail.original, thumbnail.original ? 1 : 0);
|
||||||
|
|
||||||
|
assert.strictEqual(dbVotes.votes, 0);
|
||||||
|
assert.strictEqual(dbVotes.locked, 0);
|
||||||
|
assert.strictEqual(dbVotes.shadowHidden, 0);
|
||||||
|
|
||||||
|
assert.strictEqual(oldDBVotes.votes, -1);
|
||||||
|
assert.strictEqual(oldDBVotes.locked, 0);
|
||||||
|
assert.strictEqual(oldDBVotes.shadowHidden, 0);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue