## Summary - Replaces custom "Vampyr" font with style guide fonts (Griffy, Kalam, Creepster, Henny Penny) - Fixes illegible tagline, search placeholder, search results, shortcut badge, theme dropdown, and active sidebar item across light and dark modes - Applies witchy code themes for light and dark mode - Fixes invalid `env` language in code blocks (replaced with `sh`) - Fixes invalid `message` aside icon in contact page (replaced with `star`) ✨ This PR was created with help from Hikari~ 🌸 Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com> Reviewed-on: #31 Co-authored-by: Hikari <hikari@nhcarrigan.com> Co-committed-by: Hikari <hikari@nhcarrigan.com>
27 KiB
title
| title |
|---|
| Artists4Palestine Bot |
Artists4Palestine Bot (hereinafter the "Application") is a Discord bot designed to facilitate the Art for Palestine charity event. The Application serves as an automated bridge between Airtable, Trello, and Discord to manage art commission requests, artist assignments, delivery tracking, and support tickets for the charity event.
1. User Documentation
This section is for those interacting with a live instance of the Application.
1.1. Getting Started
The Art for Palestine Bot is available on the Art for Palestine Discord server. Once you join the server, you will automatically be assigned the member role and can begin interacting with the bot's features.
1.2. Requesting Art Commissions
Art commission requests are submitted through an Airtable form (external to Discord). Once submitted, your request will automatically appear in the designated commission channel where artists can view and claim it. Your request should include:
- Your name
- Preferred contact method (Email, Discord, or Twitter)
- Your contact handle/username
- Description of the art you would like drawn
- Reference images (optional)
- Any additional notes or requirements
1.3. Artist Features
1.3.1. Claiming Art Commissions
As an artist, you can claim art commissions by reacting to commission posts in the art commission channel (ID: 1172568787330019340).
Important Notes:
- You can only claim up to 2 commissions at a time
- Claiming a commission creates a private thread for coordination
- The thread will include your mention and the requester's information
1.3.2. Submitting Completed Artwork
Once you've completed the artwork:
- Post the completed artwork as an image attachment in the private thread
- The bot will automatically forward your submission to the distribution channel
- Your thread will be archived
- The commission will be removed from your active count
1.3.3. Art Reminders
The bot sends automated reminders to help manage workload:
- Unclaimed Art Reminders: Sent Monday, Wednesday, and Friday at 9:00 AM
- Unfinished Art Reminders: Sent Saturday at 9:00 AM
1.4. Distribution Features
1.4.1. Claiming Distributions
Distribution team members can claim distribution tasks by reacting to posts in the distribution channel (ID: 1173061747737903315). Similar to art commissions:
- Maximum 2 concurrent distributions per member
- Creates a private coordination thread
- Includes recipient and artwork details
1.4.2. Confirming Deliveries
To confirm a distribution:
- Deliver the artwork to the recipient
- Post a confirmation image in the private thread
- The bot will close and archive the thread
1.4.3. Distribution Reminders
- Unclaimed Distribution Reminders: Sent Monday, Wednesday, and Friday at 9:00 AM
- Unfinished Distribution Reminders: Sent Saturday at 9:00 AM
1.5. Support Ticket System
1.5.1. Opening a Ticket
Users can open support tickets using the ticket button in the designated ticket channel:
- Click the "Open Ticket" button
- Fill out the modal form with your issue description
- A private thread will be created for your ticket
- Support team members will be notified
1.5.2. Ticket Workflow
- For Users: Describe your issue in the private thread and wait for a support team member to claim it
- For Support Team: Click "Claim Ticket" to add your mention and take responsibility for the issue
- Conversations in the ticket thread are automatically logged
1.5.3. Closing Tickets
Support team members can close tickets using the "Close Ticket" button:
- A log file of the entire conversation will be generated
- The log is sent to the ticket archive channel
- The thread is closed and archived
1.6. Moderation Commands
Moderation team members with the support role (ID: 1173582640843063366) have access to these commands:
!mute <user_id> <duration> <reason>
Temporarily timeout a user.
Parameters:
user_id: The Discord user ID to muteduration: Duration with unit (e.g.,30m,2h,1d)- Supported units:
s(seconds),m(minutes),h(hours),d(days)
- Supported units:
reason: Explanation for the timeout
Example:
!mute 123456789012345678 1h Spam in general channel
!unmute <user_id> <reason>
Remove a timeout from a user.
Parameters:
user_id: The Discord user ID to unmutereason: Explanation for removing the timeout
Example:
!unmute 123456789012345678 Appeal accepted
1.7. Palestine News Updates
The bot automatically fetches and posts news updates from Al Jazeera's Palestine live blog:
- Updates are checked every 10 minutes
- New articles are posted to the news channel
- Prevents duplicate posts using article ID tracking
1.8. Getting Help
If you encounter issues or have questions:
- Open a support ticket in the Discord server
- Report bugs in the #bug-reports forum channel on our Discord community
- Contact via the chat server or email at
contact@nhcarrigan.com
2. Technical Documentation
This section is for those interested in running their own instance of the Application.
2.1. Prerequisites
Before running your own instance, ensure you have:
- Node.js: Version 22 (specified in
package.json) - pnpm: Version 10 (package manager)
- Discord Bot Account: With a bot token and appropriate permissions
- Airtable Account: With API access
- Discord Webhooks: Multiple webhooks configured for different channels
2.2. Required Discord Permissions
Your Discord bot requires the following Gateway Intents:
GuildMessages: Access to guild message eventsGuilds: Access to guild/server dataGuildMessageReactions: Access to message reaction eventsMessageContent: Privileged intent for full message content accessGuildMembers: Access to member data
2.3. Environment Configuration
Create a .env file in the project root with the following variables:
# Discord Bot Configuration
TOKEN=your_discord_bot_token
# Discord Webhooks
DEBUG=https://discord.com/api/webhooks/... # Debug/error logging
COMM=https://discord.com/api/webhooks/... # Commission notifications
DIST=https://discord.com/api/webhooks/... # Distribution notifications
NEWS=https://discord.com/api/webhooks/... # Palestine news updates
TICKET=https://discord.com/api/webhooks/... # Ticket logs
# Airtable Configuration
AIRTABLE_KEY=your_airtable_api_key
AIRTABLE_BASE_ID=your_base_id
AIRTABLE_TABLE_ID=your_table_name
# Server Configuration (optional)
NODE_ENV=production # Set to enable HTTPS server on port 10443
2.4. Hardcoded Configuration
Several IDs are hardcoded in the src/config/ directory and must be updated for your server:
File: src/config/Tickets.ts
guildId: Your Discord server IDsupportRole: Your support team role ID
File: src/config/Webhooks.ts
artChannelId: Channel for art commission postsdistributionChannelId: Channel for distribution posts
File: src/config/Trello.ts
- Trello board, list, and label IDs (if using Trello integration)
2.5. Installation
- Clone the repository:
git clone https://git.nhcarrigan.com/NHCarrigan/a4p-bot.git
cd nodejs-typescript-template
- Install dependencies:
pnpm install
-
Configure environment variables (see section 2.3)
-
Build the TypeScript code:
pnpm build
2.6. Running the Bot
Start the bot in production mode:
pnpm start
This will:
- Load environment variables from
.env - Execute the compiled JavaScript from
prod/index.js - Connect to Discord
- Initialize event listeners and scheduled tasks
- Start the HTTP server on port 10080 (HTTP) or 10443 (HTTPS if
NODE_ENV=production)
2.7. Development Workflow
For development and testing:
Linting:
pnpm lint
Runs ESLint and Prettier to check code style and formatting.
Testing:
pnpm test
Runs Mocha test suite with TypeScript support (timeout: 10 seconds).
Building:
pnpm build
Compiles TypeScript files from src/ to JavaScript in prod/.
2.8. Architecture Overview
2.8.1. Project Structure
a4p-bot/
├── src/
│ ├── index.ts # Main entry point, bot initialization
│ ├── config/ # Configuration files (channels, webhooks, Trello)
│ ├── events/ # Discord event handlers
│ ├── modules/ # Core business logic
│ │ ├── buttons/ # Button interaction handlers
│ │ ├── messages/ # Message processing logic
│ │ ├── modals/ # Modal form handlers
│ │ └── reminders/ # Scheduled reminder tasks
│ ├── interface/ # TypeScript interfaces and types
│ ├── server/ # Express HTTP server
│ └── utils/ # Utility functions
├── prod/ # Compiled JavaScript output
├── logs/ # Ticket conversation logs (runtime)
└── .env # Environment variables (not committed)
2.8.2. Core Components
Discord Bot (src/index.ts:1)
- Initializes Discord.js client with required intents
- Registers event listeners for messages, reactions, interactions, and member joins
- Creates webhook clients for different notification types
- Starts HTTP server for monitoring
Event Handlers (src/events/)
onReady.ts:1: Initializes scheduled jobs, caches messages, sends startup notificationonMessageCreate.ts:1: Handles commands (!mute, !unmute) and ticket message loggingonInteractionCreate.ts:1: Routes button clicks and modal submissionsonReactionAdd.ts:1: Manages art commission and distribution claimsonMemberAdd.ts:1: Auto-assigns member role to new joiners
Scheduled Tasks (node-schedule)
- Runs every 60 minutes: Check Airtable for new form submissions
- Runs every 10 minutes: Fetch and post Palestine news updates
- Monday/Wednesday/Friday 9 AM: Send unclaimed art and distribution reminders
- Saturday 9 AM: Send unfinished art and distribution reminders
Ticket System (src/modules/)
buttons/ticketOpen.ts:1: Opens modal form for ticket creationmodals/handleTicketModal.ts:1: Creates private thread and initializes log filebuttons/ticketClaim.ts:1: Adds support member's mention to threadbuttons/ticketClose.ts:1: Generates log file, sends to archive, closes threadlogTicketMessage.ts:1: Appends messages to log file in real-timegenerateLogs.ts:1: Reads log file and creates Discord attachment
Airtable Integration (src/modules/checkAirtableRecords.ts:1)
- Polls Airtable API for new form submissions
- Tracks latest record ID to avoid duplicate processing
- Extracts form fields (name, contact info, request details, reference images)
- Posts formatted messages to commission channel via webhook
News Feed (src/utils/getNewsFeed.ts:1)
- Fetches latest articles from Al Jazeera Palestine live blog via GraphQL
- Tracks last posted article ID to prevent duplicates
- Sends new updates to news webhook channel
2.8.3. Data Flow
User Action (Discord) → Event Listener → Event Handler → Module Logic
↓
External API / Webhook Call
↓
Response/Notification
↓
Logging (Winston + Debug Webhook)
Scheduled Task → External API (Airtable/Al Jazeera) → Parse Response
↓
Send to Discord Webhook
↓
Update Cache/State
2.9. Database
While Prisma ORM is installed as a dependency, the Application does not currently use a database. All state is managed in memory using cache objects attached to the extended Discord client:
bot.ticketLogs: Maps channel IDs to log file message IDsbot.lastArticle: Tracks the most recent news article ID
Ticket conversation logs are temporarily stored as text files in the logs/ directory and deleted after being sent to the archive channel.
2.10. API Integrations
2.10.1. Airtable REST API
Endpoint: https://api.airtable.com/v0/{BASE_ID}/{TABLE_ID}
Method: GET
Headers:
Authorization: Bearer {AIRTABLE_KEY}
Query Parameters:
maxRecords=100: Limit resultssort[0][field]=Created: Sort by creation timesort[0][direction]=desc: Newest first
Response Structure (src/interface/AirtableResponse.ts:1):
{
records: [{
id: string;
createdTime: string;
fields: {
Name: string;
"Contact Method": "Email" | "Discord" | "Twitter";
Handle: string;
"What would you like us to draw?": string;
"Anything Else?": string;
Reference?: { url: string }[];
}
}]
}
2.10.2. Al Jazeera GraphQL API
Endpoint: https://www.aljazeera.com/graphql (inferred from code)
Operations:
SingleLiveBlogChildrensQuery: Fetch live blog structureLiveBlogUpdateQuery: Fetch latest blog updates
The bot extracts article content and posts to the news webhook channel.
2.11. HTTP Server
The Application includes a minimal Express server (src/server/serve.ts:1):
Endpoints:
GET /- Returns HTML landing page with project information
Ports:
- HTTP: 10080 (default)
- HTTPS: 10443 (when
NODE_ENV=production)
Note: The server file includes a TODO comment suggesting deletion after Trello integration is complete.
2.12. Logging
The Application uses Winston for structured logging (src/utils/logHandler.ts:1):
Log Levels:
info: General information (bot startup, scheduled task execution)error: Error conditions (API failures, Discord errors)
Log Format:
[TIMESTAMP] LEVEL: MESSAGE
Log Destinations:
- Console (stdout)
- Debug webhook (errors only)
2.13. Error Handling
All errors are caught and:
- Logged to console via Winston
- Sent to the debug webhook with error details
- Presented to users with friendly messages (when applicable)
Example error flow (src/modules/checkAirtableRecords.ts):
try {
// API call
} catch (error) {
logHandler.error("Error message", error);
debugHook.send({ content: "Error details" });
}
2.14. Performance Considerations
- Message Caching: Fetches messages in batches of 100 to reduce API calls
- Duplicate Prevention: Tracks latest Airtable record ID and news article ID
- Rate Limiting:
- Airtable: 60-minute polling interval
- News API: 10-minute polling interval
- Concurrent Limits: Artists/distributors limited to 2 active tasks each
2.15. Security Considerations
- Environment Variables: Sensitive tokens stored in
.env(not committed) - Role Verification: Commands require support role for execution (src/events/onMessageCreate.ts:1)
- Webhook Validation: Checks webhook existence before use (src/utils/isValidWebhook.ts:1)
- Privileged Intents: Requires approval from Discord for
MessageContentintent
2.16. Troubleshooting
Bot doesn't start:
- Verify
TOKENis valid in.env - Check Node.js version is 22
- Ensure all dependencies are installed:
pnpm install
Webhooks not working:
- Verify webhook URLs are valid and accessible
- Check webhook permissions in Discord channel settings
- Use
isValidWebhookutility for validation
Airtable integration failing:
- Verify
AIRTABLE_KEY,AIRTABLE_BASE_ID, andAIRTABLE_TABLE_ID - Check Airtable API permissions
- Review Airtable API rate limits
Scheduled tasks not running:
- Check server timezone matches expected cron schedule
- Review
onReady.tsfor cron expression syntax - Check debug webhook for error messages
Ticket logs not saving:
- Verify write permissions for
logs/directory - Check disk space availability
- Review console for Winston logging errors
3. Legal Documentation
This section is for expansions to our legal policies specific to the Application.
3.1. Terms of Service
The Application is subject to our global Terms of Service, which can be found at:
https://docs.nhcarrigan.com/#/terms
3.2. Privacy Policy
The Application's privacy practices are governed by our global Privacy Policy, which can be found at:
https://docs.nhcarrigan.com/#/privacy
3.2.1. Data Collection
The Application collects and temporarily stores the following data:
Discord Data:
- User IDs (for role assignment, moderation, and ticket management)
- Message content in ticket threads (logged to text files)
- Reaction events (for tracking commission/distribution claims)
- Member join events (for auto-role assignment)
Airtable Data:
- Form submission data (name, contact method, handle, art request details)
- Reference images (URLs only)
- Submission timestamps and record IDs
Temporary Storage:
- Ticket conversation logs (stored as text files, deleted after archival)
- In-memory cache for article IDs and ticket log mappings
Data Retention:
- Ticket logs: Deleted immediately after being sent to the archive channel
- Cached data: Cleared on bot restart
- Airtable record IDs: Stored in memory to prevent duplicate processing
Third-Party Services: The Application integrates with:
- Discord (message delivery and bot functionality)
- Airtable (form submission retrieval)
- Al Jazeera (public news feed)
- Trello (configuration only, no active integration)
Users should review the privacy policies of these services for their data handling practices.
3.3. License
This software is licensed under our global software licence:
https://docs.nhcarrigan.com/#/license
Copyright: Held by Naomi Carrigan
License Type: Proprietary (see link above for full terms)
3.4. Code of Conduct
All contributors and users must adhere to our Code of Conduct:
See: CODE_OF_CONDUCT.md in the repository root
3.5. Security Policy
Security vulnerabilities should be reported according to our Security Policy:
See: SECURITY.md in the repository root
For security concerns, please contact us through:
- Chat Server: https://chat.nhcarrigan.com
- Email: contact@nhcarrigan.com
3.6. Disclaimer
The Application is provided for the specific purpose of facilitating the Art for Palestine charity event. While we strive for reliability and accuracy, the Application is provided "as-is" without warranties of any kind.
Moderation Actions: The Application includes moderation features (mute/unmute). Server administrators and support team members are responsible for using these features in accordance with Discord's Terms of Service and Community Guidelines.
External Content: The Application fetches and displays news content from Al Jazeera. We do not control or endorse this content and are not responsible for its accuracy or appropriateness.
Charity Event: This Application is specifically designed for the Art for Palestine charity event. For questions about the event itself, please visit https://art4palestine.org or contact the event organizers.
4. Contributing Documentation
This section is for documentation related to contributing to the Application's codebase.
4.1. Contributing Guidelines
Our complete contributing guidelines can be found at:
https://docs.nhcarrigan.com/#/contributing
4.2. Getting Started with Development
-
Fork the Repository
# Visit GitHub and fork the repository to your account -
Clone Your Fork
git clone https://github.com/YOUR_USERNAME/nodejs-typescript-template.git cd nodejs-typescript-template -
Install Dependencies
pnpm install -
Set Up Environment
- Create a
.envfile (see section 2.3) - Create a test Discord server and bot
- Configure test webhooks
- Create a
-
Create a Branch
git checkout -b feature/your-feature-name
4.3. Code Style and Standards
The project enforces code style through automated tooling:
ESLint Configuration:
- Extends
@nhcarrigan/eslint-config - Maximum warnings allowed: 0 (all warnings treated as errors)
- Checks both
src/andtest/directories
Prettier Configuration:
- Extends
@nhcarrigan/prettier-config - Enforces consistent formatting
TypeScript Configuration:
- Extends
@nhcarrigan/typescript-config - Strict type checking enabled
- Root directory:
./src - Output directory:
./prod
Running Linters:
pnpm lint
Auto-Fixing Issues:
# Fix ESLint issues
npx eslint src test --fix
# Fix Prettier issues
npx prettier src test --write
4.4. Writing Tests
The project uses Mocha and Chai for testing:
Test Structure:
- Test files:
test/**/*.spec.ts - Test style: TDD (Test-Driven Development)
- Timeout: 10 seconds per test
- Type: TypeScript (via ts-mocha)
Running Tests:
pnpm test
Writing a Test:
import { expect } from "chai";
import { suite, test } from "mocha";
suite("Feature Name", () => {
test("should do something", () => {
// Arrange
const input = "test";
// Act
const result = myFunction(input);
// Assert
expect(result).to.equal("expected");
});
});
4.5. Documentation Standards
JSDoc Comments: All functions, classes, and complex logic should include JSDoc comments:
/**
* Brief description of the function.
*
* @param {Type} paramName - Parameter description
* @returns {Type} Return value description
*/
function myFunction(paramName: Type): Type {
// Implementation
}
Inline Comments: Use inline comments for complex logic:
// Explanation of why this approach is used
const result = complexOperation();
Commit Messages: Follow conventional commit format:
feat: Add new featurefix: Resolve bug in ticket systemdocs: Update READMEchore: Update dependenciesrefactor: Restructure event handlerstest: Add tests for webhook validation
4.6. Pull Request Process
-
Ensure All Checks Pass:
- Run
pnpm lint(must pass with 0 warnings) - Run
pnpm test(all tests must pass) - Run
pnpm build(must compile without errors)
- Run
-
Create Pull Request:
- Use a descriptive title
- Provide detailed description of changes
- Reference any related issues
- Include screenshots/videos for UI changes
-
Code Review:
- Address reviewer feedback
- Make requested changes
- Re-request review after updates
-
Merge:
- Maintainers will merge approved PRs
- Squash and merge is preferred for clean history
4.7. Areas for Contribution
The project welcomes contributions in these areas:
Feature Enhancements:
- Trello integration completion (see TODO in
src/server/serve.ts) - Database integration using Prisma (currently installed but unused)
- Additional moderation commands
- Enhanced reporting and analytics
Bug Fixes:
- Report bugs in the #bug-reports forum channel on our Discord community
- Include reproduction steps and environment details
- PRs to fix bugs are highly appreciated
Documentation:
- Improve code comments
- Expand user guides
- Add troubleshooting sections
- Create video tutorials
Testing:
- Increase test coverage
- Add integration tests
- Create test utilities
Performance:
- Optimise message caching
- Reduce webhook API calls
- Improve scheduled task efficiency
4.8. Development Environment Setup
Recommended Tools:
- Editor: VS Code (or any TypeScript-compatible editor)
- Extensions:
- ESLint
- Prettier
- TypeScript and JavaScript Language Features
- Node Version Manager: nvm (for managing Node.js versions)
- Package Manager: pnpm 10
Discord Developer Portal Setup:
- Create a new application at https://discord.com/developers/applications
- Create a bot user
- Enable required privileged intents:
Message Content,Server Members - Generate and save bot token
- Invite bot to test server with required permissions
Webhook Setup:
- Create test channels in your Discord server
- Go to channel settings → Integrations → Webhooks
- Create webhooks for: debug, comm, dist, news, ticket
- Copy webhook URLs to
.env
4.9. Debugging
Console Logging: The project uses Winston for logging. To add debug logs:
import { logHandler } from "./utils/logHandler.js";
logHandler.info("Informational message");
logHandler.error("Error message", error);
Discord Debug Webhook: Error details are automatically sent to the debug webhook. Check this channel for runtime errors.
VS Code Launch Configuration:
Create .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Debug Bot",
"runtimeArgs": ["-r", "dotenv/config"],
"program": "${workspaceFolder}/prod/index.js",
"preLaunchTask": "npm: build",
"outFiles": ["${workspaceFolder}/prod/**/*.js"]
}
]
}
4.10. Common Development Tasks
Adding a New Command:
- Add handler logic to
src/events/onMessageCreate.ts - Implement command functionality in
src/modules/ - Update user documentation (section 1)
- Add tests in
test/
Adding a New Button:
- Create button handler in
src/modules/buttons/ - Export handler in button module
- Register handler in
src/events/onInteractionCreate.ts - Update user documentation
Adding a New Event Listener:
- Create event handler in
src/events/ - Register listener in
src/index.ts - Add error handling
- Update technical documentation
Modifying Configuration:
- Update relevant file in
src/config/ - Document changes in section 2.4
- Update environment variable documentation if needed
4.11. Release Process
(For maintainers)
-
Version Bump:
- Update version in
package.json - Follow semantic versioning (MAJOR.MINOR.PATCH)
- Update version in
-
Changelog:
- Document all changes since last release
- Include breaking changes, features, and bug fixes
-
Testing:
- Run full test suite
- Test in staging environment
- Verify all integrations work
-
Deployment:
- Build production bundle:
pnpm build - Deploy to production server
- Monitor logs for issues
- Build production bundle:
-
Tag Release:
git tag -a v2.0.0 -m "Release version 2.0.0" git push origin v2.0.0
4.12. Contact for Contributors
If you have questions about contributing:
- Discord Forum: Post in the #bug-reports or #feature-requests forum channels on our Discord community
- Chat Server: https://chat.nhcarrigan.com
- Email: contact@nhcarrigan.com
We review pull requests as soon as possible and appreciate all contributions to the project.