Static type checking, part 1: SQLAlchemy 2.0 annotations #222

Closed
TriHard wants to merge 7 commits from TriHard/rDrama:type-checking into master
36 changed files with 758 additions and 544 deletions

View File

@ -1,6 +1,7 @@
# load sqlalchemy's declarative base... # load sqlalchemy's declarative base...
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import DeclarativeBase
Base = declarative_base() class Base(DeclarativeBase):
pass
# then load all of our classes :) # then load all of our classes :)
from .alts import * from .alts import *

View File

@ -1,17 +1,19 @@
import time import time
from typing import Optional
from sqlalchemy import Column, ForeignKey from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.types import user_id_fk_pk
class Alt(Base): class Alt(Base):
__tablename__ = "alts" __tablename__ = "alts"
user1 = Column(Integer, ForeignKey("users.id"), primary_key=True) user1: Mapped[user_id_fk_pk]
user2 = Column(Integer, ForeignKey("users.id"), primary_key=True) user2: Mapped[user_id_fk_pk]
is_manual = Column(Boolean, default=False) is_manual: Mapped[bool] = mapped_column(default=False)
created_utc = Column(Integer) created_utc: Mapped[Optional[int]]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,30 +1,34 @@
import time import time
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Column, ForeignKey from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.orm import relationship
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.config.awards import AWARDS, HOUSE_AWARDS from files.helpers.config.awards import AWARDS, HOUSE_AWARDS
from files.helpers.lazy import lazy from files.helpers.lazy import lazy
from files.helpers.types import comment_id_fk, int_pk, post_id_fk, user_id_fk
if TYPE_CHECKING:
from files.classes import Comment, Post, User
class AwardRelationship(Base): class AwardRelationship(Base):
__tablename__ = "award_relationships" __tablename__ = "award_relationships"
id = Column(Integer, primary_key=True) id: Mapped[int_pk]
user_id = Column(Integer, ForeignKey("users.id")) user_id: Mapped[user_id_fk]
post_id = Column(Integer, ForeignKey("posts.id")) post_id: Mapped[Optional[post_id_fk]]
comment_id = Column(Integer, ForeignKey("comments.id")) comment_id: Mapped[Optional[comment_id_fk]]
kind = Column(String) kind: Mapped[str]
awarded_utc = Column(Integer) awarded_utc: Mapped[Optional[int]]
created_utc = Column(Integer) created_utc: Mapped[Optional[int]]
price_paid = Column(Integer, default = 0) price_paid: Mapped[int] = mapped_column(default = 0)
note = Column(String) note: Mapped[Optional[str]]
user = relationship("User", primaryjoin="AwardRelationship.user_id==User.id", back_populates="awards") user: Mapped["User"] = relationship(primaryjoin="AwardRelationship.user_id==User.id", back_populates="awards")
post = relationship("Post", primaryjoin="AwardRelationship.post_id==Post.id", back_populates="awards") post: Mapped["Post"] = relationship(primaryjoin="AwardRelationship.post_id==Post.id", back_populates="awards")
comment = relationship("Comment", primaryjoin="AwardRelationship.comment_id==Comment.id", back_populates="awards") comment: Mapped["Comment"] = relationship(primaryjoin="AwardRelationship.comment_id==Comment.id", back_populates="awards")
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,20 +1,26 @@
import time import time
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Column, ForeignKey from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.config.const import * from files.helpers.config.const import *
from files.helpers.lazy import lazy from files.helpers.lazy import lazy
from files.helpers.types import int_pk, user_id_fk_pk
if TYPE_CHECKING:
from files.classes import User
class BadgeDef(Base): class BadgeDef(Base):
__tablename__ = "badge_defs" __tablename__ = "badge_defs"
id = Column(Integer, primary_key=True, autoincrement=True) id: Mapped[int_pk] = mapped_column(autoincrement=True)
name = Column(String) name: Mapped[str]
description = Column(String) description: Mapped[Optional[str]]
created_utc = Column(Integer) created_utc: Mapped[int]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())
@ -32,14 +38,14 @@ class Badge(Base):
__tablename__ = "badges" __tablename__ = "badges"
user_id = Column(Integer, ForeignKey('users.id'), primary_key=True) user_id: Mapped[user_id_fk_pk]
badge_id = Column(Integer, ForeignKey('badge_defs.id'), primary_key=True) badge_id: Mapped[int] = mapped_column(ForeignKey('badge_defs.id'), primary_key=True)
description = Column(String) description: Mapped[Optional[str]]
url = Column(String) url: Mapped[Optional[str]]
created_utc = Column(Integer) created_utc: Mapped[int]
user = relationship("User", back_populates="badges") user: Mapped["User"] = relationship(back_populates="badges")
badge = relationship("BadgeDef", primaryjoin="Badge.badge_id == BadgeDef.id", lazy="joined", innerjoin=True) badge: Mapped["BadgeDef"] = relationship(primaryjoin="Badge.badge_id == BadgeDef.id", lazy="joined", innerjoin=True)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: if "created_utc" not in kwargs:

View File

@ -1,29 +1,33 @@
import json import json
import time import time
from typing import TYPE_CHECKING
from sqlalchemy import Column, ForeignKey from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.orm import relationship
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.lazy import lazy from files.helpers.lazy import lazy
from files.helpers.types import int_pk, user_id_fk
if TYPE_CHECKING:
from files.classes import User
CASINO_GAME_KINDS = ['blackjack', 'slots', 'roulette'] CASINO_GAME_KINDS = ['blackjack', 'slots', 'roulette']
class CasinoGame(Base): class CasinoGame(Base):
__tablename__ = "casino_games" __tablename__ = "casino_games"
id = Column(Integer, primary_key=True) id: Mapped[int_pk]
user_id = Column(Integer, ForeignKey("users.id")) user_id: Mapped[user_id_fk]
created_utc = Column(Integer) created_utc: Mapped[int]
active = Column(Boolean, default=True) active: Mapped[bool] = mapped_column(default=True)
currency = Column(String) currency: Mapped[str]
wager = Column(Integer) wager: Mapped[int]
winnings = Column(Integer) winnings: Mapped[int]
kind = Column(String) kind: Mapped[str]
game_state = Column(JSON) game_state: Mapped[str] = mapped_column(JSON)
user = relationship("User") user: Mapped["User"] = relationship()
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: if "created_utc" not in kwargs:

View File

@ -1,29 +1,35 @@
import time import time
from typing import Annotated, Optional, TYPE_CHECKING
from flask import g from flask import g
from sqlalchemy import Column, ForeignKey from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship, load_only from sqlalchemy.orm import Mapped, load_only, mapped_column, relationship
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.config.const import * from files.helpers.config.const import *
from files.helpers.lazy import lazy from files.helpers.lazy import lazy
from files.helpers.types import int_pk, user_id_fk, user_id_fk_pk
from .comment import Comment from .comment import Comment
from .post import Post from .post import Post
if TYPE_CHECKING:
from files.classes import User
class OauthApp(Base): class OauthApp(Base):
__tablename__ = "oauth_apps" __tablename__ = "oauth_apps"
id = Column(Integer, primary_key=True) id: Mapped[int_pk]
client_id = Column(String) client_id: Mapped[Optional[Annotated[str, 64]]]
app_name = Column(String) app_name: Mapped[str]
redirect_uri = Column(String) redirect_uri: Mapped[str]
description = Column(String) description: Mapped[str]
author_id = Column(Integer, ForeignKey("users.id")) author_id: Mapped[user_id_fk]
created_utc = Column(Integer) created_utc: Mapped[Optional[int]]
author = relationship("User", back_populates="apps") author: Mapped["User"] = relationship(back_populates="apps")
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())
@ -51,13 +57,13 @@ class OauthApp(Base):
class ClientAuth(Base): class ClientAuth(Base):
__tablename__ = "client_auths" __tablename__ = "client_auths"
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) user_id: Mapped[user_id_fk_pk]
oauth_client = Column(Integer, ForeignKey("oauth_apps.id"), primary_key=True) oauth_client: Mapped[int] = mapped_column(ForeignKey("oauth_apps.id"), primary_key=True)
access_token = Column(String) access_token: Mapped[str]
created_utc = Column(Integer) created_utc: Mapped[Optional[int]]
user = relationship("User") user: Mapped["User"] = relationship()
application = relationship("OauthApp") application: Mapped["OauthApp"] = relationship()
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,12 +1,13 @@
import time import time
from math import floor from math import floor
from random import randint from random import randint
from typing import Optional, TYPE_CHECKING
from urllib.parse import parse_qs, urlencode, urlparse from urllib.parse import parse_qs, urlencode, urlparse
from flask import g from flask import g
from sqlalchemy import Column, ForeignKey from sqlalchemy import ForeignKey
from sqlalchemy.dialects.postgresql import TSVECTOR from sqlalchemy.dialects.postgresql import TSVECTOR
from sqlalchemy.orm import relationship from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.schema import FetchedValue from sqlalchemy.schema import FetchedValue
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
@ -17,10 +18,14 @@ from files.helpers.slurs_and_profanities import *
from files.helpers.lazy import lazy from files.helpers.lazy import lazy
from files.helpers.regex import * from files.helpers.regex import *
from files.helpers.sorting_and_time import * from files.helpers.sorting_and_time import *
from files.helpers.types import comment_id_fk, int_pk, post_id_fk, user_id_fk
from files.helpers.bleach_body import * from files.helpers.bleach_body import *
from .saves import CommentSaveRelationship from .saves import CommentSaveRelationship
if TYPE_CHECKING:
from files.classes import AwardRelationship, CasinoGame, CommentOption, CommentReport, OauthApp, Post, User
def get_emoji_awards_emojis(obj, v, kind, NSFW_EMOJIS): def get_emoji_awards_emojis(obj, v, kind, NSFW_EMOJIS):
if g.show_nsfw: if g.show_nsfw:
emojis = [x.note for x in obj.awards if x.kind == kind] emojis = [x.note for x in obj.awards if x.kind == kind]
@ -172,60 +177,60 @@ def add_options(self, body, v):
class Comment(Base): class Comment(Base):
__tablename__ = "comments" __tablename__ = "comments"
id = Column(Integer, primary_key=True) id: Mapped[int_pk]
author_id = Column(Integer, ForeignKey("users.id")) author_id: Mapped[user_id_fk]
parent_post = Column(Integer, ForeignKey("posts.id")) parent_post: Mapped[Optional[post_id_fk]]
wall_user_id = Column(Integer, ForeignKey("users.id")) wall_user_id: Mapped[Optional[user_id_fk]]
created_utc = Column(Integer) created_utc: Mapped[int]
edited_utc = Column(Integer, default=0) edited_utc: Mapped[int] = mapped_column(default=0)
is_banned = Column(Boolean, default=False) is_banned: Mapped[bool] = mapped_column(default=False)
ghost = Column(Boolean, default=False) ghost: Mapped[bool] = mapped_column(default=False)
bannedfor = Column(String) bannedfor: Mapped[Optional[str]]
chuddedfor = Column(String) chuddedfor: Mapped[Optional[str]]
distinguished = Column(Boolean, default=False) distinguished: Mapped[bool] = mapped_column(default=False)
deleted_utc = Column(Integer, default=0) deleted_utc: Mapped[int] = mapped_column(default=0)
is_approved = Column(Integer, ForeignKey("users.id")) is_approved: Mapped[Optional[user_id_fk]]
level = Column(Integer, default=1) level: Mapped[int] = mapped_column(default=1)
parent_comment_id = Column(Integer, ForeignKey("comments.id")) parent_comment_id: Mapped[Optional[comment_id_fk]]
top_comment_id = Column(Integer) top_comment_id: Mapped[Optional[int]]
is_bot = Column(Boolean, default=False) is_bot: Mapped[bool] = mapped_column(default=False)
stickied = Column(String) stickied: Mapped[Optional[str]]
stickied_utc = Column(Integer) stickied_utc: Mapped[Optional[int]]
num_of_pinned_children = Column(Integer, default=0) num_of_pinned_children: Mapped[int] = mapped_column(default=0)
sentto = Column(Integer, ForeignKey("users.id")) sentto: Mapped[Optional[user_id_fk]]
app_id = Column(Integer, ForeignKey("oauth_apps.id")) app_id: Mapped[Optional[int]] = mapped_column(ForeignKey("oauth_apps.id"))
upvotes = Column(Integer, default=1) upvotes: Mapped[int] = mapped_column(default=1)
downvotes = Column(Integer, default=0) downvotes: Mapped[int] = mapped_column(default=0)
realupvotes = Column(Integer, default=1) realupvotes: Mapped[int] = mapped_column(default=1)
body = Column(String) body: Mapped[Optional[str]]
body_html = Column(String) body_html: Mapped[Optional[str]]
body_ts = Column(TSVECTOR(), server_default=FetchedValue()) body_ts: Mapped[str] = mapped_column(TSVECTOR(), server_default=FetchedValue())
ban_reason = Column(String) ban_reason: Mapped[Optional[str]]
treasure_amount = Column(String) treasure_amount: Mapped[Optional[str]]
slots_result = Column(String) slots_result: Mapped[Optional[str]]
ping_cost = Column(Integer, default=0) ping_cost: Mapped[int] = mapped_column(default=0)
blackjack_result = Column(String) blackjack_result: Mapped[Optional[str]]
casino_game_id = Column(Integer, ForeignKey("casino_games.id")) casino_game_id: Mapped[Optional[int]] = mapped_column(ForeignKey("casino_games.id"))
chudded = Column(Boolean, default=False) chudded: Mapped[bool] = mapped_column(default=False)
rainbowed = Column(Boolean, default=False) rainbowed: Mapped[bool] = mapped_column(default=False)
queened = Column(Boolean, default=False) queened: Mapped[bool] = mapped_column(default=False)
sharpened = Column(Boolean, default=False) sharpened: Mapped[bool] = mapped_column(default=False)
if FEATURES['NSFW_MARKING']: if FEATURES['NSFW_MARKING']:
nsfw = Column(Boolean, default=False) nsfw: Mapped[bool] = mapped_column(default=False)
else: else:
nsfw = False nsfw = False
oauth_app = relationship("OauthApp") oauth_app: Mapped["OauthApp"] = relationship()
post = relationship("Post", back_populates="comments") post: Mapped["Post"] = relationship(back_populates="comments")
author = relationship("User", primaryjoin="User.id==Comment.author_id") author: Mapped["User"] = relationship(primaryjoin="User.id==Comment.author_id")
senttouser = relationship("User", primaryjoin="User.id==Comment.sentto") senttouser: Mapped["User"] = relationship(primaryjoin="User.id==Comment.sentto")
parent_comment = relationship("Comment", remote_side=[id]) parent_comment: Mapped["Comment"] = relationship(remote_side="Comment.id")
awards = relationship("AwardRelationship", order_by="AwardRelationship.awarded_utc.desc()", back_populates="comment") awards: Mapped[list["AwardRelationship"]] = relationship(order_by="AwardRelationship.awarded_utc.desc()", back_populates="comment")
reports = relationship("CommentReport", order_by="CommentReport.created_utc") reports: Mapped[list["CommentReport"]] = relationship(order_by="CommentReport.created_utc")
options = relationship("CommentOption", order_by="CommentOption.id") options: Mapped[list["CommentOption"]] = relationship(order_by="CommentOption.id")
casino_game = relationship("CasinoGame") casino_game: Mapped["CasinoGame"] = relationship()
wall_user = relationship("User", primaryjoin="User.id==Comment.wall_user_id") wall_user: Mapped["User"] = relationship(primaryjoin="User.id==Comment.wall_user_id")
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: if "created_utc" not in kwargs:

View File

@ -1,15 +1,17 @@
import time import time
from typing import Optional
from sqlalchemy import Column from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.types import str_pk
class BannedDomain(Base): class BannedDomain(Base):
__tablename__ = "banneddomains" __tablename__ = "banneddomains"
domain = Column(String, primary_key=True) domain: Mapped[str_pk]
reason = Column(String) reason: Mapped[str]
created_utc = Column(Integer) created_utc: Mapped[Optional[int]]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,21 +1,23 @@
import time import time
from typing import Optional
from sqlalchemy import Column, ForeignKey from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.types import str_pk, user_id_fk
class Emoji(Base): class Emoji(Base):
__tablename__ = "emojis" __tablename__ = "emojis"
name = Column(String, primary_key=True) name: Mapped[str_pk]
kind = Column(String) kind: Mapped[str]
author_id = Column(Integer, ForeignKey("users.id")) author_id: Mapped[user_id_fk]
tags = Column(String) tags: Mapped[str]
count = Column(Integer, default=0) count: Mapped[int] = mapped_column(default=0)
submitter_id = Column(Integer, ForeignKey("users.id")) submitter_id: Mapped[Optional[user_id_fk]]
created_utc = Column(Integer) created_utc: Mapped[int]
nsfw = Column(Boolean, default=False) nsfw: Mapped[bool] = mapped_column(default=False)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,19 +1,24 @@
import time import time
from typing import TYPE_CHECKING
from sqlalchemy import Column, ForeignKey from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.orm import relationship
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.types import user_id_fk_pk
if TYPE_CHECKING:
from files.classes import User
class Follow(Base): class Follow(Base):
__tablename__ = "follows" __tablename__ = "follows"
target_id = Column(Integer, ForeignKey("users.id"), primary_key=True) target_id: Mapped[user_id_fk_pk]
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) user_id: Mapped[user_id_fk_pk]
created_utc = Column(Integer) created_utc: Mapped[int]
user = relationship("User", uselist=False, primaryjoin="User.id==Follow.user_id", back_populates="following") user: Mapped["User"] = relationship(uselist=False, primaryjoin="User.id==Follow.user_id", back_populates="following")
target = relationship("User", uselist=False, primaryjoin="User.id==Follow.target_id", back_populates="followers") target: Mapped["User"] = relationship(uselist=False, primaryjoin="User.id==Follow.target_id", back_populates="followers")
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,25 +1,29 @@
import time import time
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Column from sqlalchemy.orm import Mapped, relationship
from sqlalchemy.orm import relationship
from sqlalchemy.types import Integer
from files.classes import Base from files.classes import Base
from files.helpers.lazy import lazy from files.helpers.lazy import lazy
from files.helpers.config.const import * from files.helpers.config.const import *
from files.helpers.types import str_pk, user_id_fk
from .group_membership import * from .group_membership import *
if TYPE_CHECKING:
from files.classes import User
class Group(Base): class Group(Base):
__tablename__ = "groups" __tablename__ = "groups"
name = Column(String, primary_key=True) name: Mapped[str_pk]
created_utc = Column(Integer) created_utc: Mapped[int]
owner_id = Column(Integer, ForeignKey("users.id")) owner_id: Mapped[Optional[user_id_fk]]
description = Column(String) description: Mapped[Optional[str]]
description_html = Column(String) description_html: Mapped[Optional[str]]
memberships = relationship("GroupMembership", primaryjoin="GroupMembership.group_name==Group.name", order_by="GroupMembership.approved_utc") memberships: Mapped[list["GroupMembership"]] = relationship(primaryjoin="GroupMembership.group_name==Group.name", order_by="GroupMembership.approved_utc")
owner = relationship("User", primaryjoin="Group.owner_id==User.id") owner: Mapped["User"] = relationship(primaryjoin="Group.owner_id==User.id")
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,20 +1,25 @@
import time import time
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Column, ForeignKey from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.types import Integer, String, Boolean
from files.classes import Base from files.classes import Base
from files.helpers.types import user_id_fk_pk
if TYPE_CHECKING:
from files.classes.user import User
class GroupMembership(Base): class GroupMembership(Base):
__tablename__ = "group_memberships" __tablename__ = "group_memberships"
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) user_id: Mapped[user_id_fk_pk]
group_name = Column(String, ForeignKey("groups.name"), primary_key=True) group_name: Mapped[str] = mapped_column(ForeignKey("groups.name"), primary_key=True)
created_utc = Column(Integer) created_utc: Mapped[int]
approved_utc = Column(Integer) approved_utc: Mapped[Optional[int]]
is_mod = Column(Boolean, default=False) is_mod: Mapped[bool] = mapped_column(default=False)
user = relationship("User", uselist=False) user: Mapped["User"] = relationship(uselist=False)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,27 +1,33 @@
import time import time
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Column, ForeignKey from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from flask import g from flask import g
from files.classes import Base from files.classes import Base
from files.helpers.lazy import lazy from files.helpers.lazy import lazy
from files.helpers.slurs_and_profanities import censor_slurs_profanities from files.helpers.slurs_and_profanities import censor_slurs_profanities
from files.helpers.types import int_pk, user_id_fk
if TYPE_CHECKING:
from files.classes import User
class HatDef(Base): class HatDef(Base):
__tablename__ = "hat_defs" __tablename__ = "hat_defs"
id = Column(Integer, primary_key=True) id: Mapped[int_pk]
name = Column(String) name: Mapped[str]
description = Column(String) description: Mapped[str]
author_id = Column(Integer, ForeignKey('users.id')) author_id: Mapped[int] = mapped_column(ForeignKey('users.id'))
price = Column(Integer) price: Mapped[int]
submitter_id = Column(Integer, ForeignKey("users.id")) submitter_id: Mapped[Optional[user_id_fk]]
created_utc = Column(Integer) created_utc: Mapped[int]
author = relationship("User", primaryjoin="HatDef.author_id == User.id", back_populates="designed_hats") author: Mapped["User"] = relationship(primaryjoin="HatDef.author_id == User.id", back_populates="designed_hats")
submitter = relationship("User", primaryjoin="HatDef.submitter_id == User.id") submitter: Mapped["User"] = relationship(primaryjoin="HatDef.submitter_id == User.id")
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())
@ -48,13 +54,13 @@ class HatDef(Base):
class Hat(Base): class Hat(Base):
__tablename__ = "hats" __tablename__ = "hats"
user_id = Column(Integer, ForeignKey('users.id'), primary_key=True) user_id: Mapped[int] = mapped_column(ForeignKey('users.id'), primary_key=True)
hat_id = Column(Integer, ForeignKey('hat_defs.id'), primary_key=True) hat_id: Mapped[int] = mapped_column(ForeignKey('hat_defs.id'), primary_key=True)
equipped = Column(Boolean, default=False) equipped: Mapped[Optional[bool]] = mapped_column(default=False)
created_utc = Column(Integer) created_utc: Mapped[Optional[int]]
hat_def = relationship("HatDef") hat_def: Mapped["HatDef"] = relationship()
owners = relationship("User", back_populates="owned_hats") owners: Mapped[list["User"]] = relationship(back_populates="owned_hats")
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,10 +1,9 @@
import random import random
import time import time
from typing import Annotated, Optional
from sqlalchemy import Column
from sqlalchemy.ext.mutable import MutableList from sqlalchemy.ext.mutable import MutableList
from sqlalchemy.orm import relationship, deferred from sqlalchemy.orm import DynamicMapped, Mapped, mapped_column, relationship
from sqlalchemy.types import *
from sqlalchemy.dialects.postgresql import ARRAY from sqlalchemy.dialects.postgresql import ARRAY
from files.classes import Base from files.classes import Base
@ -15,24 +14,24 @@ from .hole_relationship import *
class Hole(Base): class Hole(Base):
__tablename__ = "holes" __tablename__ = "holes"
name = Column(String, primary_key=True) name: Mapped[str] = mapped_column(primary_key=True)
sidebar = Column(String) sidebar: Mapped[Optional[str]]
sidebar_html = Column(String) sidebar_html: Mapped[Optional[str]]
sidebarurls = Column(MutableList.as_mutable(ARRAY(String)), default=MutableList([])) sidebarurls: Mapped[list[str]] = mapped_column(MutableList.as_mutable(ARRAY(String)), default=MutableList([]))
bannerurls = Column(MutableList.as_mutable(ARRAY(String)), default=MutableList([])) bannerurls: Mapped[list[str]] = mapped_column(MutableList.as_mutable(ARRAY(String)), default=MutableList([]))
marseyurl = Column(String) marseyurl: Mapped[Optional[str]]
css = deferred(Column(String)) css: Mapped[Optional[str]] = mapped_column(deferred=True)
stealth = Column(Boolean, default=False) stealth: Mapped[Optional[bool]] = mapped_column(default=False)
public_use = Column(Boolean, default=False) public_use: Mapped[bool] = mapped_column(default=False)
created_utc = Column(Integer) created_utc: Mapped[Optional[int]]
if SITE_NAME == 'WPD': if SITE_NAME == 'WPD':
snappy_quotes = None snappy_quotes = None
else: else:
snappy_quotes = deferred(Column(String)) snappy_quotes: Mapped[Optional[Annotated[str, HOLE_SNAPPY_QUOTES_LENGTH]]] = mapped_column(deferred=True)
blocks = relationship("HoleBlock", primaryjoin="HoleBlock.hole==Hole.name") blocks: Mapped[list["HoleBlock"]] = relationship(primaryjoin="HoleBlock.hole==Hole.name")
followers = relationship("HoleFollow", primaryjoin="HoleFollow.hole==Hole.name") followers: Mapped[list["HoleFollow"]] = relationship(primaryjoin="HoleFollow.hole==Hole.name")
stealth_hole_unblocks = relationship("StealthHoleUnblock", lazy="dynamic", primaryjoin="StealthHoleUnblock.hole==Hole.name") stealth_hole_unblocks: DynamicMapped["StealthHoleUnblock"] = relationship(primaryjoin="StealthHoleUnblock.hole==Hole.name")
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,7 +1,8 @@
import time import time
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Column, ForeignKey from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from flask import g from flask import g
@ -10,23 +11,28 @@ from files.helpers.config.const import *
from files.helpers.lazy import lazy from files.helpers.lazy import lazy
from files.helpers.slurs_and_profanities import censor_slurs_profanities from files.helpers.slurs_and_profanities import censor_slurs_profanities
from files.helpers.sorting_and_time import make_age_string from files.helpers.sorting_and_time import make_age_string
from files.helpers.types import comment_id_fk, int_pk, post_id_fk, user_id_fk
if TYPE_CHECKING:
from files.classes import Comment, Post, User
class HoleAction(Base): class HoleAction(Base):
__tablename__ = "hole_actions" __tablename__ = "hole_actions"
id = Column(Integer, primary_key=True) id: Mapped[int_pk]
hole = Column(String, ForeignKey("holes.name")) hole: Mapped[str] = mapped_column(ForeignKey("holes.name"))
user_id = Column(Integer, ForeignKey("users.id")) user_id: Mapped[Optional[user_id_fk]]
kind = Column(String) kind: Mapped[Optional[str]]
target_user_id = Column(Integer, ForeignKey("users.id")) target_user_id: Mapped[Optional[user_id_fk]]
target_post_id = Column(Integer, ForeignKey("posts.id")) target_post_id: Mapped[Optional[post_id_fk]]
target_comment_id = Column(Integer, ForeignKey("comments.id")) target_comment_id: Mapped[Optional[comment_id_fk]]
_note = Column(String) _note: Mapped[Optional[str]]
created_utc = Column(Integer) created_utc: Mapped[int]
user = relationship("User", primaryjoin="User.id==HoleAction.user_id") user: Mapped["User"] = relationship(primaryjoin="User.id==HoleAction.user_id")
target_user = relationship("User", primaryjoin="User.id==HoleAction.target_user_id") target_user: Mapped["User"] = relationship(primaryjoin="User.id==HoleAction.target_user_id")
target_post = relationship("Post") target_post: Mapped["Post"] = relationship()
target_comment = relationship("Comment") target_comment: Mapped["Comment"] = relationship()
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,18 +1,23 @@
import time import time
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Column, ForeignKey from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship from sqlalchemy.orm import Mapped, relationship, mapped_column
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
if TYPE_CHECKING:
from files.classes import User
class HoleRelationship(Base): class HoleRelationship(Base):
__tablename__ = NotImplemented __tablename__ = NotImplemented
__abstract__ = True __abstract__ = True
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), primary_key=True)
hole = Column(String, ForeignKey("holes.name"), primary_key=True) hole: Mapped[str] = mapped_column(ForeignKey("holes.name"), primary_key=True)
created_utc = Column(Integer) created_utc: Mapped[Optional[int]]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())
@ -35,5 +40,5 @@ class Mod(HoleRelationship):
class Exile(HoleRelationship): class Exile(HoleRelationship):
__tablename__ = "exiles" __tablename__ = "exiles"
exiler_id = Column(Integer, ForeignKey("users.id")) exiler_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
exiler = relationship("User", primaryjoin="User.id==Exile.exiler_id") exiler: Mapped["User"] = relationship(primaryjoin="User.id==Exile.exiler_id")

View File

@ -1,19 +1,24 @@
import time import time
from typing import TYPE_CHECKING
from sqlalchemy import Column, ForeignKey from sqlalchemy.orm import Mapped, relationship
from sqlalchemy.orm import relationship
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.types import str_pk, user_id_fk_pk
if TYPE_CHECKING:
from files.classes import User
class IPLog(Base): class IPLog(Base):
__tablename__ = "ip_logs" __tablename__ = "ip_logs"
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) user_id: Mapped[user_id_fk_pk]
ip = Column(String, primary_key=True) ip: Mapped[str_pk]
created_utc = Column(Integer) created_utc: Mapped[int]
last_used = Column(Integer) last_used: Mapped[int]
user = relationship("User") user: Mapped["User"] = relationship()
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: if "created_utc" not in kwargs:

View File

@ -1,22 +1,24 @@
import time import time
from typing import Optional
from sqlalchemy import Column, ForeignKey from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.config.const import * from files.helpers.config.const import *
from files.helpers.lazy import lazy from files.helpers.lazy import lazy
from files.helpers.types import int_pk, user_id_fk
class Lottery(Base): class Lottery(Base):
__tablename__ = "lotteries" __tablename__ = "lotteries"
id = Column(Integer, primary_key=True) id: Mapped[int_pk]
is_active = Column(Boolean, default=False) is_active: Mapped[bool] = mapped_column(default=False)
ends_at = Column(Integer) ends_at: Mapped[int]
prize = Column(Integer, default=0) prize: Mapped[int] = mapped_column(default=0)
tickets_sold = Column(Integer, default=0) tickets_sold: Mapped[int] = mapped_column(default=0)
winner_id = Column(Integer, ForeignKey("users.id")) winner_id: Mapped[Optional[user_id_fk]]
created_utc = Column(Integer) created_utc: Mapped[Optional[int]]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,16 +1,17 @@
import time import time
from sqlalchemy import Column, ForeignKey from sqlalchemy.orm import Mapped
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.types import str_pk, user_id_fk
class Media(Base): class Media(Base):
__tablename__ = "media" __tablename__ = "media"
kind = Column(String, primary_key=True) kind: Mapped[str_pk]
filename = Column(String, primary_key=True) filename: Mapped[str_pk]
user_id = Column(Integer, ForeignKey("users.id")) user_id: Mapped[user_id_fk]
created_utc = Column(Integer) created_utc: Mapped[int]
size = Column(Integer) size: Mapped[int]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,7 +1,7 @@
import time import time
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Column, ForeignKey from sqlalchemy.orm import Mapped, relationship
from sqlalchemy.orm import relationship
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from flask import g from flask import g
@ -10,22 +10,27 @@ from files.helpers.config.const import *
from files.helpers.lazy import lazy from files.helpers.lazy import lazy
from files.helpers.slurs_and_profanities import censor_slurs_profanities from files.helpers.slurs_and_profanities import censor_slurs_profanities
from files.helpers.sorting_and_time import make_age_string from files.helpers.sorting_and_time import make_age_string
from files.helpers.types import comment_id_fk, int_pk, post_id_fk, user_id_fk
if TYPE_CHECKING:
from files.classes import Comment, Post, User
class ModAction(Base): class ModAction(Base):
__tablename__ = "modactions" __tablename__ = "modactions"
id = Column(Integer, primary_key=True) id: Mapped[int_pk]
user_id = Column(Integer, ForeignKey("users.id")) user_id: Mapped[Optional[user_id_fk]]
kind = Column(String) kind: Mapped[Optional[str]]
target_user_id = Column(Integer, ForeignKey("users.id")) target_user_id: Mapped[Optional[user_id_fk]]
target_post_id = Column(Integer, ForeignKey("posts.id")) target_post_id: Mapped[Optional[post_id_fk]]
target_comment_id = Column(Integer, ForeignKey("comments.id")) target_comment_id: Mapped[Optional[comment_id_fk]]
_note = Column(String) _note: Mapped[Optional[str]]
created_utc = Column(Integer) created_utc: Mapped[int]
user = relationship("User", primaryjoin="User.id==ModAction.user_id") user: Mapped["User"] = relationship(primaryjoin="User.id==ModAction.user_id")
target_user = relationship("User", primaryjoin="User.id==ModAction.target_user_id") target_user: Mapped["User"] = relationship(primaryjoin="User.id==ModAction.target_user_id")
target_post = relationship("Post") target_post: Mapped["Post"] = relationship()
target_comment = relationship("Comment") target_comment: Mapped["Comment"] = relationship()
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,21 +1,26 @@
import time import time
from typing import TYPE_CHECKING
from sqlalchemy import Column, ForeignKey from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.orm import relationship
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.types import comment_id_fk_pk, user_id_fk_pk
if TYPE_CHECKING:
from files.classes import Comment, User
class Notification(Base): class Notification(Base):
__tablename__ = "notifications" __tablename__ = "notifications"
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) user_id: Mapped[user_id_fk_pk]
comment_id = Column(Integer, ForeignKey("comments.id"), primary_key=True) comment_id: Mapped[comment_id_fk_pk]
read = Column(Boolean, default=False) read: Mapped[bool] = mapped_column(default=False)
created_utc = Column(Integer) created_utc: Mapped[int]
comment = relationship("Comment") comment: Mapped["Comment"] = relationship()
user = relationship("User") user: Mapped["User"] = relationship()
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,11 +1,13 @@
import time import time
from flask import g, abort from flask import g, abort
import requests import requests
from typing import Optional
from sqlalchemy import Column, or_ from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.types import int_pk
from files.helpers.lazy import lazy from files.helpers.lazy import lazy
from files.helpers.config.const import * from files.helpers.config.const import *
@ -13,13 +15,13 @@ from files.helpers.config.const import *
class Orgy(Base): class Orgy(Base):
__tablename__ = "orgies" __tablename__ = "orgies"
created_utc = Column(Integer, primary_key=True) created_utc: Mapped[int_pk]
type = Column(String) type: Mapped[str]
data = Column(String) data: Mapped[str]
title = Column(String) title: Mapped[str]
start_utc = Column(Integer) start_utc: Mapped[int]
end_utc = Column(Integer) end_utc: Mapped[Optional[int]]
started = Column(Boolean, default=False) started: Mapped[bool] = mapped_column(default=False)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,23 +1,29 @@
import time import time
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Column, ForeignKey from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.lazy import lazy from files.helpers.lazy import lazy
from files.helpers.types import comment_id_fk, int_pk, post_id_fk, user_id_fk_pk
if TYPE_CHECKING:
from files.classes import Comment, Post, User
class PostOption(Base): class PostOption(Base):
__tablename__ = "post_options" __tablename__ = "post_options"
id = Column(Integer, primary_key=True) id: Mapped[int_pk]
parent_id = Column(Integer, ForeignKey("posts.id")) parent_id: Mapped[post_id_fk]
body_html = Column(Text) body_html: Mapped[str] = mapped_column(Text)
exclusive = Column(Integer) exclusive: Mapped[int]
created_utc = Column(Integer) created_utc: Mapped[Optional[int]]
votes = relationship("PostOptionVote") votes: Mapped[list["PostOptionVote"]] = relationship()
parent = relationship("Post", back_populates="options") parent: Mapped["Post"] = relationship(back_populates="options")
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())
@ -40,12 +46,12 @@ class PostOptionVote(Base):
__tablename__ = "post_option_votes" __tablename__ = "post_option_votes"
option_id = Column(Integer, ForeignKey("post_options.id"), primary_key=True) option_id: Mapped[int] = mapped_column(ForeignKey("post_options.id"), primary_key=True)
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) user_id: Mapped[user_id_fk_pk]
created_utc = Column(Integer) created_utc: Mapped[int]
post_id = Column(Integer, ForeignKey("posts.id")) post_id: Mapped[Optional[post_id_fk]]
user = relationship("User") user: Mapped["User"] = relationship()
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())
@ -59,14 +65,14 @@ class CommentOption(Base):
__tablename__ = "comment_options" __tablename__ = "comment_options"
id = Column(Integer, primary_key=True) id: Mapped[int_pk]
parent_id = Column(Integer, ForeignKey("comments.id")) parent_id: Mapped[comment_id_fk]
body_html = Column(Text) body_html: Mapped[str] = mapped_column(Text)
exclusive = Column(Integer) exclusive: Mapped[int]
created_utc = Column(Integer) created_utc: Mapped[Optional[int]]
votes = relationship("CommentOptionVote") votes: Mapped[list["CommentOptionVote"]] = relationship()
parent = relationship("Comment", back_populates="options") parent: Mapped["Comment"] = relationship(back_populates="options")
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())
@ -89,12 +95,12 @@ class CommentOptionVote(Base):
__tablename__ = "comment_option_votes" __tablename__ = "comment_option_votes"
option_id = Column(Integer, ForeignKey("comment_options.id"), primary_key=True) option_id: Mapped[int] = mapped_column(ForeignKey("comment_options.id"), primary_key=True)
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) user_id: Mapped[user_id_fk_pk]
created_utc = Column(Integer) created_utc: Mapped[int]
comment_id = Column(Integer, ForeignKey("comments.id")) comment_id: Mapped[Optional[comment_id_fk]]
user = relationship("User") user: Mapped["User"] = relationship()
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,10 +1,11 @@
import random import random
import time import time
from typing import Optional, TYPE_CHECKING
from urllib.parse import urlparse from urllib.parse import urlparse
from flask import g from flask import g
from sqlalchemy import Column, FetchedValue, ForeignKey from sqlalchemy import ForeignKey
from sqlalchemy.orm import deferred, relationship from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
@ -14,6 +15,7 @@ from files.helpers.slurs_and_profanities import *
from files.helpers.lazy import lazy from files.helpers.lazy import lazy
from files.helpers.regex import * from files.helpers.regex import *
from files.helpers.sorting_and_time import make_age_string from files.helpers.sorting_and_time import make_age_string
from files.helpers.types import int_pk, user_id_fk
from files.helpers.bleach_body import * from files.helpers.bleach_body import *
from .comment import * from .comment import *
@ -22,69 +24,73 @@ from .hole import *
from .subscriptions import * from .subscriptions import *
from .saves import SaveRelationship from .saves import SaveRelationship
if TYPE_CHECKING:
from files.classes import OauthApp, Report
class Post(Base): class Post(Base):
__tablename__ = "posts" __tablename__ = "posts"
id = Column(Integer, primary_key=True) id: Mapped[int_pk]
author_id = Column(Integer, ForeignKey("users.id")) author_id: Mapped[user_id_fk]
edited_utc = Column(Integer, default=0) edited_utc: Mapped[int] = mapped_column(default=0)
created_utc = Column(Integer) created_utc: Mapped[int]
thumburl = Column(String) thumburl: Mapped[Optional[str]]
posterurl = Column(String) posterurl: Mapped[Optional[str]]
is_banned = Column(Boolean, default=False) is_banned: Mapped[bool] = mapped_column(default=False)
bannedfor = Column(String) bannedfor: Mapped[Optional[str]]
chuddedfor = Column(String) chuddedfor: Mapped[Optional[str]]
ghost = Column(Boolean, default=False) ghost: Mapped[bool] = mapped_column(default=False)
effortpost = Column(Boolean, default=False) effortpost: Mapped[bool] = mapped_column(default=False)
views = Column(Integer, default=0) views: Mapped[int] = mapped_column(default=0)
deleted_utc = Column(Integer, default=0) deleted_utc: Mapped[int] = mapped_column(default=0)
distinguished = Column(Boolean, default=False) distinguished: Mapped[bool] = mapped_column(default=False)
stickied = Column(String) stickied: Mapped[Optional[str]]
stickied_utc = Column(Integer) stickied_utc: Mapped[Optional[int]]
hole_pinned = Column(String) hole_pinned: Mapped[Optional[str]]
hole = Column(String, ForeignKey("holes.name")) hole: Mapped[Optional[str]] = mapped_column(ForeignKey("holes.name"))
is_pinned = Column(Boolean, default=False) is_pinned: Mapped[bool] = mapped_column(default=False)
private = Column(Boolean, default=False) private: Mapped[bool] = mapped_column(default=False)
comment_count = Column(Integer, default=0) comment_count: Mapped[int] = mapped_column(default=0)
is_approved = Column(Integer, ForeignKey("users.id")) is_approved: Mapped[Optional[user_id_fk]]
is_bot = Column(Boolean, default=False) is_bot: Mapped[bool] = mapped_column(default=False)
upvotes = Column(Integer, default=1) upvotes: Mapped[int] = mapped_column(default=1)
downvotes = Column(Integer, default=0) downvotes: Mapped[int] = mapped_column(default=0)
realupvotes = Column(Integer, default=1) realupvotes: Mapped[Optional[int]] = mapped_column(default=1)
app_id = Column(Integer, ForeignKey("oauth_apps.id")) app_id: Mapped[Optional[int]] = mapped_column(ForeignKey("oauth_apps.id"))
title = Column(String) title: Mapped[str]
title_html = Column(String) title_html: Mapped[str]
url = Column(String) url: Mapped[Optional[str]]
body = Column(String) body: Mapped[Optional[str]]
body_html = Column(String) body_html: Mapped[Optional[str]]
flair = Column(String) flair: Mapped[Optional[str]]
ban_reason = Column(String) ban_reason: Mapped[Optional[str]]
embed = Column(String) embed: Mapped[Optional[str]]
new = Column(Boolean) new: Mapped[Optional[bool]]
notify = Column(Boolean) notify: Mapped[bool]
chudded = Column(Boolean, default=False) chudded: Mapped[bool] = mapped_column(default=False)
rainbowed = Column(Boolean, default=False) rainbowed: Mapped[bool] = mapped_column(default=False)
queened = Column(Boolean, default=False) queened: Mapped[bool] = mapped_column(default=False)
sharpened = Column(Boolean, default=False) sharpened: Mapped[bool] = mapped_column(default=False)
ping_cost = Column(Integer, default=0) ping_cost: Mapped[int] = mapped_column(default=0)
bump_utc = Column(Integer) bump_utc: Mapped[int]
if FEATURES['NSFW_MARKING']: if FEATURES['NSFW_MARKING']:
nsfw = Column(Boolean, default=False) nsfw: Mapped[bool] = mapped_column(default=False)
else: else:
nsfw = False nsfw = False
if SITE_NAME == 'WPD': if SITE_NAME == 'WPD':
cw = Column(Boolean, default=False) cw: Mapped[bool] = mapped_column(default=False)
author = relationship("User", primaryjoin="Post.author_id==User.id") author: Mapped["User"] = relationship(primaryjoin="Post.author_id==User.id")
oauth_app = relationship("OauthApp") oauth_app: Mapped["OauthApp"] = relationship()
approved_by = relationship("User", uselist=False, primaryjoin="Post.is_approved==User.id") approved_by: Mapped["User"] = relationship(uselist=False, primaryjoin="Post.is_approved==User.id")
awards = relationship("AwardRelationship", order_by="AwardRelationship.awarded_utc.desc()", back_populates="post") awards: Mapped[list["AwardRelationship"]] = relationship(order_by="AwardRelationship.awarded_utc.desc()", back_populates="post")
reports = relationship("Report", order_by="Report.created_utc") reports: Mapped[list["Report"]] = relationship(order_by="Report.created_utc")
comments = relationship("Comment", primaryjoin="Comment.parent_post==Post.id", back_populates="post") comments: Mapped[list["Comment"]] = relationship(primaryjoin="Comment.parent_post==Post.id", back_populates="post")
hole_obj = relationship("Hole", primaryjoin="foreign(Post.hole)==remote(Hole.name)") hole_obj: Mapped["Hole"] = relationship(primaryjoin="foreign(Post.hole)==remote(Hole.name)")
options = relationship("PostOption", order_by="PostOption.id") options: Mapped[list["PostOption"]] = relationship(order_by="PostOption.id")
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: if "created_utc" not in kwargs:

View File

@ -1,15 +1,16 @@
import time import time
from sqlalchemy import Column, ForeignKey from sqlalchemy.orm import Mapped
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.types import str_pk, user_id_fk_pk
class PushSubscription(Base): class PushSubscription(Base):
__tablename__ = "push_subscriptions" __tablename__ = "push_subscriptions"
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) user_id: Mapped[user_id_fk_pk]
subscription_json = Column(String, primary_key=True) subscription_json: Mapped[str_pk]
created_utc = Column(Integer) created_utc: Mapped[int]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,22 +1,27 @@
import time import time
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Column, ForeignKey from sqlalchemy.orm import Mapped, relationship
from sqlalchemy.orm import relationship
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.lazy import lazy from files.helpers.lazy import lazy
from files.helpers.slurs_and_profanities import censor_slurs_profanities from files.helpers.slurs_and_profanities import censor_slurs_profanities
from files.helpers.types import comment_id_fk_pk, post_id_fk_pk, user_id_fk_pk
if TYPE_CHECKING:
from files.classes import User
class Report(Base): class Report(Base):
__tablename__ = "reports" __tablename__ = "reports"
post_id = Column(Integer, ForeignKey("posts.id"), primary_key=True) post_id: Mapped[post_id_fk_pk]
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) user_id: Mapped[user_id_fk_pk]
reason = Column(String) reason: Mapped[Optional[str]]
created_utc = Column(Integer) created_utc: Mapped[int]
user = relationship("User", primaryjoin = "Report.user_id == User.id", uselist = False) user: Mapped["User"] = relationship(primaryjoin = "Report.user_id == User.id", uselist = False)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())
@ -39,12 +44,12 @@ class Report(Base):
class CommentReport(Base): class CommentReport(Base):
__tablename__ = "commentreports" __tablename__ = "commentreports"
comment_id = Column(Integer, ForeignKey("comments.id"), primary_key=True) comment_id: Mapped[comment_id_fk_pk]
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) user_id: Mapped[user_id_fk_pk]
reason = Column(String) reason: Mapped[Optional[str]]
created_utc = Column(Integer) created_utc: Mapped[int]
user = relationship("User", primaryjoin = "CommentReport.user_id == User.id", uselist = False) user: Mapped["User"] = relationship(primaryjoin = "CommentReport.user_id == User.id", uselist = False)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,19 +1,25 @@
import time import time
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Column, ForeignKey from sqlalchemy.orm import Mapped, relationship
from sqlalchemy.orm import relationship
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.types import comment_id_fk_pk, post_id_fk_pk, user_id_fk_pk
if TYPE_CHECKING:
from files.classes.comment import Comment
from files.classes.post import Post
class SaveRelationship(Base): class SaveRelationship(Base):
__tablename__ = "save_relationship" __tablename__ = "save_relationship"
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) user_id: Mapped[user_id_fk_pk]
post_id = Column(Integer, ForeignKey("posts.id"), primary_key=True) post_id: Mapped[post_id_fk_pk]
created_utc = Column(Integer) created_utc: Mapped[Optional[int]]
post = relationship("Post", uselist=False) post: Mapped["Post"] = relationship(uselist=False)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())
@ -27,11 +33,11 @@ class CommentSaveRelationship(Base):
__tablename__ = "comment_save_relationship" __tablename__ = "comment_save_relationship"
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) user_id: Mapped[user_id_fk_pk]
comment_id = Column(Integer, ForeignKey("comments.id"), primary_key=True) comment_id: Mapped[comment_id_fk_pk]
created_utc = Column(Integer) created_utc: Mapped[Optional[int]]
comment = relationship("Comment", uselist=False) comment: Mapped["Comment"] = relationship(uselist=False)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,19 +1,24 @@
import time import time
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Column, ForeignKey from sqlalchemy.orm import Mapped, relationship
from sqlalchemy.orm import relationship
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.types import post_id_fk_pk, user_id_fk_pk
if TYPE_CHECKING:
from files.classes import Post, User
class Subscription(Base): class Subscription(Base):
__tablename__ = "subscriptions" __tablename__ = "subscriptions"
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) user_id: Mapped[user_id_fk_pk]
post_id = Column(Integer, ForeignKey("posts.id"), primary_key=True) post_id: Mapped[post_id_fk_pk]
created_utc = Column(Integer) created_utc: Mapped[Optional[int]]
user = relationship("User", uselist=False) user: Mapped["User"] = relationship(uselist=False)
post = relationship("Post", uselist=False) post: Mapped["Post"] = relationship(uselist=False)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,16 +1,19 @@
from sqlalchemy import Column from typing import Optional
from sqlalchemy.orm import Mapped
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.types import str_pk
class Transaction(Base): class Transaction(Base):
__tablename__ = "transactions" __tablename__ = "transactions"
id = Column(String, primary_key=True) id: Mapped[str_pk]
created_utc = Column(Integer) created_utc: Mapped[int]
type = Column(String) type: Mapped[str]
amount = Column(Integer) amount: Mapped[int]
email = Column(String) email: Mapped[str]
claimed = Column(Boolean) claimed: Mapped[Optional[bool]]
def __repr__(self): def __repr__(self):
return f"<{self.__class__.__name__}(id={self.id})>" return f"<{self.__class__.__name__}(id={self.id})>"

View File

@ -1,9 +1,9 @@
import random import random
from operator import * from operator import *
from typing import Optional
import pyotp import pyotp
from sqlalchemy import Column, ForeignKey, FetchedValue from sqlalchemy.orm import DynamicMapped, Mapped, aliased, mapped_column
from sqlalchemy.orm import aliased, deferred, Query
from sqlalchemy.sql import case, func, literal from sqlalchemy.sql import case, func, literal
from sqlalchemy.sql.expression import not_, and_, or_ from sqlalchemy.sql.expression import not_, and_, or_
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
@ -20,6 +20,7 @@ from files.helpers.config.awards import AWARDS_ENABLED, HOUSE_AWARDS
from files.helpers.media import * from files.helpers.media import *
from files.helpers.security import * from files.helpers.security import *
from files.helpers.sorting_and_time import * from files.helpers.sorting_and_time import *
from files.helpers.types import int_pk, user_id_fk
from files.helpers.can_see import * from files.helpers.can_see import *
from .alts import Alt from .alts import Alt
@ -49,106 +50,106 @@ else:
class User(Base): class User(Base):
__tablename__ = "users" __tablename__ = "users"
id = Column(Integer, primary_key=True) id: Mapped[int_pk]
username = Column(String) username: Mapped[str]
namecolor = Column(String, default=DEFAULT_COLOR) namecolor: Mapped[str] = mapped_column(default=DEFAULT_COLOR)
background = Column(String) background: Mapped[Optional[str]]
profile_background = Column(String) profile_background: Mapped[Optional[str]]
flair = deferred(Column(String)) flair: Mapped[Optional[str]] = mapped_column(deferred=True)
flair_html = Column(String) flair_html: Mapped[Optional[str]]
flaircolor = Column(String, default=DEFAULT_COLOR) flaircolor: Mapped[str] = mapped_column(default=DEFAULT_COLOR)
theme = Column(String, default=DEFAULT_THEME) theme: Mapped[str] = mapped_column(default=DEFAULT_THEME)
themecolor = Column(String, default=DEFAULT_COLOR) themecolor: Mapped[str] = mapped_column(default=DEFAULT_COLOR)
song = Column(String) song: Mapped[Optional[str]]
highres = Column(String) highres: Mapped[Optional[str]]
profileurl = Column(String) profileurl: Mapped[Optional[str]]
bannerurl = Column(String) bannerurl: Mapped[Optional[str]]
house = Column(String, default='') house: Mapped[Optional[str]] = mapped_column(default='')
old_house = Column(String, default='') old_house: Mapped[Optional[str]] = mapped_column(default='')
patron = Column(Integer, default=0) patron: Mapped[int] = mapped_column(default=0)
patron_utc = Column(Integer, default=0) patron_utc: Mapped[int] = mapped_column(default=0)
verified = Column(String) verified: Mapped[Optional[str]]
verifiedcolor = Column(String) verifiedcolor: Mapped[Optional[str]]
hieroglyphs = Column(Integer, default=0) hieroglyphs: Mapped[Optional[int]] = mapped_column(default=0)
rehab = Column(Integer, default=0) rehab: Mapped[Optional[int]] = mapped_column(default=0)
longpost = Column(Integer, default=0) longpost: Mapped[Optional[int]] = mapped_column(default=0)
bird = Column(Integer, default=0) bird: Mapped[Optional[int]] = mapped_column(default=0)
email = deferred(Column(String)) email: Mapped[Optional[str]] = mapped_column(deferred=True)
css = Column(String) css: Mapped[Optional[str]]
profilecss = deferred(Column(String)) profilecss: Mapped[Optional[str]] = mapped_column(deferred=True)
passhash = deferred(Column(String)) passhash: Mapped[str] = mapped_column(deferred=True)
post_count = Column(Integer, default=0) post_count: Mapped[int] = mapped_column(default=0)
comment_count = Column(Integer, default=0) comment_count: Mapped[int] = mapped_column(default=0)
received_award_count = Column(Integer, default=0) received_award_count: Mapped[int] = mapped_column(default=0)
created_utc = Column(Integer) created_utc: Mapped[int]
admin_level = Column(Integer, default=DEFAULT_ADMIN_LEVEL) admin_level: Mapped[int] = mapped_column(default=DEFAULT_ADMIN_LEVEL)
last_active = Column(Integer) last_active: Mapped[int]
coins_spent = Column(Integer, default=0) coins_spent: Mapped[int] = mapped_column(default=0)
coins_spent_on_hats = Column(Integer, default=0) coins_spent_on_hats: Mapped[int] = mapped_column(default=0)
lootboxes_bought = Column(Integer, default=0) lootboxes_bought: Mapped[int] = mapped_column(default=0)
chud = Column(Integer, default=0) chud: Mapped[int] = mapped_column(default=0)
queen = Column(Integer, default=0) queen: Mapped[Optional[int]] = mapped_column(default=0)
chud_phrase = Column(String) chud_phrase: Mapped[Optional[str]]
email_verified = Column(Boolean, default=False) email_verified: Mapped[bool] = mapped_column(default=False)
shadowbanned = Column(Integer, ForeignKey("users.id")) shadowbanned: Mapped[Optional[user_id_fk]]
chudded_by = Column(Integer, ForeignKey("users.id")) chudded_by: Mapped[Optional[user_id_fk]]
slurreplacer = Column(Integer, default=1) slurreplacer: Mapped[int] = mapped_column(default=1)
profanityreplacer = Column(Integer, default=1) profanityreplacer: Mapped[int] = mapped_column(default=1)
flairchanged = Column(Integer, default=0) flairchanged: Mapped[Optional[int]] = mapped_column(default=0)
namechanged = Column(Integer, default=0) namechanged: Mapped[Optional[int]] = mapped_column(default=0)
newtab = Column(Boolean, default=False) newtab: Mapped[bool] = mapped_column(default=False)
newtabexternal = Column(Boolean, default=True) newtabexternal: Mapped[bool] = mapped_column(default=True)
frontsize = Column(Integer, default=25) frontsize: Mapped[int] = mapped_column(default=25)
bio = deferred(Column(String)) bio: Mapped[Optional[str]] = mapped_column(deferred=True)
bio_html = Column(String) bio_html: Mapped[Optional[str]]
sig = deferred(Column(String)) sig: Mapped[Optional[str]] = mapped_column(deferred=True)
sig_html = Column(String) sig_html: Mapped[Optional[str]]
show_sigs = Column(Boolean, default=True) show_sigs: Mapped[bool] = mapped_column(default=True)
progressivestack = Column(Integer, default=0) progressivestack: Mapped[Optional[int]] = mapped_column(default=0)
deflector = Column(Integer, default=0) deflector: Mapped[Optional[int]] = mapped_column(default=0)
friends = deferred(Column(String)) friends: Mapped[Optional[str]] = mapped_column(deferred=True)
friends_html = deferred(Column(String)) friends_html: Mapped[Optional[str]] = mapped_column(deferred=True)
enemies = deferred(Column(String)) enemies: Mapped[Optional[str]] = mapped_column(deferred=True)
enemies_html = deferred(Column(String)) enemies_html: Mapped[Optional[str]] = mapped_column(deferred=True)
is_banned = Column(Integer, ForeignKey("users.id")) is_banned: Mapped[Optional[user_id_fk]]
unban_utc = Column(Integer) unban_utc: Mapped[Optional[int]]
ban_reason = deferred(Column(String)) ban_reason: Mapped[Optional[str]] = mapped_column(deferred=True)
shadowban_reason = deferred(Column(String)) shadowban_reason: Mapped[Optional[str]] = mapped_column(deferred=True)
is_muted = Column(Boolean, default=False) is_muted: Mapped[bool] = mapped_column(default=False)
login_nonce = Column(Integer, default=0) login_nonce: Mapped[int] = mapped_column(default=0)
coins = Column(Integer, default=DEFAULT_COINS) coins: Mapped[int] = mapped_column(default=DEFAULT_COINS)
truescore = Column(Integer, default=0) truescore: Mapped[int] = mapped_column(default=0)
marseybux = Column(Integer, default=DEFAULT_MARSEYBUX) marseybux: Mapped[int] = mapped_column(default=DEFAULT_MARSEYBUX)
mfa_secret = deferred(Column(String)) mfa_secret: Mapped[Optional[str]] = mapped_column(deferred=True)
is_private = Column(Boolean, default=False) is_private: Mapped[bool] = mapped_column(default=False)
stored_subscriber_count = Column(Integer, default=0) stored_subscriber_count: Mapped[int] = mapped_column(default=0)
defaultsortingcomments = Column(String, default="hot") defaultsortingcomments: Mapped[str] = mapped_column(default="hot")
defaultsorting = Column(String, default="hot") defaultsorting: Mapped[str] = mapped_column(default="hot")
defaulttime = Column(String, default=DEFAULT_TIME_FILTER) defaulttime: Mapped[str] = mapped_column(default=DEFAULT_TIME_FILTER)
custom_filter_list = Column(String) custom_filter_list: Mapped[Optional[str]]
original_username = Column(String) original_username: Mapped[Optional[str]]
extra_username = Column(String) extra_username: Mapped[Optional[str]]
prelock_username = Column(String) prelock_username: Mapped[Optional[str]]
referred_by = Column(Integer, ForeignKey("users.id")) referred_by: Mapped[Optional[user_id_fk]]
currently_held_lottery_tickets = Column(Integer, default=0) currently_held_lottery_tickets: Mapped[int] = mapped_column(default=0)
total_held_lottery_tickets = Column(Integer, default=0) total_held_lottery_tickets: Mapped[int] = mapped_column(default=0)
total_lottery_winnings = Column(Integer, default=0) total_lottery_winnings: Mapped[int] = mapped_column(default=0)
last_viewed_modmail_notifs = Column(Integer, default=0) last_viewed_modmail_notifs: Mapped[int] = mapped_column(default=0)
last_viewed_post_notifs = Column(Integer, default=0) last_viewed_post_notifs: Mapped[int] = mapped_column(default=0)
last_viewed_log_notifs = Column(Integer, default=0) last_viewed_log_notifs: Mapped[int] = mapped_column(default=0)
last_viewed_offsite_notifs = Column(Integer, default=0) last_viewed_offsite_notifs: Mapped[int] = mapped_column(default=0)
bite = Column(Integer, default=0) bite: Mapped[Optional[int]] = mapped_column(default=0)
owoify = Column(Integer, default=0) owoify: Mapped[Optional[int]] = mapped_column(default=0)
sharpen = Column(Integer, default=0) sharpen: Mapped[Optional[int]] = mapped_column(default=0)
marsify = Column(Integer, default=0) marsify: Mapped[Optional[int]] = mapped_column(default=0)
rainbow = Column(Integer, default=0) rainbow: Mapped[Optional[int]] = mapped_column(default=0)
spider = Column(Integer, default=0) spider: Mapped[Optional[int]] = mapped_column(default=0)
lifetimedonated = Column(Integer, default=0) lifetimedonated: Mapped[int] = mapped_column(default=0)
lifetimedonated_visible = Column(Boolean, default=False) lifetimedonated_visible: Mapped[bool] = mapped_column(default=False)
blacklisted_by = Column(Integer, ForeignKey("users.id")) blacklisted_by: Mapped[Optional[user_id_fk]]
grinch = Column(Boolean, default=SITE_NAME != 'rDrama') #don't put in an if condition, it will cause an error bc it has a not-null constraint grinch: Mapped[bool] = mapped_column(default=SITE_NAME != 'rDrama') #don't put in an if condition, it will cause an error bc it has a not-null constraint
group_creation_notifs = Column(Boolean, default=False) group_creation_notifs: Mapped[bool] = mapped_column(default=False)
effortpost_notifs = Column(Boolean, default=False) effortpost_notifs: Mapped[bool] = mapped_column(default=False)
if SITE_NAME == 'WPD': if SITE_NAME == 'WPD':
nitter = False nitter = False
@ -158,37 +159,37 @@ class User(Base):
pronouns = 'they/them' pronouns = 'they/them'
earlylife = 0 earlylife = 0
hole_creation_notifs = False hole_creation_notifs = False
hidevotedon = Column(Boolean, default=False) hidevotedon: Mapped[bool] = mapped_column(default=False)
hide_cw = Column(Boolean, default=False) hide_cw: Mapped[bool] = mapped_column(default=False)
else: else:
nitter = Column(Boolean, default=False) nitter: Mapped[bool] = mapped_column(default=False)
imgsed = Column(Boolean, default=False) imgsed: Mapped[bool] = mapped_column(default=False)
controversial = Column(Boolean, default=False) controversial: Mapped[bool] = mapped_column(default=False)
reddit = Column(String, default='old.reddit.com') reddit: Mapped[str] = mapped_column(default='old.reddit.com')
pronouns = Column(String, default='they/them') pronouns: Mapped[str] = mapped_column(default='they/them')
earlylife = Column(Integer, default=0) earlylife: Mapped[Optional[int]] = mapped_column(default=0)
hole_creation_notifs = Column(Boolean, default=True) hole_creation_notifs: Mapped[bool] = mapped_column(default=True)
hidevotedon = False hidevotedon = False
hide_cw = False hide_cw = False
if IS_HOMOWEEN(): if IS_HOMOWEEN():
zombie = Column(Integer, default=0) # > 0 vaxxed; < 0 zombie zombie: Mapped[int] = mapped_column(default=0) # > 0 vaxxed; < 0 zombie
jumpscare = Column(Integer, default=0) jumpscare: Mapped[int] = mapped_column(default=0)
badges = relationship("Badge", order_by="Badge.created_utc", back_populates="user") badges: Mapped[list["Badge"]] = relationship(order_by="Badge.created_utc", back_populates="user")
subscriptions = relationship("Subscription", back_populates="user") subscriptions: Mapped[list["Subscription"]] = relationship(back_populates="user")
following = relationship("Follow", primaryjoin="Follow.user_id==User.id", back_populates="user") following: Mapped[list["Follow"]] = relationship(primaryjoin="Follow.user_id==User.id", back_populates="user")
followers = relationship("Follow", primaryjoin="Follow.target_id==User.id", back_populates="target") followers: Mapped[list["Follow"]] = relationship(primaryjoin="Follow.target_id==User.id", back_populates="target")
blocking = relationship("UserBlock", lazy="dynamic", primaryjoin="User.id==UserBlock.user_id", back_populates="user") blocking: DynamicMapped["UserBlock"] = relationship(primaryjoin="User.id==UserBlock.user_id", back_populates="user")
blocked = relationship("UserBlock", lazy="dynamic", primaryjoin="User.id==UserBlock.target_id", back_populates="target") blocked: DynamicMapped["UserBlock"] = relationship(primaryjoin="User.id==UserBlock.target_id", back_populates="target")
authorizations = relationship("ClientAuth", back_populates="user") authorizations: Mapped[list["ClientAuth"]] = relationship(back_populates="user")
apps = relationship("OauthApp", back_populates="author") apps: Mapped[list["OauthApp"]] = relationship(back_populates="author")
awards = relationship("AwardRelationship", primaryjoin="User.id==AwardRelationship.user_id", back_populates="user") awards: Mapped[list["AwardRelationship"]] = relationship(primaryjoin="User.id==AwardRelationship.user_id", back_populates="user")
referrals = relationship("User", primaryjoin="User.id==User.referred_by", order_by="User.created_utc") referrals: Mapped[list["User"]] = relationship(primaryjoin="User.id==User.referred_by", order_by="User.created_utc")
designed_hats = relationship("HatDef", primaryjoin="User.id==HatDef.author_id", back_populates="author") designed_hats: Mapped[list["HatDef"]] = relationship(primaryjoin="User.id==HatDef.author_id", back_populates="author")
owned_hats = relationship("Hat", back_populates="owners") owned_hats: Mapped[list["Hat"]] = relationship(back_populates="owners")
hats_equipped = relationship("Hat", lazy="raise", viewonly=True) hats_equipped: Mapped[list["Hat"]] = relationship(lazy="raise", viewonly=True)
hole_mods = relationship("Mod", primaryjoin="User.id == Mod.user_id", lazy="raise") hole_mods: Mapped[list["Mod"]] = relationship(primaryjoin="User.id == Mod.user_id", lazy="raise")
def __init__(self, **kwargs): def __init__(self, **kwargs):

View File

@ -1,19 +1,24 @@
import time import time
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Column, ForeignKey from sqlalchemy.orm import Mapped, relationship
from sqlalchemy.orm import relationship
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.types import user_id_fk_pk
if TYPE_CHECKING:
from files.classes import User
class UserBlock(Base): class UserBlock(Base):
__tablename__ = "userblocks" __tablename__ = "userblocks"
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) user_id: Mapped[user_id_fk_pk]
target_id = Column(Integer, ForeignKey("users.id"), primary_key=True) target_id: Mapped[user_id_fk_pk]
created_utc = Column(Integer) created_utc: Mapped[Optional[int]]
user = relationship("User", primaryjoin="User.id==UserBlock.user_id", back_populates="blocking") user: Mapped["User"] = relationship(primaryjoin="User.id==UserBlock.user_id", back_populates="blocking")
target = relationship("User", primaryjoin="User.id==UserBlock.target_id", back_populates="blocked") target: Mapped["User"] = relationship(primaryjoin="User.id==UserBlock.target_id", back_populates="blocked")
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,19 +1,24 @@
import time import time
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Column, ForeignKey from sqlalchemy.orm import Mapped, relationship
from sqlalchemy.orm import relationship
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.types import user_id_fk_pk
if TYPE_CHECKING:
from files.classes import User
class UserMute(Base): class UserMute(Base):
__tablename__ = "usermutes" __tablename__ = "usermutes"
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) user_id: Mapped[user_id_fk_pk]
target_id = Column(Integer, ForeignKey("users.id"), primary_key=True) target_id: Mapped[user_id_fk_pk]
created_utc = Column(Integer) created_utc: Mapped[Optional[int]]
user = relationship("User", primaryjoin="User.id==UserMute.user_id") user: Mapped["User"] = relationship(primaryjoin="User.id==UserMute.user_id")
target = relationship("User", primaryjoin="User.id==UserMute.target_id") target: Mapped["User"] = relationship(primaryjoin="User.id==UserMute.target_id")
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,22 +1,27 @@
import time import time
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Column, ForeignKey from sqlalchemy.orm import Mapped, relationship
from sqlalchemy.orm import relationship
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.lazy import * from files.helpers.lazy import *
from files.helpers.sorting_and_time import make_age_string from files.helpers.sorting_and_time import make_age_string
from files.helpers.types import user_id_fk_pk
if TYPE_CHECKING:
from files.classes import User
class ViewerRelationship(Base): class ViewerRelationship(Base):
__tablename__ = "viewers" __tablename__ = "viewers"
user_id = Column(Integer, ForeignKey('users.id'), primary_key=True) user_id: Mapped[user_id_fk_pk]
viewer_id = Column(Integer, ForeignKey('users.id'), primary_key=True) viewer_id: Mapped[user_id_fk_pk]
last_view_utc = Column(Integer) last_view_utc: Mapped[int]
created_utc = Column(Integer) created_utc: Mapped[Optional[int]]
viewer = relationship("User", primaryjoin="ViewerRelationship.viewer_id == User.id") viewer: Mapped["User"] = relationship(primaryjoin="ViewerRelationship.viewer_id == User.id")
def __init__(self, **kwargs): def __init__(self, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -1,23 +1,28 @@
import time import time
from typing import TYPE_CHECKING
from sqlalchemy import Column, ForeignKey from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.orm import relationship
from sqlalchemy.sql.sqltypes import * from sqlalchemy.sql.sqltypes import *
from files.classes import Base from files.classes import Base
from files.helpers.lazy import lazy from files.helpers.lazy import lazy
from files.helpers.types import comment_id_fk_pk, post_id_fk_pk, user_id_fk_pk
if TYPE_CHECKING:
from files.classes import User
class Vote(Base): class Vote(Base):
__tablename__ = "votes" __tablename__ = "votes"
post_id = Column(Integer, ForeignKey("posts.id"), primary_key=True) post_id: Mapped[post_id_fk_pk]
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) user_id: Mapped[user_id_fk_pk]
vote_type = Column(Integer) vote_type: Mapped[int]
real = Column(Boolean, default=True) real: Mapped[bool] = mapped_column(default=True)
coins = Column(Integer, default=1) coins: Mapped[int] = mapped_column(default=1)
created_utc = Column(Integer) created_utc: Mapped[int]
user = relationship("User") user: Mapped["User"] = relationship()
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())
@ -40,14 +45,14 @@ class CommentVote(Base):
__tablename__ = "commentvotes" __tablename__ = "commentvotes"
comment_id = Column(Integer, ForeignKey("comments.id"), primary_key=True) comment_id: Mapped[comment_id_fk_pk]
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) user_id: Mapped[user_id_fk_pk]
vote_type = Column(Integer) vote_type: Mapped[int]
real = Column(Boolean, default=True) real: Mapped[bool] = mapped_column(default=True)
coins = Column(Integer, default=1) coins: Mapped[int] = mapped_column(default=1)
created_utc = Column(Integer) created_utc: Mapped[int]
user = relationship("User") user: Mapped["User"] = relationship()
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

