Skip to content

ak811/community-votes

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Community Votes (Discord Bot)

A lightweight “democracy-driven” moderation bot for Discord: members vote on actions (timeout, jail/unjail, delete, channel management, VIP), and when the vote total reaches a threshold, the bot executes the action.

It’s basically crowdsourced moderation with guardrails, plus optional “force” actions for trusted roles/users (with a 1-week cooldown). Because humans needed more buttons.


What this bot does

Core idea

  • Every vote has an action (e.g., timeout) and a target (a user, message, or channel).
  • Votes are weighted by each voter’s configured vote power (default weight = 1).
  • Votes remain open for a vote window (default: 30 minutes) and then expire if the threshold isn’t reached.
  • When the threshold is reached, the bot executes the action and clears the vote.

Key features

  • Vote-based actions:
    • Jail (ban) / Unjail (unban)
    • Timeout / Untimeout
    • Delete message (by link or reply)
    • Make VIP
    • Channel actions: Create, Archive, Unarchive, Move, Rename, Reposition
  • Weighted voting:
    • Configure vote power by role or user override.
  • “Force” actions:
    • # commands for trusted roles/users, enforced with a 7-day cooldown.
  • Logging:
    • Staff log embeds to a configured logs channel.
    • Deletion logging includes message content, embed flattening, attachment URLs, and image attachment capture.
  • Persistence:
    • SQLite DB stores server config, thresholds, vote powers, force grants, force cooldowns, jailed state.

Quick start

1) Install dependencies

python -m venv .venv
# Windows:
.venv\Scripts\activate
# macOS/Linux:
source .venv/bin/activate

pip install -r requirements.txt

2) Create .env

Copy .env.example.env and fill it in:

DISCORD_TOKEN="YOUR_TOKEN_HERE"
DEFAULT_PREFIX=!
DB_PATH=./data/community_votes.sqlite
LOG_LEVEL=INFO

# Optional: where delete-action image attachments get stored
DELETED_MEDIA_DIR=./data/deleted_media

3) Initialize the database

python -m community_votes.bootstrap.loader --init-db

4) Run the bot

python -m community_votes.bootstrap.loader

Required Discord permissions

At minimum, the bot needs:

  • Read Messages / View Channels
  • Send Messages
  • Manage Webhooks (recommended, so it can speak using personas; it will fall back to normal sends if it can’t)
  • Manage Roles (for jail/unjail and VIP role assignment)
  • Moderate Members (for timeouts)
  • Manage Messages (for deletion)
  • Manage Channels (for create/move/rename/archive/unarchive/reposition)

Also:

  • Ensure the bot’s highest role is above the roles it must assign/remove (Jail, Member, VIP).

Server setup (one command that matters)

You must configure your server roles/channels before moderation actions will work correctly.

!cv setup

!cv setup <MemberRole> <JailRole> <VIPRole> <#logs> <#jail>

Accepted inputs:

  • Roles: mention (@Role), raw ID, or exact name (case-insensitive).
  • Channels: mention (#channel), raw ID, or exact name (case-insensitive).

Example:

!cv setup @Member @Jail @VIP #staff-logs #jail

Confirm config

!cv show_config

How voting works

Vote window

  • Default: 30 minutes (DEFAULT_VOTE_WINDOW_SECONDS = 30 * 60)
  • Can be overridden per guild in the database (guild_config.vote_window_seconds).

Thresholds

  • Defaults live in community_votes/config.py (DEFAULT_THRESHOLDS)
  • Can be overridden per action per guild with:
    • !vote set-threshold <action> <number>
    • !vote reset-threshold [action]

Show effective thresholds:

!vote show-thresholds

Important note about “sensitive bumps”:

  • delete in sensitive channels: adds +20 to threshold (implemented)
  • create_channel, move_channel, unarchive_channel in sensitive categories: adds +5 to threshold (implemented)
    • If you see docs/messages saying +20 for categories, that’s a mismatch with the current code. The code uses +5.

Vote power

Vote power = how much your vote counts.

Resolution order:

  1. User override (can be 0 to disable voting)
  2. Highest configured role weight
  3. Default 1

Commands:

!vote set-power <@role|role_id|@user|user_id|name> <weight>
!vote unset-power <@role|role_id|@user|user_id|name>
!vote show-roles
!vote show-power

Force actions (#) and cooldown

Some commands have a “force” version that executes immediately (no vote), but only for granted roles/users and only once per action per week.

Grant or revoke force power:

!vote set-forceban-power <@role|role_id|@user|user_id|name> on|off
!vote show-forceban-power

Cooldown:

  • 7 days per action (FORCE_COOLDOWN = timedelta(days=7))

Force examples:

!ban# @user spamming
!timeout# @user 10m chill
!delete# <message link>   # or reply to message and run !delete#
!unban# <user_id>

Commands users actually care about

The bot exposes most commands both as:

  • direct commands like !ban, and
  • subcommands under the hub like !vote ban

Hub

!vote

Shows a help-style “how it works” embed and lists default thresholds.

Moderation actions

!ban @user [reason]       # aka !jail
!unban <user_id|mention>  # aka !unjail
!timeout @user 10m [reason]
!untimeout @user

Message deletion

Delete a message by link:

!delete https://discord.com/channels/<guild>/<channel>/<message>

Or reply to a message and run:

!delete

VIP

!make vip @user
# alias: !make_vip @user

Channel management

!create tc|vc <name> <category_id> [position]
!archive #channel
!unarchive                 # lists channels inside the archive category
!unarchive #channel <category_id> [position]
!move #channel <category_id> [position]
!rename #channel <new_name>
!reposition #channel <position>
!reposition #channel <category_id> <position>

Archiving behavior (channel lifecycle)

Archiving is opinionated:

Archive

When a vote reaches threshold for archive_channel:

  • Sets @everyoneview_channel = False
  • Moves the channel into a fixed archive category

That category is configured in code:

  • community_votes/config.pyARCHIVE_CATEGORY_ID

If you move servers or recreate categories, update that constant.

Unarchive

Unarchive is only allowed if the channel currently lives in ARCHIVE_CATEGORY_ID, then it:

  • restores @everyone view
  • restores @everyone connect for voice/stage channels
  • moves to the requested category (and optional position)

Also:

  • Running !unarchive with no args lists channels currently in the archive category.

Database (SQLite)

Default path: ./data/community_votes.sqlite (configurable via DB_PATH in .env)

Tables:

  • guild_config (roles/channels, vote window, sensitive/protected lists)
  • thresholds (per-guild action overrides)
  • vote_power_roles, vote_power_users
  • force_power_roles, force_power_users
  • force_cooldowns
  • jailed_users

Schema lives at:

  • community_votes/db/schema.sql

Protected & sensitive channels/categories

The schema supports:

  • sensitive_channel_ids, sensitive_category_ids
  • protected_channel_ids, protected_category_ids

Currently implemented behaviors:

  • Sensitive:
    • delete votes get +20 threshold bump if the target message is in a sensitive channel
    • channel actions create/move/unarchive get +5 bump if the destination category is sensitive
  • Protected:
    • delete action refuses to delete in protected_channel_ids

You can populate those lists by updating guild_config in the DB (there is no chat command for this yet).


Logging & deletion media retention

If you set a logs channel via !cv setup, the bot will post staff log embeds.

For delete:

  • The bot logs:
    • author, channel, message id, jump link (pre-deletion)
    • content (trimmed), embeds (flattened/trimmed), attachments list
  • Image attachments are also:
    • downloaded
    • saved to disk under DELETED_MEDIA_DIR (default ./data/deleted_media)
    • uploaded into the logs channel as attachments for auditability

License

MIT (see LICENSE).

About

Community Votes (Discord Bot)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages