README.md 9.2 KB

disbot-a4 — Simple, robust role selector bot

Author: Lari Natri, 2025

License: MIT

A simple, robust Discord role-picker bot built with py-cord and packaged for Docker Compose.

  • Language/Libs: Python 3.12, py-cord only
  • Persistence: SQLite (stdlib), bind-mounted ./data
  • Daily inactivity cleanup removes all pickable roles from users inactive for N days (default 14).
  • Auto-refresh updates all status panels and DM panels at a configurable interval (default 5 minutes).
  • Restart-safe: DB + tasks resume; re-create UI via /role-admin-post-status (or auto-post on startup if configured)
  • Public status panels: list pickable roles with member counts and "(inactive)/(full)" hints from configurable min/max values.
  • UI: Personal role picker via /roles (sent to your DMs) with buttons to toggle your roles.
  • UI: User slash commands for listing and toggling roles.
  • UI: Admin slash commands to configure pickable roles, limits, inactivity timeout, refresh cadence, list members, manage users, and post status panels.

1) Quick start

  1. Discord Developer Portal setup

Discord Developer Portal

  1. Create Application -> Bot: copy the token to secrets/discord_token.txt.
  2. Privileged Gateway Intents (Bot settings -> Privileged Gateway Intents):
    • Enable Server Members Intent
    • (Optional) Enable Message Content Intent if you want the bot to track activity from messages for inactivity cleanup. Otherwise the bot still works; you can set activity via role interactions only.
  3. Invite the bot with scopes:
    • bot, applications.commands
  4. Bot Permissions: at minimum grant
    • Manage Roles
    • View Channel
    • Send Messages
    • Read Message History
    • Manage Messages
  5. Copy the generated Invite URL and invite the bot to your server.
  6. Grab your Guild ID (enable Developer Mode in Discord client -> right-click server icon -> Copy Server ID) and set it in .env as GUILD_ID.

Role hierarchy: Move the bot's highest role above every pickable role you want it to manage. The bot cannot add/remove roles equal to or above its top role. Managed/integration roles cannot be assigned by bots.

  1. Create secrets & env

    mkdir -p secrets data
    sudo chown -R 10001:10001 data
    echo "YOUR_BOT_TOKEN_HERE" > secrets/discord_token.txt
    cp .env.example .env
    # Edit .env: set GUILD_ID and (optionally) ROLE_PANEL_CHANNEL_ID, etc.
    
  2. Build & run

    docker compose up -d --build --remove-orphans
    
  3. Add selectable roles for the server

    • On Discord server, add selectable roles with slash command: /role-admin-add-pickable:@Role (optional min_users, max_users)

    • See all commands with /role-help

  4. Post the role panel

    • If you set ROLE_PANEL_CHANNEL_ID in .env, the bot will auto-post the panel on startup.
    • Otherwise, in any channel, run (as an admin): /role-admin-post-status

2) Environment variables

Name Required Default Notes
GUILD_ID Yes Guild (server) ID where the bot operates & registers commands (fast sync).
ROLE_PANEL_CHANNEL_ID No If set, bot auto-posts the panel on startup to this channel.
INACTIVITY_DAYS_DEFAULT No 14 Initial value for inactivity (can be changed with slash command).
REFRESH_MINUTES_DEFAULT No '5' Initial value for refreshing role status on posts (can be changed with slash command).
DATABASE_PATH No /app/data/bot.db SQLite DB path (persisted via volume ./data:/app/data).
LOG_LEVEL No INFO DEBUG, INFO, WARNING, ERROR.
TZ No Europe/Helsinki Provided via Docker environment in docker-compose.yml.

Secret (via Docker secrets):

  • ./secrets/discord_token.txt — put your bot token here (no quotes, single line).

3) What the bot does

Public status panels

  • Posted with /role-admin-post-status (admin-only; posts a message visible to everyone).
  • Lists each pickable role, current member count, plus (inactive) if count < min and (full) if count ≥ max (when configured).
  • Contains a Refresh button.
  • The bot stores all posted panel message IDs and auto-refreshes them (see below).

