sidequest_common.models.members =============================== .. py:module:: sidequest_common.models.members .. autoapi-nested-parse:: Guild members who have signed in through Discord OAuth. Classes ------- .. autoapisummary:: sidequest_common.models.members.Member Module Contents --------------- .. py:class:: Member Bases: :py:obj:`advanced_alchemy.base.BigIntAuditBase` One Discord user who has logged into the member hub. ``id`` is a small internal integer (the contract's ``Me.id``), distinct from ``discord_id`` (Discord's 64-bit snowflake, carried as a string in JSON). ``username``/``global_name``/``roles``/``guild_nick``/ ``avatar_hash``/``is_guild_member`` are refreshed from Discord both at sign-in and continuously by the bot (``PUT /api/guilds/{guild_id}/member-profiles``: a full sweep plus debounced pushes on Discord profile/role/ membership changes), so they stay current even for a member who never signs in again after renaming. ``avatar_hash`` is Discord's raw avatar hash (``null`` for the default avatar); build the CDN URL from it rather than storing a URL that can go stale. ``battlenet_id``/``battletag`` are set when the member links Battle.net (one Battle.net account per member, so one Blizzard account can't vouch for several Discord accounts); officers compare the BattleTag to the roster. ``officer_notice_posted_at`` is when the bot posted the new-signup notice embed for this member in the configured signup-notice channel (``null`` until posted; existing members are backfilled non-null at migration so prod isn't flooded). ``officer_notice_channel_id``/``officer_notice_message_id`` locate that message so it can be edited later. ``officer_notice_resolved_at`` is set once the posted message accurately reflects the member's current roster status (approved via the embed's button, or edited after a site confirmation). .. py:attribute:: avatar_hash :type: sqlalchemy.orm.Mapped[str | None] .. py:attribute:: battlenet_id :type: sqlalchemy.orm.Mapped[int | None] .. py:attribute:: battlenet_linked_at :type: sqlalchemy.orm.Mapped[datetime.datetime | None] .. py:attribute:: battletag :type: sqlalchemy.orm.Mapped[str | None] .. py:attribute:: calendar_token :type: sqlalchemy.orm.Mapped[str | None] Secret token for the member's private calendar feed (``GET /api/calendar/{token}.ics``); generated lazily. .. py:attribute:: discord_id :type: sqlalchemy.orm.Mapped[int] .. py:property:: display_name :type: str Guild nick, else Discord global name, else username. .. py:attribute:: global_name :type: sqlalchemy.orm.Mapped[str | None] .. py:attribute:: guild_nick :type: sqlalchemy.orm.Mapped[str | None] .. py:attribute:: is_guild_member :type: sqlalchemy.orm.Mapped[bool] .. py:attribute:: last_login_at :type: sqlalchemy.orm.Mapped[datetime.datetime | None] .. py:attribute:: officer_notice_channel_id :type: sqlalchemy.orm.Mapped[int | None] .. py:attribute:: officer_notice_message_id :type: sqlalchemy.orm.Mapped[int | None] .. py:attribute:: officer_notice_posted_at :type: sqlalchemy.orm.Mapped[datetime.datetime | None] .. py:attribute:: officer_notice_resolved_at :type: sqlalchemy.orm.Mapped[datetime.datetime | None] .. py:attribute:: raid_status :type: sqlalchemy.orm.Mapped[str | None] EPGP roster status (``"trial"``/``"raider"``, or ``null`` for not-yet-rostered); set by an officer. .. py:attribute:: roles :type: sqlalchemy.orm.Mapped[list[int]] .. py:attribute:: roster_confirmed_at :type: sqlalchemy.orm.Mapped[datetime.datetime | None] .. py:attribute:: trial_started_at :type: sqlalchemy.orm.Mapped[datetime.datetime | None] When ``raid_status`` was last set to ``"trial"``; the EPGP bid order treats a trial as a trial for 14 days. .. py:attribute:: username :type: sqlalchemy.orm.Mapped[str]