Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
"types": "./dist/env.d.ts",
"default": "./src/env.ts"
},
"./minio/minio-client": "./src/minio/minio-client.ts",
"./minio/minio-client": {
"types": "./dist/minio/minio-client.d.ts",
"default": "./src/minio/minio-client.ts"
},
"./utils": {
"types": "./dist/utils.d.ts",
"default": "./src/utils.ts"
Expand Down
1 change: 0 additions & 1 deletion packages/db/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
"dependencies": {
"@forge/consts": "workspace:*",
"@t3-oss/env-core": "^0.13.10",
"drizzle-orm": "^0.45.1",
"drizzle-zod": "^0.8.3",
"minimatch": "^10.2.4",
"pg": "^8.19.0",
Expand Down
87 changes: 72 additions & 15 deletions packages/db/scripts/seed_devdb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,57 @@
// I probably messed a lot up :D. See get_prod_db.ts for how to get prod data
// into your local db for deving.

// TODO: look into moving into a separate area so we don't have to do the BS
// that we do with `../../api` and `../../utils`

import { exec } from "child_process";
import { unlink } from "fs/promises";
import { promisify } from "util";
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
import type { Client } from "pg";
import { REST } from "@discordjs/rest";
import { Routes } from "discord-api-types/v10";
import { sql } from "drizzle-orm";
import { drizzle } from "drizzle-orm/node-postgres";
import { Client as MinioClient } from "minio";
import Pool from "pg-pool";
import { stringify } from "superjson";

import { DISCORD, MINIO } from "@forge/consts";

// Scripts can use relative imports to avoid circular dependencies
import { minioClient } from "../../api/src/minio/minio-client";
import * as discord from "../../utils/src/discord";
import { env } from "../src/env";
import * as authSchema from "../src/schemas/auth";
import * as knightHacksSchema from "../src/schemas/knight-hacks";

const execAsync = promisify(exec);
console.log("Starting seeding script");

function requireEnvVar(name: string): string {
/* eslint-disable no-restricted-properties */
const value = process.env[name];
/* eslint-enable no-restricted-properties */
if (!value) {
throw new Error(`Missing required env var: ${name}`);
}
return value;
}

const requiredEnv = {
DISCORD_BOT_TOKEN: requireEnvVar("DISCORD_BOT_TOKEN"),
MINIO_ENDPOINT: requireEnvVar("MINIO_ENDPOINT"),
MINIO_ACCESS_KEY: requireEnvVar("MINIO_ACCESS_KEY"),
MINIO_SECRET_KEY: requireEnvVar("MINIO_SECRET_KEY"),
};

const discordApi = new REST({ version: "10" }).setToken(
requiredEnv.DISCORD_BOT_TOKEN,
);

const minioClient = new MinioClient({
endPoint: requiredEnv.MINIO_ENDPOINT,
port: 443,
useSSL: true,
accessKey: requiredEnv.MINIO_ACCESS_KEY,
secretKey: requiredEnv.MINIO_SECRET_KEY,
});

type AuthSchema = typeof authSchema;
type KnightHacksSchema = typeof knightHacksSchema;
type DatabaseSchema = AuthSchema & KnightHacksSchema;
Expand Down Expand Up @@ -243,12 +268,12 @@ async function syncRoles() {
await backupDb.query.Roles.findMany({ columns: { discordRoleId: true } })
).map((row) => row.discordRoleId),
);
let prodRoles = (await discord.api.get(
let prodRoles = (await discordApi.get(
Routes.guildRoles(DISCORD.PROD_KNIGHTHACKS_GUILD),
)) as DiscordRole[];
prodRoles = prodRoles.filter((role) => prodRolesWithPerms.has(role.id));

const devRolesArr = (await discord.api.get(
const devRolesArr = (await discordApi.get(
Routes.guildRoles(DISCORD.DEV_KNIGHTHACKS_GUILD),
)) as DiscordRole[];
const devRoles = Object.fromEntries(
Expand All @@ -261,7 +286,7 @@ async function syncRoles() {
roleIdMappings[role.id] = devRoles[hash].id;
} else {
await new Promise((resolve) => setTimeout(resolve, 100));
const newRole = (await discord.api.post(
const newRole = (await discordApi.post(
Routes.guildRoles(DISCORD.DEV_KNIGHTHACKS_GUILD),
{
body: {
Expand Down Expand Up @@ -300,14 +325,46 @@ interface DiscordGuildScheduledEvent {
image?: string | null;
}

async function logDiscord({
title,
message,
color,
userId,
}: {
title: string;
message: string;
color: "tk_blue" | "blade_purple" | "uhoh_red" | "success_green";
userId: string;
}) {
await discordApi.post(Routes.channelMessages(DISCORD.LOG_CHANNEL), {
body: {
embeds: [
{
title,
description: message + `\n\nUser: <@${userId}>`,
color: {
tk_blue: 0x1a73e8,
blade_purple: 0xcca4f4,
uhoh_red: 0xff0000,
success_green: 0x00ff00,
}[color],
footer: {
text: new Date().toLocaleString(),
},
},
],
},
});
}

async function syncEvents() {
if (!backupDb) return;

const prodEvents = (await discord.api.get(
const prodEvents = (await discordApi.get(
Routes.guildScheduledEvents(DISCORD.PROD_KNIGHTHACKS_GUILD),
)) as DiscordGuildScheduledEvent[];

const devEventsArr = (await discord.api.get(
const devEventsArr = (await discordApi.get(
Routes.guildScheduledEvents(DISCORD.DEV_KNIGHTHACKS_GUILD),
)) as DiscordGuildScheduledEvent[];
const devEvents = Object.fromEntries(
Expand All @@ -320,7 +377,7 @@ async function syncEvents() {
eventIdMappings[event.id] = devEvents[hash].id;
} else {
await new Promise((resolve) => setTimeout(resolve, 100));
const newEvent = (await discord.api.post(
const newEvent = (await discordApi.post(
Routes.guildScheduledEvents(DISCORD.DEV_KNIGHTHACKS_GUILD),
{
body: {
Expand Down Expand Up @@ -430,7 +487,7 @@ async function main() {
console.log("Cleaning up backup db");
await cleanUp();

await discord.log({
await logDiscord({
title: `Successfully saved limited prod db to minio`,
message: `Successfully saved limited prod db to minio. Run the get_prod_db.ts script to get it into your local dev db.`,
color: "success_green",
Expand All @@ -440,9 +497,9 @@ async function main() {
process.exit(0);
} catch (error) {
console.error("Error during database seeding:", error);
await discord.log({
await logDiscord({
title: `Failed to save limited prod db to minio`,
message: `Failed to sav limited prod db to minio. Error: ${stringify(error)}`,
message: `Failed to save limited prod db to minio. Error: ${stringify(error)}`,
color: "uhoh_red",
userId: "Host",
});
Expand Down
5 changes: 4 additions & 1 deletion packages/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
"type": "module",
"exports": {
".": "./src/index.ts",
"./discord": "./src/discord.ts",
"./discord": {
"types": "./dist/discord.d.ts",
"default": "./src/discord.ts"
},
"./forms": "./src/forms.ts",
"./forms.client": "./src/forms.client.ts",
"./google": "./src/google.ts",
Expand Down
5 changes: 2 additions & 3 deletions packages/utils/src/discord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ import { Routes } from "discord-api-types/v10";
import { and, desc, eq } from "drizzle-orm";

import type { Session } from "@forge/auth/server";
import { DISCORD } from "@forge/consts";
import { DISCORD, TEAM } from "@forge/consts";
import { db } from "@forge/db/client";
import { Account } from "@forge/db/schemas/auth";

import { TEAMS } from "../../consts/src/team";
import { env } from "./env";
import { logger } from "./logger";

Expand All @@ -29,7 +28,7 @@ export async function sendRecruitingApplication(
gradYear: string;
},
) {
const team = TEAMS.find((x) => x.team === teamName);
const team = TEAM.TEAMS.find((x) => x.team === teamName);
if (!team) {
throw new Error("Team not found");
}
Expand Down
48 changes: 18 additions & 30 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading