sendou.ink/app/db/seed/dev/misc.ts
2026-07-29 10:52:57 +03:00

212 lines
5.7 KiB
TypeScript

import { sub } from "date-fns";
import { Config } from "~/config";
import type { Tables } from "~/db/tables";
import type { Notification } from "~/features/notifications/notifications-types";
import type { MainWeaponId, ModeShort } from "~/modules/in-game-lists/types";
import {
getArtFilename,
SEED_ART_URLS,
} from "../../../../scripts/seed-art-urls";
import { NZAP_TEST_DISCORD_ID } from "../constants";
import { faker } from "../core/faker";
import placements from "../data/placements.json";
import * as ArtFactory from "../factories/ArtFactory";
import * as FriendRequestFactory from "../factories/FriendRequestFactory";
import * as FriendshipFactory from "../factories/FriendshipFactory";
import * as LiveStreamFactory from "../factories/LiveStreamFactory";
import * as NotificationFactory from "../factories/NotificationFactory";
import * as SplatoonRotationFactory from "../factories/SplatoonRotationFactory";
import * as UserReportFactory from "../factories/UserReportFactory";
import * as XRankPlacementFactory from "../factories/XRankPlacementFactory";
import type { SeededSendouQ } from "./sendouq";
import type { SeededUsers } from "./users";
const ADMIN_PLAYER_SPL_ID = "qx6imlx72tfeqrhqfnmm";
const FRIEND_COUNT = 8;
const STREAM_COUNT = 20;
export async function seedMisc({
users,
sendouq,
}: {
users: SeededUsers;
sendouq: SeededSendouQ;
}) {
await seedXRankPlacements(users);
await seedArts(users);
await seedFriends(users);
await seedNotifications(users);
await seedUserReports(users, sendouq);
await LiveStreamFactory.replaceAll(
users.showcaseIds.slice(0, STREAM_COUNT).map((userId) => ({ userId })),
);
await SplatoonRotationFactory.replaceAll();
}
async function seedXRankPlacements(users: SeededUsers) {
// a top 500 player who is a site user without plus membership
const unaffiliatedTopPlayerId = users.crowdIds[users.crowdIds.length - 1];
for (const [i, placement] of placements.entries()) {
const playerUserId =
placement.playerSplId === ADMIN_PLAYER_SPL_ID
? users.adminId
: i === 0
? unaffiliatedTopPlayerId
: undefined;
await XRankPlacementFactory.create(
{
...placement,
mode: placement.mode as ModeShort,
region: placement.region as Tables["XRankPlacement"]["region"],
weaponSplId: placement.weaponSplId as MainWeaponId,
playerUserId,
},
{ refreshPeakXp: i === placements.length - 1 },
);
}
}
async function seedArts(users: SeededUsers) {
let nextUrl = 0;
for (const authorId of users.artistIds) {
const artCount = faker.helpers.arrayElement([1, 2, 3, 3, 4]);
for (let i = 0; i < artCount; i++) {
await ArtFactory.create({
authorId,
url: getArtFilename(nextUrl++ % SEED_ART_URLS.length),
description:
faker.number.float(1) < 0.5 ? faker.lorem.paragraph() : null,
linkedUsers:
i === 1
? [
users.nzapId,
...faker.helpers.arrayElements(users.showcaseIds, {
min: 0,
max: 2,
}),
]
: [],
});
}
}
}
async function seedFriends(users: SeededUsers) {
const friendIds = users.showcaseIds.slice(0, FRIEND_COUNT);
for (const friendId of friendIds) {
await FriendshipFactory.create({
userOneId: users.adminId,
userTwoId: friendId,
});
}
// mutual friends between some of them, so user cards show the overlap
await FriendshipFactory.create({
userOneId: friendIds[0],
userTwoId: friendIds[1],
});
await FriendshipFactory.create({
userOneId: friendIds[0],
userTwoId: friendIds[2],
});
await FriendRequestFactory.create({
senderId: users.showcaseIds[FRIEND_COUNT],
receiverId: users.adminId,
});
}
async function seedNotifications(users: SeededUsers) {
const notifications: Notification[] = [
{ type: "PLUS_SUGGESTION_ADDED", meta: { tier: 1 } },
{ type: "SEASON_STARTED", meta: { seasonNth: 1 } },
{
type: "TO_ADDED_TO_TEAM",
meta: {
adderUsername: "N-ZAP",
teamName: "Chimera",
tournamentId: 1,
tournamentName: "Paddling Pool 253",
tournamentTeamId: 1,
},
},
{
type: "TO_BRACKET_STARTED",
meta: {
tournamentId: 1,
tournamentName: "Paddling Pool 253",
bracketIdx: 0,
bracketName: "Groups Stage",
},
},
{ type: "BADGE_ADDED", meta: { badgeName: "4v4 Sundaes", badgeId: 1 } },
{
type: "TAGGED_TO_ART",
meta: {
adderUsername: "N-ZAP",
adderDiscordId: NZAP_TEST_DISCORD_ID,
artId: 1,
},
},
{ type: "SQ_ADDED_TO_GROUP", meta: { adderUsername: "N-ZAP" } },
{ type: "SQ_NEW_MATCH", meta: { matchId: 100 } },
{ type: "PLUS_VOTING_STARTED", meta: { seasonNth: 1 } },
{
type: "TO_CHECK_IN_OPENED",
meta: { tournamentId: 1, tournamentName: "Paddling Pool 253" },
pictureUrl: `${Config.staticAssetsUrl}/img/tournament-logos/pn.avif`,
},
];
for (const [i, notification] of notifications.entries()) {
const createdAt = sub(new Date(), {
days: notifications.length - 1 - i,
minutes: i * 17,
});
await NotificationFactory.create(
{
notification,
users: [
{ userId: users.adminId, seen: i <= 7 ? 1 : 0 },
{ userId: users.nzapId, seen: i <= 7 ? 1 : 0 },
],
},
{ createdAt },
);
}
}
async function seedUserReports(users: SeededUsers, sendouq: SeededSendouQ) {
// uneven spread over the trailing year so the admin tab's bar graph shows variety
const monthsAgoDistribution = [
0, 0, 0, 1, 2, 2, 2, 2, 5, 5, 7, 8, 10, 11, 11,
];
for (const [i, monthsAgo] of monthsAgoDistribution.entries()) {
await UserReportFactory.create(
{
reportedUserId: users.nzapId,
reporterUserId: users.showcaseIds[10 + i],
matchId:
i % 3 === 0
? faker.helpers.arrayElement(sendouq.recentMatchIds)
: null,
},
{
createdAt: sub(new Date(), {
months: monthsAgo,
days: (i * 3) % 7,
hours: i,
}),
},
);
}
}