proudly-snoring / seat-comlink
SeAT plugin managing Discord roles (from squads) and nicknames on multiple servers
Package info
github.com/Proudly-Snoring/seat-comlink
Type:seat-plugin
pkg:composer/proudly-snoring/seat-comlink
Requires
- php: ^8.1
- ext-json: *
- eveseat/eveapi: ^5.0
- eveseat/services: ^5.1
- eveseat/web: ^5.0.35
- guzzlehttp/guzzle: ^7.0
- laravel/framework: ^10.0
Requires (Dev)
- josiasmontag/laravel-redis-mock: ^1.0
- mockery/mockery: ^1.6
- orchestra/testbench: ^8.0
- phpunit/phpunit: ^10.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
A SeAT plugin that manages Discord members from SeAT data:
it assigns Discord roles based on SeAT squads and enforces Discord nicknames based on the users' characters
(ex: [TICKR] Character Name), on one or more Discord servers.
How it works
- An admin creates a Discord application with a bot, enters its credentials in SeAT and invites the bot to one or more Discord servers.
- Admins map SeAT squads to Discord roles, per server (
Comlink > Discord Mappings). A user gets a role if they belong to at least one squad mapped to it. - Users link their Discord account from
Comlink > Identity("Link my discord" button, Discord OAuth,identifyscope only). Users must join the Discord servers by themselves. - At a regular interval (1 to 60 minutes, configurable), the bot polls each server through the Discord REST API and, for every non-bot member:
- linked member: adds/removes the managed roles to match their squads, and enforces their nickname,
- unknown member: removes all managed roles.
Only mapped roles are managed: other roles are never touched.
Nickname and role enforcement can be disabled per server.
Every action is recorded in Comlink > Logs.
Nickname format
The format is defined per server. Default: [{corp_ticker}] {character}.
| Token | Value |
|---|---|
{character} |
Main character name (first character if no main) |
{corp_ticker} |
Main character's corporation ticker |
{corp_name} |
Main character's corporation name |
{alliance_ticker} |
Main character's alliance ticker |
Missing values are replaced by -.
Nicknames follow Discord naming rules: extra whitespaces and zero-width/non-rendering characters are removed, then the result is truncated to 32 characters.
Views and permissions
| View | Purpose | Permission |
|---|---|---|
Comlink > Identity |
Link / unlink one's Discord account | comlink.identity |
Comlink > Discord Mappings |
Squads -> roles mapping, per server | comlink.mappings |
Comlink > Discord Servers |
Per-server options, nickname format | comlink.servers |
Comlink > Users |
Linked users and their Discord state | comlink.users |
Comlink > Logs |
Plugin logs | comlink.logs |
Comlink > Settings |
Bot credentials, sync rate, logs retention | comlink.settings |
Grant them from Settings > Access Management. Give comlink.identity to the role(s) of all users who should be able to link their account.
Requirements
- SeAT 5.x (PHP 8.1+, Laravel 10).
- A Discord application with a bot.
Installation
1. Install the package
Docker installation
In your seat-docker directory (ex: /opt/seat-docker), add the package to SEAT_PLUGINS in the .env file (comma separated):
SEAT_PLUGINS=proudly-snoring/seat-comlink
Then restart the stack with your usual compose files, for example:
# Traefik docker compose -f docker-compose.yml -f docker-compose.mariadb.yml -f docker-compose.traefik.yml up -d # Reverse proxy docker compose -f docker-compose.yml -f docker-compose.mariadb.yml -f docker-compose.proxy.yml up -d
The plugin is installed, migrated and scheduled when the containers start. Follow progress with docker compose logs --tail 10 -f.
Standalone (bare metal) installation
From the SeAT directory (ex: /var/www/seat):
sudo -H -u www-data bash -c 'php artisan down' sudo -H -u www-data bash -c 'composer require proudly-snoring/seat-comlink' sudo -H -u www-data bash -c 'php artisan vendor:publish --force --all' sudo -H -u www-data bash -c 'php artisan migrate' sudo -H -u www-data bash -c 'php artisan route:cache' sudo -H -u www-data bash -c 'php artisan config:cache' sudo -H -u www-data bash -c 'php artisan seat:cache:clear' sudo -H -u www-data bash -c 'php artisan db:seed --class=Seat\\Services\\Database\\Seeders\\PluginDatabaseSeeder' sudo -H -u www-data bash -c 'php artisan up'
Then restart your queue workers (supervisor) so they load the plugin.
2. Create the Discord application
- Go to the Discord developer portal and create an application.
- In OAuth2, copy the Client ID and Client Secret.
Then in Redirects, click Add Redirect, paste the callback URL displayed in
Comlink > Settings(https://<your-seat>/seat-comlink/discord/callback) and click Save Changes. Without it, users get an "Invalid OAuth2 redirect_uri" error when linking their account. - In Bot:
- reset and copy the Token,
- enable the Server Members Intent (privileged intent, required to list members),
- optionally disable Public Bot.
3. Configure the plugin
- In
Comlink > Settings, enter the Client ID, Client Secret and Bot Token, then save. - Click Invite bot and add it to each Discord server (requires the Manage Roles and Manage Nicknames permissions).
- On each Discord server, drag the bot's role above every role it must manage (Discord hierarchy rule).
- In
Comlink > Discord Servers, adjust the per-server options (the server appears after the next synchronization, or after "Import roles now" in the mappings). - Create the mappings in
Comlink > Discord Mappings. - Grant the
comlink.*permissions inSettings > Access Management.
Artisan commands
Docker: prefix the commands with docker compose exec front (ex: docker compose exec front php artisan comlink:discord:sync).
Bare metal: run them as www-data from the SeAT directory.
| Command | Description |
|---|---|
php artisan comlink:discord:sync |
Queues a synchronization of all Discord servers. Options: --server=<id> to sync a single server, --now to run synchronously instead of queueing (debug). Scheduled automatically at the configured rate. |
php artisan comlink:discord:import-warlof |
Imports the users' Discord links from seat-discord-connector. Conflicting links are skipped and reported. Option: --dry-run to only report. Credentials and policies are not imported. |
php artisan comlink:logs:prune |
Deletes logs older than the retention setting (default 30 days). Option: --days=<n> to override. Scheduled daily. |
Migrating from seat-discord-connector
- Install and configure seat-comlink (you may reuse the same Discord application, adding the new redirect URL).
- Run
php artisan comlink:discord:import-warlof --dry-run, then without--dry-run. - Recreate the access rules as squads + mappings (warlof's corporation/alliance/title filters map to squad filters).
- Uninstall seat-discord-connector, so that both bots do not fight over the same roles.
Troubleshooting
Failed to update nickname/role ... Missing Permissions: the bot's role is below the target role or member. Move it up in the server's role list. The server owner's nickname can never be changed by a bot.Failed to synchronize server ... Missing Access (50001): the Server Members Intent is not enabled on the bot.- Nothing happens: check the bot token in
Comlink > Settings, then runphp artisan comlink:discord:sync --nowand readComlink > Logs.
Tests
Tests run on Testbench with an in-memory sqlite database and a stateful fake of the Discord API (no network):
composer update vendor/bin/phpunit