No description
- Python 100%
| .gitignore | ||
| app.py | ||
| config.json.example | ||
| moderator.py | ||
| portal_client.py | ||
| pyproject.toml | ||
| README.md | ||
| requirements.txt | ||
| slack_manifest.json | ||
| uv.lock | ||
Slack Moderator Bot
A Slack bot that monitors configured channels and enforces posting permissions based on Portal user groups.
Requirements
- Python 3.8+
- Slack App with Socket Mode enabled
- Portal API key with access to user mapping and group membership endpoints
Setup
-
Install dependencies:
Using
uv(recommended):uv syncOr using
pip:pip install -r requirements.txt -
Configure Slack App:
- Create a Slack App at https://api.slack.com/apps using slack_manifest.json
- Enable Socket Mode
- Generate an App-Level Token with
connections:writescope (this is yourapp_token) - Install the app to the workspace
- Copy the Bot User OAuth Token (this is your
bot_token, starts withxoxb-) - Copy the User OAuth Token (this is your
user_token, starts withxoxp-)
- Copy the Bot User OAuth Token (this is your
-
Get Portal API Key:
- Log into the Portal as an admin
- Navigate to
/admin/api-keys - Generate a new API key
-
Configure the bot:
Edit
config.json:{ "slack": { "app_token": "xapp-...", "log_channel": "C1234567890" }, "portal": { "base_url": "https://members.artifactory.org.au", "api_key": "your-api-key-here" }, "channels": { "C1234567890": { "allowed_groups": ["portal.management_committee", "portal.moderators"], "message": "You don't have permission to post directly in this channel" }, "C0987654321": { "allowed_groups": ["portal.members"], "message": "Custom message for this channel", "log_channel": "C123123" }, "C123464354": { "allowed_groups": ["portal.members"] } } }slack.app_token: Your Slack App-Level Token (starts withxapp-, used for Socket Mode connection)slack.bot_token: Your Slack Bot User OAuth Token (starts withxoxb-, used for most API calls)slack.user_token: Your Slack User OAuth Token (starts withxoxp-, required for deleting messages)slack.log_channel: Channel ID where removal logs will be postedportal.base_url: Base URL of the Portal APIportal.api_key: Your Portal API keychannels: Map of channel IDs to their configurationallowed_groups: List of Portal groups allowed to post (user must be in at least one)message: Optional custom message to send when message is removed (defaults to "You don't have permission to post directly in this channel. Use 'reply in thread' instead.")log_channel: Optional channel ID to override the global log channel for this specific channel's removal logs
-
Get Channel IDs:
- In Slack, right-click on a channel → "View channel details"
- Scroll to the bottom to find the Channel ID (starts with
C)
Running
Start the bot:
Using uv:
uv run app.py
Or using python directly:
python app.py
The bot will connect to Slack via Socket Mode and begin monitoring configured channels.
How It Works
- Bot receives a
messageevent from Slack - Checks if the channel is configured for moderation
- Allows the message if:
- It's from a bot
- It's a threaded reply
- The user is a member of at least one allowed group
- If the message is forbidden:
- Deletes the message
- Sends an ephemeral message to the user
- DMs the removed message content to the user
- Logs the removal to the configured log channel
Error Handling
- If the Portal API is unavailable, errors are logged and messages are allowed (fail open)
- If a user is not found in the Portal, the message is deleted (assume no permissions)
- If logging to the log channel fails, the error is logged but the operation continues