mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2025-12-06 03:26:59 +03:00
Store titles for casual vote submissions
When an uploader changes the title, it will reset the casual votes
This commit is contained in:
@@ -95,6 +95,15 @@ CREATE TABLE IF NOT EXISTS "casualVotes" (
|
|||||||
"timeSubmitted" INTEGER NOT NULL
|
"timeSubmitted" INTEGER NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "casualVoteTitles" (
|
||||||
|
"videoID" TEXT NOT NULL,
|
||||||
|
"service" TEXT NOT NULL,
|
||||||
|
"id" INTEGER NOT NULL,
|
||||||
|
"hashedVideoID" TEXT NOT NULL,
|
||||||
|
"title" TEXT NOT NULL,
|
||||||
|
PRIMARY KEY("videoID", "service", "id")
|
||||||
|
);
|
||||||
|
|
||||||
CREATE EXTENSION IF NOT EXISTS pgcrypto; --!sqlite-ignore
|
CREATE EXTENSION IF NOT EXISTS pgcrypto; --!sqlite-ignore
|
||||||
CREATE EXTENSION IF NOT EXISTS pg_trgm; --!sqlite-ignore
|
CREATE EXTENSION IF NOT EXISTS pg_trgm; --!sqlite-ignore
|
||||||
|
|
||||||
|
|||||||
7
databases/_upgrade_private_13.sql
Normal file
7
databases/_upgrade_private_13.sql
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE "casualVotes" ADD "titleID" INTEGER default 0;
|
||||||
|
|
||||||
|
UPDATE "config" SET value = 13 WHERE key = 'version';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
7
databases/_upgrade_sponsorTimes_43.sql
Normal file
7
databases/_upgrade_sponsorTimes_43.sql
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE "casualVotes" ADD "titleID" INTEGER default 0;
|
||||||
|
|
||||||
|
UPDATE "config" SET value = 43 WHERE key = 'version';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -153,6 +153,9 @@ addDefaults(config, {
|
|||||||
{
|
{
|
||||||
name: "casualVotes",
|
name: "casualVotes",
|
||||||
order: "timeSubmitted"
|
order: "timeSubmitted"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "casualVoteTitles"
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
diskCacheURL: null,
|
diskCacheURL: null,
|
||||||
|
|||||||
@@ -53,9 +53,10 @@ export async function getVideoBranding(res: Response, videoID: VideoID, service:
|
|||||||
|
|
||||||
const getCasualVotes = () => db.prepare(
|
const getCasualVotes = () => db.prepare(
|
||||||
"all",
|
"all",
|
||||||
`SELECT "category", "upvotes" FROM "casualVotes"
|
`SELECT "casualVotes"."category", "casualVotes"."upvotes", "casualVoteTitles"."title"
|
||||||
WHERE "videoID" = ? AND "service" = ?
|
FROM "casualVotes" LEFT JOIN "casualVoteTitles" ON "casualVotes"."videoID" = "casualVoteTitles"."videoID" AND "casualVotes"."service" = "casualVoteTitles"."service" AND "casualVotes"."titleID" = "casualVoteTitles"."id"
|
||||||
ORDER BY "timeSubmitted" ASC`,
|
WHERE "casualVotes"."videoID" = ? AND "casualVotes"."service" = ?
|
||||||
|
ORDER BY "casualVotes"."timeSubmitted" ASC`,
|
||||||
[videoID, service],
|
[videoID, service],
|
||||||
{ useReplica: true }
|
{ useReplica: true }
|
||||||
) as Promise<CasualVoteDBResult[]>;
|
) as Promise<CasualVoteDBResult[]>;
|
||||||
@@ -131,9 +132,10 @@ export async function getVideoBrandingByHash(videoHashPrefix: VideoIDHash, servi
|
|||||||
|
|
||||||
const getCasualVotes = () => db.prepare(
|
const getCasualVotes = () => db.prepare(
|
||||||
"all",
|
"all",
|
||||||
`SELECT "videoID", "category", "upvotes" FROM "casualVotes"
|
`SELECT "casualVotes"."videoID", "casualVotes"."category", "casualVotes"."upvotes", "casualVoteTitles"."title"
|
||||||
WHERE "hashedVideoID" LIKE ? AND "service" = ?
|
FROM "casualVotes" LEFT JOIN "casualVoteTitles" ON "casualVotes"."videoID" = "casualVoteTitles"."videoID" AND "casualVotes"."service" = "casualVoteTitles"."service" AND "casualVotes"."titleID" = "casualVoteTitles"."id"
|
||||||
ORDER BY "timeSubmitted" ASC`,
|
WHERE "casualVotes"."hashedVideoID" LIKE ? AND "casualVotes"."service" = ?
|
||||||
|
ORDER BY "casualVotes"."timeSubmitted" ASC`,
|
||||||
[`${videoHashPrefix}%`, service],
|
[`${videoHashPrefix}%`, service],
|
||||||
{ useReplica: true }
|
{ useReplica: true }
|
||||||
) as Promise<CasualVoteHashDBResult[]>;
|
) as Promise<CasualVoteHashDBResult[]>;
|
||||||
@@ -233,7 +235,8 @@ async function filterAndSortBranding(videoID: VideoID, returnUserID: boolean, fe
|
|||||||
const casualDownvotes = dbCasualVotes.filter((r) => r.category === "downvote")[0];
|
const casualDownvotes = dbCasualVotes.filter((r) => r.category === "downvote")[0];
|
||||||
const casualVotes = dbCasualVotes.filter((r) => r.category !== "downvote").map((r) => ({
|
const casualVotes = dbCasualVotes.filter((r) => r.category !== "downvote").map((r) => ({
|
||||||
id: r.category,
|
id: r.category,
|
||||||
count: r.upvotes - (casualDownvotes?.upvotes ?? 0)
|
count: r.upvotes - (casualDownvotes?.upvotes ?? 0),
|
||||||
|
title: r.title
|
||||||
})).filter((a) => a.count > 0);
|
})).filter((a) => a.count > 0);
|
||||||
|
|
||||||
const videoDuration = dbSegments.filter(s => s.videoDuration !== 0)[0]?.videoDuration ?? null;
|
const videoDuration = dbSegments.filter(s => s.videoDuration !== 0)[0]?.videoDuration ?? null;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ interface ExistingVote {
|
|||||||
export async function postCasual(req: Request, res: Response) {
|
export async function postCasual(req: Request, res: Response) {
|
||||||
const { videoID, userID, downvote } = req.body as CasualVoteSubmission;
|
const { videoID, userID, downvote } = req.body as CasualVoteSubmission;
|
||||||
let categories = req.body.categories as CasualCategory[];
|
let categories = req.body.categories as CasualCategory[];
|
||||||
|
const title = (req.body.title as string)?.toLowerCase();
|
||||||
const service = getService(req.body.service);
|
const service = getService(req.body.service);
|
||||||
|
|
||||||
if (downvote) {
|
if (downvote) {
|
||||||
@@ -50,19 +51,41 @@ export async function postCasual(req: Request, res: Response) {
|
|||||||
return res.status(200).send("OK");
|
return res.status(200).send("OK");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let titleID = 0;
|
||||||
|
if (title) {
|
||||||
|
// See if title needs to be added
|
||||||
|
const titles = await db.prepare("all", `SELECT "title", "id" from "casualVoteTitles" WHERE "videoID" = ? AND "service" = ? ORDER BY "id"`, [videoID, service]) as { title: string, id: number }[];
|
||||||
|
if (titles.length > 0) {
|
||||||
|
const existingTitle = titles.find((t) => t.title === title);
|
||||||
|
if (existingTitle) {
|
||||||
|
titleID = existingTitle.id;
|
||||||
|
} else {
|
||||||
|
titleID = titles[titles.length - 1].id + 1;
|
||||||
|
await db.prepare("run", `INSERT INTO "casualVoteTitles" ("videoID", "service", "hashedVideoID", "id", "title") VALUES (?, ?, ?, ?, ?)`, [videoID, service, hashedVideoID, titleID, title]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await db.prepare("run", `INSERT INTO "casualVoteTitles" ("videoID", "service", "hashedVideoID", "id", "title") VALUES (?, ?, ?, ?, ?)`, [videoID, service, hashedVideoID, titleID, title]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const titles = await db.prepare("all", `SELECT "title", "id" from "casualVoteTitles" WHERE "videoID" = ? AND "service" = ? ORDER BY "id"`, [videoID, service]) as { title: string, id: number }[];
|
||||||
|
if (titles.length > 0) {
|
||||||
|
titleID = titles[titles.length - 1].id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
for (const category of categories) {
|
for (const category of categories) {
|
||||||
const existingUUID = (await db.prepare("get", `SELECT "UUID" from "casualVotes" where "videoID" = ? AND "category" = ?`, [videoID, category]))?.UUID;
|
const existingUUID = (await db.prepare("get", `SELECT "UUID" from "casualVotes" where "videoID" = ? AND "service" = ? AND "titleID" = ? AND "category" = ?`, [videoID, service, titleID, category]))?.UUID;
|
||||||
const UUID = existingUUID || crypto.randomUUID();
|
const UUID = existingUUID || crypto.randomUUID();
|
||||||
|
|
||||||
const alreadyVotedTheSame = await handleExistingVotes(videoID, service, UUID, hashedUserID, hashedIP, category, downvote, now);
|
const alreadyVotedTheSame = await handleExistingVotes(videoID, service, titleID, hashedUserID, hashedIP, category, downvote, now);
|
||||||
if (existingUUID) {
|
if (existingUUID) {
|
||||||
if (!alreadyVotedTheSame) {
|
if (!alreadyVotedTheSame) {
|
||||||
await db.prepare("run", `UPDATE "casualVotes" SET "upvotes" = "upvotes" + 1 WHERE "UUID" = ?`, [UUID]);
|
await db.prepare("run", `UPDATE "casualVotes" SET "upvotes" = "upvotes" + 1 WHERE "UUID" = ?`, [UUID]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await db.prepare("run", `INSERT INTO "casualVotes" ("videoID", "service", "hashedVideoID", "timeSubmitted", "UUID", "category", "upvotes") VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
await db.prepare("run", `INSERT INTO "casualVotes" ("videoID", "service", "titleID", "hashedVideoID", "timeSubmitted", "UUID", "category", "upvotes") VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||||
[videoID, service, hashedVideoID, now, UUID, category, 1]);
|
[videoID, service, titleID, hashedVideoID, now, UUID, category, 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,31 +100,31 @@ export async function postCasual(req: Request, res: Response) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleExistingVotes(videoID: VideoID, service: Service, UUID: string,
|
async function handleExistingVotes(videoID: VideoID, service: Service, titleID: number,
|
||||||
hashedUserID: HashedUserID, hashedIP: HashedIP, category: CasualCategory, downvote: boolean, now: number): Promise<boolean> {
|
hashedUserID: HashedUserID, hashedIP: HashedIP, category: CasualCategory, downvote: boolean, now: number): Promise<boolean> {
|
||||||
const existingVote = await privateDB.prepare("get", `SELECT "UUID" from "casualVotes" WHERE "videoID" = ? AND "service" = ? AND "userID" = ? AND "category" = ?`, [videoID, service, hashedUserID, category]) as ExistingVote;
|
const existingVote = await privateDB.prepare("get", `SELECT "UUID" from "casualVotes" WHERE "videoID" = ? AND "service" = ? AND "titleID" = ? AND "userID" = ? AND "category" = ?`, [videoID, service, titleID, hashedUserID, category]) as ExistingVote;
|
||||||
if (existingVote) {
|
if (existingVote) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (downvote) {
|
if (downvote) {
|
||||||
// Remove upvotes for all categories on this video
|
// Remove upvotes for all categories on this video
|
||||||
const existingUpvotes = await privateDB.prepare("all", `SELECT "category" from "casualVotes" WHERE "category" != 'downvote' AND "videoID" = ? AND "service" = ? AND "userID" = ?`, [videoID, service, hashedUserID]);
|
const existingUpvotes = await privateDB.prepare("all", `SELECT "category" from "casualVotes" WHERE "category" != 'downvote' AND "videoID" = ? AND "service" = ? AND "titleID" = ? AND "userID" = ?`, [videoID, service, titleID, hashedUserID]);
|
||||||
for (const existingUpvote of existingUpvotes) {
|
for (const existingUpvote of existingUpvotes) {
|
||||||
await db.prepare("run", `UPDATE "casualVotes" SET "upvotes" = "upvotes" - 1 WHERE "videoID" = ? AND "category" = ?`, [videoID, existingUpvote.category]);
|
await db.prepare("run", `UPDATE "casualVotes" SET "upvotes" = "upvotes" - 1 WHERE "videoID" = ? AND "service" = ? AND "titleID" = ? AND "category" = ?`, [videoID, service, titleID, existingUpvote.category]);
|
||||||
await privateDB.prepare("run", `DELETE FROM "casualVotes" WHERE "videoID" = ? AND "userID" = ? AND "category" = ?`, [videoID, hashedUserID, existingUpvote.category]);
|
await privateDB.prepare("run", `DELETE FROM "casualVotes" WHERE "videoID" = ? AND "service" = ? AND "titleID" = ? AND "userID" = ? AND "category" = ?`, [videoID, service, titleID, hashedUserID, existingUpvote.category]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Undo a downvote if it exists
|
// Undo a downvote if it exists
|
||||||
const existingDownvote = await privateDB.prepare("get", `SELECT "UUID" from "casualVotes" WHERE "category" = 'downvote' AND "videoID" = ? AND "service" = ? AND "userID" = ?`, [videoID, service, hashedUserID]) as ExistingVote;
|
const existingDownvote = await privateDB.prepare("get", `SELECT "UUID" from "casualVotes" WHERE "category" = 'downvote' AND "videoID" = ? AND "service" = ? AND "titleID" = ? AND "userID" = ?`, [videoID, service, titleID, hashedUserID]) as ExistingVote;
|
||||||
if (existingDownvote) {
|
if (existingDownvote) {
|
||||||
await db.prepare("run", `UPDATE "casualVotes" SET "upvotes" = "upvotes" - 1 WHERE "category" = 'downvote' AND "videoID" = ?`, [videoID]);
|
await db.prepare("run", `UPDATE "casualVotes" SET "upvotes" = "upvotes" - 1 WHERE "category" = 'downvote' AND "videoID" = ? AND "service" = ? AND "titleID" = ?`, [videoID, service, titleID]);
|
||||||
await privateDB.prepare("run", `DELETE FROM "casualVotes" WHERE "category" = 'downvote' AND "videoID" = ? AND "userID" = ?`, [videoID, hashedUserID]);
|
await privateDB.prepare("run", `DELETE FROM "casualVotes" WHERE "category" = 'downvote' AND "videoID" = ? AND "service" = ? AND "titleID" = ? AND "userID" = ?`, [videoID, service, titleID, hashedUserID]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await privateDB.prepare("run", `INSERT INTO "casualVotes" ("videoID", "service", "userID", "hashedIP", "category", "timeSubmitted") VALUES (?, ?, ?, ?, ?, ?)`,
|
await privateDB.prepare("run", `INSERT INTO "casualVotes" ("videoID", "service", "titleID", "userID", "hashedIP", "category", "timeSubmitted") VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
||||||
[videoID, service, hashedUserID, hashedIP, category, now]);
|
[videoID, service, titleID, hashedUserID, hashedIP, category, now]);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -54,7 +54,8 @@ export interface ThumbnailResult {
|
|||||||
|
|
||||||
export interface CasualVote {
|
export interface CasualVote {
|
||||||
id: string,
|
id: string,
|
||||||
count: number
|
count: number,
|
||||||
|
title: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BrandingResult {
|
export interface BrandingResult {
|
||||||
@@ -107,6 +108,7 @@ export interface CasualVoteSubmission {
|
|||||||
service: Service;
|
service: Service;
|
||||||
downvote: boolean | undefined;
|
downvote: boolean | undefined;
|
||||||
categories: CasualCategory[];
|
categories: CasualCategory[];
|
||||||
|
title?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BrandingSegmentDBResult {
|
export interface BrandingSegmentDBResult {
|
||||||
@@ -120,6 +122,7 @@ export interface CasualVoteDBResult {
|
|||||||
category: CasualCategory;
|
category: CasualCategory;
|
||||||
upvotes: number;
|
upvotes: number;
|
||||||
downvotes: number;
|
downvotes: number;
|
||||||
|
title?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BrandingSegmentHashDBResult extends BrandingDBSubmissionData {
|
export interface BrandingSegmentHashDBResult extends BrandingDBSubmissionData {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ describe("getBranding", () => {
|
|||||||
const videoIDvidDuration = "videoID7";
|
const videoIDvidDuration = "videoID7";
|
||||||
const videoIDCasual = "videoIDCasual";
|
const videoIDCasual = "videoIDCasual";
|
||||||
const videoIDCasualDownvoted = "videoIDCasualDownvoted";
|
const videoIDCasualDownvoted = "videoIDCasualDownvoted";
|
||||||
|
const videoIDCasualTitle = "videoIDCasualTitle";
|
||||||
|
|
||||||
const videoID1Hash = getHash(videoID1, 1).slice(0, 4);
|
const videoID1Hash = getHash(videoID1, 1).slice(0, 4);
|
||||||
const videoID2LockedHash = getHash(videoID2Locked, 1).slice(0, 4);
|
const videoID2LockedHash = getHash(videoID2Locked, 1).slice(0, 4);
|
||||||
@@ -26,6 +27,7 @@ describe("getBranding", () => {
|
|||||||
const videoIDvidDurationHash = getHash(videoIDUnverified, 1).slice(0, 4);
|
const videoIDvidDurationHash = getHash(videoIDUnverified, 1).slice(0, 4);
|
||||||
const videoIDCasualHash = getHash(videoIDCasual, 1).slice(0, 4);
|
const videoIDCasualHash = getHash(videoIDCasual, 1).slice(0, 4);
|
||||||
const videoIDCasualDownvotedHash = getHash(videoIDCasualDownvoted, 1).slice(0, 4);
|
const videoIDCasualDownvotedHash = getHash(videoIDCasualDownvoted, 1).slice(0, 4);
|
||||||
|
const videoIDCasualTitleHash = getHash(videoIDCasualTitle, 1).slice(0, 4);
|
||||||
|
|
||||||
const endpoint = "/api/branding";
|
const endpoint = "/api/branding";
|
||||||
const getBranding = (params: Record<string, any>) => client({
|
const getBranding = (params: Record<string, any>) => client({
|
||||||
@@ -48,6 +50,7 @@ describe("getBranding", () => {
|
|||||||
const thumbnailVotesQuery = `INSERT INTO "thumbnailVotes" ("UUID", "votes", "locked", "shadowHidden", "downvotes", "removed") VALUES (?, ?, ?, ?, ?, ?)`;
|
const thumbnailVotesQuery = `INSERT INTO "thumbnailVotes" ("UUID", "votes", "locked", "shadowHidden", "downvotes", "removed") VALUES (?, ?, ?, ?, ?, ?)`;
|
||||||
const segmentQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "actionType", "service", "videoDuration", "hidden", "shadowHidden", "description", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
const segmentQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "actionType", "service", "videoDuration", "hidden", "shadowHidden", "description", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
||||||
const insertCasualVotesQuery = `INSERT INTO "casualVotes" ("UUID", "videoID", "service", "hashedVideoID", "category", "upvotes", "timeSubmitted") VALUES (?, ?, ?, ?, ?, ?, ?)`;
|
const insertCasualVotesQuery = `INSERT INTO "casualVotes" ("UUID", "videoID", "service", "hashedVideoID", "category", "upvotes", "timeSubmitted") VALUES (?, ?, ?, ?, ?, ?, ?)`;
|
||||||
|
const insertCasualVotesTitleQuery = `INSERT INTO "casualVoteTitles" ("videoID", "service", "hashedVideoID", "id", "title") VALUES (?, ?, ?, ?, ?)`;
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
db.prepare("run", titleQuery, [videoID1, "title1", 0, "userID1", Service.YouTube, videoID1Hash, 1, "UUID1"]),
|
db.prepare("run", titleQuery, [videoID1, "title1", 0, "userID1", Service.YouTube, videoID1Hash, 1, "UUID1"]),
|
||||||
@@ -154,6 +157,13 @@ describe("getBranding", () => {
|
|||||||
db.prepare("run", insertCasualVotesQuery, ["postBrandCasual2", videoIDCasualDownvoted, Service.YouTube, videoIDCasualDownvotedHash, "clever", 1, Date.now()]),
|
db.prepare("run", insertCasualVotesQuery, ["postBrandCasual2", videoIDCasualDownvoted, Service.YouTube, videoIDCasualDownvotedHash, "clever", 1, Date.now()]),
|
||||||
db.prepare("run", insertCasualVotesQuery, ["postBrandCasual2d", videoIDCasualDownvoted, Service.YouTube, videoIDCasualDownvotedHash, "downvote", 1, Date.now()]),
|
db.prepare("run", insertCasualVotesQuery, ["postBrandCasual2d", videoIDCasualDownvoted, Service.YouTube, videoIDCasualDownvotedHash, "downvote", 1, Date.now()]),
|
||||||
db.prepare("run", insertCasualVotesQuery, ["postBrandCasual3", videoIDCasualDownvoted, Service.YouTube, videoIDCasualDownvotedHash, "other", 4, Date.now()]),
|
db.prepare("run", insertCasualVotesQuery, ["postBrandCasual3", videoIDCasualDownvoted, Service.YouTube, videoIDCasualDownvotedHash, "other", 4, Date.now()]),
|
||||||
|
db.prepare("run", insertCasualVotesQuery, ["postBrandCasual4", videoIDCasualTitle, Service.YouTube, videoIDCasualTitleHash, "clever", 8, Date.now()]),
|
||||||
|
db.prepare("run", insertCasualVotesQuery, ["postBrandCasual4d", videoIDCasualTitle, Service.YouTube, videoIDCasualTitleHash, "downvote", 4, Date.now()]),
|
||||||
|
db.prepare("run", insertCasualVotesQuery, ["postBrandCasual4o", videoIDCasualTitle, Service.YouTube, videoIDCasualTitleHash, "other", 3, Date.now()]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
db.prepare("run", insertCasualVotesTitleQuery, [videoIDCasualTitle, Service.YouTube, videoIDCasualTitleHash, 0, "a cool title"]),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -351,7 +361,8 @@ describe("getBranding", () => {
|
|||||||
await checkVideo(videoIDCasual, videoIDCasualHash, true, {
|
await checkVideo(videoIDCasual, videoIDCasualHash, true, {
|
||||||
casualVotes: [{
|
casualVotes: [{
|
||||||
id: "clever",
|
id: "clever",
|
||||||
count: 1
|
count: 1,
|
||||||
|
title: null
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -360,7 +371,18 @@ describe("getBranding", () => {
|
|||||||
await checkVideo(videoIDCasualDownvoted, videoIDCasualDownvotedHash, true, {
|
await checkVideo(videoIDCasualDownvoted, videoIDCasualDownvotedHash, true, {
|
||||||
casualVotes: [{
|
casualVotes: [{
|
||||||
id: "other",
|
id: "other",
|
||||||
count: 3
|
count: 3,
|
||||||
|
title: null
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should get casual votes with title", async () => {
|
||||||
|
await checkVideo(videoIDCasualTitle, videoIDCasualTitleHash, true, {
|
||||||
|
casualVotes: [{
|
||||||
|
id: "clever",
|
||||||
|
count: 4,
|
||||||
|
title: "a cool title"
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ describe("postCasual", () => {
|
|||||||
data
|
data
|
||||||
});
|
});
|
||||||
|
|
||||||
const queryCasualVotesByVideo = (videoID: string, all = false) => db.prepare(all ? "all" : "get", `SELECT * FROM "casualVotes" WHERE "videoID" = ? ORDER BY "timeSubmitted" ASC`, [videoID]);
|
const queryCasualVotesByVideo = (videoID: string, all = false, titleID = 0) => db.prepare(all ? "all" : "get", `SELECT * FROM "casualVotes" WHERE "videoID" = ? AND "titleID" = ? ORDER BY "timeSubmitted" ASC`, [videoID, titleID]);
|
||||||
|
|
||||||
it("submit casual vote", async () => {
|
it("submit casual vote", async () => {
|
||||||
const videoID = "postCasual1";
|
const videoID = "postCasual1";
|
||||||
@@ -25,6 +25,7 @@ describe("postCasual", () => {
|
|||||||
categories: ["clever"],
|
categories: ["clever"],
|
||||||
userID: userID1,
|
userID: userID1,
|
||||||
service: Service.YouTube,
|
service: Service.YouTube,
|
||||||
|
title: "title",
|
||||||
videoID
|
videoID
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -42,6 +43,7 @@ describe("postCasual", () => {
|
|||||||
categories: ["clever"],
|
categories: ["clever"],
|
||||||
userID: userID1,
|
userID: userID1,
|
||||||
service: Service.YouTube,
|
service: Service.YouTube,
|
||||||
|
title: "title",
|
||||||
videoID
|
videoID
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -59,6 +61,7 @@ describe("postCasual", () => {
|
|||||||
categories: ["clever"],
|
categories: ["clever"],
|
||||||
userID: userID2,
|
userID: userID2,
|
||||||
service: Service.YouTube,
|
service: Service.YouTube,
|
||||||
|
title: "title",
|
||||||
videoID
|
videoID
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -96,6 +99,7 @@ describe("postCasual", () => {
|
|||||||
downvote: true,
|
downvote: true,
|
||||||
userID: userID3,
|
userID: userID3,
|
||||||
service: Service.YouTube,
|
service: Service.YouTube,
|
||||||
|
title: "title",
|
||||||
videoID
|
videoID
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -117,6 +121,7 @@ describe("postCasual", () => {
|
|||||||
downvote: false,
|
downvote: false,
|
||||||
userID: userID3,
|
userID: userID3,
|
||||||
service: Service.YouTube,
|
service: Service.YouTube,
|
||||||
|
title: "title",
|
||||||
videoID
|
videoID
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -137,6 +142,7 @@ describe("postCasual", () => {
|
|||||||
categories: ["clever", "other"],
|
categories: ["clever", "other"],
|
||||||
userID: userID1,
|
userID: userID1,
|
||||||
service: Service.YouTube,
|
service: Service.YouTube,
|
||||||
|
title: "title",
|
||||||
videoID
|
videoID
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -157,6 +163,7 @@ describe("postCasual", () => {
|
|||||||
downvote: true,
|
downvote: true,
|
||||||
userID: userID1,
|
userID: userID1,
|
||||||
service: Service.YouTube,
|
service: Service.YouTube,
|
||||||
|
title: "title",
|
||||||
videoID
|
videoID
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -180,6 +187,7 @@ describe("postCasual", () => {
|
|||||||
categories: ["clever", "other"],
|
categories: ["clever", "other"],
|
||||||
userID: userID1,
|
userID: userID1,
|
||||||
service: Service.YouTube,
|
service: Service.YouTube,
|
||||||
|
title: "title",
|
||||||
videoID
|
videoID
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -199,6 +207,7 @@ describe("postCasual", () => {
|
|||||||
const res = await postCasual({
|
const res = await postCasual({
|
||||||
userID: userID1,
|
userID: userID1,
|
||||||
service: Service.YouTube,
|
service: Service.YouTube,
|
||||||
|
title: "title",
|
||||||
videoID,
|
videoID,
|
||||||
downvote: true
|
downvote: true
|
||||||
});
|
});
|
||||||
@@ -210,4 +219,33 @@ describe("postCasual", () => {
|
|||||||
assert.strictEqual(dbVotes.upvotes, 1);
|
assert.strictEqual(dbVotes.upvotes, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("submit multiple casual votes for different title", async () => {
|
||||||
|
const videoID = "postCasual2";
|
||||||
|
|
||||||
|
const res = await postCasual({
|
||||||
|
categories: ["clever", "funny"],
|
||||||
|
userID: userID2,
|
||||||
|
service: Service.YouTube,
|
||||||
|
title: "title 2",
|
||||||
|
videoID
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
const dbVotes = await queryCasualVotesByVideo(videoID, true, 1);
|
||||||
|
|
||||||
|
assert.strictEqual(dbVotes[0].category, "clever");
|
||||||
|
assert.strictEqual(dbVotes[0].upvotes, 1);
|
||||||
|
|
||||||
|
assert.strictEqual(dbVotes[1].category, "funny");
|
||||||
|
assert.strictEqual(dbVotes[1].upvotes, 1);
|
||||||
|
|
||||||
|
const dbVotesOriginal = await queryCasualVotesByVideo(videoID, true, 0);
|
||||||
|
|
||||||
|
assert.strictEqual(dbVotesOriginal[0].category, "clever");
|
||||||
|
assert.strictEqual(dbVotesOriginal[0].upvotes, 1);
|
||||||
|
|
||||||
|
assert.strictEqual(dbVotesOriginal[1].category, "other");
|
||||||
|
assert.strictEqual(dbVotesOriginal[1].upvotes, 1);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export const partialDeepEquals = (actual: Record<string, any>, expected: Record<
|
|||||||
// loop over key, value of expected
|
// loop over key, value of expected
|
||||||
for (const [key, value] of Object.entries(expected)) {
|
for (const [key, value] of Object.entries(expected)) {
|
||||||
// if value is object or array, recurse
|
// if value is object or array, recurse
|
||||||
if (Array.isArray(value) || typeof value === "object") {
|
if (Array.isArray(value) || (typeof value === "object" && value !== null)) {
|
||||||
if (!partialDeepEquals(actual?.[key], value, false)) {
|
if (!partialDeepEquals(actual?.[key], value, false)) {
|
||||||
if (print) printActualExpected(actual, expected, key);
|
if (print) printActualExpected(actual, expected, key);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user