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...
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
pass
# then load all of our classes :)
from .alts import *

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,19 +1,24 @@
import time
from typing import TYPE_CHECKING
from sqlalchemy import Column, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.orm import Mapped, relationship
from sqlalchemy.sql.sqltypes import *
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):
__tablename__ = "ip_logs"
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
ip = Column(String, primary_key=True)
created_utc = Column(Integer)
last_used = Column(Integer)
user_id: Mapped[user_id_fk_pk]
ip: Mapped[str_pk]
created_utc: Mapped[int]
last_used: Mapped[int]
user = relationship("User")
user: Mapped["User"] = relationship()
def __init__(self, *args, **kwargs):
if "created_utc" not in kwargs:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,22 +1,27 @@
import time
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Column, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.orm import Mapped, relationship
from sqlalchemy.sql.sqltypes import *
from files.classes import Base
from files.helpers.lazy import lazy
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):
__tablename__ = "reports"
post_id = Column(Integer, ForeignKey("posts.id"), primary_key=True)
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
reason = Column(String)
created_utc = Column(Integer)
post_id: Mapped[post_id_fk_pk]
user_id: Mapped[user_id_fk_pk]
reason: Mapped[Optional[str]]
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):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())
@ -39,12 +44,12 @@ class Report(Base):
class CommentReport(Base):
__tablename__ = "commentreports"
comment_id = Column(Integer, ForeignKey("comments.id"), primary_key=True)
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
reason = Column(String)
created_utc = Column(Integer)
comment_id: Mapped[comment_id_fk_pk]
user_id: Mapped[user_id_fk_pk]
reason: Mapped[Optional[str]]
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):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

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

View File

@ -1,19 +1,24 @@
import time
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Column, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.orm import Mapped, relationship
from sqlalchemy.sql.sqltypes import *
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):
__tablename__ = "subscriptions"
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
post_id = Column(Integer, ForeignKey("posts.id"), primary_key=True)
created_utc = Column(Integer)
user_id: Mapped[user_id_fk_pk]
post_id: Mapped[post_id_fk_pk]
created_utc: Mapped[Optional[int]]
user = relationship("User", uselist=False)
post = relationship("Post", uselist=False)
user: Mapped["User"] = relationship(uselist=False)
post: Mapped["Post"] = relationship(uselist=False)
def __init__(self, *args, **kwargs):
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 files.classes import Base
from files.helpers.types import str_pk
class Transaction(Base):
__tablename__ = "transactions"
id = Column(String, primary_key=True)
created_utc = Column(Integer)
type = Column(String)
amount = Column(Integer)
email = Column(String)
claimed = Column(Boolean)
id: Mapped[str_pk]
created_utc: Mapped[int]
type: Mapped[str]
amount: Mapped[int]
email: Mapped[str]
claimed: Mapped[Optional[bool]]
def __repr__(self):
return f"<{self.__class__.__name__}(id={self.id})>"

View File

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

View File

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

View File

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

View File

@ -1,22 +1,27 @@
import time
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Column, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.orm import Mapped, relationship
from sqlalchemy.sql.sqltypes import *
from files.classes import Base
from files.helpers.lazy import *
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):
__tablename__ = "viewers"
user_id = Column(Integer, ForeignKey('users.id'), primary_key=True)
viewer_id = Column(Integer, ForeignKey('users.id'), primary_key=True)
last_view_utc = Column(Integer)
created_utc = Column(Integer)
user_id: Mapped[user_id_fk_pk]
viewer_id: Mapped[user_id_fk_pk]
last_view_utc: Mapped[int]
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):
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())

View File

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