sidequest_common.models.events#
Guild events and member signups. A raid is one kind of guild event; see EventKind.
EventSeries is a repeating-event rule (e.g. “every Friday at 7pm”); it never shows up to members directly.
Instead the API materializes it into ordinary GuildEvent rows (its “occurrences”) up to a 14-day horizon, each
with its own sign-ups and Discord event. See local://event-series-contract.md.
Attributes#
Classes#
A Discord scheduled event whose guild event was deleted on the site; the bot deletes it, then this row. |
|
One Discord user who clicked "Interested" on a guild event's linked Discord scheduled event. |
|
A repeating guild event rule ("every Friday at 7pm"). Materializes into |
|
One member's signup for one guild event. |
|
One sign-up status or comment change, queued to post as a comment on the event's Discord forum thread. |
|
Minutes a Discord member spent in the guild's voice channels while one event ran. |
|
One scheduled guild event, mirrored to a Discord scheduled event when the bot is running. |
Module Contents#
- class sidequest_common.models.events.DiscordEventTombstone#
Bases:
advanced_alchemy.base.UUIDAuditBaseA Discord scheduled event whose guild event was deleted on the site; the bot deletes it, then this row.
- discord_event_id: sqlalchemy.orm.Mapped[int]#
- class sidequest_common.models.events.EventDiscordInterest#
Bases:
advanced_alchemy.base.UUIDAuditBaseOne Discord user who clicked “Interested” on a guild event’s linked Discord scheduled event.
Discord -> site only: the API can’t mark a Discord user interested on the site’s behalf. Replaced wholesale per event whenever the bot reports the current interested-user list.
- discord_id: sqlalchemy.orm.Mapped[int]#
- event_id: sqlalchemy.orm.Mapped[uuid.UUID]#
- class sidequest_common.models.events.EventSeries#
Bases:
advanced_alchemy.base.UUIDAuditBaseA repeating guild event rule (“every Friday at 7pm”). Materializes into
GuildEventoccurrences.weekdaysis0(Monday) through6(Sunday).interval_weeksis1(every week) or2(every other week, anchored onstarts_on’s week).start_timeis wall-clock time intimezone(IANA, e.g."America/Chicago"); occurrences convert it to UTC per-occurrence viazoneinfo, so DST shifts land correctly.skipped_dates(ISO date strings) are occurrence dates a member deleted; they are never recreated.activeis cleared onceuntilhas passed.ep_overrideis copied onto occurrences.- active: sqlalchemy.orm.Mapped[bool]#
- duration_minutes: sqlalchemy.orm.Mapped[int | None]#
- ep_override: sqlalchemy.orm.Mapped[int | None]#
- interval_weeks: sqlalchemy.orm.Mapped[int]#
- kind: sqlalchemy.orm.Mapped[str]#
- location: sqlalchemy.orm.Mapped[str]#
- notes: sqlalchemy.orm.Mapped[str | None]#
- occurrences: sqlalchemy.orm.Mapped[list[GuildEvent]]#
- size: sqlalchemy.orm.Mapped[int | None]#
- skipped_dates: sqlalchemy.orm.Mapped[list[str]]#
- start_time: sqlalchemy.orm.Mapped[datetime.time]#
- starts_on: sqlalchemy.orm.Mapped[datetime.date]#
- timezone: sqlalchemy.orm.Mapped[str]#
- title: sqlalchemy.orm.Mapped[str]#
- until: sqlalchemy.orm.Mapped[datetime.date | None]#
- weekdays: sqlalchemy.orm.Mapped[list[int]]#
- class sidequest_common.models.events.EventSignup#
Bases:
advanced_alchemy.base.UUIDAuditBaseOne member’s signup for one guild event.
classis a Python keyword, so the column iswow_class.character/wow_class/roleare nullable: only role kinds (raid, dungeon) require them.- attended: sqlalchemy.orm.Mapped[bool | None]#
- bench: sqlalchemy.orm.Mapped[bool]#
- character: sqlalchemy.orm.Mapped[str | None]#
- chart_group: sqlalchemy.orm.Mapped[int | None]#
- comment: sqlalchemy.orm.Mapped[str | None]#
- event_id: sqlalchemy.orm.Mapped[uuid.UUID]#
- is_walk_in: sqlalchemy.orm.Mapped[bool]#
- member_id: sqlalchemy.orm.Mapped[int]#
- role: sqlalchemy.orm.Mapped[str | None]#
- status: sqlalchemy.orm.Mapped[str]#
- wow_class: sqlalchemy.orm.Mapped[str | None]#
- class sidequest_common.models.events.EventSignupActivity#
Bases:
advanced_alchemy.base.UUIDAuditBaseOne sign-up status or comment change, queued to post as a comment on the event’s Discord forum thread.
actionis one ofSIGNUP_ACTIVITY_ACTIONS:going/maybe/not_goingmirror a signup’sstatus, andwithdrewmarks a deleted signup.detailis the short “Character · Class · Role” line for role-kind events, elseNone.discord_idlets the bot @-mention the member (rows written before it existed have none), andcommentis the sign-up’s comment when the row was written.posted_atis set once the bot acks it; rows for events with no Discord thread stay unposted (and are dropped by the API if older than 24h) rather than posted.- action: sqlalchemy.orm.Mapped[str]#
- comment: sqlalchemy.orm.Mapped[str | None]#
- detail: sqlalchemy.orm.Mapped[str | None]#
- discord_id: sqlalchemy.orm.Mapped[int | None]#
- display_name: sqlalchemy.orm.Mapped[str]#
- event_id: sqlalchemy.orm.Mapped[uuid.UUID]#
- posted_at: sqlalchemy.orm.Mapped[datetime.datetime | None]#
- class sidequest_common.models.events.EventVoicePresence#
Bases:
advanced_alchemy.base.UUIDAuditBaseMinutes a Discord member spent in the guild’s voice channels while one event ran.
Bot-reported (
PUT /api/guilds/{guild_id}/attendance/voice) with cumulative minutes-so-far per member for the event; each push storesmax(existing, reported), so repeated pushes – including after a bot restart resets its in-memory counter – are idempotent and never lower an already-accumulated total.- discord_id: sqlalchemy.orm.Mapped[int]#
- event_id: sqlalchemy.orm.Mapped[uuid.UUID]#
- minutes: sqlalchemy.orm.Mapped[int]#
- class sidequest_common.models.events.GuildEvent#
Bases:
advanced_alchemy.base.UUIDAuditBaseOne scheduled guild event, mirrored to a Discord scheduled event when the bot is running.
kinddistinguishes raids from other events (dungeon runs, leveling sessions, PvP, social hangs); only “role kinds” (raid, dungeon) use the character/class/role sign-up fields and the raid chart.locationis""andsizeisNonefor events first created in Discord (Discord has neither). Thediscord_*columns belong to the two-way sync:discord_pushed_hashis the hash of the last desired state the bot wrote to Discord,discord_seen_hashthe hash of the last Discord state the bot reported. An event needs a push when its current desired-state hash differs fromdiscord_pushed_hash; a Discord report whose hash equalsdiscord_seen_hashis our own echo and is ignored.series_id/occurrence_datelink an occurrence back to theEventSeriesthat materialized it;series_detachedis set once an officer edits or deletes that one occurrence, so series-wide edits stop touching it.ep_overrideis the officer-set attendance EP;Nonemeans the kind’s preset (EVENT_KIND_EP), so retuning a preset reaches every event that kept it.- attendance_taken_at: sqlalchemy.orm.Mapped[datetime.datetime | None]#
- discord_event_id: sqlalchemy.orm.Mapped[int | None]#
- discord_pushed_hash: sqlalchemy.orm.Mapped[str | None]#
- discord_seen_hash: sqlalchemy.orm.Mapped[str | None]#
- discord_thread_id: sqlalchemy.orm.Mapped[int | None]#
- ends_at: sqlalchemy.orm.Mapped[datetime.datetime | None]#
- ep_override: sqlalchemy.orm.Mapped[int | None]#
- kind: sqlalchemy.orm.Mapped[str]#
- location: sqlalchemy.orm.Mapped[str]#
- notes: sqlalchemy.orm.Mapped[str | None]#
- occurrence_date: sqlalchemy.orm.Mapped[datetime.date | None]#
- series: sqlalchemy.orm.Mapped[EventSeries | None]#
- series_detached: sqlalchemy.orm.Mapped[bool]#
- series_id: sqlalchemy.orm.Mapped[uuid.UUID | None]#
- size: sqlalchemy.orm.Mapped[int | None]#
- starts_at: sqlalchemy.orm.Mapped[datetime.datetime]#
- status: sqlalchemy.orm.Mapped[str]#
- title: sqlalchemy.orm.Mapped[str]#
- sidequest_common.models.events.EVENT_KINDS = ('raid', 'dungeon', 'leveling', 'pvp', 'social', 'transmog', 'other')#
- sidequest_common.models.events.EVENT_STATUSES = ('scheduled', 'cancelled', 'completed')#
- sidequest_common.models.events.ROLE_KINDS = ('raid', 'dungeon')#
- sidequest_common.models.events.SIGNUP_ACTIVITY_ACTIONS = ('going', 'maybe', 'not_going', 'withdrew')#
- sidequest_common.models.events.SIGNUP_ROLES = ('tank', 'healer', 'dps')#
- sidequest_common.models.events.SIGNUP_STATUSES = ('signed', 'tentative', 'absent')#
- sidequest_common.models.events.WOW_CLASSES = ('warrior', 'paladin', 'hunter', 'rogue', 'priest', 'shaman', 'mage', 'warlock', 'druid')#