From 2773c5f500e506b1fc0111d16b5c4565b7809211 Mon Sep 17 00:00:00 2001 From: Haidang666 Date: Wed, 21 Jul 2021 16:16:58 +0700 Subject: [PATCH 1/3] Update: most upvoted segments on locked videos as locked submissions --- src/utils/reputation.ts | 76 +++++++++++++++++++------------- test/cases/reputation.ts | 95 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 136 insertions(+), 35 deletions(-) diff --git a/src/utils/reputation.ts b/src/utils/reputation.ts index 5d06517..61233e8 100644 --- a/src/utils/reputation.ts +++ b/src/utils/reputation.ts @@ -10,7 +10,8 @@ interface ReputationDBResult { votedSum: number, lockedSum: number, semiOldUpvotedSubmissions: number, - oldUpvotedSubmissions: number + oldUpvotedSubmissions: number, + mostUpvotedInLockedVideoSum: number } export async function getReputation(userID: UserID): Promise { @@ -28,43 +29,58 @@ export async function getReputation(userID: UserID): Promise { SUM(CASE WHEN "timeSubmitted" > 1596240000000 THEN "votes" ELSE 0 END) AS "votedSum", SUM(locked) AS "lockedSum", SUM(CASE WHEN "timeSubmitted" < ? AND "timeSubmitted" > 1596240000000 AND "votes" > 0 THEN 1 ELSE 0 END) AS "semiOldUpvotedSubmissions", - SUM(CASE WHEN "timeSubmitted" < ? AND "timeSubmitted" > 1596240000000 AND "votes" > 0 THEN 1 ELSE 0 END) AS "oldUpvotedSubmissions" + SUM(CASE WHEN "timeSubmitted" < ? AND "timeSubmitted" > 1596240000000 AND "votes" > 0 THEN 1 ELSE 0 END) AS "oldUpvotedSubmissions", + SUM(CASE WHEN "votes" > 0 + AND NOT EXISTS ( + SELECT * FROM "sponsorTimes" as c + WHERE c."videoID" = "a"."videoID" AND c."votes" > "a"."votes" LIMIT 1) + AND EXISTS ( + SELECT * FROM "lockCategories" as l + WHERE l."videoID" = "a"."videoID" AND l."category" = "a"."category" LIMIT 1) + THEN 1 ELSE 0 END) AS "mostUpvotedInLockedVideoSum" FROM "sponsorTimes" as "a" WHERE "userID" = ?`, [userID, weekAgo, pastDate, userID]) as Promise; const result = await QueryCacher.get(fetchFromDB, reputationKey(userID)); - // Grace period - if (result.totalSubmissions < 5) { - return 0; - } - - const downvoteRatio = result.downvotedSubmissions / result.totalSubmissions; - if (downvoteRatio > 0.3) { - return convertRange(Math.min(downvoteRatio, 0.7), 0.3, 0.7, -0.5, -2.5); - } - - const nonSelfDownvoteRatio = result.nonSelfDownvotedSubmissions / result.totalSubmissions; - if (nonSelfDownvoteRatio > 0.05) { - return convertRange(Math.min(nonSelfDownvoteRatio, 0.4), 0.05, 0.4, -0.5, -2.5); - } - - if (result.votedSum < 5) { - return 0; - } - - if (result.oldUpvotedSubmissions < 3) { - if (result.semiOldUpvotedSubmissions > 3) { - return convertRange(Math.min(result.votedSum, 150), 5, 150, 0, 2) + convertRange(Math.min(result.lockedSum ?? 0, 50), 0, 50, 0, 5); - } else { - return 0; - } - } - - return convertRange(Math.min(result.votedSum, 150), 5, 150, 0, 7) + convertRange(Math.min(result.lockedSum ?? 0, 50), 0, 50, 0, 20); + return calculateFromMetrics(result); } +// convert a number from one range to another. function convertRange(value: number, currentMin: number, currentMax: number, targetMin: number, targetMax: number): number { const currentRange = currentMax - currentMin; const targetRange = targetMax - targetMin; return ((value - currentMin) / currentRange) * targetRange + targetMin; } + +export function calculateFromMetrics(metrics: ReputationDBResult): number { + // Grace period + if (metrics.totalSubmissions < 5) { + return 0; + } + + const downvoteRatio = metrics.downvotedSubmissions / metrics.totalSubmissions; + if (downvoteRatio > 0.3) { + return convertRange(Math.min(downvoteRatio, 0.7), 0.3, 0.7, -0.5, -2.5); + } + + const nonSelfDownvoteRatio = metrics.nonSelfDownvotedSubmissions / metrics.totalSubmissions; + if (nonSelfDownvoteRatio > 0.05) { + return convertRange(Math.min(nonSelfDownvoteRatio, 0.4), 0.05, 0.4, -0.5, -2.5); + } + + if (metrics.votedSum < 5) { + return 0; + } + + if (metrics.oldUpvotedSubmissions < 3) { + if (metrics.semiOldUpvotedSubmissions > 3) { + return convertRange(Math.min(metrics.votedSum, 150), 5, 150, 0, 2) + + convertRange(Math.min((metrics.lockedSum ?? 0) + (metrics.mostUpvotedInLockedVideoSum ?? 0), 50), 0, 50, 0, 5); + } else { + return 0; + } + } + + return convertRange(Math.min(metrics.votedSum, 150), 5, 150, 0, 7) + + convertRange(Math.min((metrics.lockedSum ?? 0) + (metrics.mostUpvotedInLockedVideoSum ?? 0), 50), 0, 50, 0, 20); +} \ No newline at end of file diff --git a/test/cases/reputation.ts b/test/cases/reputation.ts index 8f09a41..dd41d29 100644 --- a/test/cases/reputation.ts +++ b/test/cases/reputation.ts @@ -2,7 +2,7 @@ import assert from "assert"; import { db } from "../../src/databases/databases"; import { UserID } from "../../src/types/user.model"; import { getHash } from "../../src/utils/getHash"; -import { getReputation } from "../../src/utils/reputation"; +import { getReputation, calculateFromMetrics } from "../../src/utils/reputation"; const userIDLowSubmissions = "reputation-lowsubmissions" as UserID; const userIDHighDownvotes = "reputation-highdownvotes" as UserID; @@ -12,11 +12,13 @@ const userIDLowSum = "reputation-lowsum" as UserID; const userIDHighRepBeforeManualVote = "reputation-oldhighrep" as UserID; const userIDHighRep = "reputation-highrep" as UserID; const userIDHighRepAndLocked = "reputation-highlockedrep" as UserID; +const userIDHaveMostUpvotedInLockedVideo = "reputation-mostupvotedaslocked" as UserID; describe("reputation", () => { before(async function() { this.timeout(5000); // this preparation takes longer then usual const videoID = "reputation-videoID"; + const videoID2 = "reputation-videoID-2"; const sponsorTimesInsertQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "service", "videoDuration", "hidden", "shadowHidden", "hashedVideoID") VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'; await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-0-uuid-0", getHash(userIDLowSubmissions), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]); @@ -87,6 +89,28 @@ describe("reputation", () => { await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-6-uuid-5", getHash(userIDHighRepAndLocked), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-6-uuid-6", getHash(userIDHighRepAndLocked), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-6-uuid-7", getHash(userIDHighRepAndLocked), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]); + + //Record has most upvoted + await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 5, 0, "reputation-7-uuid-0", getHash(userIDHaveMostUpvotedInLockedVideo), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]); + await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 101, 0, "reputation-7-uuid-1", getHash(userIDHaveMostUpvotedInLockedVideo), 1606240000000, 50, "intro", "YouTube", 100, 0, 0, getHash(videoID, 1)]); + await db.prepare("run", sponsorTimesInsertQuery, [videoID2, 1, 11, 5, 0, "reputation-7-uuid-8", getHash(userIDHaveMostUpvotedInLockedVideo), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID2, 1)]); + await db.prepare("run", sponsorTimesInsertQuery, [videoID2, 1, 11, 0, 0, "reputation-7-uuid-9", getHash(userIDHaveMostUpvotedInLockedVideo), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID2, 1)]); + // other segments + await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-7-uuid-2", getHash(userIDHaveMostUpvotedInLockedVideo), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]); + await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-7-uuid-3", getHash(userIDHaveMostUpvotedInLockedVideo), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]); + await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-7-uuid-4", getHash(userIDHaveMostUpvotedInLockedVideo), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]); + await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-7-uuid-5", getHash(userIDHaveMostUpvotedInLockedVideo), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]); + await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-7-uuid-6", getHash(userIDHaveMostUpvotedInLockedVideo), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]); + await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-7-uuid-7", getHash(userIDHaveMostUpvotedInLockedVideo), 1606240000000, 50, "sponsor", "YouTube", 100, 0, 0, getHash(videoID, 1)]); + + // lock video + const insertVipUserQuery = 'INSERT INTO "vipUsers" ("userID") VALUES (?)'; + await db.prepare("run", insertVipUserQuery, [getHash("VIPUser-getLockCategories")]); + + const insertLockCategoryQuery = 'INSERT INTO "lockCategories" ("userID", "videoID", "category", "hashedVideoID") VALUES (?, ?, ?, ?)'; + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), videoID, "sponsor", getHash(videoID, 1)]); + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), videoID, "intro", getHash(videoID, 1)]); + await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), videoID2, "sponsor", getHash(videoID2, 1)]); }); it("user in grace period", async () => { @@ -94,11 +118,34 @@ describe("reputation", () => { }); it("user with high downvote ratio", async () => { - assert.strictEqual(await getReputation(getHash(userIDHighDownvotes)), -2.125); + // -2.125 + const metrics = { + totalSubmissions: 8, + downvotedSubmissions: 5, + nonSelfDownvotedSubmissions: 0, + votedSum: -7, + lockedSum: 0, + semiOldUpvotedSubmissions: 1, + oldUpvotedSubmissions: 1, + mostUpvotedInLockedVideoSum: 0 + }; + + assert.strictEqual(await getReputation(getHash(userIDHighDownvotes)), calculateFromMetrics(metrics)); }); it("user with high non self downvote ratio", async () => { - assert.strictEqual(await getReputation(getHash(userIDHighNonSelfDownvotes)), -1.6428571428571428); + // -1.6428571428571428 + const metrics = { + totalSubmissions: 8, + downvotedSubmissions: 2, + nonSelfDownvotedSubmissions: 2, + votedSum: -1, + lockedSum: 0, + semiOldUpvotedSubmissions: 1, + oldUpvotedSubmissions: 1, + mostUpvotedInLockedVideoSum: 0 + }; + assert.strictEqual(await getReputation(getHash(userIDHighNonSelfDownvotes)), calculateFromMetrics(metrics)); }); it("user with mostly new submissions", async () => { @@ -114,11 +161,49 @@ describe("reputation", () => { }); it("user with high reputation", async () => { - assert.strictEqual(await getReputation(getHash(userIDHighRep)), 0.19310344827586207); + // 0.19310344827586207 + const metrics = { + totalSubmissions: 8, + downvotedSubmissions: 1, + nonSelfDownvotedSubmissions: 0, + votedSum: 9, + lockedSum: 0, + semiOldUpvotedSubmissions: 5, + oldUpvotedSubmissions: 5, + mostUpvotedInLockedVideoSum: 0 + }; + + assert.strictEqual(await getReputation(getHash(userIDHighRep)), calculateFromMetrics(metrics)); }); it("user with high reputation and locked segments", async () => { - assert.strictEqual(await getReputation(getHash(userIDHighRepAndLocked)), 1.793103448275862); + // 1.793103448275862 + const metrics = { + totalSubmissions: 8, + downvotedSubmissions: 1, + nonSelfDownvotedSubmissions: 0, + votedSum: 9, + lockedSum: 4, + semiOldUpvotedSubmissions: 5, + oldUpvotedSubmissions: 5, + mostUpvotedInLockedVideoSum: 0 + }; + assert.strictEqual(await getReputation(getHash(userIDHighRepAndLocked)), calculateFromMetrics(metrics)); + }); + + it("user with most upvoted segments in locked video", async () => { + // 6.158620689655172 + const metrics = { + totalSubmissions: 10, + downvotedSubmissions: 1, + nonSelfDownvotedSubmissions: 0, + votedSum: 116, + lockedSum: 0, + semiOldUpvotedSubmissions: 6, + oldUpvotedSubmissions: 6, + mostUpvotedInLockedVideoSum: 2 + }; + assert.strictEqual(await getReputation(getHash(userIDHaveMostUpvotedInLockedVideo)), calculateFromMetrics(metrics)); }); }); From 0eb298a9438ad9cfe7989e82cbe6e66f7a3a1d9b Mon Sep 17 00:00:00 2001 From: Haidang666 Date: Sat, 24 Jul 2021 15:09:30 +0700 Subject: [PATCH 2/3] Update query and test --- src/utils/reputation.ts | 8 +++++--- test/cases/reputation.ts | 19 +++++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/utils/reputation.ts b/src/utils/reputation.ts index 61233e8..e1d5e40 100644 --- a/src/utils/reputation.ts +++ b/src/utils/reputation.ts @@ -33,7 +33,9 @@ export async function getReputation(userID: UserID): Promise { SUM(CASE WHEN "votes" > 0 AND NOT EXISTS ( SELECT * FROM "sponsorTimes" as c - WHERE c."videoID" = "a"."videoID" AND c."votes" > "a"."votes" LIMIT 1) + WHERE (c."votes" > "a"."votes" OR c."locked" > "a"."locked") AND + c."videoID" = "a"."videoID" AND + c."category" = "a"."category" LIMIT 1) AND EXISTS ( SELECT * FROM "lockCategories" as l WHERE l."videoID" = "a"."videoID" AND l."category" = "a"."category" LIMIT 1) @@ -42,7 +44,7 @@ export async function getReputation(userID: UserID): Promise { const result = await QueryCacher.get(fetchFromDB, reputationKey(userID)); - return calculateFromMetrics(result); + return calculateReputationFromMetrics(result); } // convert a number from one range to another. @@ -52,7 +54,7 @@ function convertRange(value: number, currentMin: number, currentMax: number, tar return ((value - currentMin) / currentRange) * targetRange + targetMin; } -export function calculateFromMetrics(metrics: ReputationDBResult): number { +export function calculateReputationFromMetrics(metrics: ReputationDBResult): number { // Grace period if (metrics.totalSubmissions < 5) { return 0; diff --git a/test/cases/reputation.ts b/test/cases/reputation.ts index dd41d29..4b33e59 100644 --- a/test/cases/reputation.ts +++ b/test/cases/reputation.ts @@ -2,7 +2,7 @@ import assert from "assert"; import { db } from "../../src/databases/databases"; import { UserID } from "../../src/types/user.model"; import { getHash } from "../../src/utils/getHash"; -import { getReputation, calculateFromMetrics } from "../../src/utils/reputation"; +import { getReputation, calculateReputationFromMetrics } from "../../src/utils/reputation"; const userIDLowSubmissions = "reputation-lowsubmissions" as UserID; const userIDHighDownvotes = "reputation-highdownvotes" as UserID; @@ -130,7 +130,7 @@ describe("reputation", () => { mostUpvotedInLockedVideoSum: 0 }; - assert.strictEqual(await getReputation(getHash(userIDHighDownvotes)), calculateFromMetrics(metrics)); + assert.strictEqual(await getReputation(getHash(userIDHighDownvotes)), calculateReputationFromMetrics(metrics)); }); it("user with high non self downvote ratio", async () => { @@ -145,7 +145,7 @@ describe("reputation", () => { oldUpvotedSubmissions: 1, mostUpvotedInLockedVideoSum: 0 }; - assert.strictEqual(await getReputation(getHash(userIDHighNonSelfDownvotes)), calculateFromMetrics(metrics)); + assert.strictEqual(await getReputation(getHash(userIDHighNonSelfDownvotes)), calculateReputationFromMetrics(metrics)); }); it("user with mostly new submissions", async () => { @@ -161,7 +161,6 @@ describe("reputation", () => { }); it("user with high reputation", async () => { - // 0.19310344827586207 const metrics = { totalSubmissions: 8, downvotedSubmissions: 1, @@ -172,12 +171,11 @@ describe("reputation", () => { oldUpvotedSubmissions: 5, mostUpvotedInLockedVideoSum: 0 }; - - assert.strictEqual(await getReputation(getHash(userIDHighRep)), calculateFromMetrics(metrics)); + assert.strictEqual(await getReputation(getHash(userIDHighRep)), calculateReputationFromMetrics(metrics)); + assert.strictEqual(await getReputation(getHash(userIDHighRep)), 0.19310344827586207); }); it("user with high reputation and locked segments", async () => { - // 1.793103448275862 const metrics = { totalSubmissions: 8, downvotedSubmissions: 1, @@ -188,11 +186,11 @@ describe("reputation", () => { oldUpvotedSubmissions: 5, mostUpvotedInLockedVideoSum: 0 }; - assert.strictEqual(await getReputation(getHash(userIDHighRepAndLocked)), calculateFromMetrics(metrics)); + assert.strictEqual(await getReputation(getHash(userIDHighRepAndLocked)), calculateReputationFromMetrics(metrics)); + assert.strictEqual(await getReputation(getHash(userIDHighRepAndLocked)), 1.793103448275862); }); it("user with most upvoted segments in locked video", async () => { - // 6.158620689655172 const metrics = { totalSubmissions: 10, downvotedSubmissions: 1, @@ -203,7 +201,8 @@ describe("reputation", () => { oldUpvotedSubmissions: 6, mostUpvotedInLockedVideoSum: 2 }; - assert.strictEqual(await getReputation(getHash(userIDHaveMostUpvotedInLockedVideo)), calculateFromMetrics(metrics)); + assert.strictEqual(await getReputation(getHash(userIDHaveMostUpvotedInLockedVideo)), calculateReputationFromMetrics(metrics)); + assert.strictEqual(await getReputation(getHash(userIDHaveMostUpvotedInLockedVideo)), 6.158620689655172); }); }); From 37ea8adb73ff6d1fce4317e7c3b8f0f8bff4dc0b Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Mon, 26 Jul 2021 23:46:26 -0400 Subject: [PATCH 3/3] assert fixed value --- test/cases/reputation.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/cases/reputation.ts b/test/cases/reputation.ts index 4b33e59..3bd11ca 100644 --- a/test/cases/reputation.ts +++ b/test/cases/reputation.ts @@ -118,7 +118,6 @@ describe("reputation", () => { }); it("user with high downvote ratio", async () => { - // -2.125 const metrics = { totalSubmissions: 8, downvotedSubmissions: 5, @@ -131,10 +130,10 @@ describe("reputation", () => { }; assert.strictEqual(await getReputation(getHash(userIDHighDownvotes)), calculateReputationFromMetrics(metrics)); + assert.strictEqual(await getReputation(getHash(userIDHighDownvotes)), -2.125); }); it("user with high non self downvote ratio", async () => { - // -1.6428571428571428 const metrics = { totalSubmissions: 8, downvotedSubmissions: 2, @@ -146,6 +145,7 @@ describe("reputation", () => { mostUpvotedInLockedVideoSum: 0 }; assert.strictEqual(await getReputation(getHash(userIDHighNonSelfDownvotes)), calculateReputationFromMetrics(metrics)); + assert.strictEqual(await getReputation(getHash(userIDHighNonSelfDownvotes)), -1.6428571428571428); }); it("user with mostly new submissions", async () => {