Skip to content

Add Discipline Log and State Transfer cogs + shared Event Registry#99

Open
blackdeathwos wants to merge 2 commits into
whiteout-project:mainfrom
blackdeathwos:feat/discipline-transfer-cogs
Open

Add Discipline Log and State Transfer cogs + shared Event Registry#99
blackdeathwos wants to merge 2 commits into
whiteout-project:mainfrom
blackdeathwos:feat/discipline-transfer-cogs

Conversation

@blackdeathwos

Copy link
Copy Markdown

PR: Discipline Log + State Transfer cogs + Event Registry

Summary

This PR adds two new cogs and a shared event registry module.


New Cog: Discipline Log (cogs/discipline.py)

A full infraction tracking system for alliance admins. Infractions are tied
to a player FID, an event type, an infraction category, and a punishment.
Each record carries an optional expiry date and is soft-deleted so the audit
trail is never lost.

Access: Settings menu → Discipline Log button, or /disc

Permission requirements:

  • Alliance Admin and above: log, view, and edit infractions
  • Global Admin and above: also delete records and configure settings

What it does:

Feature Description
Log Infraction Step-by-step wizard — FID → Event → Infraction type → Punishment type → Notes & expiry → Confirm. Posts a summary embed to a configured leadership channel and offers to DM the member.
View History Look up a player by FID. Filter by time range (30 / 60 / 90 days or all time) and toggle expired records on/off.
Edit Expiry Update the expiry date on any active record. Accepts "never", a number of days, or a YYYY-MM-DD date.
Delete Record Soft-delete — marks the row as deleted and records who deleted it and when. The row is retained for audit purposes. (Global Admin only)
Settings Configure the leadership channel that receives infraction posts and the default expiry period. (Global Admin only)

Slash commands registered:

  • /disc — open the main discipline menu
  • /disc-setup <channel> — set the leadership channel
  • /disc-expiry <days> — set the default expiry period

Database: db/discipline.sqlite

infractions
  id, fid, event, infraction, punishment, notes,
  logged_by_id, logged_by_name, logged_at,
  expiry_date (NULL = permanent), is_deleted, deleted_by_id, deleted_at

db/settings.sqlite → discipline_settings (key/value)
  channel_id           Discord channel for leadership posts
  default_expiry_days  Default expiry in days (default: 30)

New Cog: State Transfer Manager (cogs/transfer.py)

Maintains a prioritised list of players nominated for an outbound state
transfer. Admins create a named event, add players by FID, assign priority
tiers, and export a ranked CSV with an automatic pass-cutoff row.

Access: Settings menu → State Transfer button, or /transfer

Permission requirements:

  • Alliance Admin and above: full access

What it does:

Feature Description
Create Event Enter a name, transfer date, and optional power threshold. If an event is already active, continue it or close it and start a new one.
Add Players Enter FIDs (one per line or comma-separated). Select a priority tier for the batch (High / Med / Low). Each FID is looked up via the game API to resolve the player's nickname; unresolvable FIDs are reported as failures.
View List All players sorted by priority then addition order. Players whose power exceeds the threshold are flagged ⚠️.
Change Priority Reassign any player's priority tier via dropdown.
Remove Player Hard-remove a player from the active list.
Export CSV Enter the number of available passes. A ranked CSV is generated with a cutoff row at position N+1 and a "Special Pass Required" column for over-threshold players. Sent to the admin via DM.
Close Event Archives the event (status → closed). All data is retained.

Slash commands registered:

  • /transfer — open the transfer event manager

Database: db/transfer.sqlite

transfer_events
  id, name, transfer_date, power_threshold,
  status (active | closed), created_at, created_by_id

transfer_players
  id, event_id, fid, name, power, priority (high | med | low),
  added_by_id, added_at

New Module: Event Registry (cogs/event_registry.py)

A centralised game-event registry — single source of truth for every
in-game event referenced across the bot.

The problem it solves:

Before this module, each cog maintained its own event list with inconsistent
naming. The same real-world events appeared under different names:

