/member — Slash Command Spec¶
/member eventsand/member infoare implemented./member togis Phase 3 scope./member meis a Phase 2 stretch goal.
Commands¶
/member events [@member] [optional:role]
/member info [@member]
/member tog [add|remove|info] [@member]
/member me
/member events [@member] [optional:role]¶
Access¶
Chapter Organizer+
Parameters¶
@member— Discord mention, resolved to$Peopleviaresolve_member(snowflake)role(optional) — autocomplete:Attendee,Instructor,TA,Medic. If omitted, shows all roles where data exists.
Grist Fields Used¶
| Grist field | Type | Notes |
|---|---|---|
events_attended |
ReferenceList → Events | Events where member appears in attendees |
dates_instructed |
ReferenceList → Events | Events where member appears in instructors |
dates_TAed |
ReferenceList → Events | Events where member appears in TAs |
dates_mediced |
ReferenceList → Events | Events where member appears in medic |
regions_attended |
Text | Pre-formatted regions breakdown |
Each referenced Event row uses structured_event (ChoiceList) and event_date (Date).
Response Format¶
Ephemeral. Example for /member events @alice:
Event history — @alice
Last event: 6/14/24
Attended Instructor
Pistol 1 3x (last 4/15/24) 2x (last 6/14/24)
Pistol 2 1x (last 1/10/24) —
Rifle 1 2x (last 3/2/24) —
Regions: South: 8, North: 3
- Future-dated events are excluded from all counts and dates.
- Empty rows (no data for that event type) and empty columns (no data for that role) are omitted.
- Event types are sorted by
STRUCTURED_EVENT_TYPESorder; unknown types sort alphabetically after.
Dev Notes¶
_build_matrix()fetches all referenced event IDs across all active roles, then fetches those event rows in oneget_recordscall filtered by ID.- Future events are filtered by comparing
event_dateagainstdatetime.now(utc).timestamp(). - The matrix cell format is
Nx (last M/D/YY)or—for zero.
/member info [@member]¶
Access¶
Chapter Organizer+
Parameters¶
@member— Discord mention, resolved to$Peopleviaresolve_member(snowflake)
Grist Fields Used¶
| Display | Grist field | Type |
|---|---|---|
| Last event | derived via _build_matrix() |
see /member events |
| Handle | common_handle |
Text |
| Aliases | all_aliases_no_PII |
Text |
| Region(s) | discord_id_Region_roles_region |
List |
| Officer role(s) | discord_id_Officer_roles_role |
List |
| Backlog join date | backlog_join_date |
Date |
| Vetted date | done_vetting_date |
Date |
| Dues expiration | dues_expiration |
Date |
| LC dues current | LC_dues_current |
Bool |
| ToG | is_ToG |
Bool |
Response Format¶
Ephemeral. Example for /member info @alice:
Member info — @alice
Last event: 6/14/24 (Pistol 1, Instructor)
Handle: alice
Aliases: Alice Smith, alicesmith
Region(s): South, North
Officer role(s): Organizing Committee
Backlog join date: 3/15/23
Vetted date: 4/1/23
Dues expires: 4/1/26 ✅ current
ToG: ✅ Yes
- Last event line shows date, event type, and role. Omitted if no event history.
- Vetted date omitted if null. Officer roles omitted if empty.
- Dues:
✅ currentifLC_dues_current, otherwise⚠️ expired. Omitted ifdues_expirationis null.
Dev Notes¶
- Calls
_build_matrix()(all roles, no filter) to derive the last event line — same future-event exclusion applies. - All fields are read-only.
/member me¶
Stretch goal for Phase 2. Implementation contingent on available hours.
Signature¶
/member me
/member me email [new_email]
Access¶
Any verified member (no organizer role required)
me (no subcommand)¶
Returns an ephemeral showing the caller's own non-sensitive member profile (same fields as /member info but self-directed). Read-only.
me email [new_email]¶
Updates $People.preferred_email_address for the calling member. Bot confirms the change before writing.
Dev Notes¶
- Resolves caller via
resolve_person(interaction.user.id)— no@memberparam preferred_email_addresswrite requires confirming the no-PII bot user has write access to this field
/member tog [add|remove|info] [@member]¶
Signature¶
/member tog [@member] — defaults to info
/member tog info [@member]
/member tog add [@member]
/member tog remove [@member]
Access¶
Representative+
What is ToG¶
"Toucher of Grass" — a member who has attended at least one counts_for_ToG event in the past 18 months (~547 days). Tracked via $People.tog_dates_attended_instructed_etc and $People.is_ToG.
info action¶
Read-only. Returns ephemeral:
🌿 ToG status — @alice
Current: ✅ Yes
Last ToG event: Jun 14 2024 — South P1
ToG events (18mo window): 4
Officer role (exempt from ToG req): No
Fields:
- is_ToG — bool, pre-computed on $People
- last_facilitated_or_tog_attended → event date and title
- tog_dates_attended_instructed_etc — count those within 547 days of today
- discord_id_Officer_roles_role — if non-empty and not only ["Vetting Team"], note exemption
add action¶
Assigns the ToG Discord role to the member and adds a row to the Touchers_of_grass Grist table. No event selection, no changes to $Events.
Flow:
1. Assign the ToG Discord role to the member
2. POST a new row to Touchers_of_grass linking the member
Note: Bot may not have create-row permissions on Touchers_of_grass. Verify before implementing; if not, the organizer will need to add that row in Grist manually.
remove action¶
Revokes the ToG Discord role and removes the member's row(s) from the Touchers_of_grass Grist table. Used when ToG status expires.
Flow:
1. Remove the ToG Discord role from the member
2. DELETE the member's row(s) from Touchers_of_grass
Dev Notes¶
is_ToGformula in$People: if member has an officer role other than Vetting Team, returns True regardless of attendance. Bot should reflect this exemption in display.- Do not attempt to replicate
is_ToGlogic in the bot — read the field directly tog_dates_attended_instructed_etcis ordered by-event_date— the first element is the most recent
Open Questions¶
- Bot write access to
Touchers_of_grass— confirm whether the bot's API key has create-row permissions on this table before implementingtog add. Touchers_of_grassdelete permissions — confirm whether the bot's API key can delete rows on this table before implementingtog remove./member eventsfor non-Discord members — all current members have Discord, so@mentionis fine for now. Revisit at P3.