Skip to content
Merged
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 .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ helm-charts
.env
.editorconfig
.idea
coverage*
coverage*

data
out
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ jobs:
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
file: apps/bot/Dockerfile
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
Expand Down
53 changes: 53 additions & 0 deletions .github/workflows/build-dashboard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Publish

on:
workflow_dispatch:
push:
branches: [main]
release:
types: [created]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
REGISTRY: ghcr.io
GITHUB_REPO: ${{ github.repository }}

jobs:
docker:
permissions:
contents: read
packages: write

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.GITHUB_REPO }}-dashboard
tags: |
type=raw,value=latest
type=raw,value=stable,enable=${{ github.event_name == 'release' }}
type=semver,pattern={{version}},enable=${{ github.event_name == 'release' }}
type=sha,priority=250,enable=${{ github.event_name != 'release' }}

- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
file: apps/dashboard/Dockerfile
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
4 changes: 1 addition & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,4 @@ jobs:
- uses: oven-sh/setup-bun@v2

- run: bun install
- run: bun run type-check
- run: bun run lint
- run: bun test
- run: bun run test
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -174,4 +174,5 @@ dist
# Finder (MacOS) folder config
.DS_Store

data
data
.turbo
2 changes: 2 additions & 0 deletions apps/bot/.env.development
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
MIGRATIONS_PATH=../../migrations
DATA_PATH=../../data
26 changes: 18 additions & 8 deletions Dockerfile → apps/bot/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
# use the official Bun image
# see all versions at https://hub.docker.com/r/oven/bun/tags
FROM oven/bun:slim AS base
WORKDIR /usr/src/app

FROM base AS builder
WORKDIR /app

RUN bun install turbo@2 --global
COPY . .
RUN turbo prune @teamgalena/bot --docker

# install dependencies into temp directory
# this will cache them and speed up future builds
# install with --production (exclude devDependencies)
FROM base AS install
RUN mkdir -p /temp
COPY package.json bun.lockb /temp/
RUN cd /temp && bun install --frozen-lockfile --production

WORKDIR pruned

COPY --from=builder /app/out/json/ .
RUN bun install --frozen-lockfile --production

# copy production dependencies and source code into final image
FROM base AS release
COPY --from=install /temp/node_modules node_modules
COPY src src
COPY migrations migrations
WORKDIR /app

COPY --from=install /pruned/node_modules node_modules
COPY --from=builder /app/out/full ./
COPY migrations /migrations

# run the app
EXPOSE 3000/tcp
ENTRYPOINT [ "bun", "run", "src/app.ts" ]
ENTRYPOINT [ "bun", "run", "apps/bot/src/app.ts" ]
1 change: 1 addition & 0 deletions apps/bot/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "@teamgalena/configs/eslint";
27 changes: 27 additions & 0 deletions apps/bot/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "@teamgalena/bot",
"module": "src/app.ts",
"type": "module",
"scripts": {
"start": "bun src/app.ts",
"dev": "bun --watch src/app.ts",
"type-check": "tsc --noEmit",
"lint": "eslint"
},
"devDependencies": {
"@eslint/js": "^9.28.0",
"@types/bun": "latest",
"eslint": "^9.28.0",
"typescript-eslint": "^8.33.0"
},
"peerDependencies": {
"typescript": "^5.8.3"
},
"dependencies": {
"@dotenvx/dotenvx": "^1.45.1",
"@hapi/hapi": "^21.4.0",
"@teamgalena/shared": "workspace:*",
"@teamgalena/configs": "workspace:*",
"discord.js": "^14.16.3"
}
}
7 changes: 5 additions & 2 deletions src/app.ts → apps/bot/src/app.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { migrateDatabase } from "@teamgalena/shared/database";
import { wrapCatching } from "@teamgalena/shared/error";
import logger from "@teamgalena/shared/logger";
import { Client, Events, GatewayIntentBits } from "discord.js";
import registerCommands, { executeCommand } from "./commands/register";
import { config } from "./config";
import { wrapCatching } from "./error";
import logger from "./logger";
import "./server";

