Conversation
… eliminating redundant event list lookups during edit/delete flows
…com/CApy-RPI/discord-bot into feature/capr-55-test-event-db-calls
…o feature/capr-55-test-event-db-calls
…sing guild id, and org look-up via guild id.
…ed org id to the .env file.
Reviewer's GuideThis PR refactors the event cog to use backend organization and event identifiers instead of guild IDs and encoded descriptions, adds robust fallbacks for fetching events across multiple backend API variants, and introduces extensive tests for the event extension and new database client endpoints. Sequence diagram for resolving org id and listing eventssequenceDiagram
actor User
participant Discord
participant EventCog
participant DatabaseClient
User->>Discord: /event list
Discord->>EventCog: handle_list_action(interaction)
EventCog->>EventCog: _resolve_org_id(guild)
alt org_id cached
EventCog-->>EventCog: return cached org_id
else org_id not cached
EventCog->>DatabaseClient: get_bot_organization_by_guild_id(guild.id)
alt organization exists
DatabaseClient-->>EventCog: OrganizationResponse(oid)
else HTTP_STATUS_NOT_FOUND
DatabaseClient-->>EventCog: BackendAPIError(404)
EventCog->>DatabaseClient: create_bot_organization(guild_id, name)
DatabaseClient-->>EventCog: OrganizationResponse(oid)
end
EventCog->>EventCog: cache org_id by guild.id
end
EventCog->>EventCog: _fetch_backend_events(org_id)
EventCog->>DatabaseClient: list_events_by_organization(org_id)
alt list_events_by_organization 404
DatabaseClient-->>EventCog: BackendAPIError(404)
EventCog->>DatabaseClient: list_organization_events(org_id)
alt list_organization_events 404
DatabaseClient-->>EventCog: BackendAPIError(404)
EventCog->>DatabaseClient: list_events(limit, offset)
alt list_events fails
DatabaseClient-->>EventCog: BackendAPIError
EventCog-->>Discord: log error, return []
else list_events success
DatabaseClient-->>EventCog: [EventResponse]
end
else list_organization_events success
DatabaseClient-->>EventCog: [EventResponse]
end
else list_events_by_organization success
DatabaseClient-->>EventCog: [EventResponse]
end
EventCog->>EventCog: filter events by org_id
EventCog->>EventCog: map EventResponse to EventSchema (event_id, title, ...)
EventCog-->>Discord: send list of events to user
Sequence diagram for creating, updating, and deleting events with backend idssequenceDiagram
actor User
participant Discord
participant EventCog
participant DatabaseClient
rect rgb(230,230,250)
note over User,DatabaseClient: Create event
User->>Discord: submit event creation modal
Discord->>EventCog: _handle_event_submit(interaction, event)
EventCog->>EventCog: _resolve_org_id(guild)
EventCog->>DatabaseClient: create_event(CreateEventRequest(org_id, title, description, event_time, location))
DatabaseClient-->>EventCog: EventResponse(eid, ...)
EventCog-->>Discord: success_embed("Event Created")
end
rect rgb(220,245,220)
note over User,DatabaseClient: Update event
User->>Discord: open edit, submit updated event
Discord->>EventCog: _handle_event_update(interaction, original_event, updated_event)
EventCog->>EventCog: compute event_time_iso
EventCog->>EventCog: event_id = original_event.event_id
alt event_id missing
EventCog-->>Discord: error_embed("Event Not Found")
else event_id present
EventCog->>DatabaseClient: update_event(event_id, UpdateEventRequest(title, description, event_time, location))
DatabaseClient-->>EventCog: EventResponse
EventCog-->>Discord: success_embed("Event Updated")
end
end
rect rgb(245,230,230)
note over User,DatabaseClient: Delete event
User->>Discord: select event to delete
Discord->>EventCog: _on_delete_select(interaction, selected_event)
EventCog->>EventCog: event_id = selected_event.event_id
alt event_id missing
EventCog-->>Discord: error_embed("Event Not Found")
else event_id present
EventCog->>DatabaseClient: delete_event(event_id)
DatabaseClient-->>EventCog: success
EventCog-->>Discord: success_embed("Event Deleted")
end
end
Entity relationship diagram for organizations, guilds, and eventserDiagram
ORGANIZATION {
string oid
string name
int guild_id
string date_created
string date_modified
}
EVENT {
string eid
string org_id
string title
string description
string event_time
string location
string date_created
string date_modified
}
DISCORD_GUILD {
int guild_id
string name
}
DISCORD_GUILD ||--o| ORGANIZATION : maps_to
ORGANIZATION ||--o{ EVENT : owns
Class diagram for updated event schemas and database clientclassDiagram
class EventSchema {
+str event_id
+str event_name
+date event_date
+time event_time
+str description
+str location
}
class CreateEventRequest {
+str org_id
+str title
+str description
+str event_time
+str location
}
class UpdateEventRequest {
+str title
+str description
+str event_time
+str location
}
class EventResponse {
+str eid
+str title
+str description
+str event_time
+str location
+str org_id
+str date_created
+str date_modified
}
class CreateOrganizationRequest {
+str name
+str creator_uid
}
class BotCreateOrganizationRequest {
+int guild_id
+str name
}
class OrganizationResponse {
+str oid
+str name
+int guild_id
+str date_created
+str date_modified
}
class DatabaseClient {
+async get_bot_organization_by_guild_id(guild_id int) OrganizationResponse
+async create_organization(data CreateOrganizationRequest) OrganizationResponse
+async create_bot_organization(data BotCreateOrganizationRequest) OrganizationResponse
+async list_events_by_organization(org_id str) list~EventResponse~
+async list_organization_events(org_id str) list~EventResponse~
+async list_events(limit int, offset int) list~EventResponse~
+async create_event(data CreateEventRequest) EventResponse
+async update_event(event_id str, data UpdateEventRequest) EventResponse
+async delete_event(event_id str) None
}
class EventCog {
-dict~int, dict~str, int~~ event_announcements
-dict~int, str~ _guild_org_ids
+async _resolve_org_id(guild discord_Guild) str
+async _fetch_backend_events(org_id str) list~EventSchema~
+_from_backend_event(backend_event EventResponse) EventSchema
}
EventCog ..> DatabaseClient : uses
EventCog ..> EventSchema : manages
EventCog ..> EventResponse : converts
DatabaseClient ..> CreateEventRequest : creates
DatabaseClient ..> UpdateEventRequest : updates
DatabaseClient ..> EventResponse : returns
DatabaseClient ..> CreateOrganizationRequest : creates
DatabaseClient ..> BotCreateOrganizationRequest : creates bot org
DatabaseClient ..> OrganizationResponse : returns
EventSchema ..> EventResponse : built_from
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- The nested try/except flow in
_fetch_backend_eventshas a lot of repeated error handling and early returns; consider refactoring the fallback logic into smaller helpers or a loop over strategies so the control flow and logging paths are easier to follow and reason about. - The
_guild_org_idscache never expires or updates if the guild metadata changes (e.g., rename or reassociation in the backend); if that’s a realistic scenario, consider either adding an invalidation path or storing only theoidwhile always relying on the backend as the source of truth for mutable fields likename.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The nested try/except flow in `_fetch_backend_events` has a lot of repeated error handling and early returns; consider refactoring the fallback logic into smaller helpers or a loop over strategies so the control flow and logging paths are easier to follow and reason about.
- The `_guild_org_ids` cache never expires or updates if the guild metadata changes (e.g., rename or reassociation in the backend); if that’s a realistic scenario, consider either adding an invalidation path or storing only the `oid` while always relying on the backend as the source of truth for mutable fields like `name`.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Pull request overview
This PR updates the Discord event extension to use backend organization IDs (resolved from guild IDs) and to rely on first-class backend event identifiers/titles, while adding focused tests around the new backend call paths.
Changes:
- Add org-id resolution + caching (
guild_id -> oid) and use it for event list/show/edit/delete flows. - Switch events to use backend
eidasevent_idand backendtitleinstead of encoding names intodescription. - Expand backend client and tests to support bot organization endpoints and event API fallbacks.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
tests/capy_discord/test_database.py |
Adds bot organization endpoint tests and validates guild_id presence in org payloads. |
tests/capy_discord/exts/test_event.py |
Adds comprehensive tests for event cog org resolution, event fetching fallbacks, and UI flows. |
capy_discord/exts/event/event.py |
Implements org-id resolution/caching, event-id plumbing, and fallback backend event listing logic. |
capy_discord/exts/event/_schemas.py |
Adds hidden event_id field to the EventSchema to support edit/delete by backend id. |
capy_discord/database.py |
Extends typed payloads with title and adds bot organization client methods + guild_id on org responses. |
Comments suppressed due to low confidence (1)
capy_discord/exts/event/event.py:283
handle_myevents_actioncalls_fetch_backend_events(...)beforeinteraction.response.defer(...). If the backend call takes > ~3s, Discord may time out the interaction. Consider deferring immediately after the guild checks (like the other handlers) and then usinginteraction.followup.send(...)for the "No Events" case too.
events = await self._fetch_backend_events(await self._resolve_org_id(guild))
if not events:
embed = error_embed("No Events", "No events found in this server.")
await interaction.response.send_message(embed=embed, ephemeral=True)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary by Sourcery
Integrate Discord event commands with backend organizations identified by guild IDs, add support for event titles and IDs in the data model, and improve event retrieval robustness and coverage.
New Features:
Enhancements:
Tests: