diff --git a/src/routes/voteOnSponsorTime.ts b/src/routes/voteOnSponsorTime.ts index c0aaac0..4cb7690 100644 --- a/src/routes/voteOnSponsorTime.ts +++ b/src/routes/voteOnSponsorTime.ts @@ -176,51 +176,54 @@ async function categoryVote(UUID: SegmentUUID, userID: UserID, isVIP: boolean, i const timeSubmitted = Date.now(); const voteAmount = isVIP ? 500 : 1; + const ableToVote = isVIP || finalResponse.finalStatus === 200 || true; - // Add the vote - 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]); - } else { - // Add a db entry - await db.prepare('run', `insert into "categoryVotes" ("UUID", "category", "votes") values (?, ?, ?)`, [UUID, category, voteAmount]); - } + if (ableToVote) { + // Add the vote + 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]); + } else { + // Add a db entry + 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]); + // 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 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', `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]); + } - // See if the submissions category is ready to change - const currentCategoryInfo = await db.prepare("get", `select votes from "categoryVotes" where "UUID" = ? and category = ?`, [UUID, videoInfo.category]); + // See if the submissions category is ready to change + const currentCategoryInfo = await db.prepare("get", `select votes from "categoryVotes" where "UUID" = ? and category = ?`, [UUID, videoInfo.category]); - const submissionInfo = await db.prepare("get", `SELECT "userID", "timeSubmitted", "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, [UUID]); - const isSubmissionVIP = submissionInfo && await isUserVIP(submissionInfo.userID); - const startingVotes = isSubmissionVIP ? 10000 : 1; + const submissionInfo = await db.prepare("get", `SELECT "userID", "timeSubmitted", "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, [UUID]); + const isSubmissionVIP = submissionInfo && await isUserVIP(submissionInfo.userID); + const startingVotes = isSubmissionVIP ? 10000 : 1; - // Change this value from 1 in the future to make it harder to change categories - // Done this way without ORs incase the value is zero - const currentCategoryCount = (currentCategoryInfo === undefined || currentCategoryInfo === null) ? startingVotes : currentCategoryInfo.votes; + // Change this value from 1 in the future to make it harder to change categories + // Done this way without ORs incase the value is zero + const currentCategoryCount = (currentCategoryInfo === undefined || currentCategoryInfo === null) ? startingVotes : currentCategoryInfo.votes; - // Add submission as vote - if (!currentCategoryInfo && submissionInfo) { - await db.prepare("run", `insert into "categoryVotes" ("UUID", "category", "votes") values (?, ?, ?)`, [UUID, videoInfo.category, currentCategoryCount]); + // Add submission as vote + if (!currentCategoryInfo && submissionInfo) { + await db.prepare("run", `insert into "categoryVotes" ("UUID", "category", "votes") values (?, ?, ?)`, [UUID, videoInfo.category, currentCategoryCount]); - await privateDB.prepare("run", `insert into "categoryVotes" ("UUID", "userID", "hashedIP", "category", "timeSubmitted") values (?, ?, ?, ?, ?)`, [UUID, submissionInfo.userID, "unknown", videoInfo.category, submissionInfo.timeSubmitted]); - } + await privateDB.prepare("run", `insert into "categoryVotes" ("UUID", "userID", "hashedIP", "category", "timeSubmitted") values (?, ?, ?, ?, ?)`, [UUID, submissionInfo.userID, "unknown", videoInfo.category, submissionInfo.timeSubmitted]); + } - const nextCategoryCount = (nextCategoryInfo?.votes || 0) + voteAmount; + const nextCategoryCount = (nextCategoryInfo?.votes || 0) + voteAmount; - //TODO: In the future, raise this number from zero to make it harder to change categories - // 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]); + //TODO: In the future, raise this number from zero to make it harder to change categories + // 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]); + } } clearRedisCache(videoInfo); @@ -283,13 +286,19 @@ export async function voteOnSponsorTime(req: Request, res: Response) { return categoryVote(UUID, nonAnonUserID, isVIP, isOwnSubmission, category, hashedIP, finalResponse, res); } - if (type == 1 && !isVIP && !isOwnSubmission) { + if (type !== undefined && !isVIP && !isOwnSubmission) { // Check if upvoting hidden segment const voteInfo = await db.prepare('get', `SELECT votes FROM "sponsorTimes" WHERE "UUID" = ?`, [UUID]); if (voteInfo && voteInfo.votes <= -2) { - res.status(403).send("Not allowed to upvote segment with too many downvotes unless you are VIP."); - return; + if (type == 1) { + res.status(403).send("Not allowed to upvote segment with too many downvotes unless you are VIP."); + return; + } else if (type == 0) { + // Already downvoted enough, ignore + res.status(200).send(); + return; + } } } @@ -374,7 +383,8 @@ export async function voteOnSponsorTime(req: Request, res: Response) { const ableToVote = isVIP || ((await db.prepare("get", `SELECT "userID" FROM "sponsorTimes" WHERE "userID" = ?`, [nonAnonUserID])) !== undefined && (await privateDB.prepare("get", `SELECT "userID" FROM "shadowBannedUsers" WHERE "userID" = ?`, [nonAnonUserID])) === undefined - && (await privateDB.prepare("get", `SELECT "UUID" FROM "votes" WHERE "UUID" = ? AND "hashedIP" = ? AND "userID" != ?`, [UUID, hashedIP, userID])) === undefined); + && (await privateDB.prepare("get", `SELECT "UUID" FROM "votes" WHERE "UUID" = ? AND "hashedIP" = ? AND "userID" != ?`, [UUID, hashedIP, userID])) === undefined) + && finalResponse.finalStatus === 200; if (ableToVote) { //update the votes table diff --git a/test/cases/voteOnSponsorTime.ts b/test/cases/voteOnSponsorTime.ts index 47a1f19..86c3233 100644 --- a/test/cases/voteOnSponsorTime.ts +++ b/test/cases/voteOnSponsorTime.ts @@ -368,10 +368,25 @@ describe('voteOnSponsorTime', () => { fetch(getbaseURL() + "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-5&type=1") .then(async res => { - if (res.status === 403) { + let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]); + if (res.status === 403 && row.votes === -3) { done(); } else { - done("Status code was " + res.status + " instead of 403"); + done("Status code was " + res.status + ", row is " + JSON.stringify(row)); + } + }) + .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 => { + let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]); + if (res.status === 200 && row.votes === -3) { + done(); + } else { + done("Status code was " + res.status + ", row is " + JSON.stringify(row)); } }) .catch(err => done(err)); @@ -410,12 +425,13 @@ describe('voteOnSponsorTime', () => { it('Non-VIP should not be able to downvote on a segment with no-segments category', (done: Done) => { fetch(getbaseURL() - + "/api/voteOnSponsorTime?userID=no-segments-voter&UUID=no-sponsor-segments-uuid-0&type=0") + + "/api/voteOnSponsorTime?userID=randomID&UUID=no-sponsor-segments-uuid-0&type=0") .then(async res => { - if (res.status === 403) { + let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["no-sponsor-segments-uuid-0"]); + if (res.status === 403 && row.votes === 2) { done(); } else { - done("Status code was " + res.status + " instead of 403"); + done("Status code was " + res.status + " instead of 403, row was " + JSON.stringify(row)); } }) .catch(err => done(err)); @@ -423,12 +439,13 @@ describe('voteOnSponsorTime', () => { it('Non-VIP should be able to upvote on a segment with no-segments category', (done: Done) => { fetch(getbaseURL() - + "/api/voteOnSponsorTime?userID=no-segments-voter&UUID=no-sponsor-segments-uuid-0&type=1") + + "/api/voteOnSponsorTime?userID=randomID&UUID=no-sponsor-segments-uuid-0&type=1") .then(async res => { - if (res.status === 200) { + let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["no-sponsor-segments-uuid-0"]); + if (res.status === 200 && row.votes === 3) { done(); } else { - done("Status code was " + res.status + " instead of 200"); + done("Status code was " + res.status + " instead of 403, row was " + JSON.stringify(row)); } }) .catch(err => done(err)); @@ -436,12 +453,13 @@ describe('voteOnSponsorTime', () => { it('Non-VIP should not be able to category vote on a segment with no-segments category', (done: Done) => { fetch(getbaseURL() - + "/api/voteOnSponsorTime?userID=no-segments-voter&UUID=no-sponsor-segments-uuid-0&category=outro") + + "/api/voteOnSponsorTime?userID=randomID&UUID=no-sponsor-segments-uuid-0&category=outro") .then(async res => { - if (res.status === 403) { + let row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["no-sponsor-segments-uuid-0"]); + if (res.status === 403 && row.category === "sponsor") { done(); } else { - done("Status code was " + res.status + " instead of 403"); + done("Status code was " + res.status + " instead of 403, row was " + JSON.stringify(row)); } }) .catch(err => done(err));