Personal DM role picker

  • Users run /roles to receive a DM with a personalized panel.
  • Buttons show primary/secondary style depending on whether the user currently has each role.
  • If DMs are closed, the bot shows a one-off ephemeral panel in the channel instead (not tracked for auto-refresh).

Auto-refresh

  • Refresh cadence is configurable globally per guild via /role-admin-refresh (minutes).
  • The bot updates:
    • All public status panels it has posted in that guild.
    • All tracked DM panels it sent with /roles.
  • Also refreshes promptly after admin config changes and user role toggles.

Inactivity cleanup

  • Daily, removes all pickable roles from members whose last activity timestamp is older than N days (configurable).
  • "Activity" is updated on any message or role interaction handled by the bot.
  • Default inactivity days come from INACTIVITY_DAYS_DEFAULT and can be changed live using /role-admin-set-inactivity-days.

What counts as activity?

  • Any message a user sends in the guild updates their last_active timestamp.
  • The daily job removes selectable roles from users with no messages for longer than inactivity_days.

You can change inactivity_days anytime using /role-admin-set-inactivity-days. Default is taken from INACTIVITY_DAYS_DEFAULT when the bot first sees the guild.


4) Commands

User commands

  • /roles Open your personal role picker (DM). Shows the server name & ID in the message. > NOTE: The UI shows at most 25 role buttons in a single panel message > due to Discord limits.
  • /role-list List the pickable roles you currently have (ephemeral reply).
  • /role-pick <role> Add yourself to a pickable role.
  • /role-unpick <role> Remove yourself from a pickable role.
  • /role-toggle <role> Toggle a pickable role on/off.
  • /role-help Show all user commands. If you're an admin, admin commands are listed as well.

Admin commands

  • /role-admin-post-status Post a public role status panel in the current channel (anyone can see it). Panel lines include min/max-based labels: "(inactive)" if count < min and "(full)" if count ≥ max.
  • /role-admin-add-pickable <role> [min] [max] Add or update a pickable role and optional min/max hints.
  • /role-admin-remove-pickable <role> Remove a role from the pickable list.
  • /role-admin-set-role-limits <role> [min] [max] Adjust min/max hints for a pickable role.
  • /role-admin-set-inactivity-days <days> Set inactivity timeout in days (default: 14).
  • /role-admin-set-refresh-interval <minutes> Set auto-refresh interval in minutes (default: 5).
  • /role-admin-refresh-now Trigger an immediate refresh
  • /role-admin-list-users List all pickable roles and the users in each (ephemeral to the admin).
  • /role-admin-list-config Show current configuration (inactivity days, refresh minutes, pickable roles with limits).
  • /role-admin-add-user-for-role <user> <role> Add a specific user to a pickable role (admin-controlled).
  • /role-admin-remove-user-from-role <user> <role> Remove a specific user from a pickable role (admin-controlled).

All admin commands respond ephemerally to the invoking admin. Public status panels are visible to everyone.


5) Persistence

  • SQLite database at DATABASE_PATH (default /app/data/bot.db), bind-mounted to ./data/bot.db by docker-compose.
  • Tables:
    • settings (inactivity_days, refresh_minutes)
    • roles (pickable role IDs + optional min/max)
    • activity (last activity per user)
    • panels (public panel messages for auto-refresh)
    • dm_panels (user DM panels for auto-refresh)

Back up by copying the data/ directory (container must be stopped for consistent copy if heavy write load is ongoing).


6) Troubleshooting

  • Buttons say "I cannot manage that role due to role hierarchy/permissions."

    • Grant the bot Manage Roles permission.
    • Move the bot's highest role above all pickable roles.
    • Don't use managed/integration roles as pickables.
  • "Missing Access (50001)" when posting a status panel Verify the bot has View Channel and Send Messages in that channel. Avoid forum roots; use a text channel or a thread.

  • Commands don't show up If GUILD_ID is set, commands register immediately for that guild. Without it, global registration can take a while. Set GUILD_ID to your server ID in .env for instant registration during setup.

  • Inactivity cleanup appears to skip Ensure GUILD_ID is set to your target guild. The daily task only runs for GUILD_ID (by design).

  • DM panel not received User may have DMs closed. The bot will fallback with an ephemeral panel (not tracked for auto-refresh).