const client = new Client({ intents: [GatewayIntentBits.Guilds] });
Expand All @@ -13,6 +14,8 @@ client.once(Events.ClientReady, (it) => {

client.on(Events.InteractionCreate, wrapCatching(executeCommand));

await migrateDatabase();

await client.login(config.botToken);

await registerCommands(client);
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { addFlags } from "@teamgalena/shared/database";
import { UserError } from "@teamgalena/shared/error";
import { type Flag } from "@teamgalena/shared/flags";
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import { addFlags } from "../database";
import { UserError } from "../error";
import { type Flag } from "../flags";

type DatePredicate = (date: Date) => boolean;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import {
ChatInputCommandInteraction,
GuildMemberRoleManager,
SlashCommandBuilder,
} from "discord.js";
import {
addFlags,
loadSupporterRoles,
persistLink,
updateRank,
} from "../database";
import { SUPPORTER_FLAGS } from "../flags";
import queryUUID from "../mojang";
} from "@teamgalena/shared/database";
import { SUPPORTER_FLAGS } from "@teamgalena/shared/flags";
import queryUUID from "@teamgalena/shared/mojang";
import {
ChatInputCommandInteraction,
GuildMemberRoleManager,
SlashCommandBuilder,
} from "discord.js";

const linkTypes = {
UUID: "uuid",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { UserError } from "@teamgalena/shared/error";
import logger from "@teamgalena/shared/logger";
import {
ChatInputCommandInteraction,
Client,
Expand All @@ -9,8 +11,6 @@ import {
type RESTPostAPIChatInputApplicationCommandsJSONBody,
} from "discord.js";
import { config } from "../config";
import { UserError } from "../error";
import logger from "../logger";
import * as claimFlag from "./claimFlag";
import * as linkMinecraft from "./linkMinecraft";

Expand Down
10 changes: 10 additions & 0 deletions apps/bot/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import dotenv from "@dotenvx/dotenvx";
import { requireEnv } from "@teamgalena/shared/config";

dotenv.config({ convention: "flow" });

export const config = {
applicationId: requireEnv("APPLICATION_ID"),
publicKey: requireEnv("PUBLIC_KEY"),
botToken: requireEnv("BOT_TOKEN"),
};
29 changes: 29 additions & 0 deletions apps/bot/src/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { server as createServer } from "@hapi/hapi";
import { getLinkByUuid } from "@teamgalena/shared/database";
import { extractFlags } from "@teamgalena/shared/flags";
import logger from "@teamgalena/shared/logger";

const server = createServer({ port: 3000 });

server.route({
method: "GET",
path: `/api/{uuid}`,
handler: async (req, tools) => {
const uuid = req.params.uuid?.replaceAll(/[-_]/g, "");
const link = await getLinkByUuid(uuid);
if (!link) {
return tools
.response({
message: `unknown uuid '${uuid}'`,
})
.code(404);
}

const flags = extractFlags(link.flags);
const { rank } = link;
return { flags, rank };
},
});

await server.start();
logger.debug(`server accepting responses at ${server.info.uri}`);
5 changes: 4 additions & 1 deletion test/flags.test.ts → apps/bot/test/flags.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import type { LinkEntry } from "@teamgalena/shared/database";
import { expect, test } from "bun:test";
import type { LinkEntry } from "../src/database";
import { flagQuery, withFlags } from "../src/flags";

function createLinkEntry(values: Partial<LinkEntry> = {}): LinkEntry {
return {
id: -1,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
discordId: "test-id",
flags: 0b00000000,
rank: 99,
Expand Down
6 changes: 6 additions & 0 deletions apps/bot/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": "@teamgalena/configs/tsconfig",
"include": [
"src"
]
}
1 change: 1 addition & 0 deletions apps/dashboard/.env.development
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DATA_PATH=../../data
24 changes: 24 additions & 0 deletions apps/dashboard/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# build output
dist/
# generated types
.astro/

# dependencies
node_modules/

# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*


# environment variables
.env
.env.production

# macOS-specific files
.DS_Store

# jetbrains setting folder
.idea/
4 changes: 4 additions & 0 deletions apps/dashboard/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"recommendations": ["astro-build.astro-vscode"],
"unwantedRecommendations": []
}
11 changes: 11 additions & 0 deletions apps/dashboard/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "./node_modules/.bin/astro dev",
"name": "Development server",
"request": "launch",
"type": "node-terminal"
}
]
}
37 changes: 37 additions & 0 deletions apps/dashboard/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# use the official Bun image
# see all versions at https://hub.docker.com/r/oven/bun/tags
FROM oven/bun:slim AS base

FROM base AS builder
WORKDIR /app

RUN bun install turbo@2 --global
COPY . .
RUN turbo prune @teamgalena/dashboard --docker

# install dependencies into temp directory
# this will cache them and speed up future builds
# install with --production (exclude devDependencies)
FROM base AS install
WORKDIR /pruned

COPY --from=builder /app/out/json/ .
RUN bun install --frozen-lockfile --production

COPY --from=builder /app/out/full .
RUN bun run --filter @teamgalena/dashboard build

# copy production dependencies and source code into final image
FROM base AS release
WORKDIR /app

COPY --from=install /pruned/node_modules node_modules
COPY --from=install /pruned/apps/dashboard/dist dist
COPY --from=install /pruned/apps/dashboard/public public

# run the app
ENV HOST=0.0.0.0
ENV PORT=80
EXPOSE 80/tcp

CMD ["bun", "run", "dist/server/entry.mjs"]
Loading