Skip to content

Commit 1f94b7a

Browse files
authored
Merge branch 'main' into feat/onboarding
2 parents 00b10df + fc598ab commit 1f94b7a

File tree

15 files changed

+125
-34
lines changed

15 files changed

+125
-34
lines changed

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ dist/
77
# Environment files
88
.env
99
.env.*
10+
!.env.production
1011

1112
# Git
1213
.git/

.env.test

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Local Environment Variables (Secrets)
2+
# Copy this file to .env and fill in your actual values
3+
# .env is gitignored and should NEVER be committed
4+
5+
# Discord Bot Token & Application ID (REQUIRED)
6+
# Get this from: https://discord.com/developers/applications
7+
DISCORD_TOKEN=your-bot-token-here
8+
CLIENT_ID=your-bot-application-id
9+
10+
# Override any public config values for local testing
11+
12+
# Discord Server ID (your dev server)
13+
SERVER_ID=your-server-id
14+
15+
# Channel IDs (from your dev server)
16+
GUIDES_CHANNEL_ID=your-guide-channel-id
17+
REPEL_LOG_CHANNEL_ID=your-repel-log-channel-id
18+
19+
# Role IDs (from your dev server)
20+
REPEL_ROLE_ID=your-repel-role-id
21+
MODERATORS_ROLE_IDS=your-moderator-role-id
22+
23+
# Other
24+
GUIDES_TRACKER_PATH=guides-tracker.json
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Deploy Discord Commands
2+
3+
on:
4+
workflow_dispatch: # Manual trigger only
5+
6+
jobs:
7+
deploy-commands:
8+
runs-on: ubuntu-latest
9+
10+
steps:
11+
- name: Checkout code
12+
uses: actions/checkout@v4
13+
14+
- name: Read Node version
15+
run: |
16+
NODE_VERSION=$(cat .nvmrc | sed 's/v//')
17+
echo "NODE_VERSION=$NODE_VERSION" >> $GITHUB_ENV
18+
19+
- name: Deploy Discord Commands to VPS
20+
uses: appleboy/[email protected]
21+
with:
22+
host: ${{ secrets.VPS_HOST }}
23+
username: ${{ secrets.VPS_USER }}
24+
key: ${{ secrets.VPS_SSH_KEY }}
25+
script: |
26+
cd /home/${{ secrets.VPS_USER }}/webdev-bot-deploy
27+
28+
# Read NODE_VERSION from .nvmrc
29+
export NODE_VERSION=$(cat .nvmrc | sed 's/v//')
30+
echo "Using Node version: $NODE_VERSION"
31+
32+
# Run deploy script inside the already running Docker container
33+
# .env file should already exist from main deployment
34+
echo "Deploying Discord commands..."
35+
docker compose --profile prod exec bot-prod node dist/util/deploy.js
36+
37+
echo "Discord commands deployment completed!"

.github/workflows/test.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,7 @@ jobs:
3737

3838
- name: Build
3939
run: npm run build:ci
40-
env:
41-
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
42-
CLIENT_ID: ${{ secrets.CLIENT_ID }}
4340

44-
- name: Run tests
41+
- name: Test
4542
run: npm run test:ci
4643

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ yarn-error.log*
1818
# Public config (committed to repo)
1919
!.env.production
2020
!.env.example
21+
!.env.test
2122

2223
# guides tracker
2324
guides-tracker.json

biome.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@
3333
}
3434
},
3535
"files": {
36-
"includes": ["*.ts", "*.js", "*.json", "src/**/*"]
36+
"includes": ["*.ts", "*.js", "*.json", "src/**/*", "test/**/*"]
3737
}
3838
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"check:fix": "biome check --write .",
2323
"typecheck": "tsc --noEmit",
2424
"test": "pnpm run build:dev && node --test dist/**/*.test.js",
25-
"test:ci": "node --test dist/**/*.test.js",
25+
"test:ci": "NODE_ENV=test node --test dist/**/*.test.js",
2626
"prepare": "husky",
2727
"pre-commit": "lint-staged",
2828
"sync-guides": "tsx scripts/sync-guides.js",

