mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2024-11-10 01:02:30 +01:00
DeArrow downvotes
This commit is contained in:
parent
33dad0a5e4
commit
b04e0dcd97
6 changed files with 389 additions and 56 deletions
11
databases/_upgrade_sponsorTimes_39.sql
Normal file
11
databases/_upgrade_sponsorTimes_39.sql
Normal file
|
@ -0,0 +1,11 @@
|
|||
BEGIN TRANSACTION;
|
||||
|
||||
ALTER TABLE "titleVotes" ADD "downvotes" INTEGER default 0;
|
||||
ALTER TABLE "titleVotes" ADD "removed" INTEGER default 0;
|
||||
|
||||
ALTER TABLE "thumbnailVotes" ADD "downvotes" INTEGER default 0;
|
||||
ALTER TABLE "thumbnailVotes" ADD "removed" INTEGER default 0;
|
||||
|
||||
UPDATE "config" SET value = 39 WHERE key = 'version';
|
||||
|
||||
COMMIT;
|
|
@ -24,18 +24,18 @@ enum BrandingSubmissionType {
|
|||
export async function getVideoBranding(res: Response, videoID: VideoID, service: Service, ip: IPAddress, returnUserID: boolean): Promise<BrandingResult> {
|
||||
const getTitles = () => db.prepare(
|
||||
"all",
|
||||
`SELECT "titles"."title", "titles"."original", "titleVotes"."votes", "titleVotes"."locked", "titleVotes"."shadowHidden", "titles"."UUID", "titles"."videoID", "titles"."hashedVideoID", "titleVotes"."verification", "titles"."userID"
|
||||
`SELECT "titles"."title", "titles"."original", "titleVotes"."votes", "titleVotes"."downvotes", "titleVotes"."locked", "titleVotes"."shadowHidden", "titles"."UUID", "titles"."videoID", "titles"."hashedVideoID", "titleVotes"."verification", "titles"."userID"
|
||||
FROM "titles" JOIN "titleVotes" ON "titles"."UUID" = "titleVotes"."UUID"
|
||||
WHERE "titles"."videoID" = ? AND "titles"."service" = ? AND "titleVotes"."votes" > -1`,
|
||||
WHERE "titles"."videoID" = ? AND "titles"."service" = ? AND "titleVotes"."votes" > -1 AND "titleVotes"."votes" - "titleVotes"."downvotes" > -2 AND "titleVotes"."removed" = 0`,
|
||||
[videoID, service],
|
||||
{ useReplica: true }
|
||||
) as Promise<TitleDBResult[]>;
|
||||
|
||||
const getThumbnails = () => db.prepare(
|
||||
"all",
|
||||
`SELECT "thumbnailTimestamps"."timestamp", "thumbnails"."original", "thumbnailVotes"."votes", "thumbnailVotes"."locked", "thumbnailVotes"."shadowHidden", "thumbnails"."UUID", "thumbnails"."videoID", "thumbnails"."hashedVideoID", "thumbnails"."userID"
|
||||
`SELECT "thumbnailTimestamps"."timestamp", "thumbnails"."original", "thumbnailVotes"."votes", "thumbnailVotes"."downvotes", "thumbnailVotes"."locked", "thumbnailVotes"."shadowHidden", "thumbnails"."UUID", "thumbnails"."videoID", "thumbnails"."hashedVideoID", "thumbnails"."userID"
|
||||
FROM "thumbnails" LEFT JOIN "thumbnailVotes" ON "thumbnails"."UUID" = "thumbnailVotes"."UUID" LEFT JOIN "thumbnailTimestamps" ON "thumbnails"."UUID" = "thumbnailTimestamps"."UUID"
|
||||
WHERE "thumbnails"."videoID" = ? AND "thumbnails"."service" = ? AND "thumbnailVotes"."votes" > -2
|
||||
WHERE "thumbnails"."videoID" = ? AND "thumbnails"."service" = ? AND "thumbnailVotes"."votes" - "thumbnailVotes"."downvotes" > -2 AND "thumbnailVotes"."removed" = 0
|
||||
ORDER BY "thumbnails"."timeSubmitted" ASC`,
|
||||
[videoID, service],
|
||||
{ useReplica: true }
|
||||
|
@ -89,18 +89,18 @@ export async function getVideoBranding(res: Response, videoID: VideoID, service:
|
|||
export async function getVideoBrandingByHash(videoHashPrefix: VideoIDHash, service: Service, ip: IPAddress, returnUserID: boolean): Promise<Record<VideoID, BrandingResult>> {
|
||||
const getTitles = () => db.prepare(
|
||||
"all",
|
||||
`SELECT "titles"."title", "titles"."original", "titleVotes"."votes", "titleVotes"."locked", "titleVotes"."shadowHidden", "titles"."UUID", "titles"."videoID", "titles"."hashedVideoID", "titleVotes"."verification"
|
||||
`SELECT "titles"."title", "titles"."original", "titleVotes"."votes", "titleVotes"."downvotes", "titleVotes"."locked", "titleVotes"."shadowHidden", "titles"."UUID", "titles"."videoID", "titles"."hashedVideoID", "titleVotes"."verification"
|
||||
FROM "titles" JOIN "titleVotes" ON "titles"."UUID" = "titleVotes"."UUID"
|
||||
WHERE "titles"."hashedVideoID" LIKE ? AND "titles"."service" = ? AND "titleVotes"."votes" > -2`,
|
||||
WHERE "titles"."hashedVideoID" LIKE ? AND "titles"."service" = ? AND "titleVotes"."votes" > -1 AND "titleVotes"."votes" - "titleVotes"."downvotes" > -2 AND "titleVotes"."removed" = 0`,
|
||||
[`${videoHashPrefix}%`, service],
|
||||
{ useReplica: true }
|
||||
) as Promise<TitleDBResult[]>;
|
||||
|
||||
const getThumbnails = () => db.prepare(
|
||||
"all",
|
||||
`SELECT "thumbnailTimestamps"."timestamp", "thumbnails"."original", "thumbnailVotes"."votes", "thumbnailVotes"."locked", "thumbnailVotes"."shadowHidden", "thumbnails"."UUID", "thumbnails"."videoID", "thumbnails"."hashedVideoID"
|
||||
`SELECT "thumbnailTimestamps"."timestamp", "thumbnails"."original", "thumbnailVotes"."votes", "thumbnailVotes"."downvotes", "thumbnailVotes"."locked", "thumbnailVotes"."shadowHidden", "thumbnails"."UUID", "thumbnails"."videoID", "thumbnails"."hashedVideoID"
|
||||
FROM "thumbnails" LEFT JOIN "thumbnailVotes" ON "thumbnails"."UUID" = "thumbnailVotes"."UUID" LEFT JOIN "thumbnailTimestamps" ON "thumbnails"."UUID" = "thumbnailTimestamps"."UUID"
|
||||
WHERE "thumbnails"."hashedVideoID" LIKE ? AND "thumbnails"."service" = ? AND "thumbnailVotes"."votes" > -2
|
||||
WHERE "thumbnails"."hashedVideoID" LIKE ? AND "thumbnails"."service" = ? AND "thumbnailVotes"."votes" - "thumbnailVotes"."downvotes" > -2 AND "thumbnailVotes"."removed" = 0
|
||||
ORDER BY "thumbnails"."timeSubmitted" ASC`,
|
||||
[`${videoHashPrefix}%`, service],
|
||||
{ useReplica: true }
|
||||
|
@ -176,7 +176,7 @@ async function filterAndSortBranding(videoID: VideoID, returnUserID: boolean, db
|
|||
.map((r) => ({
|
||||
title: r.title,
|
||||
original: r.original === 1,
|
||||
votes: r.votes + r.verification,
|
||||
votes: r.votes + r.verification - r.downvotes,
|
||||
locked: r.locked === 1,
|
||||
UUID: r.UUID,
|
||||
userID: returnUserID ? r.userID : undefined
|
||||
|
@ -191,7 +191,7 @@ async function filterAndSortBranding(videoID: VideoID, returnUserID: boolean, db
|
|||
.map((r) => ({
|
||||
timestamp: r.timestamp,
|
||||
original: r.original === 1,
|
||||
votes: r.votes,
|
||||
votes: r.votes - r.downvotes,
|
||||
locked: r.locked === 1,
|
||||
UUID: r.UUID,
|
||||
userID: returnUserID ? r.userID : undefined
|
||||
|
|
|
@ -24,6 +24,11 @@ enum BrandingType {
|
|||
Thumbnail
|
||||
}
|
||||
|
||||
enum BrandingVoteType {
|
||||
Upvote = 1,
|
||||
Downvote = 2
|
||||
}
|
||||
|
||||
interface ExistingVote {
|
||||
UUID: BrandingUUID;
|
||||
type: number;
|
||||
|
@ -31,7 +36,7 @@ interface ExistingVote {
|
|||
}
|
||||
|
||||
export async function postBranding(req: Request, res: Response) {
|
||||
const { videoID, userID, title, thumbnail, autoLock } = req.body as BrandingSubmission;
|
||||
const { videoID, userID, title, thumbnail, autoLock, downvote } = req.body as BrandingSubmission;
|
||||
const service = getService(req.body.service);
|
||||
|
||||
if (!videoID || !userID || userID.length < 30 || !service
|
||||
|
@ -57,7 +62,7 @@ export async function postBranding(req: Request, res: Response) {
|
|||
}
|
||||
|
||||
const now = Date.now();
|
||||
const voteType = 1;
|
||||
const voteType: BrandingVoteType = downvote ? BrandingVoteType.Downvote : BrandingVoteType.Upvote;
|
||||
|
||||
if (title && !isVip && title.title.length > config.maxTitleLength) {
|
||||
lock.unlock();
|
||||
|
@ -74,10 +79,14 @@ export async function postBranding(req: Request, res: Response) {
|
|||
if (existingUUID != undefined && isBanned) return; // ignore votes on existing details from banned users
|
||||
const UUID = existingUUID || crypto.randomUUID();
|
||||
|
||||
const existingVote = await handleExistingVotes(BrandingType.Title, videoID, hashedUserID, UUID, hashedIP, voteType);
|
||||
await handleExistingVotes(BrandingType.Title, videoID, hashedUserID, UUID, hashedIP, voteType);
|
||||
if (existingUUID) {
|
||||
await updateVoteTotals(BrandingType.Title, existingVote, UUID, shouldLock);
|
||||
await updateVoteTotals(BrandingType.Title, UUID, shouldLock, !!downvote);
|
||||
} else {
|
||||
if (downvote) {
|
||||
throw new Error("Title submission doesn't exist");
|
||||
}
|
||||
|
||||
await db.prepare("run", `INSERT INTO "titles" ("videoID", "title", "original", "userID", "service", "hashedVideoID", "timeSubmitted", "UUID") VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[videoID, title.title, title.original ? 1 : 0, hashedUserID, service, hashedVideoID, now, UUID]);
|
||||
|
||||
|
@ -111,10 +120,14 @@ export async function postBranding(req: Request, res: Response) {
|
|||
if (existingUUID != undefined && isBanned) return; // ignore votes on existing details from banned users
|
||||
const UUID = existingUUID || crypto.randomUUID();
|
||||
|
||||
const existingVote = await handleExistingVotes(BrandingType.Thumbnail, videoID, hashedUserID, UUID, hashedIP, voteType);
|
||||
await handleExistingVotes(BrandingType.Thumbnail, videoID, hashedUserID, UUID, hashedIP, voteType);
|
||||
if (existingUUID) {
|
||||
await updateVoteTotals(BrandingType.Thumbnail, existingVote, UUID, shouldLock);
|
||||
await updateVoteTotals(BrandingType.Thumbnail, UUID, shouldLock, !!downvote);
|
||||
} else {
|
||||
if (downvote) {
|
||||
throw new Error("Thumbnail submission doesn't exist");
|
||||
}
|
||||
|
||||
await db.prepare("run", `INSERT INTO "thumbnails" ("videoID", "original", "userID", "service", "hashedVideoID", "timeSubmitted", "UUID") VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
||||
[videoID, thumbnail.original ? 1 : 0, hashedUserID, service, hashedVideoID, now, UUID]);
|
||||
|
||||
|
@ -152,38 +165,54 @@ export async function postBranding(req: Request, res: Response) {
|
|||
* If no existing vote, it adds one.
|
||||
*/
|
||||
async function handleExistingVotes(type: BrandingType, videoID: VideoID,
|
||||
hashedUserID: HashedUserID, UUID: BrandingUUID, hashedIP: HashedIP, voteType: number): Promise<ExistingVote> {
|
||||
hashedUserID: HashedUserID, UUID: BrandingUUID, hashedIP: HashedIP, voteType: BrandingVoteType) {
|
||||
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]);
|
||||
// Either votes of the same type, or on the same submission (undo a downvote)
|
||||
const existingVotes = await privateDB.prepare("all", `SELECT "id", "UUID", "type" from ${table} where "videoID" = ? AND "userID" = ? AND ("type" = ? OR "UUID" = ?)`, [videoID, hashedUserID, voteType, UUID]) as ExistingVote[];
|
||||
if (existingVotes.length > 0) {
|
||||
// Only one upvote per video
|
||||
if (voteType === BrandingVoteType.Upvote) {
|
||||
for (const existingVote of existingVotes) {
|
||||
switch (existingVote.type) {
|
||||
case BrandingVoteType.Upvote:
|
||||
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]);
|
||||
break;
|
||||
case BrandingVoteType.Downvote:
|
||||
// Undoing a downvote now that it is being upvoted
|
||||
await db.prepare("run", `UPDATE ${table} SET "downvotes" = "downvotes" - 1 WHERE "UUID" = ?`, [existingVote.UUID]);
|
||||
await privateDB.prepare("run", `DELETE FROM ${table} WHERE "id" = ?`, [existingVote.id]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await privateDB.prepare("run", `UPDATE ${table} SET "type" = ?, "UUID" = ? WHERE "id" = ?`, [voteType, UUID, existingVote.id]);
|
||||
} else if (!existingVote) {
|
||||
} else {
|
||||
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, shouldLock: boolean): Promise<void> {
|
||||
async function updateVoteTotals(type: BrandingType, UUID: BrandingUUID, shouldLock: boolean, downvote: boolean): Promise<void> {
|
||||
const table = type === BrandingType.Title ? `"titleVotes"` : `"thumbnailVotes"`;
|
||||
|
||||
// Don't upvote if we vote on the same submission
|
||||
if (!existingVote || existingVote.UUID !== UUID) {
|
||||
if (downvote) {
|
||||
await db.prepare("run", `UPDATE ${table} SET "downvotes" = "downvotes" + 1 WHERE "UUID" = ?`, [UUID]);
|
||||
} else {
|
||||
await db.prepare("run", `UPDATE ${table} SET "votes" = "votes" + 1 WHERE "UUID" = ?`, [UUID]);
|
||||
}
|
||||
|
||||
if (shouldLock) {
|
||||
await db.prepare("run", `UPDATE ${table} SET "locked" = 1 WHERE "UUID" = ?`, [UUID]);
|
||||
if (downvote) {
|
||||
await db.prepare("run", `UPDATE ${table} SET "removed" = 1 WHERE "UUID" = ?`, [UUID]);
|
||||
} else {
|
||||
await db.prepare("run", `UPDATE ${table} SET "locked" = 1, "removed" = 0 WHERE "UUID" = ?`, [UUID]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ export interface TitleDBResult extends BrandingDBSubmission {
|
|||
title: string,
|
||||
original: number,
|
||||
votes: number,
|
||||
downvotes: number,
|
||||
locked: number,
|
||||
verification: number,
|
||||
userID: UserID
|
||||
|
@ -35,6 +36,7 @@ export interface ThumbnailDBResult extends BrandingDBSubmission {
|
|||
timestamp?: number,
|
||||
original: number,
|
||||
votes: number,
|
||||
downvotes: number,
|
||||
locked: number,
|
||||
userID: UserID
|
||||
}
|
||||
|
@ -84,6 +86,7 @@ export interface BrandingSubmission {
|
|||
userID: UserID;
|
||||
service: Service;
|
||||
autoLock: boolean | undefined;
|
||||
downvote: boolean | undefined;
|
||||
}
|
||||
|
||||
export interface BrandingSegmentDBResult {
|
||||
|
|
|
@ -36,29 +36,34 @@ describe("getBranding", () => {
|
|||
|
||||
before(async () => {
|
||||
const titleQuery = `INSERT INTO "titles" ("videoID", "title", "original", "userID", "service", "hashedVideoID", "timeSubmitted", "UUID") VALUES (?, ?, ?, ?, ?, ?, ?, ?)`;
|
||||
const titleVotesQuery = `INSERT INTO "titleVotes" ("UUID", "votes", "locked", "shadowHidden", "verification") VALUES (?, ?, ?, ?, ?)`;
|
||||
const titleVotesQuery = `INSERT INTO "titleVotes" ("UUID", "votes", "locked", "shadowHidden", "verification", "downvotes", "removed") VALUES (?, ?, ?, ?, ?, ?, ?)`;
|
||||
const thumbnailQuery = `INSERT INTO "thumbnails" ("videoID", "original", "userID", "service", "hashedVideoID", "timeSubmitted", "UUID") VALUES (?, ?, ?, ?, ?, ?, ?)`;
|
||||
const thumbnailTimestampsQuery = `INSERT INTO "thumbnailTimestamps" ("UUID", "timestamp") VALUES (?, ?)`;
|
||||
const thumbnailVotesQuery = `INSERT INTO "thumbnailVotes" ("UUID", "votes", "locked", "shadowHidden") VALUES (?, ?, ?, ?)`;
|
||||
const thumbnailVotesQuery = `INSERT INTO "thumbnailVotes" ("UUID", "votes", "locked", "shadowHidden", "downvotes", "removed") VALUES (?, ?, ?, ?, ?, ?)`;
|
||||
|
||||
await Promise.all([
|
||||
db.prepare("run", titleQuery, [videoID1, "title1", 0, "userID1", Service.YouTube, videoID1Hash, 1, "UUID1"]),
|
||||
db.prepare("run", titleQuery, [videoID1, "title2", 0, "userID2", Service.YouTube, videoID1Hash, 1, "UUID2"]),
|
||||
db.prepare("run", titleQuery, [videoID1, "title3", 1, "userID3", Service.YouTube, videoID1Hash, 1, "UUID3"]),
|
||||
db.prepare("run", titleQuery, [videoID1, "title4removed", 0, "userID4", Service.YouTube, videoID1Hash, 1, "UUID4"]),
|
||||
db.prepare("run", thumbnailQuery, [videoID1, 0, "userID1", Service.YouTube, videoID1Hash, 1, "UUID1T"]),
|
||||
db.prepare("run", thumbnailQuery, [videoID1, 1, "userID2", Service.YouTube, videoID1Hash, 1, "UUID2T"]),
|
||||
db.prepare("run", thumbnailQuery, [videoID1, 0, "userID3", Service.YouTube, videoID1Hash, 1, "UUID3T"]),
|
||||
db.prepare("run", thumbnailQuery, [videoID1, 0, "userID4", Service.YouTube, videoID1Hash, 1, "UUID4T"]),
|
||||
]);
|
||||
|
||||
await Promise.all([
|
||||
db.prepare("run", titleVotesQuery, ["UUID1", 3, 0, 0, 0]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID2", 2, 0, 0, 0]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID3", 1, 0, 0, 0]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID1", 3, 0, 0, 0, 0, 0]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID2", 3, 0, 0, 0, 1, 0]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID3", 1, 0, 0, 0, 0, 0]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID4", 5, 0, 0, 0, 0, 1]),
|
||||
db.prepare("run", thumbnailTimestampsQuery, ["UUID1T", 1]),
|
||||
db.prepare("run", thumbnailTimestampsQuery, ["UUID3T", 3]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID1T", 3, 0, 0]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID2T", 2, 0, 0]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID3T", 1, 0, 0])
|
||||
db.prepare("run", thumbnailTimestampsQuery, ["UUID4T", 18]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID1T", 3, 0, 0, 0, 0]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID2T", 3, 0, 0, 1, 0]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID3T", 1, 0, 0, 0, 0]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID4T", 5, 0, 0, 0, 1])
|
||||
]);
|
||||
|
||||
await Promise.all([
|
||||
|
@ -71,15 +76,15 @@ describe("getBranding", () => {
|
|||
]);
|
||||
|
||||
await Promise.all([
|
||||
db.prepare("run", titleVotesQuery, ["UUID11", 3, 0, 0, 0]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID21", 2, 0, 0, 0]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID31", 1, 1, 0, 0]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID11", 3, 0, 0, 0, 0, 0]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID21", 2, 0, 0, 0, 0, 0]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID31", 1, 1, 0, 0, 0, 0]),
|
||||
|
||||
db.prepare("run", thumbnailTimestampsQuery, ["UUID11T", 1]),
|
||||
db.prepare("run", thumbnailTimestampsQuery, ["UUID31T", 3]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID11T", 3, 0, 0]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID21T", 2, 0, 0]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID31T", 1, 1, 0]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID11T", 3, 0, 0, 0, 0]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID21T", 2, 0, 0, 0, 0]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID31T", 1, 1, 0, 0, 0]),
|
||||
]);
|
||||
|
||||
await Promise.all([
|
||||
|
@ -92,14 +97,14 @@ describe("getBranding", () => {
|
|||
]);
|
||||
|
||||
await Promise.all([
|
||||
db.prepare("run", titleVotesQuery, ["UUID12", 3, 0, 0, 0]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID22", 2, 0, 0, 0]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID32", 1, 0, 1, 0]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID12", 3, 0, 0, 0, 0, 0]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID22", 2, 0, 0, 0, 0, 0]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID32", 1, 0, 1, 0, 0, 0]),
|
||||
db.prepare("run", thumbnailTimestampsQuery, ["UUID12T", 1]),
|
||||
db.prepare("run", thumbnailTimestampsQuery, ["UUID32T", 3]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID12T", 3, 0, 0]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID22T", 2, 0, 0]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID32T", 1, 0, 1])
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID12T", 3, 0, 0, 0, 0]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID22T", 2, 0, 0, 0, 0]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID32T", 1, 0, 1, 0, 0])
|
||||
]);
|
||||
|
||||
const query = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "actionType", "service", "videoDuration", "hidden", "shadowHidden", "description", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
||||
|
@ -116,14 +121,14 @@ describe("getBranding", () => {
|
|||
]);
|
||||
|
||||
await Promise.all([
|
||||
db.prepare("run", titleVotesQuery, ["UUID-uv-1", 3, 0, 0, -1]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID-uv-2", 2, 0, 0, -1]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID-uv-3", 0, 0, 0, -1]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID-uv-1", 3, 0, 0, -1, 0, 0]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID-uv-2", 2, 0, 0, -1, 0, 0]),
|
||||
db.prepare("run", titleVotesQuery, ["UUID-uv-3", 0, 0, 0, -1, 0, 0]),
|
||||
db.prepare("run", thumbnailTimestampsQuery, ["UUID-uv-1T", 1]),
|
||||
db.prepare("run", thumbnailTimestampsQuery, ["UUID-uv-3T", 3]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID-uv-1T", 3, 0, 0]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID-uv-2T", 2, 0, 0]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID-uv-3T", 1, 0, 0])
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID-uv-1T", 3, 0, 0, 0, 0]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID-uv-2T", 2, 0, 0, 0, 0]),
|
||||
db.prepare("run", thumbnailVotesQuery, ["UUID-uv-3T", 1, 0, 0, 0, 0])
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
|
@ -54,6 +54,21 @@ describe("postBranding", () => {
|
|||
await db.prepare("run", insertThumbnailVotesQuery, ["postBrandLocked1", 0, 1, 0]);
|
||||
await db.prepare("run", insertThumbnailVotesQuery, ["postBrandLocked2", 0, 1, 0]);
|
||||
|
||||
// Testing vip submission removal
|
||||
await db.prepare("run", insertTitleQuery, ["postBrandRemoved1", "Some title", 0, getHash(userID1), Service.YouTube, getHash("postBrandRemoved1"), Date.now(), "postBrandRemoved1"]);
|
||||
await db.prepare("run", insertTitleVotesQuery, ["postBrandRemoved1", 0, 1, 0, 0]);
|
||||
await db.prepare("run", insertTitleQuery, ["postBrandRemoved1", "Some other title", 0, getHash(userID1), Service.YouTube, getHash("postBrandRemoved1"), Date.now(), "postBrandRemoved2"]);
|
||||
await db.prepare("run", insertTitleVotesQuery, ["postBrandRemoved2", 0, 1, 0, 0]);
|
||||
|
||||
// Testing vip submission removal
|
||||
const insertThumbnailTimestampQuery = 'INSERT INTO "thumbnailTimestamps" ("UUID", "timestamp") VALUES (?, ?)';
|
||||
await db.prepare("run", insertThumbnailQuery, ["postBrandRemoved1", 0, getHash(userID3), Service.YouTube, getHash("postBrandRemoved1"), Date.now(), "postBrandRemoved1"]);
|
||||
await db.prepare("run", insertThumbnailTimestampQuery, ["postBrandRemoved1", 12.34]);
|
||||
await db.prepare("run", insertThumbnailVotesQuery, ["postBrandRemoved1", 0, 1, 0]);
|
||||
await db.prepare("run", insertThumbnailQuery, ["postBrandRemoved1", 0, getHash(userID3), Service.YouTube, getHash("postBrandRemoved1"), Date.now(), "postBrandRemoved2"]);
|
||||
await db.prepare("run", insertThumbnailTimestampQuery, ["postBrandRemoved2", 13.34]);
|
||||
await db.prepare("run", insertThumbnailVotesQuery, ["postBrandRemoved2", 0, 1, 0]);
|
||||
|
||||
// Verified through title submissions
|
||||
await db.prepare("run", insertTitleQuery, ["postBrandVerified1", "Some title", 0, getHash(userID7), Service.YouTube, getHash("postBrandVerified1"), Date.now(), "postBrandVerified1"]);
|
||||
await db.prepare("run", insertTitleQuery, ["postBrandVerified2", "Some title", 1, getHash(userID7), Service.YouTube, getHash("postBrandVerified2"), Date.now(), "postBrandVerified2"]);
|
||||
|
@ -75,7 +90,6 @@ describe("postBranding", () => {
|
|||
await db.prepare("run", insertThumbnailQuery, ["postBrandBannedOriginalVote", 1, getHash(userID1), Service.YouTube, getHash("postBrandBannedOriginalVote"), Date.now(), "postBrandBannedOriginalVote"]);
|
||||
await db.prepare("run", insertThumbnailVotesQuery, ["postBrandBannedCustomVote", 0, 0, 0]);
|
||||
await db.prepare("run", insertThumbnailVotesQuery, ["postBrandBannedOriginalVote", 0, 0, 0]);
|
||||
const insertThumbnailTimestampQuery = 'INSERT INTO "thumbnailTimestamps" ("UUID", "timestamp") VALUES (?, ?)';
|
||||
await db.prepare("run", insertThumbnailTimestampQuery, ["postBrandBannedCustomVote", 12.34]);
|
||||
});
|
||||
|
||||
|
@ -127,6 +141,7 @@ describe("postBranding", () => {
|
|||
assert.strictEqual(dbTitle.original, title.original ? 1 : 0);
|
||||
|
||||
assert.strictEqual(dbVotes.votes, 0);
|
||||
assert.strictEqual(dbVotes.downvotes, 0);
|
||||
assert.strictEqual(dbVotes.locked, 0);
|
||||
assert.strictEqual(dbVotes.shadowHidden, 0);
|
||||
});
|
||||
|
@ -223,6 +238,177 @@ describe("postBranding", () => {
|
|||
assert.strictEqual(dbThumbnailVotes.shadowHidden, 0);
|
||||
});
|
||||
|
||||
it("Submit another title and thumbnail", async () => {
|
||||
const videoID = "postBrand5";
|
||||
const title = {
|
||||
title: "Some other title",
|
||||
original: false
|
||||
};
|
||||
const thumbnail = {
|
||||
timestamp: 13.42,
|
||||
original: false
|
||||
};
|
||||
|
||||
const res = await postBranding({
|
||||
title,
|
||||
thumbnail,
|
||||
userID: userID4,
|
||||
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("Downvote title and thumbnail", async () => {
|
||||
const videoID = "postBrand5";
|
||||
const title = {
|
||||
title: "Some other title",
|
||||
original: false
|
||||
};
|
||||
const thumbnail = {
|
||||
timestamp: 13.42,
|
||||
original: false
|
||||
};
|
||||
|
||||
const res = await postBranding({
|
||||
title,
|
||||
thumbnail,
|
||||
userID: userID6,
|
||||
service: Service.YouTube,
|
||||
videoID,
|
||||
downvote: true
|
||||
});
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
const dbTitles = await queryTitleByVideo(videoID, true);
|
||||
for (const dbTitle of dbTitles) {
|
||||
if (dbTitle.title === title.title) {
|
||||
const dbTitleVotes = await queryTitleVotesByUUID(dbTitle.UUID);
|
||||
assert.strictEqual(dbTitleVotes.votes, 0);
|
||||
assert.strictEqual(dbTitleVotes.downvotes, 1);
|
||||
assert.strictEqual(dbTitleVotes.locked, 0);
|
||||
assert.strictEqual(dbTitleVotes.shadowHidden, 0);
|
||||
}
|
||||
}
|
||||
|
||||
const dbThumbnails = await queryThumbnailByVideo(videoID, true);
|
||||
for (const dbThumbnail of dbThumbnails) {
|
||||
if (dbThumbnail.timestamp === thumbnail.timestamp) {
|
||||
const dbThumbnailVotes = await queryThumbnailVotesByUUID(dbThumbnail.UUID);
|
||||
|
||||
assert.strictEqual(dbThumbnailVotes.votes, 0);
|
||||
assert.strictEqual(dbThumbnailVotes.downvotes, 1);
|
||||
assert.strictEqual(dbThumbnailVotes.locked, 0);
|
||||
assert.strictEqual(dbThumbnailVotes.shadowHidden, 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("Downvote another 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: userID6,
|
||||
service: Service.YouTube,
|
||||
videoID,
|
||||
downvote: true
|
||||
});
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
const dbTitles = await queryTitleByVideo(videoID, true);
|
||||
for (const dbTitle of dbTitles) {
|
||||
const dbTitleVotes = await queryTitleVotesByUUID(dbTitle.UUID);
|
||||
assert.strictEqual(dbTitleVotes.votes, 0);
|
||||
assert.strictEqual(dbTitleVotes.downvotes, 1);
|
||||
assert.strictEqual(dbTitleVotes.locked, 0);
|
||||
assert.strictEqual(dbTitleVotes.shadowHidden, 0);
|
||||
}
|
||||
|
||||
const dbThumbnails = await queryThumbnailByVideo(videoID, true);
|
||||
for (const dbThumbnail of dbThumbnails) {
|
||||
const dbThumbnailVotes = await queryThumbnailVotesByUUID(dbThumbnail.UUID);
|
||||
|
||||
assert.strictEqual(dbThumbnailVotes.votes, 0);
|
||||
assert.strictEqual(dbThumbnailVotes.downvotes, 1);
|
||||
assert.strictEqual(dbThumbnailVotes.locked, 0);
|
||||
assert.strictEqual(dbThumbnailVotes.shadowHidden, 0);
|
||||
}
|
||||
});
|
||||
|
||||
it("Upvote after downvoting title and thumbnail", async () => {
|
||||
const videoID = "postBrand5";
|
||||
const title = {
|
||||
title: "Some other title",
|
||||
original: false
|
||||
};
|
||||
const thumbnail = {
|
||||
timestamp: 13.42,
|
||||
original: false
|
||||
};
|
||||
|
||||
const res = await postBranding({
|
||||
title,
|
||||
thumbnail,
|
||||
userID: userID6,
|
||||
service: Service.YouTube,
|
||||
videoID
|
||||
});
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
const dbTitles = await queryTitleByVideo(videoID, true);
|
||||
for (const dbTitle of dbTitles) {
|
||||
if (dbTitle.title === title.title) {
|
||||
const dbTitleVotes = await queryTitleVotesByUUID(dbTitle.UUID);
|
||||
assert.strictEqual(dbTitleVotes.votes, 1);
|
||||
assert.strictEqual(dbTitleVotes.downvotes, 0);
|
||||
assert.strictEqual(dbTitleVotes.locked, 0);
|
||||
assert.strictEqual(dbTitleVotes.shadowHidden, 0);
|
||||
}
|
||||
}
|
||||
|
||||
const dbThumbnails = await queryThumbnailByVideo(videoID, true);
|
||||
for (const dbThumbnail of dbThumbnails) {
|
||||
if (dbThumbnail.timestamp === thumbnail.timestamp) {
|
||||
const dbThumbnailVotes = await queryThumbnailVotesByUUID(dbThumbnail.UUID);
|
||||
|
||||
assert.strictEqual(dbThumbnailVotes.votes, 1);
|
||||
assert.strictEqual(dbThumbnailVotes.downvotes, 0);
|
||||
assert.strictEqual(dbThumbnailVotes.locked, 0);
|
||||
assert.strictEqual(dbThumbnailVotes.shadowHidden, 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("Submit title and thumbnail as VIP", async () => {
|
||||
const videoID = "postBrand6";
|
||||
const title = {
|
||||
|
@ -350,6 +536,104 @@ describe("postBranding", () => {
|
|||
assert.strictEqual(dbThumbnailVotes.locked, 0);
|
||||
});
|
||||
|
||||
it("Downvote title and thumbnail as VIP", async () => {
|
||||
const videoID = "postBrandRemoved1";
|
||||
const title = {
|
||||
title: "Some title",
|
||||
original: false
|
||||
};
|
||||
const thumbnail = {
|
||||
timestamp: 12.34,
|
||||
original: false
|
||||
};
|
||||
|
||||
const res = await postBranding({
|
||||
title,
|
||||
thumbnail,
|
||||
userID: vipUser,
|
||||
service: Service.YouTube,
|
||||
videoID,
|
||||
downvote: true
|
||||
});
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
|
||||
const otherSegmentTitleVotes1 = await queryTitleVotesByUUID("postBrandRemoved1");
|
||||
const otherSegmentTitleVotes2 = await queryTitleVotesByUUID("postBrandRemoved2");
|
||||
const otherSegmentThumbnailVotes1 = await queryThumbnailVotesByUUID("postBrandRemoved1");
|
||||
const otherSegmentThumbnailVotes2 = await queryThumbnailVotesByUUID("postBrandRemoved2");
|
||||
|
||||
assert.strictEqual(otherSegmentTitleVotes1.removed, 1);
|
||||
assert.strictEqual(otherSegmentTitleVotes2.removed, 0);
|
||||
assert.strictEqual(otherSegmentThumbnailVotes1.removed, 1);
|
||||
assert.strictEqual(otherSegmentThumbnailVotes2.removed, 0);
|
||||
});
|
||||
|
||||
it("Downvote another title and thumbnail as VIP", async () => {
|
||||
const videoID = "postBrandRemoved1";
|
||||
const title = {
|
||||
title: "Some other title",
|
||||
original: false
|
||||
};
|
||||
const thumbnail = {
|
||||
timestamp: 13.34,
|
||||
original: false
|
||||
};
|
||||
|
||||
const res = await postBranding({
|
||||
title,
|
||||
thumbnail,
|
||||
userID: vipUser,
|
||||
service: Service.YouTube,
|
||||
videoID,
|
||||
downvote: true
|
||||
});
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
|
||||
const otherSegmentTitleVotes1 = await queryTitleVotesByUUID("postBrandRemoved1");
|
||||
const otherSegmentTitleVotes2 = await queryTitleVotesByUUID("postBrandRemoved2");
|
||||
const otherSegmentThumbnailVotes1 = await queryThumbnailVotesByUUID("postBrandRemoved1");
|
||||
const otherSegmentThumbnailVotes2 = await queryThumbnailVotesByUUID("postBrandRemoved2");
|
||||
|
||||
assert.strictEqual(otherSegmentTitleVotes1.removed, 1);
|
||||
assert.strictEqual(otherSegmentTitleVotes2.removed, 1);
|
||||
assert.strictEqual(otherSegmentThumbnailVotes1.removed, 1);
|
||||
assert.strictEqual(otherSegmentThumbnailVotes2.removed, 1);
|
||||
});
|
||||
|
||||
it("Remove downvote on title and thumbnail as VIP", async () => {
|
||||
const videoID = "postBrandRemoved1";
|
||||
const title = {
|
||||
title: "Some title",
|
||||
original: false
|
||||
};
|
||||
const thumbnail = {
|
||||
timestamp: 12.34,
|
||||
original: false
|
||||
};
|
||||
|
||||
const res = await postBranding({
|
||||
title,
|
||||
thumbnail,
|
||||
userID: vipUser,
|
||||
service: Service.YouTube,
|
||||
videoID
|
||||
});
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
|
||||
const otherSegmentTitleVotes1 = await queryTitleVotesByUUID("postBrandRemoved1");
|
||||
const otherSegmentTitleVotes2 = await queryTitleVotesByUUID("postBrandRemoved2");
|
||||
const otherSegmentThumbnailVotes1 = await queryThumbnailVotesByUUID("postBrandRemoved1");
|
||||
const otherSegmentThumbnailVotes2 = await queryThumbnailVotesByUUID("postBrandRemoved2");
|
||||
|
||||
assert.strictEqual(otherSegmentTitleVotes1.removed, 0);
|
||||
assert.strictEqual(otherSegmentTitleVotes2.removed, 1);
|
||||
assert.strictEqual(otherSegmentThumbnailVotes1.removed, 0);
|
||||
assert.strictEqual(otherSegmentThumbnailVotes2.removed, 1);
|
||||
});
|
||||
|
||||
it("Vote the same title again", async () => {
|
||||
const videoID = "postBrand1";
|
||||
const title = {
|
||||
|
@ -516,6 +800,7 @@ describe("postBranding", () => {
|
|||
assert.strictEqual(dbTitle.original, title.original ? 1 : 0);
|
||||
|
||||
assert.strictEqual(dbVotes.votes, 1);
|
||||
assert.strictEqual(dbVotes.downvotes, 0);
|
||||
assert.strictEqual(dbVotes.locked, 0);
|
||||
assert.strictEqual(dbVotes.shadowHidden, 0);
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue