Files
dakiny-bot/dakiny_bot/database/models.py
T
2025-07-17 09:14:51 -04:00

171 lines
7.5 KiB
Python

"""File holds all model definitions of SQL tables."""
from sqlalchemy.dialects.mysql import BIGINT, BOOLEAN, INTEGER, VARCHAR
from sqlmodel import Column, Field, ForeignKey, Relationship, SQLModel
class ElectionInformation(SQLModel, table=True):
"""
Represents all required information for an election.
Attributes:
name: Name of the election.
thread_id: Thread of where all the election related messages take place.
council_vote_msg_id: Message where the council vote is presented.
high_council_vote_msg_id: Message where the high council vote is presented.
council_nomination_msg_id: Message where council nomination button is held.
high_council_nomination_msg_id: Message where high council nomination button is held.
council_members: List of council members who ran during this election.
votes: All votes cast during this election.
"""
name: str = Field(sa_column=Column("ElectionName", VARCHAR, primary_key=True, unique=True), max_length=30)
thread_id: int = Field(sa_column=Column("ThreadId", BIGINT(unsigned=True), nullable=False))
council_vote_msg_id: int | None = Field(
sa_column=Column("CouncilVoteMsgId", BIGINT(unsigned=True), nullable=True), default=None
)
high_council_vote_msg_id: int | None = Field(
sa_column=Column("HighCouncilVoteMsgId", BIGINT(unsigned=True), nullable=True), default=None
)
council_nomination_msg_id: int | None = Field(
sa_column=Column("CouncilNominationMsgId", BIGINT(unsigned=True), nullable=True), default=None
)
high_council_nomination_msg_id: int | None = Field(
sa_column=Column("HighCouncilNominationMsgId", BIGINT(unsigned=True), nullable=True), default=None
)
council_members: list["CouncilMember"] = Relationship(back_populates="election", cascade_delete=True)
votes: list["Vote"] = Relationship(back_populates="election", cascade_delete=True)
class CouncilMember(SQLModel, table=True):
"""
Represents members involved in a given election.
Records speech message ids for general election and high council position. Booleans record if the user was elected
to a council/high council position.
Attributes:
member_id: User that is running for council's discord id.
speech_msg_id: Message id of user's speech.
elected: Whether the user got elected to council.
discord_manager: Whether the user got elected to the Discord Manager position.
clan_leader: Whether the user got elected to the Clan Leader position.
discord_manager_speech_id: Message id of the user's Discord Manager speech.
clan_leader_speech_id: Message id of the user's Clan Leader speech.
election: The election this user object is for.
votes: A list of votes for this user.
"""
__tablename__: str = "CouncilMembers"
election_name: str = Field(
sa_column=Column(
"ElectionName",
VARCHAR,
ForeignKey("ElectionInformation.ElectionName", ondelete="CASCADE"),
primary_key=True,
),
max_length=30,
)
member_id: int = Field(sa_column=Column("MemberId", BIGINT(unsigned=True), primary_key=True, nullable=False))
speech_msg_id: int = Field(sa_column=Column("SpeechMsgId", BIGINT(unsigned=True), nullable=False))
elected: bool = Field(sa_column=Column("Elected", BOOLEAN), default=False)
discord_manager: bool = Field(sa_column=Column("DiscordManager", BOOLEAN), default=False)
clan_leader: bool = Field(sa_column=Column("ClanLeader", BOOLEAN), default=False)
discord_manager_speech_id: int = Field(
sa_column=Column("DiscordManagerSpeechId", BIGINT(unsigned=True), nullable=True)
)
clan_leader_speech_id: int = Field(sa_column=Column("ClanLeaderSpeechId", BIGINT(unsigned=True), nullable=True))
election: ElectionInformation | None = Relationship(back_populates="council_members")
votes: list["Vote"] = Relationship(back_populates="council_member")
class Vote(SQLModel, table=True):
"""
Represents a vote cast during an election.
Attributes:
election_name: Election this vote was cast in.
voter_id: User id that cast the vote.
voted_for_id: User id that was voted for.
type: Type of election, council, discordmanager, or clanleader.
election: A link to the ElectionInformation object that the vote was cast in.
council_member: A link to the CouncilMember object that the vote is for.
"""
__tablename__: str = "Votes"
election_name: str = Field(
sa_column=Column(
"ElectionName",
VARCHAR,
ForeignKey("ElectionInformation.ElectionName", ondelete="CASCADE"),
primary_key=True,
),
max_length=30,
)
voter_id: int = Field(sa_column=Column("VoterId", BIGINT(unsigned=True), primary_key=True, nullable=False))
# might have to set this foreign key later with alembic migration...
voted_for_id: int | None = Field(
sa_column=Column("VotedForId", BIGINT(unsigned=True), ForeignKey("CouncilMembers.member_id"), nullable=True)
)
type: str = Field(sa_column=Column("Type", primary_key=True, nullable=False, default="council"), max_length=14)
election: ElectionInformation | None = Relationship(back_populates="votes")
council_member: CouncilMember | None = Relationship(back_populates="votes")
class UserBirthday(SQLModel, table=True):
"""
Represents a user's birth month and day.
Attributes:
id: User's discord id.
birthday: Month/day that is a user's birthday.
"""
id: int = Field(sa_column=Column("UserId", BIGINT(unsigned=True), primary_key=True, nullable=False))
# TODO(imcompiling): split into month and day. Also relies on Alembic migration.
# https://gitea.cheezers.org/imcompiling/dakiny-bot/issues/93
birthday: str = Field(sa_column=Column("Birthday", VARCHAR, nullable=False), max_length=5)
class Presence(SQLModel, table=True):
"""
Stores presences for the bot to pull and use.
Attributes:
id: Auto-incremented id for each entry.
presence: The presence itself.
"""
__tablename__: str = "Presences"
id: int | None = Field(sa_column=Column("Id", INTEGER, primary_key=True), default=None)
presence: str = Field(sa_column=Column("Presence", VARCHAR, nullable=False), max_length=100)
class Points(SQLModel, table=True):
"""
Stores activity points a user can gain by participating in clan activities.
Event points and clan points were separated out.
Attributes:
quarter_name: Name of the quarter the points were earned in.
user_id: The user that earned them. Is a discord id if the user is a discord member, otherwise their rsn.
discord_member: Boolean on whether the user is a discord member or not. Used to know what the user_id
represents.
event_points: Event points earned during the quarter.
clan_points: Clan points earned during the quarter.
"""
quarter_name: str = Field(sa_column=Column("QuarterName", VARCHAR, primary_key=True, nullable=False), max_length=30)
user_id: str = Field(sa_column=Column("UserId", VARCHAR, primary_key=True, nullable=False), max_length=32)
discord_member: bool = Field(sa_column=Column("DiscordMember", BOOLEAN, nullable=False))
event_points: int = Field(sa_column=Column("EventPoints", INTEGER(unsigned=True), nullable=False))
clan_points: int = Field(sa_column=Column("ClanPoints", INTEGER(unsigned=True), nullable=False))