Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
7fe31aa
feat: add Advent of Code channel ID to environment configuration
wiktoriavh Nov 11, 2025
54e8f8b
chore: add node-cron dependency with types
wiktoriavh Nov 11, 2025
cbdad05
feat: implement Advent of Code scheduler to automate daily post creat…
wiktoriavh Nov 11, 2025
f16dabf
feat: integrate Advent of Code scheduler initialization in ready even…
wiktoriavh Nov 11, 2025
297816f
test: add unit tests for Advent scheduler tracker file operations
wiktoriavh Nov 11, 2025
0e59157
chore: update .gitignore to include advent-of-code-tracker.json and r…
wiktoriavh Nov 11, 2025
b741052
feat: add Advent of Code tracker path to environment configuration an…
wiktoriavh Nov 11, 2025
1bf9785
chore: update docker-compose.yml to clarify tracker data volume comment
wiktoriavh Nov 11, 2025
79c128e
chore: update .env.example to clarify required Discord bot credential…
wiktoriavh Nov 11, 2025
fa1dabc
fix: correct month check in Advent scheduler to ensure posts are crea…
wiktoriavh Nov 11, 2025
2224bc1
chore: update test command in package.json to use tsx for TypeScript …
wiktoriavh Nov 12, 2025
a69c0bd
refactor: export functions to be used for testing
wiktoriavh Nov 12, 2025
949c3c1
refactor: convert to ts file
wiktoriavh Nov 12, 2025
f22a94d
chore: update biome.json to include test files in the includes array
wiktoriavh Nov 12, 2025
014be19
refactor: remove redundant comments and improve clarity in Advent sch…
wiktoriavh Nov 12, 2025
e3fe8f1
refactor: update Advent scheduler documentation to reflect time zone …
wiktoriavh Nov 12, 2025
34b9f0a
Merge branch 'main' into feat/daily-aoc-post
wiktoriavh Nov 12, 2025
3ff2ee1
Merge branch 'main' into feat/daily-aoc-post
wiktoriavh Nov 12, 2025
a06c6a8
feat: add Advent of Code channel and tracker path to test environment…
wiktoriavh Nov 12, 2025
ac64ff8
refactor: update file path handling in Advent scheduler tests
wiktoriavh Nov 12, 2025
80a47fd
fix: simplify error handling in loadTracker function by removing unus…
wiktoriavh Nov 12, 2025
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
40 changes: 21 additions & 19 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
# Local Environment Variables (Secrets)
# Copy this file to .env and fill in your actual values
# .env is gitignored and should NEVER be committed
# Discord Bot Credentials (REQUIRED - Secret values, do not commit!)
DISCORD_TOKEN=your_discord_bot_token_here
CLIENT_ID=your_discord_client_id_here

# Discord Bot Token & Application ID (REQUIRED)
# Get this from: https://discord.com/developers/applications
DISCORD_TOKEN=your-bot-token-here
CLIENT_ID=your-bot-application-id
# Server Configuration (REQUIRED)
SERVER_ID=your_server_id_here

# Override any public config values for local testing
# Channel IDs (REQUIRED)
GUIDES_CHANNEL_ID=your_guides_channel_id_here
ADVENT_OF_CODE_CHANNEL_ID=your_advent_of_code_forum_channel_id_here
REPEL_LOG_CHANNEL_ID=your_repel_log_channel_id_here

# Discord Server ID (your dev server)
SERVER_ID=your-server-id
# Role IDs (REQUIRED)
MODERATORS_ROLE_IDS=role_id_1,role_id_2,role_id_3
REPEL_ROLE_ID=your_repel_role_id_here

# Channel IDs (from your dev server)
GUIDES_CHANNEL_ID=your-guide-channel-id
REPEL_LOG_CHANNEL_ID=your-repel-log-channel-id
# Optional Role IDs
# ROLE_A_ID=optional_role_a_id
# ROLE_B_ID=optional_role_b_id
# ROLE_C_ID=optional_role_c_id

# Role IDs (from your dev server)
REPEL_ROLE_ID=your-repel-role-id
MODERATORS_ROLE_IDS=your-moderator-role-id

# Other
GUIDES_TRACKER_PATH=guides-tracker.json
# Data Persistence (OPTIONAL)
# Local development defaults to current directory
# Docker deployments should use /app/data for persistence
GUIDES_TRACKER_PATH=guides-tracker.json
ADVENT_OF_CODE_TRACKER_PATH=advent-of-code-tracker.json
2 changes: 2 additions & 0 deletions .env.production
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ SERVER_ID=434487340535382016
# Channel IDs (from your dev server)
GUIDES_CHANNEL_ID=1429492053825290371
REPEL_LOG_CHANNEL_ID=1403558160144531589
ADVENT_OF_CODE_CHANNEL_ID=1047623689488830495

# Role IDs (from your dev server)
REPEL_ROLE_ID=1002411741776461844
MODERATORS_ROLE_IDS=849481536654803004

# Other
GUIDES_TRACKER_PATH=/app/data/guides-tracker.json
ADVENT_OF_CODE_TRACKER_PATH=/app/data/advent-of-code-tracker.json