Event discipline.py attendance.py notification_event_types.py
Foundry Battle "Foundry Battle" "Foundry" "Foundry Battle"
Bear Trap "Bear Hunt" "Bear Trap" "Bear Trap"
Castle Battle "Sun Fire Castle" "Castle Battle" "Castle Battle"
Frost Dragon Tyrant "Frost Dragon Tyrant" "Frostdragon Tyrant"
State vs State "State vs State" "SvS"

It also fixes a long-standing typo: "Icefife Warhymn League"
"Icefire Warhymn League".

How it works:

REGISTRY is a list of dicts — one per event — each carrying:

  • key — stable snake_case identifier (matches OCR parser keys)
  • display_name — canonical in-game name shown in all menus
  • short_name — abbreviated form for space-constrained contexts
  • Flags: discipline, attendance, notifications, legion, ocr_key
  • legacy_names — previous names used in other cogs (migration reference)

Pre-filtered lists are derived from the registry at import time:

from .event_registry import DISCIPLINE_EVENTS as EVENTS
from .event_registry import ATTENDANCE_EVENT_TYPES as EVENT_TYPES
from .event_registry import ATTENDANCE_LEGION_EVENT_TYPES as LEGION_EVENT_TYPES

Cogs updated in this PR:

  • discipline.py — imports DISCIPLINE_EVENTS from registry (replaces hardcoded list)

Cogs that should adopt the registry in a follow-up:

  • attendance.py — replace EVENT_TYPES and LEGION_EVENT_TYPES
  • notification_event_types.py — align key names with display_name values
  • attendance_ocr_parsers.pylabel fields already match; use key for cross-referencing

Data migration note:

Event names are stored as plain strings in db/discipline.sqlite and
db/attendance.sqlite. Renaming an event here does not update existing rows.
The legacy_names field on each registry entry documents the old strings so
a migration script can be written if needed:

-- Example: align old discipline records with canonical names
UPDATE infractions SET event = 'Bear Trap'      WHERE event = 'Bear Hunt';
UPDATE infractions SET event = 'Castle Battle'  WHERE event = 'Sun Fire Castle';
UPDATE infractions SET event = 'Icefire Warhymn League' WHERE event = 'Icefife Warhymn League';

Running these is optional — existing records still display correctly using
whatever string was stored.


Files changed

File Change
cogs/discipline.py New cog
cogs/transfer.py New cog
cogs/event_registry.py New shared module
cogs/bot_main_menu.py Added Discipline Log and State Transfer buttons to Settings menu (row 3)

blackdeathwos and others added 2 commits June 25, 2026 20:36
- cogs/discipline.py: full infraction tracking system for alliance admins
  (log, view, edit, soft-delete, settings; posts to leadership channel,
  DMs member, stores in db/discipline.sqlite)
- cogs/transfer.py: outbound state transfer manager (create event, add
  players by FID, set priority tiers, export ranked CSV with pass-cutoff
  row; stores in db/transfer.sqlite)
- cogs/event_registry.py: centralised game-event registry — single source
  of truth for every in-game event name; fixes long-standing "Icefife"
  typo; discipline.py imports DISCIPLINE_EVENTS from it
- cogs/bot_main_menu.py: add Discipline Log and State Transfer buttons to
  Settings menu (row 3) with handler methods on MainMenu cog

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@justncodes justncodes self-assigned this Jun 26, 2026
@justncodes

Copy link
Copy Markdown
Member

Thanks for your submission. At a glance I will say that we actually have 3 separate PRs here - 3 distinct features that do not really depend on each other and 3 different decisions to make on whether to merge them or not. Whether we accept one feature does not imply we need to accept the others to. Transfer and discipline both look like features we can definitely integrate, though I'll have to consider where to put their respective buttons to avoid the menu getting messy.

For event registry; I do think we could have a centralized registry for consistency, but this needs to be carefully considered. The inconsistency you point out was literally non-existent until the other cog which you created - the existing ones were already very consistent in naming, and the naming correctly matches the in-game event (except the shortened "Foundry" instead of "Foundry Battle", which was done on purpose in this case and is a legit shortening of the event name)...

Can you please submit separate PRs for each feature you are proposing here? Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants