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
3 changes: 3 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@
| `src/utils/splitMessage.js` | Message splitting for Discord's 2000-char limit |
| `src/utils/debugFooter.js` | Debug stats footer builder and Discord embed wrapper for AI responses |
| `src/utils/duration.js` | Duration parsing — "1h", "7d" ↔ ms with human-readable formatting |
| `src/commands/announce.js` | Scheduled message command — `/announce` with create/list/delete subcommands (moderator-only); stores schedules to `scheduled_messages` table |
| `src/modules/scheduler.js` | Scheduled message poller — cron expression parser (`parseCron`, `getNextCronRun`), due-message dispatcher via `safeSend`, 60s interval started/stopped via `startScheduler`/`stopScheduler` |
| `migrations/002_scheduled-messages.cjs` | Migration — creates `scheduled_messages` table (id, guild_id, channel_id, content, cron_expression, next_run, is_one_time, created_by) |
| `config.json` | Default configuration (seeded to DB on first run) |
| `.env.example` | Environment variable template |

Expand Down
3 changes: 2 additions & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@
"lock": "admin",
"unlock": "admin",
"slowmode": "admin",
"modlog": "moderator"
"modlog": "moderator",
"announce": "moderator"
}
}
}
34 changes: 34 additions & 0 deletions migrations/002_scheduled-messages.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* Add scheduled_messages table for /announce command.
* Supports one-time and recurring (cron) scheduled messages.
*
* @see https://github.com/VolvoxLLC/volvox-bot/issues/42
*/

/** @param {import('node-pg-migrate').MigrationBuilder} pgm */
exports.up = (pgm) => {
pgm.sql(`
CREATE TABLE IF NOT EXISTS scheduled_messages (
id SERIAL PRIMARY KEY,
guild_id TEXT NOT NULL,
channel_id TEXT NOT NULL,
content TEXT NOT NULL,
embed_json JSONB,
cron_expression TEXT,
next_run TIMESTAMPTZ NOT NULL,
author_id TEXT NOT NULL,
enabled BOOLEAN NOT NULL DEFAULT true,
one_time BOOLEAN NOT NULL DEFAULT false,
created_at TIMESTAMPTZ DEFAULT NOW()
)
`);

pgm.sql(
'CREATE INDEX IF NOT EXISTS idx_scheduled_next_run ON scheduled_messages(next_run) WHERE enabled = true',
);
};

/** @param {import('node-pg-migrate').MigrationBuilder} pgm */
exports.down = (pgm) => {
pgm.sql('DROP TABLE IF EXISTS scheduled_messages CASCADE');
};
Loading
Loading