src/commands/moderation/repel.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -287,11 +287,9 @@ const logRepelAction = async ({
287287

288288
const modMessage = interaction.options.getString(RepelOptions.MESSAGE_FOR_MODS) ?? false;
289289
const mentionText = modMessage
290-
? `${config.moderatorsRoleIds.map((id) => `<@&${id}>`)} - ${modMessage}`
290+
? `${config.roleIds.moderators.map((id) => `<@&${id}>`)} - ${modMessage}`
291291
: undefined;
292-
const channel = interaction.client.channels.cache.get(
293-
config.repel.repelLogChannelId
294-
) as TextChannel;
292+
const channel = interaction.client.channels.cache.get(config.channelIds.repelLogs) as TextChannel;
295293

296294
const embed =
297295
failedChannelsEmbed !== null
@@ -390,7 +388,7 @@ export const repelCommand = createCommand({
390388
}
391389
await interaction.deferReply({ flags: MessageFlags.Ephemeral });
392390

393-
const repelRole = interaction.guild.roles.cache.get(config.repel.repelRoleId);
391+
const repelRole = interaction.guild.roles.cache.get(config.roleIds.repel);
394392
if (!repelRole) {
395393
await interaction.editReply({
396394
content: '❌ Repel role is not configured correctly. Please contact an administrator.',

src/env.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,21 @@ export const config = {
2020
token: requireEnv('DISCORD_TOKEN'),
2121
clientId: requireEnv('CLIENT_ID'),
2222
},
23-
repel: {
24-
repelLogChannelId: requireEnv('REPEL_LOG_CHANNEL_ID'),
25-
repelRoleId: requireEnv('REPEL_ROLE_ID'),
26-
},
27-
fetchAndSyncMessages: true,
2823
serverId: requireEnv('SERVER_ID'),
29-
moderatorsRoleIds: requireEnv('MODERATORS_ROLE_IDS')
30-
? requireEnv('MODERATORS_ROLE_IDS').split(',')
31-
: [],
32-
guides: {
33-
channelId: requireEnv('GUIDES_CHANNEL_ID'),
34-
trackerPath: optionalEnv('GUIDES_TRACKER_PATH'),
24+
fetchAndSyncMessages: true,
25+
guidesTrackerPath: optionalEnv('GUIDES_TRACKER_PATH'),
26+
roleIds: {
27+
moderators: requireEnv('MODERATORS_ROLE_IDS')
28+
? requireEnv('MODERATORS_ROLE_IDS').split(',')
29+
: [],
30+
repel: requireEnv('REPEL_ROLE_ID'),
31+
a: optionalEnv('ROLE_A_ID'),
32+
b: optionalEnv('ROLE_B_ID'),
33+
c: optionalEnv('ROLE_C_ID'),
34+
},
35+
channelIds: {
36+
repelLogs: requireEnv('REPEL_LOG_CHANNEL_ID'),
37+
guides: requireEnv('GUIDES_CHANNEL_ID'),
3538
},
3639
onboarding: {
3740
channelId: requireEnv('ONBOARDING_CHANNEL_ID'),

src/events/auto-roles.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Events } from 'discord.js';
2+
import { config } from '../env.js';
3+
import { createEvent } from '../util/events.js';
4+
import { hasRoles } from '../util/member.js';
5+
6+
export const autoRoleEvent = createEvent(
7+
{
8+
name: Events.GuildMemberUpdate,
9+
},
10+
async (_, newMember) => {
11+
const hasRoleC = hasRoles(newMember, config.roleIds.c);
12+
if (!hasRoleC) {
13+
const hasRequiredRoles = hasRoles(newMember, config.roleIds.a, config.roleIds.b);
14+
if (hasRequiredRoles) {
15+
try {
16+
await newMember.roles.add(config.roleIds.c);
17+
} catch (error) {
18+
console.error(`Failed to add roleC to ${newMember.user.tag}:`, error);
19+
}
20+
}
21+
}
22+
}
23+
);

0 commit comments

Comments
 (0)