From b68cfc2aa4227d4a7e2ed2e657a5fd129bb96e7f Mon Sep 17 00:00:00 2001
From: "Kalle (Sendou)" <38327916+Sendouc@users.noreply.github.com>
Date: Mon, 19 Jul 2021 19:50:11 +0300
Subject: [PATCH] Make ending plus voting a script
---
package.json | 1 +
pages/admin.tsx | 18 ---
prisma/scripts/endPlusVoting.ts | 208 ++++++++++++++++++++++++++++++++
services/plus.ts | 191 -----------------------------
4 files changed, 209 insertions(+), 209 deletions(-)
create mode 100644 prisma/scripts/endPlusVoting.ts
diff --git a/package.json b/package.json
index cbae25f7b..d8d56fdc7 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"migrate:reset": "prisma migrate reset",
"gen": "npx prisma generate",
"prebuild": "ts-node prisma/scripts/preBuild.ts",
+ "results": "ts-node prisma/scripts/endPlusVoting.ts",
"mongo": "ts-node prisma/scripts/dataFromMongo.ts",
"top500": "ts-node prisma/scripts/top500jsons.ts",
"league": "cross-env NODE_OPTIONS=--max-old-space-size=8192 ts-node prisma/scripts/leagueJsons.ts",
diff --git a/pages/admin.tsx b/pages/admin.tsx
index 003009b47..167bcb790 100644
--- a/pages/admin.tsx
+++ b/pages/admin.tsx
@@ -5,7 +5,6 @@ import { useState } from "react";
import { ADMIN_DISCORD_ID } from "utils/constants";
import { getToastOptions } from "utils/objects";
import { sendData } from "utils/postData";
-import { trpc } from "utils/trpc";
const AdminPage = () => {
const toast = useToast();
@@ -15,16 +14,6 @@ const AdminPage = () => {
switchAccountId: "",
discordId: "",
});
- const endVoting = trpc.useMutation("plus.endVoting", {
- onSuccess: () => console.log("success"),
- onError: (e) => console.error(e.message),
- });
-
- const handleEndVoting = () => {
- if (!window.confirm("End voting?")) return;
-
- endVoting.mutate(null);
- };
if (!user || user.discordId !== ADMIN_DISCORD_ID) return null;
@@ -60,13 +49,6 @@ const AdminPage = () => {
- End voting
-
>
);
diff --git a/prisma/scripts/endPlusVoting.ts b/prisma/scripts/endPlusVoting.ts
new file mode 100644
index 000000000..8c8349721
--- /dev/null
+++ b/prisma/scripts/endPlusVoting.ts
@@ -0,0 +1,208 @@
+import { Prisma } from "@prisma/client";
+import { getPercentageFromCounts } from "../../utils/plus";
+import { VOUCH_CRITERIA } from "../../utils/constants";
+import prisma from "../client";
+
+// Include Prisma's .env file as well, so we can fetch the DATABASE_URL
+require("dotenv").config({ path: "prisma/.env" });
+
+const main = async () => {
+ const [ballots, statuses, suggestions] = await Promise.all([
+ prisma.plusBallot.findMany({
+ where: { isStale: false },
+ include: { voterUser: { include: { plusStatus: true } } },
+ }),
+ prisma.plusStatus.findMany({}),
+ prisma.plusSuggestion.findMany({}),
+ ]);
+
+ const month = new Date().getMonth() + 1;
+ const year = new Date().getFullYear();
+
+ const summariesByTier = [
+ new Map(),
+ new Map(),
+ new Map(),
+ new Map(),
+ ];
+
+ for (const ballot of ballots) {
+ if (!summariesByTier[ballot.tier].has(ballot.votedId)) {
+ summariesByTier[ballot.tier].set(ballot.votedId, {
+ month,
+ tier: ballot.tier,
+ userId: ballot.votedId,
+ wasSuggested: suggestions.some(
+ (suggestion) =>
+ suggestion.tier === ballot.tier &&
+ suggestion.suggestedId === ballot.votedId
+ ),
+ wasVouched: statuses.some(
+ (status) =>
+ status.vouchTier === ballot.tier && status.userId === ballot.votedId
+ ),
+ year,
+ countsEU: [0, 0, 0, 0],
+ countsNA: [0, 0, 0, 0],
+ });
+ }
+
+ const summary = summariesByTier[ballot.tier].get(ballot.votedId);
+ if (!summary) throw Error("unexpected no summary");
+
+ const isNA = ballot.voterUser.plusStatus!.region === "NA";
+
+ const scoreToIndex = { "-2": 0, "-1": 1, "1": 2, "2": 3 } as const;
+ const arrToChange = (isNA ? summary.countsNA : summary.countsEU) as [
+ number,
+ number,
+ number,
+ number
+ ];
+ const key = ("" + ballot.score) as keyof typeof scoreToIndex;
+ arrToChange[scoreToIndex[key]]++;
+ }
+
+ const members: [number[], number[], number[], number[]] = [[], [], [], []];
+ const canVouch: [null, number[], number[], number[]] = [null, [], [], []];
+ const vouchRevoked: number[] = [];
+
+ const alreadyMember = new Set();
+
+ for (const [i, summaries] of [
+ Array.from(summariesByTier[1].values()),
+ Array.from(summariesByTier[2].values()),
+ Array.from(summariesByTier[3].values()),
+ ].entries()) {
+ const tier = i + 1;
+
+ for (const summary of summaries) {
+ const plusStatus = statuses.find(
+ (status) => status.userId === summary.userId
+ );
+ if (!plusStatus) {
+ throw Error("unexpected no plusStatus in loop");
+ }
+
+ const passedVoting =
+ getPercentageFromCounts(
+ summary.countsNA as number[],
+ summary.countsEU as number[],
+ plusStatus.region
+ ) >= 50;
+
+ if (passedVoting) {
+ if (!alreadyMember.has(summary.userId)) {
+ members[tier].push(summary.userId);
+ alreadyMember.add(summary.userId);
+ }
+ } else {
+ // get put to a lower tier only if not suggestion or vouch
+ if (
+ !summary.wasSuggested &&
+ !summary.wasVouched &&
+ !alreadyMember.has(summary.userId)
+ ) {
+ const tierToDemoteTo = tier === 3 ? 0 : tier + 1;
+ members[tierToDemoteTo].push(summary.userId);
+ alreadyMember.add(summary.userId);
+ }
+
+ // if they were vouched time for whoever vouched them to have their perms revoked for 6 months
+ if (plusStatus.vouchTier === tier) {
+ if (!plusStatus.voucherId) {
+ throw Error("unexpexted no voucher id");
+ }
+ vouchRevoked.push(plusStatus.voucherId);
+ }
+
+ continue;
+ }
+
+ const gotVouchPermits =
+ getPercentageFromCounts(
+ summary.countsNA as number[],
+ summary.countsEU as number[],
+ plusStatus.region
+ ) >= VOUCH_CRITERIA[tier];
+
+ if (gotVouchPermits) {
+ canVouch[tier]!.push(summary.userId);
+ }
+ }
+ }
+
+ console.log("deleting stale plus ballots and setting can vouch for null");
+
+ await Promise.all([
+ prisma.plusBallot.deleteMany({ where: { isStale: true } }),
+ prisma.plusStatus.updateMany({
+ data: { canVouchFor: null },
+ }),
+ ]);
+
+ const now = new Date();
+
+ console.log("doing a lot of stuff");
+
+ await prisma.$transaction([
+ prisma.plusBallot.updateMany({ data: { isStale: true } }),
+ prisma.plusSuggestion.deleteMany({}),
+ prisma.plusVotingSummary.createMany({
+ data: [
+ ...Array.from(summariesByTier[1].values()),
+ ...Array.from(summariesByTier[2].values()),
+ ...Array.from(summariesByTier[3].values()),
+ ],
+ }),
+ prisma.plusStatus.updateMany({
+ data: { vouchTier: null, voucherId: null },
+ }),
+ prisma.plusStatus.updateMany({
+ where: { canVouchAgainAfter: { lt: new Date() } },
+ data: { canVouchAgainAfter: null },
+ }),
+ prisma.plusStatus.updateMany({
+ where: { userId: { in: members[0] } },
+ data: { membershipTier: null },
+ }),
+ prisma.plusStatus.updateMany({
+ where: { userId: { in: members[1] } },
+ data: { membershipTier: 1 },
+ }),
+ prisma.plusStatus.updateMany({
+ where: { userId: { in: members[2] } },
+ data: { membershipTier: 2 },
+ }),
+ prisma.plusStatus.updateMany({
+ where: { userId: { in: members[3] } },
+ data: { membershipTier: 3 },
+ }),
+ prisma.plusStatus.updateMany({
+ where: { userId: { in: canVouch[1] } },
+ data: { canVouchFor: 1 },
+ }),
+ prisma.plusStatus.updateMany({
+ where: { userId: { in: canVouch[2] } },
+ data: { canVouchFor: 2 },
+ }),
+ prisma.plusStatus.updateMany({
+ where: { userId: { in: canVouch[3] } },
+ data: { canVouchFor: 3 },
+ }),
+ prisma.plusStatus.updateMany({
+ where: { userId: { in: vouchRevoked } },
+ data: {
+ canVouchAgainAfter: new Date(now.getFullYear(), now.getMonth() + 5, 1),
+ },
+ }),
+ ]);
+
+ console.log("done with a lot of stuff");
+};
+
+main()
+ .catch((e) => console.error(e))
+ .finally(async () => {
+ await prisma.$disconnect();
+ });
diff --git a/services/plus.ts b/services/plus.ts
index 8d9dd9f19..d22542a8e 100644
--- a/services/plus.ts
+++ b/services/plus.ts
@@ -2,7 +2,6 @@ import { PlusRegion, Prisma } from "@prisma/client";
import { httpError } from "@trpc/server";
import prisma from "prisma/client";
import { shuffleArray } from "utils/arrays";
-import { ADMIN_ID, VOUCH_CRITERIA } from "utils/constants";
import { getPercentageFromCounts, getVotingRange } from "utils/plus";
import { userBasicSelection } from "utils/prisma";
import { suggestionFullSchema } from "utils/validators/suggestion";
@@ -603,195 +602,6 @@ const editVote = async ({
});
};
-const endVoting = async (userId: number) => {
- if (userId !== ADMIN_ID) throw httpError.badRequest("not admin");
-
- const [ballots, statuses, suggestions] = await Promise.all([
- prisma.plusBallot.findMany({
- where: { isStale: false },
- include: { voterUser: { include: { plusStatus: true } } },
- }),
- prisma.plusStatus.findMany({}),
- prisma.plusSuggestion.findMany({}),
- ]);
-
- const month = new Date().getMonth() + 1;
- const year = new Date().getFullYear();
-
- const summariesByTier = [
- new Map(),
- new Map(),
- new Map(),
- new Map(),
- ];
-
- for (const ballot of ballots) {
- if (!summariesByTier[ballot.tier].has(ballot.votedId)) {
- summariesByTier[ballot.tier].set(ballot.votedId, {
- month,
- tier: ballot.tier,
- userId: ballot.votedId,
- wasSuggested: suggestions.some(
- (suggestion) =>
- suggestion.tier === ballot.tier &&
- suggestion.suggestedId === ballot.votedId
- ),
- wasVouched: statuses.some(
- (status) =>
- status.vouchTier === ballot.tier && status.userId === ballot.votedId
- ),
- year,
- countsEU: [0, 0, 0, 0],
- countsNA: [0, 0, 0, 0],
- });
- }
-
- const summary = summariesByTier[ballot.tier].get(ballot.votedId);
- if (!summary) throw httpError.badRequest("unexpected no summary");
-
- const isNA = ballot.voterUser.plusStatus!.region === "NA";
-
- const scoreToIndex = { "-2": 0, "-1": 1, "1": 2, "2": 3 } as const;
- const arrToChange = (isNA ? summary.countsNA : summary.countsEU) as [
- number,
- number,
- number,
- number
- ];
- const key = ("" + ballot.score) as keyof typeof scoreToIndex;
- arrToChange[scoreToIndex[key]]++;
- }
-
- const members: [number[], number[], number[], number[]] = [[], [], [], []];
- const canVouch: [null, number[], number[], number[]] = [null, [], [], []];
- const vouchRevoked: number[] = [];
-
- const alreadyMember = new Set();
-
- for (const [i, summaries] of [
- Array.from(summariesByTier[1].values()),
- Array.from(summariesByTier[2].values()),
- Array.from(summariesByTier[3].values()),
- ].entries()) {
- const tier = i + 1;
-
- for (const summary of summaries) {
- const plusStatus = statuses.find(
- (status) => status.userId === summary.userId
- );
- if (!plusStatus)
- throw httpError.badRequest("unexpected no plusStatus in loop");
-
- const passedVoting =
- getPercentageFromCounts(
- summary.countsNA as number[],
- summary.countsEU as number[],
- plusStatus.region
- ) >= 50;
-
- if (passedVoting) {
- if (!alreadyMember.has(summary.userId)) {
- members[tier].push(summary.userId);
- alreadyMember.add(summary.userId);
- }
- } else {
- // get put to a lower tier only if not suggestion or vouch
- if (
- !summary.wasSuggested &&
- !summary.wasVouched &&
- !alreadyMember.has(summary.userId)
- ) {
- const tierToDemoteTo = tier === 3 ? 0 : tier + 1;
- members[tierToDemoteTo].push(summary.userId);
- alreadyMember.add(summary.userId);
- }
-
- // if they were vouched time for whoever vouched them to have their perms revoked for 6 months
- if (plusStatus.vouchTier === tier) {
- if (!plusStatus.voucherId)
- throw httpError.badRequest("unexpexted no voucher id");
- vouchRevoked.push(plusStatus.voucherId);
- }
-
- continue;
- }
-
- const gotVouchPermits =
- getPercentageFromCounts(
- summary.countsNA as number[],
- summary.countsEU as number[],
- plusStatus.region
- ) >= VOUCH_CRITERIA[tier];
-
- if (gotVouchPermits) {
- canVouch[tier]!.push(summary.userId);
- }
- }
- }
-
- await Promise.all([
- prisma.plusBallot.deleteMany({ where: { isStale: true } }),
- prisma.plusStatus.updateMany({
- data: { canVouchFor: null },
- }),
- ]);
-
- const now = new Date();
-
- return prisma.$transaction([
- prisma.plusBallot.updateMany({ data: { isStale: true } }),
- prisma.plusSuggestion.deleteMany({}),
- prisma.plusVotingSummary.createMany({
- data: [
- ...Array.from(summariesByTier[1].values()),
- ...Array.from(summariesByTier[2].values()),
- ...Array.from(summariesByTier[3].values()),
- ],
- }),
- prisma.plusStatus.updateMany({
- data: { vouchTier: null, voucherId: null },
- }),
- prisma.plusStatus.updateMany({
- where: { canVouchAgainAfter: { lt: new Date() } },
- data: { canVouchAgainAfter: null },
- }),
- prisma.plusStatus.updateMany({
- where: { userId: { in: members[0] } },
- data: { membershipTier: null },
- }),
- prisma.plusStatus.updateMany({
- where: { userId: { in: members[1] } },
- data: { membershipTier: 1 },
- }),
- prisma.plusStatus.updateMany({
- where: { userId: { in: members[2] } },
- data: { membershipTier: 2 },
- }),
- prisma.plusStatus.updateMany({
- where: { userId: { in: members[3] } },
- data: { membershipTier: 3 },
- }),
- prisma.plusStatus.updateMany({
- where: { userId: { in: canVouch[1] } },
- data: { canVouchFor: 1 },
- }),
- prisma.plusStatus.updateMany({
- where: { userId: { in: canVouch[2] } },
- data: { canVouchFor: 2 },
- }),
- prisma.plusStatus.updateMany({
- where: { userId: { in: canVouch[3] } },
- data: { canVouchFor: 3 },
- }),
- prisma.plusStatus.updateMany({
- where: { userId: { in: vouchRevoked } },
- data: {
- canVouchAgainAfter: new Date(now.getFullYear(), now.getMonth() + 5, 1),
- },
- }),
- ]);
-};
-
const plusService = {
getPlusStatuses,
getSuggestions,
@@ -805,7 +615,6 @@ const plusService = {
addVotes,
editVote,
votedUserScores,
- endVoting,
};
export default plusService;