# Note: DISCORD_TOKEN & CLIENT_ID should be in .env.local (not committed)
4 changes: 3 additions & 1 deletion .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ SERVER_ID=your-server-id

# Channel IDs (from your dev server)
GUIDES_CHANNEL_ID=your-guide-channel-id
ADVENT_OF_CODE_CHANNEL_ID=your_advent_of_code_forum_channel_id_here
REPEL_LOG_CHANNEL_ID=your-repel-log-channel-id

# Role IDs (from your dev server)
REPEL_ROLE_ID=your-repel-role-id
MODERATORS_ROLE_IDS=your-moderator-role-id

# Other
GUIDES_TRACKER_PATH=guides-tracker.json
GUIDES_TRACKER_PATH=guides-tracker.json
ADVENT_OF_CODE_TRACKER_PATH=test-advent-tracker.json
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ yarn-error.log*
!.env.example
!.env.test

# guides tracker
# tracker
guides-tracker.json
advent-of-code-tracker.json

# Docker
docker-compose.yml
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ services:
volumes:
# Mount environment config file
- ./.env.production:/app/.env.production:ro
# Persist guides tracker data
# Persist tracker data
- guides-data:/app/data
profiles:
- prod
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"check": "biome check .",
"check:fix": "biome check --write .",
"typecheck": "tsc --noEmit",
"test": "pnpm run build:dev && node --test dist/**/*.test.js",
"test": "tsx --test '**/*.test.ts'",
"test:ci": "NODE_ENV=test node --test dist/**/*.test.js",
"prepare": "husky",
"pre-commit": "lint-staged",
Expand All @@ -34,12 +34,14 @@
"packageManager": "[email protected]",
"dependencies": {
"discord.js": "^14.22.1",
"node-cron": "^4.2.1",
"typescript": "^5.9.3",
"web-features": "^3.7.0"
},
"devDependencies": {
"@biomejs/biome": "2.2.4",
"@types/node": "^24.5.2",
"@types/node-cron": "^3.0.11",
"husky": "^9.1.7",
"lint-staged": "^16.2.1",
"tsup": "^8.5.0",
Expand Down
17 changes: 17 additions & 0 deletions pnpm-lock.yaml

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

2 changes: 2 additions & 0 deletions src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const config = {
serverId: requireEnv('SERVER_ID'),
fetchAndSyncMessages: true,
guidesTrackerPath: optionalEnv('GUIDES_TRACKER_PATH'),
adventOfCodeTrackerPath: requireEnv('ADVENT_OF_CODE_TRACKER_PATH'),
roleIds: {
moderators: requireEnv('MODERATORS_ROLE_IDS')
? requireEnv('MODERATORS_ROLE_IDS').split(',')
Expand All @@ -35,6 +36,7 @@ export const config = {
channelIds: {
repelLogs: requireEnv('REPEL_LOG_CHANNEL_ID'),
guides: requireEnv('GUIDES_CHANNEL_ID'),
adventOfCode: requireEnv('ADVENT_OF_CODE_CHANNEL_ID'),
},
};

Expand Down
8 changes: 8 additions & 0 deletions src/events/ready.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Events } from 'discord.js';
import { config } from '../env.js';
import { initializeAdventScheduler } from '../util/advent-scheduler.js';
import { fetchAndCachePublicChannelsMessages } from '../util/cache.js';
import { createEvent } from '../util/events.js';
import { syncGuidesToChannel } from '../util/post-guides.js';
Expand Down Expand Up @@ -44,5 +45,12 @@ export const readyEvent = createEvent(
}
}
}

// Initialize Advent of Code scheduler
try {
initializeAdventScheduler(client, config.channelIds.adventOfCode);
} catch (error) {
console.error('❌ Failed to initialize Advent of Code scheduler:', error);
}
}
);
47 changes: 47 additions & 0 deletions src/util/advent-scheduler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import assert from 'node:assert/strict';
import { promises as fs } from 'node:fs';
import test from 'node:test';
import { config } from '../env.js';

// Import after setting env var
const { loadTracker, saveTracker } = await import('./advent-scheduler.js');

async function cleanupTestTracker() {
try {
await fs.unlink(config.adventOfCodeTrackerPath);
} catch (_error) {
// File might not exist, that's fine
}
}

test('advent scheduler: tracker file operations', async (t) => {
await t.test('should create empty tracker if file does not exist', async () => {
await cleanupTestTracker();
const tracker = await loadTracker();
assert.deepEqual(tracker, {});
});

await t.test('should save and load tracker data correctly', async () => {
const testData = {
'2025': [1, 2, 3],
'2026': [1],
};
await saveTracker(testData);
const loaded = await loadTracker();
assert.deepEqual(loaded, testData);
});

await t.test('should track multiple days per year', async () => {
const tracker = {
'2025': [1, 5, 10, 15, 20, 25],
};
await saveTracker(tracker);
const loaded = await loadTracker();
assert.equal(loaded['2025'].length, 6);
assert.ok(loaded['2025'].includes(1));
assert.ok(loaded['2025'].includes(25));
});

// Cleanup
await cleanupTestTracker();
});
Loading