@ -0,0 +1,14 @@
from typing import Annotated
from sqlalchemy.sql.schema import ForeignKey
from sqlalchemy.orm import mapped_column
int_pk = Annotated[int, mapped_column(primary_key=True)]
str_pk = Annotated[str, mapped_column(primary_key=True)]
user_id_fk = Annotated[int, mapped_column(ForeignKey("users.id"))]
user_id_fk_pk = Annotated[int, mapped_column(ForeignKey("users.id"), primary_key=True)]
post_id_fk = Annotated[int, mapped_column(ForeignKey("posts.id"))]
post_id_fk_pk = Annotated[int, mapped_column(ForeignKey("posts.id"), primary_key=True)]
comment_id_fk = Annotated[int, mapped_column(ForeignKey("comments.id"))]
comment_id_fk_pk = Annotated[int, mapped_column(ForeignKey("comments.id"), primary_key=True)]

View File

@ -0,0 +1,65 @@
from files.classes.user import User
from flask.ctx import _AppCtxGlobals
from sqlalchemy.orm import Session
from sqlalchemy.schema import Column
import typing as t
# According to PEP 484, "all objects imported into a stub using `from ... import *` are considered
# exported", but this didn't work with Pyright for some reason, so everything has to be exported
# manually. The alternative is to put `def __getattr__(name: str) -> t.Any: ...` here instead, but
# then any symbol not in this file will be treated as Any, which prevents it from being checked.
from flask import json as json
from flask.app import Flask as Flask
from flask.blueprints import Blueprint as Blueprint
from flask.config import Config as Config
from flask.ctx import after_this_request as after_this_request
from flask.ctx import copy_current_request_context as copy_current_request_context
from flask.ctx import has_app_context as has_app_context
from flask.ctx import has_request_context as has_request_context
from flask.globals import current_app as current_app
from flask.globals import request as request
from flask.globals import session as session
from flask.helpers import abort as abort
from flask.helpers import flash as flash
from flask.helpers import get_flashed_messages as get_flashed_messages
from flask.helpers import get_template_attribute as get_template_attribute
from flask.helpers import make_response as make_response
from flask.helpers import redirect as redirect
from flask.helpers import send_file as send_file
from flask.helpers import send_from_directory as send_from_directory
from flask.helpers import stream_with_context as stream_with_context
from flask.helpers import url_for as url_for
from flask.json import jsonify as jsonify
from flask.signals import appcontext_popped as appcontext_popped
from flask.signals import appcontext_pushed as appcontext_pushed
from flask.signals import appcontext_tearing_down as appcontext_tearing_down
from flask.signals import before_render_template as before_render_template
from flask.signals import got_request_exception as got_request_exception
from flask.signals import message_flashed as message_flashed
from flask.signals import request_finished as request_finished
from flask.signals import request_started as request_started
from flask.signals import request_tearing_down as request_tearing_down
from flask.signals import template_rendered as template_rendered
from flask.templating import render_template as render_template
from flask.templating import render_template_string as render_template_string
from flask.templating import stream_template as stream_template
from flask.templating import stream_template_string as stream_template_string
from flask.wrappers import Request as Request
from flask.wrappers import Response as Response
class Globals(_AppCtxGlobals):
agent: str
browser: t.Literal["webview", "firefox", "iphone", "mac", "chromium"]
db: Session
desires_auth: bool
is_api_or_xhr: bool
is_tor: bool
loggedin_chat: int
loggedin_counter: int
loggedout_counter: int
nonce: str
show_nsfw: bool
username: Column[str]
v: User | None
g: Globals