tickets_plus.database.models
File for database models.
This file contains the SQLAlchemy models for the database. These models are used to create the database tables and to interact with the database. For more information on SQLAlchemy, please see the docs: https://docs.sqlalchemy.org/en/20/
Typical usage example:
from tickets_plus.database import models models.Base.metadata.create_all(...)
1"""File for database models. 2 3This file contains the SQLAlchemy models for the database. 4These models are used to create the database tables and 5to interact with the database. 6For more information on SQLAlchemy, please see the docs: 7https://docs.sqlalchemy.org/en/20/ 8 9Typical usage example: 10 ```py 11 from tickets_plus.database import models 12 models.Base.metadata.create_all(...) 13 ``` 14""" 15# License: EPL-2.0 16# SPDX-License-Identifier: EPL-2.0 17# Copyright (c) 2021-present The Tickets+ Contributors 18# This Source Code may also be made available under the following 19# Secondary Licenses when the conditions for such availability set forth 20# in the Eclipse Public License, v. 2.0 are satisfied: GPL-3.0-only OR 21# If later approved by the Initial Contributor, GPL-3.0-or-later. 22 23import datetime 24from typing import Type 25 26import sqlalchemy 27from sqlalchemy import orm, sql 28from sqlalchemy.ext import compiler as cmplr 29 30_METADATA_OBJ = sqlalchemy.MetaData(schema="tickets_plus") 31"""The metadata object for the database. Defines the schema.""" 32 33 34class UTCnow(sql.expression.FunctionElement): 35 """Function to get current UTC time 36 37 This is used to get the current UTC time database-side. 38 Once again, read the SQLAlchemy docs for more information. 39 40 Attributes: 41 type: The type of the expression, in this case, a datetime object 42 inherit_cache: Whether to inherit the cache, in this case, yes 43 """ 44 45 type = sqlalchemy.DateTime() 46 inherit_cache = True 47 48 49@cmplr.compiles(UTCnow, "postgresql") 50# This is as according to the docs, but pylint doesn't like it 51# Can't implement this for sqlite because it doesn't time objects 52# pylint: disable=unused-argument, invalid-name 53def pg_UTCnow(element, compiler, **kw): 54 """Compile the utcnow function for postgresql 55 56 Please see the SQLAlchemy docs for more information. 57 This script is based on the example given in the docs. 58 59 Args: 60 element: The element to compile so, in this case, the UTCnow object. 61 compiler: The Compiled object can be accessed to get information. 62 **kw: Keyword arguments. 63 64 Returns: 65 The compiled SQL expression. 66 """ 67 return "TIMEZONE('utc', CURRENT_TIMESTAMP)" 68 69 70class Base(orm.DeclarativeBase): 71 """Base of SQLAlchemy models 72 73 This is the base class for all SQLAlchemy models. 74 It is used to define the metadata object for the database. 75 A detailed database schema is available in our docs. 76 It includes a diagram of the database tables. 77 Please see the SQLAlchemy docs for more information about 78 how to use this class. 79 80 Attributes: 81 metadata: The metadata object for the database. 82 """ 83 84 metadata = _METADATA_OBJ 85 86 87class Guild(Base): 88 """General Guild-specific configuration table 89 90 This is the general configuration table. 91 It contains the general configuration for the bot. 92 This includes the staff team name, the open message, 93 and the autoclose time. 94 It also contains the relationships to all other guild-specific tables. 95 96 Attributes: 97 guild_id: The unique discord-provided guild ID. 98 open_message: The message to send when a staff thread is opened 99 defaults to "Staff notes for Ticket $channel." and it is 100 limited to 200 characters. 101 staff_team_name: The name of the staff team 102 defaults to "Staff Team" and is limited to 40 characters. 103 first_autoclose: Time since open with no response to auto-close. 104 any_autoclose: Time since last response to auto-close. 105 warn_autoclose: Time to warn user (via DM) after last response. 106 msg_discovery: Whether to allow message discovery 107 defaults to True. 108 strip_buttons: Whether to strip buttons from messages 109 defaults to False. 110 ticket_bots: The relationship to the TicketBot table. 111 tickets: The relationship to the Ticket table. 112 staff_roles: The relationship to the StaffRole table. 113 observers_roles: The relationship to the ObserversRole table. 114 community_roles: The relationship to the CommunityRole table. 115 community_pings: The relationship to the CommunityPing table. 116 members: The relationship to the Member table. 117 """ 118 119 __tablename__ = "general_configs" 120 __table_args__ = { 121 "comment": ("Table for general configurations," 122 " this is the parent table for all-guild specific tables.") 123 } 124 125 # Simple columns 126 guild_id: orm.Mapped[int] = orm.mapped_column(sqlalchemy.BigInteger(), 127 primary_key=True, 128 comment="Unique discord-provided guild ID") 129 open_message: orm.Mapped[str] = orm.mapped_column( 130 sqlalchemy.String(200), 131 default="Staff notes for Ticket $channel.", 132 nullable=False, 133 comment="Message to send when a staff thread is opened", 134 ) 135 staff_team_name: orm.Mapped[str] = orm.mapped_column( 136 sqlalchemy.String(40), 137 default="Staff Team", 138 nullable=False, 139 comment="Name of the staff team", 140 ) 141 first_autoclose: orm.Mapped[datetime.timedelta | None] = orm.mapped_column( 142 sqlalchemy.Interval(), nullable=True, comment="Time since open with no response to auto-close") 143 any_autoclose: orm.Mapped[datetime.timedelta | None] = orm.mapped_column( 144 sqlalchemy.Interval(), nullable=True, comment="Time since last response to auto-close") 145 warn_autoclose: orm.Mapped[datetime.timedelta | None] = orm.mapped_column( 146 sqlalchemy.Interval(), nullable=True, comment="Time to warn user (via DM) after last response") 147 support_block: orm.Mapped[int | None] = orm.mapped_column( 148 sqlalchemy.BigInteger(), 149 nullable=True, 150 comment=("Role to apply to users who are blocked from creating tickets" 151 " Please manually add this role to blacklist users on" 152 " https://ticketsbot.net/" 153 " If not set, considered disabled.")) 154 helping_block: orm.Mapped[int | None] = orm.mapped_column( 155 sqlalchemy.BigInteger(), 156 nullable=True, 157 comment=("Role to apply to users who are blocked from helping in tickets" 158 " I would recommend also preventing the users from obtaining" 159 " any other support roles." 160 " Using permissions checks in reaction bots." 161 " If not set, considered disabled.")) 162 163 # Toggles 164 msg_discovery: orm.Mapped[bool] = orm.mapped_column(default=True, 165 nullable=False, 166 comment="Whether to allow message discovery") 167 strip_buttons: orm.Mapped[bool] = orm.mapped_column(default=False, 168 nullable=False, 169 comment="Whether to strip buttons from messages") 170 strip_roles: orm.Mapped[bool] = orm.mapped_column( 171 default=False, nullable=False, comment="Whether to strip comsup roles when applying a helping_block") 172 integrated: orm.Mapped[bool] = orm.mapped_column(default=False, 173 nullable=False, 174 comment="Whether the bot is integrated with the main bot") 175 legacy_threads: orm.Mapped[bool] = orm.mapped_column(default=False, 176 nullable=False, 177 comment="Whether the server has legacy threads") 178 179 # Relationships 180 ticket_bots: orm.Mapped[list["TicketBot"]] = orm.relationship(back_populates="guild", lazy="raise") 181 tickets: orm.Mapped[list["Ticket"]] = orm.relationship(back_populates="guild", lazy="raise") 182 staff_roles: orm.Mapped[list["StaffRole"]] = orm.relationship(back_populates="guild", lazy="raise") 183 observers_roles: orm.Mapped[list["ObserversRole"]] = orm.relationship(back_populates="guild", lazy="raise") 184 community_roles: orm.Mapped[list["CommunityRole"]] = orm.relationship(back_populates="guild", lazy="raise") 185 community_pings: orm.Mapped[list["CommunityPing"]] = orm.relationship(back_populates="guild", lazy="raise") 186 members: orm.Mapped[list["Member"]] = orm.relationship(back_populates="guild", lazy="raise") 187 tags: orm.Mapped[list["Tag"]] = orm.relationship(back_populates="guild", lazy="raise") 188 ticket_types: orm.Mapped[list["TicketType"]] = orm.relationship(back_populates="guild", lazy="raise") 189 # Disabled for now gets sqlalchemy confused 190 # pylint: disable=line-too-long 191 # users: orm.Mapped[list["User"]] = orm.relationship( 192 # secondary="members", back_populates="guilds", lazy="raise", viewonly=True 193 # ) 194 195 # SNOWFLAKE PROTOCOL 196 @orm.reconstructor 197 def init_on_load(self): 198 """Initiate snowflake protocol 199 200 This is a snowflake protocol, which is a way to make the guild ID 201 more accessible. To use with discord.py. 202 """ 203 self.id = self.guild_id 204 205 206class TicketBot(Base): 207 """Guild-specific Ticket Bot table 208 209 This is the table for the ticket bots. 210 It contains the user ID of the ticket bot. 211 It also contains the relationship to the Guild table. 212 And the foreign key to the guild ID. 213 214 Attributes: 215 user_id: The unique discord-provided user ID 216 guild_id: The unique discord-provided guild ID 217 guild: The relationship to the Guild table 218 """ 219 220 __tablename__ = "ticket_bots" 221 __table_args__ = { 222 "comment": ("Users that open the ticket channels, mostly the Tickets bot," 223 " but can be other users due to whitelabel options.") 224 } 225 226 # Simple columns 227 user_id: orm.Mapped[int] = orm.mapped_column( 228 sqlalchemy.BigInteger(), 229 nullable=False, 230 comment=("Unique discord-provided user ID." 231 " Used in conjunction with guild_id to make a unique primary key"), 232 primary_key=True, 233 unique=False, 234 ) 235 guild_id: orm.Mapped[int] = orm.mapped_column( 236 sqlalchemy.BigInteger(), 237 sqlalchemy.ForeignKey("general_configs.guild_id"), 238 nullable=False, 239 comment=("Unique Guild ID of parent guild." 240 " Used in conjunction with user_id to make a unique primary key"), 241 primary_key=True, 242 unique=False, 243 ) 244 245 # Relationships 246 guild: orm.Mapped["Guild"] = orm.relationship(back_populates="ticket_bots", lazy="selectin") 247 248 249class TicketType(Base): 250 """Categorize tickets based on the prefix of the channel name 251 252 This is the table for the ticket types. 253 It contains the prefix of the ticket type. 254 It also contains the relationship to the Guild table. 255 And the foreign key to the guild ID. 256 And type-specific setting overrides. 257 258 Attributes: 259 prefix: The prefix of the ticket type. Also, the type name. 260 guild_id: The unique discord-provided guild ID 261 guild: The relationship to the Guild table 262 comping: Whether to ping the community roles when template matches 263 comaccs: Whether to ping the community roles when template matches 264 strpbuttns: Whether to strip buttons from open when template matches 265 """ 266 267 __tablename__ = "ticket_types" 268 __table_args__ = {"comment": "Ticket types are stored here. Each guild can have multiple."} 269 270 # Simple columns 271 prefix: orm.Mapped[str] = orm.mapped_column( 272 sqlalchemy.String(20), 273 nullable=False, 274 comment="The prefix of the ticket type", 275 primary_key=True, 276 ) 277 guild_id: orm.Mapped[int] = orm.mapped_column( 278 sqlalchemy.BigInteger(), 279 sqlalchemy.ForeignKey("general_configs.guild_id"), 280 nullable=False, 281 comment="The unique discord-provided guild ID", 282 primary_key=True, 283 ) 284 comping: orm.Mapped[bool] = orm.mapped_column(default=True, 285 nullable=False, 286 comment="Whether to ping the community roles when template matches") 287 comaccs: orm.Mapped[bool] = orm.mapped_column(default=True, 288 nullable=False, 289 comment="Whether to add the community roles when template matches") 290 strpbuttns: orm.Mapped[bool] = orm.mapped_column(default=True, 291 nullable=False, 292 comment="Whether to strip buttons from open when template matches") 293 ignore: orm.Mapped[bool] = orm.mapped_column(default=False, 294 nullable=False, 295 comment="Whether to ignore this ticket type") 296 297 # Relationships 298 guild: orm.Mapped["Guild"] = orm.relationship(back_populates="ticket_types", lazy="selectin") 299 300 @classmethod 301 def default(cls: Type["TicketType"]) -> "TicketType": 302 """Default ticket type 303 304 This is the default ticket type. 305 It is used when no ticket type is specified. 306 """ 307 return cls(prefix="", guild_id=0, comping=True, comaccs=True, strpbuttns=True, ignore=False) 308 309 310class Ticket(Base): 311 """Ticket channels table 312 313 This is the table for the ticket channels. 314 It contains the channel ID of the ticket channel. 315 It also contains the relationship to the Guild table. 316 And the foreign key to the guild ID. 317 Any closed tickets are deleted from this table. 318 319 Attributes: 320 channel_id: The unique discord-provided channel ID. 321 guild_id: The unique discord-provided guild ID. 322 user_id: The unique discord-provided user ID. 323 date_created: The date the ticket was created. 324 last_response: The date of the last response in the ticket. 325 staff_note_thread: The unique discord-provided ID of the note thread. 326 anonymous: Whether the ticket is in anonymous mode. 327 guild: The relationship to the Guild table. 328 """ 329 330 __tablename__ = "tickets" 331 __table_args__ = {"comment": "Channels that are tickets are stored here."} 332 333 # Simple columns 334 channel_id: orm.Mapped[int] = orm.mapped_column(sqlalchemy.BigInteger(), 335 primary_key=True, 336 comment="Unique discord-provided channel ID") 337 guild_id: orm.Mapped[int] = orm.mapped_column( 338 sqlalchemy.BigInteger(), 339 sqlalchemy.ForeignKey("general_configs.guild_id"), 340 nullable=False, 341 comment="Unique Guild ID of parent guild", 342 ) 343 user_id: orm.Mapped[int | None] = orm.mapped_column( 344 sqlalchemy.BigInteger(), 345 nullable=True, 346 comment="Unique discord-provided user ID", 347 ) 348 date_created: orm.Mapped[datetime.datetime] = orm.mapped_column( 349 sqlalchemy.DateTime(), 350 nullable=False, 351 comment="Date the ticket was created", 352 server_default=UTCnow(), 353 ) 354 last_response: orm.Mapped[datetime.datetime] = orm.mapped_column( 355 sqlalchemy.DateTime(), 356 nullable=False, 357 comment="Date the ticket was last responded to", 358 server_default=UTCnow(), 359 ) 360 staff_note_thread: orm.Mapped[int | None] = orm.mapped_column( 361 sqlalchemy.BigInteger(), 362 nullable=True, 363 comment="Unique discord-provided channel ID of the staff note thread", 364 unique=True, 365 ) 366 anonymous: orm.Mapped[bool] = orm.mapped_column(default=False, 367 nullable=False, 368 comment="Whether the ticket is in anonymous mode") 369 notified: orm.Mapped[bool] = orm.mapped_column(default=False, 370 nullable=False, 371 comment="Whether the user has been notified about this ticket") 372 373 # Relationships 374 guild: orm.Mapped["Guild"] = orm.relationship(back_populates="tickets", lazy="selectin") 375 376 # SNOWFLAKE PROTOCOL 377 @orm.reconstructor 378 def init_on_load(self): 379 """Initiate snowflake protocol 380 381 This is a snowflake protocol, which is a way to make the channel ID 382 more accessible. To use with discord.py. 383 """ 384 self.id = self.channel_id 385 386 387class Tag(Base): 388 """Tags table. 389 390 Stores the tags for the guild. 391 Tags are used to quickly respond to common questions. 392 Tags are stored in the database, so they can be 393 updated without restarting the bot. 394 Additionally, if additional columns besides "tag" and "content" are added, 395 the tag is automatically interpreted as an embed. 396 397 Attributes: 398 guild_id: The unique discord-provided guild ID. 399 tag_name: The 'key' of the tag. 400 title: The title of the embed. 401 description: The description of the embed. 402 url: The url of the embed. 403 color: The color of the embed. 404 footer: The footer of the embed. 405 image: The image of the embed. 406 thumbnail: The thumbnail of the embed. 407 author: The author of the embed. 408 guild: The relationship to the Guild table. 409 """ 410 411 __tablename__ = "tags" 412 __table_args__ = {"comment": "Tags for the guilds."} 413 414 # Simple columns 415 guild_id: orm.Mapped[int] = orm.mapped_column(sqlalchemy.BigInteger(), 416 sqlalchemy.ForeignKey("general_configs.guild_id"), 417 nullable=False, 418 comment="Unique Guild ID of parent guild", 419 primary_key=True) 420 tag_name: orm.Mapped[str] = orm.mapped_column(sqlalchemy.String(32), 421 nullable=False, 422 comment="The 'key' of the tag", 423 primary_key=True) 424 title: orm.Mapped[str | None] = orm.mapped_column(sqlalchemy.String(256), 425 nullable=True, 426 comment="The title of the embed") 427 description: orm.Mapped[str] = orm.mapped_column(sqlalchemy.String(4096), 428 nullable=False, 429 comment="The description of the embed") 430 url: orm.Mapped[str | None] = orm.mapped_column(sqlalchemy.String(256), 431 nullable=True, 432 comment="The url of the embed") 433 color: orm.Mapped[int | None] = orm.mapped_column(sqlalchemy.Integer(), 434 nullable=True, 435 comment="The color of the embed") 436 footer: orm.Mapped[str | None] = orm.mapped_column(sqlalchemy.String(2048), 437 nullable=True, 438 comment="The footer of the embed") 439 image: orm.Mapped[str] = orm.mapped_column(sqlalchemy.String(256), nullable=True, comment="The image of the embed") 440 thumbnail: orm.Mapped[str | None] = orm.mapped_column(sqlalchemy.String(256), 441 nullable=True, 442 comment="The thumbnail of the embed") 443 author: orm.Mapped[str | None] = orm.mapped_column(sqlalchemy.String(256), 444 nullable=True, 445 comment="The author of the embed") 446 447 # Relationships 448 guild: orm.Mapped["Guild"] = orm.relationship( 449 back_populates="tags", 450 lazy="selectin", 451 ) 452 453 454class StaffRole(Base): 455 """Staff roles table 456 457 This is the table for the staff roles. 458 It contains the role ID of the staff role. 459 It also contains the relationship to the Guild table. 460 And the foreign key to the guild ID. 461 462 Attributes: 463 role_id: The unique discord-provided role ID. 464 guild_id: The unique discord-provided guild ID. 465 guild: The relationship to the Guild table. 466 """ 467 468 __tablename__ = "staff_roles" 469 __table_args__ = { 470 "comment": ("Roles that are allowed to view ticket notes," 471 " and have access to staff commands.") 472 } 473 474 # Simple columns 475 role_id: orm.Mapped[int] = orm.mapped_column( 476 sqlalchemy.BigInteger(), 477 primary_key=True, 478 comment=("Unique discord-provided role ID," 479 " this is the primary key as it is unique across guilds"), 480 ) 481 guild_id: orm.Mapped[int] = orm.mapped_column( 482 sqlalchemy.BigInteger(), 483 sqlalchemy.ForeignKey("general_configs.guild_id"), 484 nullable=False, 485 comment="Unique Guild ID of parent guild", 486 ) 487 488 # Relationships 489 guild: orm.Mapped["Guild"] = orm.relationship(back_populates="staff_roles", lazy="selectin") 490 491 # SNOWFLAKE PROTOCOL 492 @orm.reconstructor 493 def init_on_load(self): 494 """Initiate snowflake protocol 495 496 This is a snowflake protocol, which is a way to make the role ID 497 more accessible. To use with discord.py. 498 """ 499 self.id = self.role_id 500 501 502class ObserversRole(Base): 503 """Observer roles table 504 505 This is the table for the observer roles. 506 It contains the role ID of the observer role. 507 It also contains the relationship to the Guild table. 508 And the foreign key to the guild ID. 509 510 Attributes: 511 role_id: The unique discord-provided role ID. 512 guild_id: The unique discord-provided guild ID. 513 guild: The relationship to the Guild table. 514 """ 515 516 __tablename__ = "observer_roles" 517 __table_args__ = {"comment": "Roles that are automatically added to tickets notes."} 518 519 # Simple columns 520 role_id: orm.Mapped[int] = orm.mapped_column( 521 sqlalchemy.BigInteger(), 522 primary_key=True, 523 comment=("Unique discord-provided role ID," 524 " this is the primary key as it is unique across guilds"), 525 ) 526 guild_id: orm.Mapped[int] = orm.mapped_column( 527 sqlalchemy.BigInteger(), 528 sqlalchemy.ForeignKey("general_configs.guild_id"), 529 nullable=False, 530 comment="Unique Guild ID of parent guild", 531 ) 532 533 # Relationships 534 guild: orm.Mapped["Guild"] = orm.relationship(back_populates="observers_roles", lazy="selectin") 535 536 # SNOWFLAKE PROTOCOL 537 @orm.reconstructor 538 def init_on_load(self): 539 """Initiate snowflake protocol 540 541 This is a snowflake protocol, which is a way to make the role ID 542 more accessible. To use with discord.py. 543 """ 544 self.id = self.role_id 545 546 547class CommunityRole(Base): 548 """Community roles table 549 550 This is the table for the community roles. 551 It contains the role ID of the community role. 552 It also contains the relationship to the Guild table. 553 And the foreign key to the guild ID. 554 555 Attributes: 556 role_id: The unique discord-provided role ID. 557 guild_id: The unique discord-provided guild ID. 558 guild: The relationship to the Guild table. 559 """ 560 561 __tablename__ = "community_roles" 562 __table_args__ = {"comment": "Roles that are allowed to view tickets, but aren't staff."} 563 564 # Simple columns 565 role_id: orm.Mapped[int] = orm.mapped_column( 566 sqlalchemy.BigInteger(), 567 primary_key=True, 568 comment=("Unique discord-provided role ID," 569 " this is the primary key as it is unique across guilds"), 570 ) 571 guild_id: orm.Mapped[int] = orm.mapped_column( 572 sqlalchemy.BigInteger(), 573 sqlalchemy.ForeignKey("general_configs.guild_id"), 574 nullable=False, 575 comment="Unique Guild ID of parent guild", 576 ) 577 578 # Relationships 579 guild: orm.Mapped["Guild"] = orm.relationship(back_populates="community_roles", lazy="selectin") 580 581 # SNOWFLAKE PROTOCOL 582 @orm.reconstructor 583 def init_on_load(self): 584 """Initiate snowflake protocol 585 586 This is a snowflake protocol, which is a way to make the role ID 587 more accessible. To use with discord.py. 588 """ 589 self.id = self.role_id 590 591 592class CommunityPing(Base): 593 """Community pings table 594 595 This is the table for the community pings. 596 It contains the role ID of the community ping role. 597 It also contains the relationship to the Guild table. 598 And the foreign key to the guild ID. 599 600 Attributes: 601 role_id: The unique discord-provided role ID. 602 guild_id: The unique discord-provided guild ID. 603 guild: The relationship to the Guild table. 604 """ 605 606 __tablename__ = "community_pings" 607 __table_args__ = { 608 "comment": ("Table for community pings," 609 " pinged when a ticket is opened but" 610 " after adding the community roles.") 611 } 612 613 # Simple columns 614 role_id: orm.Mapped[int] = orm.mapped_column( 615 sqlalchemy.BigInteger(), 616 primary_key=True, 617 comment=("Unique discord-provided role ID," 618 " this is the primary key as it is unique across guilds"), 619 ) 620 guild_id: orm.Mapped[int] = orm.mapped_column( 621 sqlalchemy.BigInteger(), 622 sqlalchemy.ForeignKey("general_configs.guild_id"), 623 nullable=False, 624 comment="Unique Guild ID of parent guild", 625 ) 626 627 # Relationships 628 guild: orm.Mapped["Guild"] = orm.relationship(back_populates="community_pings", lazy="selectin") 629 630 # SNOWFLAKE PROTOCOL 631 @orm.reconstructor 632 def init_on_load(self): 633 """Initiate snowflake protocol 634 635 This is a snowflake protocol, which is a way to make the role ID 636 more accessible. To use with discord.py. 637 """ 638 self.id = self.role_id 639 640 641class Member(Base): 642 """Member table 643 644 This is the table for the members. 645 It is an association table between the users and the guilds. 646 It contains the user ID and the guild ID. 647 It also contains a relationship to both the User and Guild tables. 648 It will also contain any bot information about the user. 649 650 Attributes: 651 user_id: The unique discord-provided user ID. 652 guild_id: The unique discord-provided guild ID. 653 user: The relationship to the User table. 654 guild: The relationship to the Guild table. 655 """ 656 657 __tablename__ = "members" 658 __table_args__ = { 659 "comment": ("Table for members," 660 " this is a combination of a user and a guild," 661 " as a user can be in multiple guilds.") 662 } 663 664 # Simple columns 665 user_id: orm.Mapped[int] = orm.mapped_column( 666 sqlalchemy.BigInteger(), 667 sqlalchemy.ForeignKey("users.user_id"), 668 nullable=False, 669 comment=("Unique discord-provided user ID." 670 " Used in conjunction with guild_id to make a unique primary key"), 671 primary_key=True, 672 unique=False, 673 ) 674 guild_id: orm.Mapped[int] = orm.mapped_column( 675 sqlalchemy.BigInteger(), 676 sqlalchemy.ForeignKey("general_configs.guild_id"), 677 nullable=False, 678 comment=("Unique Guild ID of parent guild." 679 " Used in conjunction with user_id to make a unique primary key"), 680 primary_key=True, 681 unique=False, 682 ) 683 status: orm.Mapped[int] = orm.mapped_column( 684 sqlalchemy.Integer(), 685 nullable=False, 686 default=0, 687 comment=("The status of the member, 0 is normal, " 688 "1 is support-blocked, 2 is barred from providing support"), 689 ) 690 status_till: orm.Mapped[datetime.datetime | None] = orm.mapped_column( 691 sqlalchemy.DateTime(), 692 nullable=True, 693 comment=("The time until the status is removed, " 694 "if None, the status is permanent"), 695 default=None) 696 697 # Relationships 698 guild: orm.Mapped["Guild"] = orm.relationship(back_populates="members", lazy="selectin") 699 user: orm.Mapped["User"] = orm.relationship(back_populates="memberships", lazy="selectin") 700 701 702class User(Base): 703 """User table 704 705 This is the table for the users. 706 It contains the user ID. 707 It also contains a relationship to the Member table. 708 It will also contain any bot information about the user. 709 710 Attributes: 711 user_id: The unique discord-provided user ID. 712 memberships: The relationship to the Member table. 713 is_owner: Is the user the owner of the bot? 714 """ 715 716 __tablename__ = "users" 717 __table_args__ = { 718 "comment": ("Table for users," 719 " this is not a guild-specific table," 720 " as a user can be in multiple guilds.") 721 } 722 723 # Simple columns 724 user_id: orm.Mapped[int] = orm.mapped_column( 725 sqlalchemy.BigInteger(), 726 primary_key=True, 727 comment=("Unique discord-provided user ID," 728 " this is the primary key as it is unique across guilds"), 729 ) 730 731 # Toggles 732 is_owner: orm.Mapped[bool] = orm.mapped_column(default=False, comment="Is the user the owner of the bot?") 733 734 # Relationships 735 memberships: orm.Mapped[list["Member"]] = orm.relationship(back_populates="user", lazy="raise") 736 # Disabled for now gets sqlalchemy confused 737 # pylint: disable=line-too-long 738 # guilds: orm.Mapped[list["Guild"]] = orm.relationship( 739 # secondary="members", back_populates="users", lazy="raise", viewonly=True 740 # ) 741 742 # SNOWFLAKE PROTOCOL 743 @orm.reconstructor 744 def init_on_load(self): 745 """Initiate snowflake protocol 746 747 This is a snowflake protocol, which is a way to make the user ID 748 more accessible. To use with discord.py. 749 """ 750 self.id = self.user_id
35class UTCnow(sql.expression.FunctionElement): 36 """Function to get current UTC time 37 38 This is used to get the current UTC time database-side. 39 Once again, read the SQLAlchemy docs for more information. 40 41 Attributes: 42 type: The type of the expression, in this case, a datetime object 43 inherit_cache: Whether to inherit the cache, in this case, yes 44 """ 45 46 type = sqlalchemy.DateTime() 47 inherit_cache = True
Function to get current UTC time
This is used to get the current UTC time database-side. Once again, read the SQLAlchemy docs for more information.
Attributes:
- type: The type of the expression, in this case, a datetime object
- inherit_cache: Whether to inherit the cache, in this case, yes
Indicate if this .HasCacheKey instance should make use of the
cache key generation scheme used by its immediate superclass.
The attribute defaults to None, which indicates that a construct has
not yet taken into account whether or not its appropriate for it to
participate in caching; this is functionally equivalent to setting the
value to False, except that a warning is also emitted.
This flag can be set to True on a particular class, if the SQL that
corresponds to the object does not change based on attributes which
are local to this class, and not its superclass.
seealso:
defined SQL constructs.
50@cmplr.compiles(UTCnow, "postgresql") 51# This is as according to the docs, but pylint doesn't like it 52# Can't implement this for sqlite because it doesn't time objects 53# pylint: disable=unused-argument, invalid-name 54def pg_UTCnow(element, compiler, **kw): 55 """Compile the utcnow function for postgresql 56 57 Please see the SQLAlchemy docs for more information. 58 This script is based on the example given in the docs. 59 60 Args: 61 element: The element to compile so, in this case, the UTCnow object. 62 compiler: The Compiled object can be accessed to get information. 63 **kw: Keyword arguments. 64 65 Returns: 66 The compiled SQL expression. 67 """ 68 return "TIMEZONE('utc', CURRENT_TIMESTAMP)"
Compile the utcnow function for postgresql
Please see the SQLAlchemy docs for more information. This script is based on the example given in the docs.
Arguments:
- element: The element to compile so, in this case, the UTCnow object.
- compiler: The Compiled object can be accessed to get information.
- **kw: Keyword arguments.
Returns:
The compiled SQL expression.
71class Base(orm.DeclarativeBase): 72 """Base of SQLAlchemy models 73 74 This is the base class for all SQLAlchemy models. 75 It is used to define the metadata object for the database. 76 A detailed database schema is available in our docs. 77 It includes a diagram of the database tables. 78 Please see the SQLAlchemy docs for more information about 79 how to use this class. 80 81 Attributes: 82 metadata: The metadata object for the database. 83 """ 84 85 metadata = _METADATA_OBJ
Base of SQLAlchemy models
This is the base class for all SQLAlchemy models. It is used to define the metadata object for the database. A detailed database schema is available in our docs. It includes a diagram of the database tables. Please see the SQLAlchemy docs for more information about how to use this class.
Attributes:
- metadata: The metadata object for the database.
2167def _declarative_constructor(self: Any, **kwargs: Any) -> None: 2168 """A simple constructor that allows initialization from kwargs. 2169 2170 Sets attributes on the constructed instance using the names and 2171 values in ``kwargs``. 2172 2173 Only keys that are present as 2174 attributes of the instance's class are allowed. These could be, 2175 for example, any mapped columns or relationships. 2176 """ 2177 cls_ = type(self) 2178 for k in kwargs: 2179 if not hasattr(cls_, k): 2180 raise TypeError( 2181 "%r is an invalid keyword argument for %s" % (k, cls_.__name__) 2182 ) 2183 setattr(self, k, kwargs[k])
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
88class Guild(Base): 89 """General Guild-specific configuration table 90 91 This is the general configuration table. 92 It contains the general configuration for the bot. 93 This includes the staff team name, the open message, 94 and the autoclose time. 95 It also contains the relationships to all other guild-specific tables. 96 97 Attributes: 98 guild_id: The unique discord-provided guild ID. 99 open_message: The message to send when a staff thread is opened 100 defaults to "Staff notes for Ticket $channel." and it is 101 limited to 200 characters. 102 staff_team_name: The name of the staff team 103 defaults to "Staff Team" and is limited to 40 characters. 104 first_autoclose: Time since open with no response to auto-close. 105 any_autoclose: Time since last response to auto-close. 106 warn_autoclose: Time to warn user (via DM) after last response. 107 msg_discovery: Whether to allow message discovery 108 defaults to True. 109 strip_buttons: Whether to strip buttons from messages 110 defaults to False. 111 ticket_bots: The relationship to the TicketBot table. 112 tickets: The relationship to the Ticket table. 113 staff_roles: The relationship to the StaffRole table. 114 observers_roles: The relationship to the ObserversRole table. 115 community_roles: The relationship to the CommunityRole table. 116 community_pings: The relationship to the CommunityPing table. 117 members: The relationship to the Member table. 118 """ 119 120 __tablename__ = "general_configs" 121 __table_args__ = { 122 "comment": ("Table for general configurations," 123 " this is the parent table for all-guild specific tables.") 124 } 125 126 # Simple columns 127 guild_id: orm.Mapped[int] = orm.mapped_column(sqlalchemy.BigInteger(), 128 primary_key=True, 129 comment="Unique discord-provided guild ID") 130 open_message: orm.Mapped[str] = orm.mapped_column( 131 sqlalchemy.String(200), 132 default="Staff notes for Ticket $channel.", 133 nullable=False, 134 comment="Message to send when a staff thread is opened", 135 ) 136 staff_team_name: orm.Mapped[str] = orm.mapped_column( 137 sqlalchemy.String(40), 138 default="Staff Team", 139 nullable=False, 140 comment="Name of the staff team", 141 ) 142 first_autoclose: orm.Mapped[datetime.timedelta | None] = orm.mapped_column( 143 sqlalchemy.Interval(), nullable=True, comment="Time since open with no response to auto-close") 144 any_autoclose: orm.Mapped[datetime.timedelta | None] = orm.mapped_column( 145 sqlalchemy.Interval(), nullable=True, comment="Time since last response to auto-close") 146 warn_autoclose: orm.Mapped[datetime.timedelta | None] = orm.mapped_column( 147 sqlalchemy.Interval(), nullable=True, comment="Time to warn user (via DM) after last response") 148 support_block: orm.Mapped[int | None] = orm.mapped_column( 149 sqlalchemy.BigInteger(), 150 nullable=True, 151 comment=("Role to apply to users who are blocked from creating tickets" 152 " Please manually add this role to blacklist users on" 153 " https://ticketsbot.net/" 154 " If not set, considered disabled.")) 155 helping_block: orm.Mapped[int | None] = orm.mapped_column( 156 sqlalchemy.BigInteger(), 157 nullable=True, 158 comment=("Role to apply to users who are blocked from helping in tickets" 159 " I would recommend also preventing the users from obtaining" 160 " any other support roles." 161 " Using permissions checks in reaction bots." 162 " If not set, considered disabled.")) 163 164 # Toggles 165 msg_discovery: orm.Mapped[bool] = orm.mapped_column(default=True, 166 nullable=False, 167 comment="Whether to allow message discovery") 168 strip_buttons: orm.Mapped[bool] = orm.mapped_column(default=False, 169 nullable=False, 170 comment="Whether to strip buttons from messages") 171 strip_roles: orm.Mapped[bool] = orm.mapped_column( 172 default=False, nullable=False, comment="Whether to strip comsup roles when applying a helping_block") 173 integrated: orm.Mapped[bool] = orm.mapped_column(default=False, 174 nullable=False, 175 comment="Whether the bot is integrated with the main bot") 176 legacy_threads: orm.Mapped[bool] = orm.mapped_column(default=False, 177 nullable=False, 178 comment="Whether the server has legacy threads") 179 180 # Relationships 181 ticket_bots: orm.Mapped[list["TicketBot"]] = orm.relationship(back_populates="guild", lazy="raise") 182 tickets: orm.Mapped[list["Ticket"]] = orm.relationship(back_populates="guild", lazy="raise") 183 staff_roles: orm.Mapped[list["StaffRole"]] = orm.relationship(back_populates="guild", lazy="raise") 184 observers_roles: orm.Mapped[list["ObserversRole"]] = orm.relationship(back_populates="guild", lazy="raise") 185 community_roles: orm.Mapped[list["CommunityRole"]] = orm.relationship(back_populates="guild", lazy="raise") 186 community_pings: orm.Mapped[list["CommunityPing"]] = orm.relationship(back_populates="guild", lazy="raise") 187 members: orm.Mapped[list["Member"]] = orm.relationship(back_populates="guild", lazy="raise") 188 tags: orm.Mapped[list["Tag"]] = orm.relationship(back_populates="guild", lazy="raise") 189 ticket_types: orm.Mapped[list["TicketType"]] = orm.relationship(back_populates="guild", lazy="raise") 190 # Disabled for now gets sqlalchemy confused 191 # pylint: disable=line-too-long 192 # users: orm.Mapped[list["User"]] = orm.relationship( 193 # secondary="members", back_populates="guilds", lazy="raise", viewonly=True 194 # ) 195 196 # SNOWFLAKE PROTOCOL 197 @orm.reconstructor 198 def init_on_load(self): 199 """Initiate snowflake protocol 200 201 This is a snowflake protocol, which is a way to make the guild ID 202 more accessible. To use with discord.py. 203 """ 204 self.id = self.guild_id
General Guild-specific configuration table
This is the general configuration table. It contains the general configuration for the bot. This includes the staff team name, the open message, and the autoclose time. It also contains the relationships to all other guild-specific tables.
Attributes:
- guild_id: The unique discord-provided guild ID.
- open_message: The message to send when a staff thread is opened defaults to "Staff notes for Ticket $channel." and it is limited to 200 characters.
- staff_team_name: The name of the staff team defaults to "Staff Team" and is limited to 40 characters.
- first_autoclose: Time since open with no response to auto-close.
- any_autoclose: Time since last response to auto-close.
- warn_autoclose: Time to warn user (via DM) after last response.
- msg_discovery: Whether to allow message discovery defaults to True.
- strip_buttons: Whether to strip buttons from messages defaults to False.
- ticket_bots: The relationship to the TicketBot table.
- tickets: The relationship to the Ticket table.
- staff_roles: The relationship to the StaffRole table.
- observers_roles: The relationship to the ObserversRole table.
- community_roles: The relationship to the CommunityRole table.
- community_pings: The relationship to the CommunityPing table.
- members: The relationship to the Member table.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
197 @orm.reconstructor 198 def init_on_load(self): 199 """Initiate snowflake protocol 200 201 This is a snowflake protocol, which is a way to make the guild ID 202 more accessible. To use with discord.py. 203 """ 204 self.id = self.guild_id
Initiate snowflake protocol
This is a snowflake protocol, which is a way to make the guild ID more accessible. To use with discord.py.
207class TicketBot(Base): 208 """Guild-specific Ticket Bot table 209 210 This is the table for the ticket bots. 211 It contains the user ID of the ticket bot. 212 It also contains the relationship to the Guild table. 213 And the foreign key to the guild ID. 214 215 Attributes: 216 user_id: The unique discord-provided user ID 217 guild_id: The unique discord-provided guild ID 218 guild: The relationship to the Guild table 219 """ 220 221 __tablename__ = "ticket_bots" 222 __table_args__ = { 223 "comment": ("Users that open the ticket channels, mostly the Tickets bot," 224 " but can be other users due to whitelabel options.") 225 } 226 227 # Simple columns 228 user_id: orm.Mapped[int] = orm.mapped_column( 229 sqlalchemy.BigInteger(), 230 nullable=False, 231 comment=("Unique discord-provided user ID." 232 " Used in conjunction with guild_id to make a unique primary key"), 233 primary_key=True, 234 unique=False, 235 ) 236 guild_id: orm.Mapped[int] = orm.mapped_column( 237 sqlalchemy.BigInteger(), 238 sqlalchemy.ForeignKey("general_configs.guild_id"), 239 nullable=False, 240 comment=("Unique Guild ID of parent guild." 241 " Used in conjunction with user_id to make a unique primary key"), 242 primary_key=True, 243 unique=False, 244 ) 245 246 # Relationships 247 guild: orm.Mapped["Guild"] = orm.relationship(back_populates="ticket_bots", lazy="selectin")
Guild-specific Ticket Bot table
This is the table for the ticket bots. It contains the user ID of the ticket bot. It also contains the relationship to the Guild table. And the foreign key to the guild ID.
Attributes:
- user_id: The unique discord-provided user ID
- guild_id: The unique discord-provided guild ID
- guild: The relationship to the Guild table
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
250class TicketType(Base): 251 """Categorize tickets based on the prefix of the channel name 252 253 This is the table for the ticket types. 254 It contains the prefix of the ticket type. 255 It also contains the relationship to the Guild table. 256 And the foreign key to the guild ID. 257 And type-specific setting overrides. 258 259 Attributes: 260 prefix: The prefix of the ticket type. Also, the type name. 261 guild_id: The unique discord-provided guild ID 262 guild: The relationship to the Guild table 263 comping: Whether to ping the community roles when template matches 264 comaccs: Whether to ping the community roles when template matches 265 strpbuttns: Whether to strip buttons from open when template matches 266 """ 267 268 __tablename__ = "ticket_types" 269 __table_args__ = {"comment": "Ticket types are stored here. Each guild can have multiple."} 270 271 # Simple columns 272 prefix: orm.Mapped[str] = orm.mapped_column( 273 sqlalchemy.String(20), 274 nullable=False, 275 comment="The prefix of the ticket type", 276 primary_key=True, 277 ) 278 guild_id: orm.Mapped[int] = orm.mapped_column( 279 sqlalchemy.BigInteger(), 280 sqlalchemy.ForeignKey("general_configs.guild_id"), 281 nullable=False, 282 comment="The unique discord-provided guild ID", 283 primary_key=True, 284 ) 285 comping: orm.Mapped[bool] = orm.mapped_column(default=True, 286 nullable=False, 287 comment="Whether to ping the community roles when template matches") 288 comaccs: orm.Mapped[bool] = orm.mapped_column(default=True, 289 nullable=False, 290 comment="Whether to add the community roles when template matches") 291 strpbuttns: orm.Mapped[bool] = orm.mapped_column(default=True, 292 nullable=False, 293 comment="Whether to strip buttons from open when template matches") 294 ignore: orm.Mapped[bool] = orm.mapped_column(default=False, 295 nullable=False, 296 comment="Whether to ignore this ticket type") 297 298 # Relationships 299 guild: orm.Mapped["Guild"] = orm.relationship(back_populates="ticket_types", lazy="selectin") 300 301 @classmethod 302 def default(cls: Type["TicketType"]) -> "TicketType": 303 """Default ticket type 304 305 This is the default ticket type. 306 It is used when no ticket type is specified. 307 """ 308 return cls(prefix="", guild_id=0, comping=True, comaccs=True, strpbuttns=True, ignore=False)
Categorize tickets based on the prefix of the channel name
This is the table for the ticket types. It contains the prefix of the ticket type. It also contains the relationship to the Guild table. And the foreign key to the guild ID. And type-specific setting overrides.
Attributes:
- prefix: The prefix of the ticket type. Also, the type name.
- guild_id: The unique discord-provided guild ID
- guild: The relationship to the Guild table
- comping: Whether to ping the community roles when template matches
- comaccs: Whether to ping the community roles when template matches
- strpbuttns: Whether to strip buttons from open when template matches
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
301 @classmethod 302 def default(cls: Type["TicketType"]) -> "TicketType": 303 """Default ticket type 304 305 This is the default ticket type. 306 It is used when no ticket type is specified. 307 """ 308 return cls(prefix="", guild_id=0, comping=True, comaccs=True, strpbuttns=True, ignore=False)
Default ticket type
This is the default ticket type. It is used when no ticket type is specified.
311class Ticket(Base): 312 """Ticket channels table 313 314 This is the table for the ticket channels. 315 It contains the channel ID of the ticket channel. 316 It also contains the relationship to the Guild table. 317 And the foreign key to the guild ID. 318 Any closed tickets are deleted from this table. 319 320 Attributes: 321 channel_id: The unique discord-provided channel ID. 322 guild_id: The unique discord-provided guild ID. 323 user_id: The unique discord-provided user ID. 324 date_created: The date the ticket was created. 325 last_response: The date of the last response in the ticket. 326 staff_note_thread: The unique discord-provided ID of the note thread. 327 anonymous: Whether the ticket is in anonymous mode. 328 guild: The relationship to the Guild table. 329 """ 330 331 __tablename__ = "tickets" 332 __table_args__ = {"comment": "Channels that are tickets are stored here."} 333 334 # Simple columns 335 channel_id: orm.Mapped[int] = orm.mapped_column(sqlalchemy.BigInteger(), 336 primary_key=True, 337 comment="Unique discord-provided channel ID") 338 guild_id: orm.Mapped[int] = orm.mapped_column( 339 sqlalchemy.BigInteger(), 340 sqlalchemy.ForeignKey("general_configs.guild_id"), 341 nullable=False, 342 comment="Unique Guild ID of parent guild", 343 ) 344 user_id: orm.Mapped[int | None] = orm.mapped_column( 345 sqlalchemy.BigInteger(), 346 nullable=True, 347 comment="Unique discord-provided user ID", 348 ) 349 date_created: orm.Mapped[datetime.datetime] = orm.mapped_column( 350 sqlalchemy.DateTime(), 351 nullable=False, 352 comment="Date the ticket was created", 353 server_default=UTCnow(), 354 ) 355 last_response: orm.Mapped[datetime.datetime] = orm.mapped_column( 356 sqlalchemy.DateTime(), 357 nullable=False, 358 comment="Date the ticket was last responded to", 359 server_default=UTCnow(), 360 ) 361 staff_note_thread: orm.Mapped[int | None] = orm.mapped_column( 362 sqlalchemy.BigInteger(), 363 nullable=True, 364 comment="Unique discord-provided channel ID of the staff note thread", 365 unique=True, 366 ) 367 anonymous: orm.Mapped[bool] = orm.mapped_column(default=False, 368 nullable=False, 369 comment="Whether the ticket is in anonymous mode") 370 notified: orm.Mapped[bool] = orm.mapped_column(default=False, 371 nullable=False, 372 comment="Whether the user has been notified about this ticket") 373 374 # Relationships 375 guild: orm.Mapped["Guild"] = orm.relationship(back_populates="tickets", lazy="selectin") 376 377 # SNOWFLAKE PROTOCOL 378 @orm.reconstructor 379 def init_on_load(self): 380 """Initiate snowflake protocol 381 382 This is a snowflake protocol, which is a way to make the channel ID 383 more accessible. To use with discord.py. 384 """ 385 self.id = self.channel_id
Ticket channels table
This is the table for the ticket channels. It contains the channel ID of the ticket channel. It also contains the relationship to the Guild table. And the foreign key to the guild ID. Any closed tickets are deleted from this table.
Attributes:
- channel_id: The unique discord-provided channel ID.
- guild_id: The unique discord-provided guild ID.
- user_id: The unique discord-provided user ID.
- date_created: The date the ticket was created.
- last_response: The date of the last response in the ticket.
- staff_note_thread: The unique discord-provided ID of the note thread.
- anonymous: Whether the ticket is in anonymous mode.
- guild: The relationship to the Guild table.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
378 @orm.reconstructor 379 def init_on_load(self): 380 """Initiate snowflake protocol 381 382 This is a snowflake protocol, which is a way to make the channel ID 383 more accessible. To use with discord.py. 384 """ 385 self.id = self.channel_id
Initiate snowflake protocol
This is a snowflake protocol, which is a way to make the channel ID more accessible. To use with discord.py.
388class Tag(Base): 389 """Tags table. 390 391 Stores the tags for the guild. 392 Tags are used to quickly respond to common questions. 393 Tags are stored in the database, so they can be 394 updated without restarting the bot. 395 Additionally, if additional columns besides "tag" and "content" are added, 396 the tag is automatically interpreted as an embed. 397 398 Attributes: 399 guild_id: The unique discord-provided guild ID. 400 tag_name: The 'key' of the tag. 401 title: The title of the embed. 402 description: The description of the embed. 403 url: The url of the embed. 404 color: The color of the embed. 405 footer: The footer of the embed. 406 image: The image of the embed. 407 thumbnail: The thumbnail of the embed. 408 author: The author of the embed. 409 guild: The relationship to the Guild table. 410 """ 411 412 __tablename__ = "tags" 413 __table_args__ = {"comment": "Tags for the guilds."} 414 415 # Simple columns 416 guild_id: orm.Mapped[int] = orm.mapped_column(sqlalchemy.BigInteger(), 417 sqlalchemy.ForeignKey("general_configs.guild_id"), 418 nullable=False, 419 comment="Unique Guild ID of parent guild", 420 primary_key=True) 421 tag_name: orm.Mapped[str] = orm.mapped_column(sqlalchemy.String(32), 422 nullable=False, 423 comment="The 'key' of the tag", 424 primary_key=True) 425 title: orm.Mapped[str | None] = orm.mapped_column(sqlalchemy.String(256), 426 nullable=True, 427 comment="The title of the embed") 428 description: orm.Mapped[str] = orm.mapped_column(sqlalchemy.String(4096), 429 nullable=False, 430 comment="The description of the embed") 431 url: orm.Mapped[str | None] = orm.mapped_column(sqlalchemy.String(256), 432 nullable=True, 433 comment="The url of the embed") 434 color: orm.Mapped[int | None] = orm.mapped_column(sqlalchemy.Integer(), 435 nullable=True, 436 comment="The color of the embed") 437 footer: orm.Mapped[str | None] = orm.mapped_column(sqlalchemy.String(2048), 438 nullable=True, 439 comment="The footer of the embed") 440 image: orm.Mapped[str] = orm.mapped_column(sqlalchemy.String(256), nullable=True, comment="The image of the embed") 441 thumbnail: orm.Mapped[str | None] = orm.mapped_column(sqlalchemy.String(256), 442 nullable=True, 443 comment="The thumbnail of the embed") 444 author: orm.Mapped[str | None] = orm.mapped_column(sqlalchemy.String(256), 445 nullable=True, 446 comment="The author of the embed") 447 448 # Relationships 449 guild: orm.Mapped["Guild"] = orm.relationship( 450 back_populates="tags", 451 lazy="selectin", 452 )
Tags table.
Stores the tags for the guild. Tags are used to quickly respond to common questions. Tags are stored in the database, so they can be updated without restarting the bot. Additionally, if additional columns besides "tag" and "content" are added, the tag is automatically interpreted as an embed.
Attributes:
- guild_id: The unique discord-provided guild ID.
- tag_name: The 'key' of the tag.
- title: The title of the embed.
- description: The description of the embed.
- url: The url of the embed.
- color: The color of the embed.
- footer: The footer of the embed.
- image: The image of the embed.
- thumbnail: The thumbnail of the embed.
- author: The author of the embed.
- guild: The relationship to the Guild table.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
455class StaffRole(Base): 456 """Staff roles table 457 458 This is the table for the staff roles. 459 It contains the role ID of the staff role. 460 It also contains the relationship to the Guild table. 461 And the foreign key to the guild ID. 462 463 Attributes: 464 role_id: The unique discord-provided role ID. 465 guild_id: The unique discord-provided guild ID. 466 guild: The relationship to the Guild table. 467 """ 468 469 __tablename__ = "staff_roles" 470 __table_args__ = { 471 "comment": ("Roles that are allowed to view ticket notes," 472 " and have access to staff commands.") 473 } 474 475 # Simple columns 476 role_id: orm.Mapped[int] = orm.mapped_column( 477 sqlalchemy.BigInteger(), 478 primary_key=True, 479 comment=("Unique discord-provided role ID," 480 " this is the primary key as it is unique across guilds"), 481 ) 482 guild_id: orm.Mapped[int] = orm.mapped_column( 483 sqlalchemy.BigInteger(), 484 sqlalchemy.ForeignKey("general_configs.guild_id"), 485 nullable=False, 486 comment="Unique Guild ID of parent guild", 487 ) 488 489 # Relationships 490 guild: orm.Mapped["Guild"] = orm.relationship(back_populates="staff_roles", lazy="selectin") 491 492 # SNOWFLAKE PROTOCOL 493 @orm.reconstructor 494 def init_on_load(self): 495 """Initiate snowflake protocol 496 497 This is a snowflake protocol, which is a way to make the role ID 498 more accessible. To use with discord.py. 499 """ 500 self.id = self.role_id
Staff roles table
This is the table for the staff roles. It contains the role ID of the staff role. It also contains the relationship to the Guild table. And the foreign key to the guild ID.
Attributes:
- role_id: The unique discord-provided role ID.
- guild_id: The unique discord-provided guild ID.
- guild: The relationship to the Guild table.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
493 @orm.reconstructor 494 def init_on_load(self): 495 """Initiate snowflake protocol 496 497 This is a snowflake protocol, which is a way to make the role ID 498 more accessible. To use with discord.py. 499 """ 500 self.id = self.role_id
Initiate snowflake protocol
This is a snowflake protocol, which is a way to make the role ID more accessible. To use with discord.py.
503class ObserversRole(Base): 504 """Observer roles table 505 506 This is the table for the observer roles. 507 It contains the role ID of the observer role. 508 It also contains the relationship to the Guild table. 509 And the foreign key to the guild ID. 510 511 Attributes: 512 role_id: The unique discord-provided role ID. 513 guild_id: The unique discord-provided guild ID. 514 guild: The relationship to the Guild table. 515 """ 516 517 __tablename__ = "observer_roles" 518 __table_args__ = {"comment": "Roles that are automatically added to tickets notes."} 519 520 # Simple columns 521 role_id: orm.Mapped[int] = orm.mapped_column( 522 sqlalchemy.BigInteger(), 523 primary_key=True, 524 comment=("Unique discord-provided role ID," 525 " this is the primary key as it is unique across guilds"), 526 ) 527 guild_id: orm.Mapped[int] = orm.mapped_column( 528 sqlalchemy.BigInteger(), 529 sqlalchemy.ForeignKey("general_configs.guild_id"), 530 nullable=False, 531 comment="Unique Guild ID of parent guild", 532 ) 533 534 # Relationships 535 guild: orm.Mapped["Guild"] = orm.relationship(back_populates="observers_roles", lazy="selectin") 536 537 # SNOWFLAKE PROTOCOL 538 @orm.reconstructor 539 def init_on_load(self): 540 """Initiate snowflake protocol 541 542 This is a snowflake protocol, which is a way to make the role ID 543 more accessible. To use with discord.py. 544 """ 545 self.id = self.role_id
Observer roles table
This is the table for the observer roles. It contains the role ID of the observer role. It also contains the relationship to the Guild table. And the foreign key to the guild ID.
Attributes:
- role_id: The unique discord-provided role ID.
- guild_id: The unique discord-provided guild ID.
- guild: The relationship to the Guild table.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
538 @orm.reconstructor 539 def init_on_load(self): 540 """Initiate snowflake protocol 541 542 This is a snowflake protocol, which is a way to make the role ID 543 more accessible. To use with discord.py. 544 """ 545 self.id = self.role_id
Initiate snowflake protocol
This is a snowflake protocol, which is a way to make the role ID more accessible. To use with discord.py.
548class CommunityRole(Base): 549 """Community roles table 550 551 This is the table for the community roles. 552 It contains the role ID of the community role. 553 It also contains the relationship to the Guild table. 554 And the foreign key to the guild ID. 555 556 Attributes: 557 role_id: The unique discord-provided role ID. 558 guild_id: The unique discord-provided guild ID. 559 guild: The relationship to the Guild table. 560 """ 561 562 __tablename__ = "community_roles" 563 __table_args__ = {"comment": "Roles that are allowed to view tickets, but aren't staff."} 564 565 # Simple columns 566 role_id: orm.Mapped[int] = orm.mapped_column( 567 sqlalchemy.BigInteger(), 568 primary_key=True, 569 comment=("Unique discord-provided role ID," 570 " this is the primary key as it is unique across guilds"), 571 ) 572 guild_id: orm.Mapped[int] = orm.mapped_column( 573 sqlalchemy.BigInteger(), 574 sqlalchemy.ForeignKey("general_configs.guild_id"), 575 nullable=False, 576 comment="Unique Guild ID of parent guild", 577 ) 578 579 # Relationships 580 guild: orm.Mapped["Guild"] = orm.relationship(back_populates="community_roles", lazy="selectin") 581 582 # SNOWFLAKE PROTOCOL 583 @orm.reconstructor 584 def init_on_load(self): 585 """Initiate snowflake protocol 586 587 This is a snowflake protocol, which is a way to make the role ID 588 more accessible. To use with discord.py. 589 """ 590 self.id = self.role_id
Community roles table
This is the table for the community roles. It contains the role ID of the community role. It also contains the relationship to the Guild table. And the foreign key to the guild ID.
Attributes:
- role_id: The unique discord-provided role ID.
- guild_id: The unique discord-provided guild ID.
- guild: The relationship to the Guild table.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
583 @orm.reconstructor 584 def init_on_load(self): 585 """Initiate snowflake protocol 586 587 This is a snowflake protocol, which is a way to make the role ID 588 more accessible. To use with discord.py. 589 """ 590 self.id = self.role_id
Initiate snowflake protocol
This is a snowflake protocol, which is a way to make the role ID more accessible. To use with discord.py.
593class CommunityPing(Base): 594 """Community pings table 595 596 This is the table for the community pings. 597 It contains the role ID of the community ping role. 598 It also contains the relationship to the Guild table. 599 And the foreign key to the guild ID. 600 601 Attributes: 602 role_id: The unique discord-provided role ID. 603 guild_id: The unique discord-provided guild ID. 604 guild: The relationship to the Guild table. 605 """ 606 607 __tablename__ = "community_pings" 608 __table_args__ = { 609 "comment": ("Table for community pings," 610 " pinged when a ticket is opened but" 611 " after adding the community roles.") 612 } 613 614 # Simple columns 615 role_id: orm.Mapped[int] = orm.mapped_column( 616 sqlalchemy.BigInteger(), 617 primary_key=True, 618 comment=("Unique discord-provided role ID," 619 " this is the primary key as it is unique across guilds"), 620 ) 621 guild_id: orm.Mapped[int] = orm.mapped_column( 622 sqlalchemy.BigInteger(), 623 sqlalchemy.ForeignKey("general_configs.guild_id"), 624 nullable=False, 625 comment="Unique Guild ID of parent guild", 626 ) 627 628 # Relationships 629 guild: orm.Mapped["Guild"] = orm.relationship(back_populates="community_pings", lazy="selectin") 630 631 # SNOWFLAKE PROTOCOL 632 @orm.reconstructor 633 def init_on_load(self): 634 """Initiate snowflake protocol 635 636 This is a snowflake protocol, which is a way to make the role ID 637 more accessible. To use with discord.py. 638 """ 639 self.id = self.role_id
Community pings table
This is the table for the community pings. It contains the role ID of the community ping role. It also contains the relationship to the Guild table. And the foreign key to the guild ID.
Attributes:
- role_id: The unique discord-provided role ID.
- guild_id: The unique discord-provided guild ID.
- guild: The relationship to the Guild table.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
632 @orm.reconstructor 633 def init_on_load(self): 634 """Initiate snowflake protocol 635 636 This is a snowflake protocol, which is a way to make the role ID 637 more accessible. To use with discord.py. 638 """ 639 self.id = self.role_id
Initiate snowflake protocol
This is a snowflake protocol, which is a way to make the role ID more accessible. To use with discord.py.
642class Member(Base): 643 """Member table 644 645 This is the table for the members. 646 It is an association table between the users and the guilds. 647 It contains the user ID and the guild ID. 648 It also contains a relationship to both the User and Guild tables. 649 It will also contain any bot information about the user. 650 651 Attributes: 652 user_id: The unique discord-provided user ID. 653 guild_id: The unique discord-provided guild ID. 654 user: The relationship to the User table. 655 guild: The relationship to the Guild table. 656 """ 657 658 __tablename__ = "members" 659 __table_args__ = { 660 "comment": ("Table for members," 661 " this is a combination of a user and a guild," 662 " as a user can be in multiple guilds.") 663 } 664 665 # Simple columns 666 user_id: orm.Mapped[int] = orm.mapped_column( 667 sqlalchemy.BigInteger(), 668 sqlalchemy.ForeignKey("users.user_id"), 669 nullable=False, 670 comment=("Unique discord-provided user ID." 671 " Used in conjunction with guild_id to make a unique primary key"), 672 primary_key=True, 673 unique=False, 674 ) 675 guild_id: orm.Mapped[int] = orm.mapped_column( 676 sqlalchemy.BigInteger(), 677 sqlalchemy.ForeignKey("general_configs.guild_id"), 678 nullable=False, 679 comment=("Unique Guild ID of parent guild." 680 " Used in conjunction with user_id to make a unique primary key"), 681 primary_key=True, 682 unique=False, 683 ) 684 status: orm.Mapped[int] = orm.mapped_column( 685 sqlalchemy.Integer(), 686 nullable=False, 687 default=0, 688 comment=("The status of the member, 0 is normal, " 689 "1 is support-blocked, 2 is barred from providing support"), 690 ) 691 status_till: orm.Mapped[datetime.datetime | None] = orm.mapped_column( 692 sqlalchemy.DateTime(), 693 nullable=True, 694 comment=("The time until the status is removed, " 695 "if None, the status is permanent"), 696 default=None) 697 698 # Relationships 699 guild: orm.Mapped["Guild"] = orm.relationship(back_populates="members", lazy="selectin") 700 user: orm.Mapped["User"] = orm.relationship(back_populates="memberships", lazy="selectin")
Member table
This is the table for the members. It is an association table between the users and the guilds. It contains the user ID and the guild ID. It also contains a relationship to both the User and Guild tables. It will also contain any bot information about the user.
Attributes:
- user_id: The unique discord-provided user ID.
- guild_id: The unique discord-provided guild ID.
- user: The relationship to the User table.
- guild: The relationship to the Guild table.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
703class User(Base): 704 """User table 705 706 This is the table for the users. 707 It contains the user ID. 708 It also contains a relationship to the Member table. 709 It will also contain any bot information about the user. 710 711 Attributes: 712 user_id: The unique discord-provided user ID. 713 memberships: The relationship to the Member table. 714 is_owner: Is the user the owner of the bot? 715 """ 716 717 __tablename__ = "users" 718 __table_args__ = { 719 "comment": ("Table for users," 720 " this is not a guild-specific table," 721 " as a user can be in multiple guilds.") 722 } 723 724 # Simple columns 725 user_id: orm.Mapped[int] = orm.mapped_column( 726 sqlalchemy.BigInteger(), 727 primary_key=True, 728 comment=("Unique discord-provided user ID," 729 " this is the primary key as it is unique across guilds"), 730 ) 731 732 # Toggles 733 is_owner: orm.Mapped[bool] = orm.mapped_column(default=False, comment="Is the user the owner of the bot?") 734 735 # Relationships 736 memberships: orm.Mapped[list["Member"]] = orm.relationship(back_populates="user", lazy="raise") 737 # Disabled for now gets sqlalchemy confused 738 # pylint: disable=line-too-long 739 # guilds: orm.Mapped[list["Guild"]] = orm.relationship( 740 # secondary="members", back_populates="users", lazy="raise", viewonly=True 741 # ) 742 743 # SNOWFLAKE PROTOCOL 744 @orm.reconstructor 745 def init_on_load(self): 746 """Initiate snowflake protocol 747 748 This is a snowflake protocol, which is a way to make the user ID 749 more accessible. To use with discord.py. 750 """ 751 self.id = self.user_id
User table
This is the table for the users. It contains the user ID. It also contains a relationship to the Member table. It will also contain any bot information about the user.
Attributes:
- user_id: The unique discord-provided user ID.
- memberships: The relationship to the Member table.
- is_owner: Is the user the owner of the bot?
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
744 @orm.reconstructor 745 def init_on_load(self): 746 """Initiate snowflake protocol 747 748 This is a snowflake protocol, which is a way to make the user ID 749 more accessible. To use with discord.py. 750 """ 751 self.id = self.user_id
Initiate snowflake protocol
This is a snowflake protocol, which is a way to make the user ID more accessible. To use with discord.py.