sidequest_common.models.guild_hub#

Guild hub v2: roster snapshot, professions/recipes, bank log, announcements, recruiting, notes, news.

Backs the addon contract’s v2 sections (local://addon-contract-v2.md): the SQX1: export’s roster, professions, bank, announcements, recruits, and member_notes arrays, read back through /api/guild/* and the officer recruiting/notes screens, and mirrored into the SQI1: game-import string. GuildNewsEvent is generated (not addon-sourced) at the moment each underlying event is recorded, so the news feed has stable ids without re-deriving (and possibly reordering) them from other tables on every read.

Classes#

CharacterProfession

One character's scanned profession (e.g. Blacksmithing 150/150); recipes replaced wholesale on each scan.

CharacterRecipeLink

Many-to-many: one character/profession pair knows one recipe.

GuildAnnouncement

One officer announcement.

GuildBankLogEntry

One guild bank log row. external_id is the addon's deterministic hash (the game's log has no ids).

GuildNewsEvent

One news feed item, generated once when its source event is first recorded.

GuildRecruit

One recruiting candidate (officer-only data), upserted by the addon's id or created on the site.

GuildRosterSnapshot

The latest GetGuildRosterInfo row for one character, upserted on every roster export.

MemberNote

One officer note about a character, voidable, never deleted. member_id resolves via the character link.

ProfessionRecipe

A known recipe, keyed by the game's recipe id (the contract's recipes[].id), shared across characters.

RecruitVote

One officer's vote on one recruit, upserted by (recruit, officer).

Module Contents#

class sidequest_common.models.guild_hub.CharacterProfession#

Bases: advanced_alchemy.base.UUIDAuditBase

One character’s scanned profession (e.g. Blacksmithing 150/150); recipes replaced wholesale on each scan.

character_id: sqlalchemy.orm.Mapped[uuid.UUID]#
max_skill: sqlalchemy.orm.Mapped[int]#
profession: sqlalchemy.orm.Mapped[str]#
scanned_at: sqlalchemy.orm.Mapped[datetime.datetime]#
skill: sqlalchemy.orm.Mapped[int]#

Bases: advanced_alchemy.base.UUIDAuditBase

Many-to-many: one character/profession pair knows one recipe.

profession_id: sqlalchemy.orm.Mapped[uuid.UUID]#
recipe_id: sqlalchemy.orm.Mapped[uuid.UUID]#
class sidequest_common.models.guild_hub.GuildAnnouncement#

Bases: advanced_alchemy.base.UUIDAuditBase

One officer announcement.

From the addon (external_id set, discord: true queues it for the bot) or made directly on the site (external_id None, source="site").

at: sqlalchemy.orm.Mapped[datetime.datetime]#
author: sqlalchemy.orm.Mapped[str]#
discord: sqlalchemy.orm.Mapped[bool]#
discord_message_id: sqlalchemy.orm.Mapped[int | None]#
external_id: sqlalchemy.orm.Mapped[str | None]#
posted_at: sqlalchemy.orm.Mapped[datetime.datetime | None]#
source: sqlalchemy.orm.Mapped[str]#
text: sqlalchemy.orm.Mapped[str]#
class sidequest_common.models.guild_hub.GuildBankLogEntry#

Bases: advanced_alchemy.base.UUIDAuditBase

One guild bank log row. external_id is the addon’s deterministic hash (the game’s log has no ids).

at: sqlalchemy.orm.Mapped[datetime.datetime]#
character_id: sqlalchemy.orm.Mapped[uuid.UUID | None]#
count: sqlalchemy.orm.Mapped[int]#
external_id: sqlalchemy.orm.Mapped[str]#
item_id: sqlalchemy.orm.Mapped[int | None]#
item_name: sqlalchemy.orm.Mapped[str | None]#
kind: sqlalchemy.orm.Mapped[str]#
money: sqlalchemy.orm.Mapped[int]#
tab: sqlalchemy.orm.Mapped[int | None]#
class sidequest_common.models.guild_hub.GuildNewsEvent#

Bases: advanced_alchemy.base.UUIDAuditBase

One news feed item, generated once when its source event is first recorded.

source_key is a deterministic string built from the source row (e.g. "loot:<loot_id>", "level:<character_id>:<level>"); its uniqueness makes re-importing the same addon data a no-op instead of duplicating news, and gives the addon a stable id (the row’s own id) across imports.

at: sqlalchemy.orm.Mapped[datetime.datetime]#
character: sqlalchemy.orm.Mapped[str | None]#
item_id: sqlalchemy.orm.Mapped[int | None]#
kind: sqlalchemy.orm.Mapped[str]#
quality: sqlalchemy.orm.Mapped[int | None]#
source_key: sqlalchemy.orm.Mapped[str]#
text: sqlalchemy.orm.Mapped[str]#
class sidequest_common.models.guild_hub.GuildRecruit#

Bases: advanced_alchemy.base.UUIDAuditBase

One recruiting candidate (officer-only data), upserted by the addon’s id or created on the site.

at: sqlalchemy.orm.Mapped[datetime.datetime]#
character: sqlalchemy.orm.Mapped[str]#
checklist: sqlalchemy.orm.Mapped[dict]#
external_id: sqlalchemy.orm.Mapped[str | None]#
note: sqlalchemy.orm.Mapped[str | None]#
status: sqlalchemy.orm.Mapped[str]#
wow_class: sqlalchemy.orm.Mapped[str | None]#
class sidequest_common.models.guild_hub.GuildRosterSnapshot#

Bases: advanced_alchemy.base.UUIDAuditBase

The latest GetGuildRosterInfo row for one character, upserted on every roster export.

One row per character (character_id unique): the addon only ever reports its latest sweep, not history. left_guild_at is set once a character goes 30 days without appearing in a roster export; never deleted.

character_id: sqlalchemy.orm.Mapped[uuid.UUID]#
last_seen_at: sqlalchemy.orm.Mapped[datetime.datetime]#
left_guild_at: sqlalchemy.orm.Mapped[datetime.datetime | None]#
level: sqlalchemy.orm.Mapped[int]#
rank: sqlalchemy.orm.Mapped[str]#
rank_index: sqlalchemy.orm.Mapped[int]#
zone: sqlalchemy.orm.Mapped[str]#
class sidequest_common.models.guild_hub.MemberNote#

Bases: advanced_alchemy.base.UUIDAuditBase

One officer note about a character, voidable, never deleted. member_id resolves via the character link.

at: sqlalchemy.orm.Mapped[datetime.datetime]#
character: sqlalchemy.orm.Mapped[str]#
external_id: sqlalchemy.orm.Mapped[str]#
member_id: sqlalchemy.orm.Mapped[int | None]#
note: sqlalchemy.orm.Mapped[str]#
officer: sqlalchemy.orm.Mapped[str]#
voided_at: sqlalchemy.orm.Mapped[datetime.datetime | None]#
class sidequest_common.models.guild_hub.ProfessionRecipe#

Bases: advanced_alchemy.base.UUIDAuditBase

A known recipe, keyed by the game’s recipe id (the contract’s recipes[].id), shared across characters.

item_id: sqlalchemy.orm.Mapped[int | None]#
name: sqlalchemy.orm.Mapped[str]#
recipe_id: sqlalchemy.orm.Mapped[int]#
class sidequest_common.models.guild_hub.RecruitVote#

Bases: advanced_alchemy.base.UUIDAuditBase

One officer’s vote on one recruit, upserted by (recruit, officer).

at: sqlalchemy.orm.Mapped[datetime.datetime]#
officer: sqlalchemy.orm.Mapped[str]#
recruit_id: sqlalchemy.orm.Mapped[uuid.UUID]#
vote: sqlalchemy.orm.Mapped[str]#