diff --git a/files/classes/award.py b/files/classes/award.py index 956306efa..48f2a9dcc 100644 --- a/files/classes/award.py +++ b/files/classes/award.py @@ -16,10 +16,12 @@ class AwardRelationship(Base): kind = Column(String) awarded_utc = Column(Integer) - user = relationship("User", primaryjoin="AwardRelationship.user_id==User.id", viewonly=True) - post = relationship("Submission", primaryjoin="AwardRelationship.submission_id==Submission.id", viewonly=True) - comment = relationship("Comment", primaryjoin="AwardRelationship.comment_id==Comment.id", viewonly=True) + user = relationship("User", primaryjoin="AwardRelationship.user_id==User.id", back_populates="awards") + post = relationship("Submission", primaryjoin="AwardRelationship.submission_id==Submission.id", back_populates="awards") + comment = relationship("Comment", primaryjoin="AwardRelationship.comment_id==Comment.id", back_populates="awards") + def __repr__(self): + return f"" @property @lazy diff --git a/files/classes/badges.py b/files/classes/badges.py index 9f770a2c5..fb28c6749 100644 --- a/files/classes/badges.py +++ b/files/classes/badges.py @@ -29,8 +29,8 @@ class Badge(Base): url = Column(String) created_utc = Column(Integer) - user = relationship("User", viewonly=True) - badge = relationship("BadgeDef", primaryjoin="foreign(Badge.badge_id) == remote(BadgeDef.id)", viewonly=True) + user = relationship("User", back_populates="badges") + badge = relationship("BadgeDef", primaryjoin="foreign(Badge.badge_id) == remote(BadgeDef.id)") def __init__(self, *args, **kwargs): if "created_utc" not in kwargs: diff --git a/files/classes/clients.py b/files/classes/clients.py index fc9ee3358..a020f73e8 100644 --- a/files/classes/clients.py +++ b/files/classes/clients.py @@ -19,9 +19,10 @@ class OauthApp(Base): description = Column(String) author_id = Column(Integer, ForeignKey("users.id")) - author = relationship("User", viewonly=True) + author = relationship("User") - def __repr__(self): return f"" + def __repr__(self): + return f"" @property @@ -36,7 +37,8 @@ class OauthApp(Base): @property @lazy - def permalink(self): return f"/admin/app/{self.id}" + def permalink(self): + return f"/admin/app/{self.id}" @lazy def idlist(self, page=1): @@ -70,8 +72,11 @@ class ClientAuth(Base): oauth_client = Column(Integer, ForeignKey("oauth_apps.id"), primary_key=True) access_token = Column(String) - user = relationship("User", viewonly=True) - application = relationship("OauthApp", viewonly=True) + user = relationship("User") + application = relationship("OauthApp") + + def __repr__(self): + return f"" @property @lazy diff --git a/files/classes/comment.py b/files/classes/comment.py index 765b9934c..3ff769163 100644 --- a/files/classes/comment.py +++ b/files/classes/comment.py @@ -76,14 +76,15 @@ class Comment(Base): wordle_result = Column(String) treasure_amount = Column(String) - oauth_app = relationship("OauthApp", viewonly=True) - post = relationship("Submission", viewonly=True) + oauth_app = relationship("OauthApp") + post = relationship("Submission", back_populates="comments") author = relationship("User", primaryjoin="User.id==Comment.author_id") - senttouser = relationship("User", primaryjoin="User.id==Comment.sentto", viewonly=True) - parent_comment = relationship("Comment", remote_side=[id], viewonly=True) - child_comments = relationship("Comment", lazy="dynamic", remote_side=[parent_comment_id], viewonly=True) - awards = relationship("AwardRelationship", order_by="AwardRelationship.awarded_utc.desc()", viewonly=True) - flags = relationship("CommentFlag", order_by="CommentFlag.created_utc", viewonly=True) + senttouser = relationship("User", primaryjoin="User.id==Comment.sentto") + parent_comment = relationship("Comment", remote_side=[id], back_populates="child_comments") + child_comments = relationship("Comment", remote_side=[parent_comment_id], back_populates="parent_comment") + awards = relationship("AwardRelationship", order_by="AwardRelationship.awarded_utc.desc()", back_populates="comment") + flags = relationship("CommentFlag", order_by="CommentFlag.created_utc") + options = relationship("CommentOption", order_by="CommentOption.id") def __init__(self, *args, **kwargs): if "created_utc" not in kwargs: @@ -99,35 +100,6 @@ class Comment(Base): def top_comment(self): return g.db.get(Comment, self.top_comment_id) - @lazy - def poll_voted(self, v): - if v: - vote = g.db.query(CommentVote.vote_type).filter_by(user_id=v.id, comment_id=self.id).one_or_none() - if vote: return vote[0] - return None - - @property - @lazy - def options(self): - return self.child_comments.filter_by(author_id=AUTOPOLLER_ID).order_by(Comment.id).all() - - @property - @lazy - def choices(self): - return self.child_comments.filter_by(author_id=AUTOCHOICE_ID).order_by(Comment.id).all() - - @lazy - def total_poll_voted(self, v): - if v: - for option in self.options: - if option.poll_voted(v): return True - return False - - @lazy - def total_choice_voted(self, v): - if v: - return g.db.query(CommentVote).filter(CommentVote.user_id == v.id, CommentVote.comment_id.in_([x.id for x in self.choices])).first() - return None @property @lazy @@ -239,8 +211,7 @@ class Comment(Base): if not self.parent_submission: return [x for x in self.child_comments.order_by(Comment.id) if not x.author.shadowbanned] - comments = self.child_comments.filter(Comment.author_id.notin_(poll_bots)) - comments = sort_comments(sort, comments) + comments = self.child_comments return [x for x in comments if not x.author.shadowbanned] @@ -250,8 +221,7 @@ class Comment(Base): if not self.parent_submission: return self.child_comments.order_by(Comment.id).all() - comments = self.child_comments.filter(Comment.author_id.notin_(poll_bots)) - return sort_comments(sort, comments).all() + return self.child_comments @property @@ -405,27 +375,25 @@ class Comment(Base): self.upvotes += amount g.db.add(self) - for c in self.options: - body += f'
' - - if self.choices: - curr = self.total_choice_voted(v) - if curr: curr = " value=" + str(curr.comment_id) + if self.options: + curr = [x for x in self.options if x.exclusive and x.voted(v)] + if curr: curr = " value=" + str(curr[0].id) else: curr = '' body += f'' - for c in self.choices: - body += f'''
' + for c in self.options: + if c.exclusive: + body += f'''
' + else: + body += f'
' if self.author.sig_html and (self.author_id == MOOSE_ID or (not self.ghost and not (v and (v.sigs_disabled or v.poor)))): body += f"
{self.author.sig_html}" diff --git a/files/classes/domains.py b/files/classes/domains.py index ed3d771f4..9047dbe76 100644 --- a/files/classes/domains.py +++ b/files/classes/domains.py @@ -5,4 +5,7 @@ class BannedDomain(Base): __tablename__ = "banneddomains" domain = Column(String, primary_key=True) - reason = Column(String) \ No newline at end of file + reason = Column(String) + + def __repr__(self): + return f"" \ No newline at end of file diff --git a/files/classes/exiles.py b/files/classes/exiles.py index 9e3274946..16ba16bc5 100644 --- a/files/classes/exiles.py +++ b/files/classes/exiles.py @@ -9,7 +9,7 @@ class Exile(Base): sub = Column(String, ForeignKey("subs.name"), primary_key=True) exiler_id = Column(Integer, ForeignKey("users.id")) - exiler = relationship("User", primaryjoin="User.id==Exile.exiler_id", viewonly=True) + exiler = relationship("User", primaryjoin="User.id==Exile.exiler_id") def __repr__(self): return f"" \ No newline at end of file diff --git a/files/classes/flags.py b/files/classes/flags.py index 4a1cef6da..6b1d2873b 100644 --- a/files/classes/flags.py +++ b/files/classes/flags.py @@ -15,7 +15,7 @@ class Flag(Base): reason = Column(String) created_utc = Column(Integer) - user = relationship("User", primaryjoin = "Flag.user_id == User.id", uselist = False, viewonly=True) + user = relationship("User", primaryjoin = "Flag.user_id == User.id", uselist = False) def __init__(self, *args, **kwargs): if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) @@ -48,7 +48,7 @@ class CommentFlag(Base): reason = Column(String) created_utc = Column(Integer) - user = relationship("User", primaryjoin = "CommentFlag.user_id == User.id", uselist = False, viewonly=True) + user = relationship("User", primaryjoin = "CommentFlag.user_id == User.id", uselist = False) def __init__(self, *args, **kwargs): if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) diff --git a/files/classes/follows.py b/files/classes/follows.py index 52a3311bc..05d4bc44e 100644 --- a/files/classes/follows.py +++ b/files/classes/follows.py @@ -9,8 +9,8 @@ class Follow(Base): user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) created_utc = Column(Integer) - user = relationship("User", uselist=False, primaryjoin="User.id==Follow.user_id", viewonly=True) - target = relationship("User", primaryjoin="User.id==Follow.target_id", viewonly=True) + 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") def __init__(self, *args, **kwargs): if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) diff --git a/files/classes/lottery.py b/files/classes/lottery.py index 0142a7166..b05ece920 100644 --- a/files/classes/lottery.py +++ b/files/classes/lottery.py @@ -15,6 +15,9 @@ class Lottery(Base): tickets_sold = Column(Integer, default=0) winner_id = Column(Integer, ForeignKey("users.id")) + def __repr__(self): + return f"" + @property @lazy def timeleft(self): diff --git a/files/classes/mod_logs.py b/files/classes/mod_logs.py index ced0b654e..e3d2759d1 100644 --- a/files/classes/mod_logs.py +++ b/files/classes/mod_logs.py @@ -18,9 +18,9 @@ class ModAction(Base): _note=Column(String) created_utc = Column(Integer) - user = relationship("User", primaryjoin="User.id==ModAction.user_id", viewonly=True) - target_user = relationship("User", primaryjoin="User.id==ModAction.target_user_id", viewonly=True) - target_post = relationship("Submission", viewonly=True) + user = relationship("User", primaryjoin="User.id==ModAction.user_id") + target_user = relationship("User", primaryjoin="User.id==ModAction.target_user_id") + target_post = relationship("Submission") def __init__(self, *args, **kwargs): if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) diff --git a/files/classes/notifications.py b/files/classes/notifications.py index a0f3a5c48..22b053767 100644 --- a/files/classes/notifications.py +++ b/files/classes/notifications.py @@ -12,8 +12,8 @@ class Notification(Base): read = Column(Boolean, default=False) created_utc = Column(Integer) - comment = relationship("Comment", viewonly=True) - user = relationship("User", viewonly=True) + comment = relationship("Comment") + user = relationship("User") def __init__(self, *args, **kwargs): if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) diff --git a/files/classes/polls.py b/files/classes/polls.py new file mode 100644 index 000000000..49e6def73 --- /dev/null +++ b/files/classes/polls.py @@ -0,0 +1,103 @@ +from sqlalchemy import * +from sqlalchemy.orm import relationship +from files.__main__ import Base +from files.helpers.lazy import lazy +import time + +class SubmissionOption(Base): + + __tablename__ = "submission_options" + + id = Column(Integer, primary_key=True) + submission_id = Column(Integer, ForeignKey("submissions.id")) + body_html = Column(Text) + exclusive = Column(Boolean) + + votes = relationship("SubmissionOptionVote") + post = relationship("Submission", back_populates="options") + + def __repr__(self): + return f"" + + @property + @lazy + def upvotes(self): + return len(self.votes) + + @lazy + def voted(self, v): + return v.id in [x.user_id for x in self.votes] + + +class SubmissionOptionVote(Base): + + __tablename__ = "submission_option_votes" + + option_id = Column(Integer, ForeignKey("submission_options.id"), primary_key=True) + user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) + created_utc = Column(Integer) + submission_id = Column(Integer, ForeignKey("submissions.id")) + + user = relationship("User") + option = relationship("SubmissionOption") + + def __init__(self, *args, **kwargs): + if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) + super().__init__(*args, **kwargs) + + def __repr__(self): + return f"" + + @property + def created_datetime(self): + return str(time.strftime("%d/%B/%Y %H:%M:%S UTC", time.gmtime(self.created_utc))) + + + +class CommentOption(Base): + + __tablename__ = "comment_options" + + id = Column(Integer, primary_key=True) + comment_id = Column(Integer, ForeignKey("comments.id")) + body_html = Column(Text) + exclusive = Column(Boolean) + + votes = relationship("CommentOptionVote") + post = relationship("Comment", back_populates="options") + + def __repr__(self): + return f"" + + @property + @lazy + def upvotes(self): + return len(self.votes) + + @lazy + def voted(self, v): + return v.id in [x.user_id for x in self.votes] + + +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")) + + user = relationship("User") + option = relationship("CommentOption") + + def __init__(self, *args, **kwargs): + if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) + super().__init__(*args, **kwargs) + + def __repr__(self): + return f"" + + @property + def created_datetime(self): + return str(time.strftime("%d/%B/%Y %H:%M:%S UTC", time.gmtime(self.created_utc))) \ No newline at end of file diff --git a/files/classes/saves.py b/files/classes/saves.py index c1ec113c4..72803b5be 100644 --- a/files/classes/saves.py +++ b/files/classes/saves.py @@ -10,6 +10,8 @@ class SaveRelationship(Base): user_id=Column(Integer, ForeignKey("users.id"), primary_key=True) submission_id=Column(Integer, ForeignKey("submissions.id"), primary_key=True) + def __repr__(self): + return f"" class CommentSaveRelationship(Base): @@ -17,4 +19,7 @@ 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) \ No newline at end of file + comment_id=Column(Integer, ForeignKey("comments.id"), primary_key=True) + + def __repr__(self): + return f"" \ No newline at end of file diff --git a/files/classes/sub.py b/files/classes/sub.py index 25c0b8a10..ca65feee2 100644 --- a/files/classes/sub.py +++ b/files/classes/sub.py @@ -19,10 +19,8 @@ class Sub(Base): bannerurl = Column(String) css = Column(String) - blocks = relationship("SubBlock", - primaryjoin="SubBlock.sub==Sub.name", viewonly=True) - followers = relationship("SubSubscription", - primaryjoin="SubSubscription.sub==Sub.name", viewonly=True) + blocks = relationship("SubBlock", primaryjoin="SubBlock.sub==Sub.name") + followers = relationship("SubSubscription", primaryjoin="SubSubscription.sub==Sub.name") def __repr__(self): return f"" diff --git a/files/classes/submission.py b/files/classes/submission.py index 19ed2827d..328ed14fa 100644 --- a/files/classes/submission.py +++ b/files/classes/submission.py @@ -16,6 +16,7 @@ from .saves import SaveRelationship from .sub import * from .subscriptions import * from .votes import CommentVote +from .polls import * from flask import g def sort_posts(sort, posts): @@ -72,12 +73,13 @@ class Submission(Base): new = Column(Boolean) author = relationship("User", primaryjoin="Submission.author_id==User.id") - oauth_app = relationship("OauthApp", viewonly=True) - approved_by = relationship("User", uselist=False, primaryjoin="Submission.is_approved==User.id", viewonly=True) - awards = relationship("AwardRelationship", order_by="AwardRelationship.awarded_utc.desc()", viewonly=True) - flags = relationship("Flag", order_by="Flag.created_utc", viewonly=True) - comments = relationship("Comment", primaryjoin="Comment.parent_submission==Submission.id") - subr = relationship("Sub", primaryjoin="foreign(Submission.sub)==remote(Sub.name)", viewonly=True) + oauth_app = relationship("OauthApp") + approved_by = relationship("User", uselist=False, primaryjoin="Submission.is_approved==User.id") + awards = relationship("AwardRelationship", order_by="AwardRelationship.awarded_utc.desc()", back_populates="post") + flags = relationship("Flag", order_by="Flag.created_utc") + comments = relationship("Comment", primaryjoin="Comment.parent_submission==Submission.id", back_populates="post") + subr = relationship("Sub", primaryjoin="foreign(Submission.sub)==remote(Sub.name)") + options = relationship("SubmissionOption", order_by="SubmissionOption.id") bump_utc = deferred(Column(Integer, server_default=FetchedValue())) @@ -94,43 +96,6 @@ class Submission(Base): if self.downvotes > 5 and 0.25 < self.upvotes / self.downvotes < 4: return True return False - @property - @lazy - def options(self): - return g.db.query(Comment).filter_by(parent_submission = self.id, author_id = AUTOPOLLER_ID, level=1).order_by(Comment.id).all() - - - @property - @lazy - def choices(self): - return g.db.query(Comment).filter_by(parent_submission = self.id, author_id = AUTOCHOICE_ID, level=1).order_by(Comment.id).all() - - - @property - @lazy - def bet_options(self): - return g.db.query(Comment).filter_by(parent_submission = self.id, author_id = AUTOBETTER_ID, level=1).all() - - @lazy - def total_poll_voted(self, v): - if v: - for option in self.options: - if option.poll_voted(v): return True - return False - - @lazy - def total_choice_voted(self, v): - if v and self.choices: - return g.db.query(CommentVote).filter(CommentVote.user_id == v.id, CommentVote.comment_id.in_([x.id for x in self.choices])).first() - return None - - @lazy - def total_bet_voted(self, v): - if "closed" in self.body.lower(): return True - if v: - for option in self.bet_options: - if option.poll_voted(v): return True - return False @property @lazy @@ -401,44 +366,31 @@ class Submission(Base): self.upvotes += amount g.db.add(self) - if not listing: - for c in self.options: + + if self.options: + curr = [x for x in self.options if x.exclusive and x.voted(v)] + if curr: curr = " value=" + str(curr[0].id) + else: curr = '' + body += f'' + + for c in self.options: + if c.exclusive: + body += f'''
' + else: body += f'
' - - if self.choices: - curr = self.total_choice_voted(v) - if curr: curr = " value=" + str(curr.comment_id) - else: curr = '' - body += f'' - - for c in self.choices: - body += f'''
' - - for c in self.bet_options: - body += f'''
= 200) or self.total_bet_voted(v) or not v.can_gamble: body += " disabled " - body += f'''>" - if v and v.admin_level > 2: - body += f'''''' - body += "
" + body += f'"> - {c.upvotes} votes' - if self.author.sig_html and (self.author_id == MOOSE_ID or (not self.ghost and not (v and (v.sigs_disabled or v.poor)))): - body += f"
{self.author.sig_html}" + + if not listing and self.author.sig_html and (self.author_id == MOOSE_ID or (not self.ghost and not (v and (v.sigs_disabled or v.poor)))): + body += f"
{self.author.sig_html}" return body diff --git a/files/classes/subscriptions.py b/files/classes/subscriptions.py index 1d4935a85..ff4ee040a 100644 --- a/files/classes/subscriptions.py +++ b/files/classes/subscriptions.py @@ -7,7 +7,7 @@ class Subscription(Base): user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) submission_id = Column(Integer, ForeignKey("submissions.id"), primary_key=True) - user = relationship("User", uselist=False, viewonly=True) + user = relationship("User", uselist=False) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/files/classes/user.py b/files/classes/user.py index f1626aab5..eb6882d86 100644 --- a/files/classes/user.py +++ b/files/classes/user.py @@ -135,16 +135,16 @@ class User(Base): total_held_lottery_tickets = Column(Integer, default=0) total_lottery_winnings = Column(Integer, default=0) - badges = relationship("Badge", order_by="Badge.created_utc", viewonly=True) - subscriptions = relationship("Subscription", viewonly=True) - following = relationship("Follow", primaryjoin="Follow.user_id==User.id", viewonly=True) - followers = relationship("Follow", primaryjoin="Follow.target_id==User.id", viewonly=True) - viewers = relationship("ViewerRelationship", primaryjoin="User.id == ViewerRelationship.user_id", viewonly=True) - blocking = relationship("UserBlock", lazy="dynamic", primaryjoin="User.id==UserBlock.user_id", viewonly=True) - blocked = relationship("UserBlock", lazy="dynamic", primaryjoin="User.id==UserBlock.target_id", viewonly=True) - authorizations = relationship("ClientAuth", viewonly=True) - awards = relationship("AwardRelationship", primaryjoin="User.id==AwardRelationship.user_id", viewonly=True) - referrals = relationship("User", viewonly=True) + 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") + viewers = relationship("ViewerRelationship", primaryjoin="User.id == ViewerRelationship.user_id") + 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") + awards = relationship("AwardRelationship", primaryjoin="User.id==AwardRelationship.user_id", back_populates="user") + referrals = relationship("User") def __init__(self, **kwargs): @@ -157,6 +157,10 @@ class User(Base): super().__init__(**kwargs) + def __repr__(self): + return f"" + + @lazy def mods(self, sub): return self.admin_level == 3 or bool(g.db.query(Mod.user_id).filter_by(user_id=self.id, sub=sub).one_or_none()) diff --git a/files/classes/userblock.py b/files/classes/userblock.py index 78339f404..b4c5ad3ac 100644 --- a/files/classes/userblock.py +++ b/files/classes/userblock.py @@ -8,8 +8,8 @@ class UserBlock(Base): user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) target_id = Column(Integer, ForeignKey("users.id"), primary_key=True) - user = relationship("User", primaryjoin="User.id==UserBlock.user_id", viewonly=True) - target = relationship("User", primaryjoin="User.id==UserBlock.target_id", viewonly=True) + user = relationship("User", primaryjoin="User.id==UserBlock.user_id", back_populates="blocking") + target = relationship("User", primaryjoin="User.id==UserBlock.target_id", back_populates="blocked") def __repr__(self): return f"" \ No newline at end of file diff --git a/files/classes/views.py b/files/classes/views.py index 036663d01..2b12f5695 100644 --- a/files/classes/views.py +++ b/files/classes/views.py @@ -12,7 +12,7 @@ class ViewerRelationship(Base): viewer_id = Column(Integer, ForeignKey('users.id'), primary_key=True) last_view_utc = Column(Integer) - viewer = relationship("User", primaryjoin="ViewerRelationship.viewer_id == User.id", viewonly=True) + viewer = relationship("User", primaryjoin="ViewerRelationship.viewer_id == User.id") def __init__(self, **kwargs): @@ -21,6 +21,9 @@ class ViewerRelationship(Base): super().__init__(**kwargs) + def __repr__(self): + return f"" + @property @lazy def last_view_since(self): diff --git a/files/classes/votes.py b/files/classes/votes.py index 866464452..524fbc563 100644 --- a/files/classes/votes.py +++ b/files/classes/votes.py @@ -16,8 +16,8 @@ class Vote(Base): real = Column(Boolean, default=True) created_utc = Column(Integer) - user = relationship("User", lazy="subquery", viewonly=True) - post = relationship("Submission", lazy="subquery", viewonly=True) + user = relationship("User", lazy="subquery") + post = relationship("Submission", lazy="subquery") def __init__(self, *args, **kwargs): if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) @@ -62,7 +62,7 @@ class CommentVote(Base): created_utc = Column(Integer) user = relationship("User", lazy="subquery") - comment = relationship("Comment", lazy="subquery", viewonly=True) + comment = relationship("Comment", lazy="subquery") def __init__(self, *args, **kwargs): if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) diff --git a/files/helpers/const.py b/files/helpers/const.py index 841571566..6c4153614 100644 --- a/files/helpers/const.py +++ b/files/helpers/const.py @@ -155,9 +155,6 @@ AUTOJANNY_ID = 2 SNAPPY_ID = 3 LONGPOSTBOT_ID = 4 ZOZBOT_ID = 5 -AUTOPOLLER_ID = 6 -AUTOBETTER_ID = 7 -AUTOCHOICE_ID = 8 BASEDBOT_ID = 0 SCHIZO_ID = 0 @@ -203,9 +200,6 @@ if SITE in {'rdrama.net', 'devrama.xyz'}: SNAPPY_ID = 261 LONGPOSTBOT_ID = 1832 ZOZBOT_ID = 1833 - AUTOPOLLER_ID = 6176 - AUTOBETTER_ID = 7668 - AUTOCHOICE_ID = 9167 SCHIZO_ID = 8494 A_ID = 1230 @@ -254,9 +248,6 @@ elif SITE == 'pcmemes.net': SNAPPY_ID = 261 LONGPOSTBOT_ID = 1832 ZOZBOT_ID = 1833 - AUTOPOLLER_ID = 2129 - AUTOBETTER_ID = 1867 - AUTOCHOICE_ID = 2072 BASEDBOT_ID = 800 KIPPY_ID = 1592 @@ -313,9 +304,7 @@ elif SITE == 'lgbdropthet.com': else: # localhost or testing environment implied pass -poll_bots = AUTOPOLLER_ID, AUTOBETTER_ID, AUTOCHOICE_ID - -bots = {NOTIFICATIONS_ID, AUTOJANNY_ID, SNAPPY_ID, LONGPOSTBOT_ID, ZOZBOT_ID, BASEDBOT_ID}.union(poll_bots) +bots = {NOTIFICATIONS_ID, AUTOJANNY_ID, SNAPPY_ID, LONGPOSTBOT_ID, ZOZBOT_ID, BASEDBOT_ID} IMGUR_KEY = environ.get("IMGUR_KEY").strip() PUSHER_ID = environ.get("PUSHER_ID", "").strip() diff --git a/files/helpers/get.py b/files/helpers/get.py index 9daf3aa0f..55782e701 100644 --- a/files/helpers/get.py +++ b/files/helpers/get.py @@ -144,7 +144,13 @@ def get_post(i, v=None, graceful=False, rendered=False): ) if rendered: - posts = post.options(joinedload(Submission.flags), joinedload(Submission.awards), joinedload(Submission.author)) + posts = post.options( + joinedload(Submission.flags), + joinedload(Submission.awards), + joinedload(Submission.author), + joinedload(Submission.options), + joinedload(Submission.options, SubmissionOption.votes) + ) post=post.one_or_none() @@ -196,7 +202,12 @@ def get_posts(pids, v=None): blocked, blocked.c.user_id == Submission.author_id, isouter=True - ).options(joinedload(Submission.flags), joinedload(Submission.awards), joinedload(Submission.author)).all() + ).options(joinedload(Submission.flags), + joinedload(Submission.awards), + joinedload(Submission.author), + joinedload(Submission.options), + joinedload(Submission.options, SubmissionOption.votes) + ).all() output = [p[0] for p in query] for i in range(len(output)): diff --git a/files/routes/__init__.py b/files/routes/__init__.py index 46a9ae564..b1bdab958 100644 --- a/files/routes/__init__.py +++ b/files/routes/__init__.py @@ -16,4 +16,5 @@ from .feeds import * from .awards import * from .giphy import * from .subs import * -from .lottery import * \ No newline at end of file +from .lottery import * +from .polls import * \ No newline at end of file diff --git a/files/routes/comments.py b/files/routes/comments.py index aee5225dc..833e61e66 100644 --- a/files/routes/comments.py +++ b/files/routes/comments.py @@ -101,8 +101,7 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None): comments = comments.join(User, User.id == Comment.author_id).filter(User.shadowbanned == None) comments=comments.filter( - Comment.top_comment_id == c.top_comment_id, - Comment.author_id.notin_(poll_bots) + Comment.top_comment_id == c.top_comment_id ).join( votes, votes.c.comment_id == Comment.id, @@ -365,30 +364,20 @@ def api_comment(v): else: c.top_comment_id = parent.top_comment_id for option in options: - c_option = Comment(author_id=AUTOPOLLER_ID, - parent_submission=parent_submission, - parent_comment_id=c.id, - level=level+1, + option = CommentOption( + comment_id=c.id, body_html=filter_emojis_only(option), - upvotes=0, - is_bot=True, - ghost=c.ghost - ) - - g.db.add(c_option) + exclusive=False + ) + g.db.add(option) for choice in choices: - c_choice = Comment(author_id=AUTOCHOICE_ID, - parent_submission=parent_submission, - parent_comment_id=c.id, - level=level+1, + choice = CommentOption( + comment_id=c.id, body_html=filter_emojis_only(choice), - upvotes=0, - is_bot=True, - ghost=c.ghost - ) - - g.db.add(c_choice) + exclusive=True + ) + g.db.add(choice) if request.host == 'pcmemes.net' and c.body.lower().startswith("based"): pill = based_regex.match(body) @@ -664,29 +653,21 @@ def edit_comment(cid, v): for i in poll_regex.finditer(body): body = body.replace(i.group(0), "") - c_option = Comment(author_id=AUTOPOLLER_ID, - parent_submission=c.parent_submission, - parent_comment_id=c.id, - level=c.level+1, + option = CommentOption( + comment_id=c.id, body_html=filter_emojis_only(i.group(1)), - upvotes=0, - is_bot=True, - ghost=c.ghost - ) - g.db.add(c_option) + exclusive = False + ) + g.db.add(option) for i in choice_regex.finditer(body): body = body.replace(i.group(0), "") - c_choice = Comment(author_id=AUTOCHOICE_ID, - parent_submission=c.parent_submission, - parent_comment_id=c.id, - level=c.level+1, + option = CommentOption( + comment_id=c.id, body_html=filter_emojis_only(i.group(1)), - upvotes=0, - is_bot=True, - ghost=c.ghost - ) - g.db.add(c_choice) + exclusive = True + ) + g.db.add(option) if '!slots' not in body.lower() and '!blackjack' not in body.lower() and '!wordle' not in body.lower() and AGENDAPOSTER_PHRASE not in body.lower(): now = int(time.time()) diff --git a/files/routes/front.py b/files/routes/front.py index f29a4b4f3..75792f8c6 100644 --- a/files/routes/front.py +++ b/files/routes/front.py @@ -463,9 +463,7 @@ def all_comments(v): @cache.memoize(timeout=86400) def comment_idlist(page=1, v=None, nsfw=False, sort="new", t="all", gt=0, lt=0, site=None): - excluded = v.userblocks + [AUTOPOLLER_ID, AUTOBETTER_ID, AUTOCHOICE_ID] - - comments = g.db.query(Comment.id).filter(Comment.parent_submission != None, Comment.author_id.notin_(excluded)) + comments = g.db.query(Comment.id).filter(Comment.parent_submission != None, Comment.author_id.notin_(v.userblocks)) if v.admin_level < 2: private = [x[0] for x in g.db.query(Submission.id).filter(Submission.private == True).all()] diff --git a/files/routes/login.py b/files/routes/login.py index ed6105468..24482a283 100644 --- a/files/routes/login.py +++ b/files/routes/login.py @@ -313,7 +313,7 @@ def sign_up_post(v): ref_id = int(request.values.get("referred_by", 0)) users_count = g.db.query(User).count() - if users_count == 8: + if users_count == 5: admin_level=3 session["history"] = [] else: admin_level=0 diff --git a/files/routes/polls.py b/files/routes/polls.py new file mode 100644 index 000000000..ca5289728 --- /dev/null +++ b/files/routes/polls.py @@ -0,0 +1,109 @@ +from files.helpers.wrappers import * +from files.helpers.get import * +from files.helpers.const import * +from files.classes import * +from flask import * +from files.__main__ import app + + +@app.post("/vote/post/option/") +@is_not_permabanned +def api_vote_option(option_id, v): + + option_id = int(option_id) + + option = g.db.get(SubmissionOption, option_id) + + if not option: abort(404) + + if option.exclusive: + vote = g.db.query(SubmissionOptionVote).join(SubmissionOption).filter( + SubmissionOptionVote.user_id==v.id, + SubmissionOptionVote.submission_id==option.submission_id, + SubmissionOption.exclusive==True).one_or_none() + if vote: + g.db.delete(vote) + + existing = g.db.query(SubmissionOptionVote).filter_by(option_id=option_id, user_id=v.id).one_or_none() + if not existing: + vote = SubmissionOptionVote( + option_id=option_id, + user_id=v.id, + submission_id=option.submission_id, + ) + g.db.add(vote) + elif existing: + g.db.delete(existing) + + return "", 204 + +@app.get("/votes/post/option/") +@auth_required +def option_votes(option_id, v): + + option_id = int(option_id) + + option = g.db.get(SubmissionOption, option_id) + + if not option: abort(404) + + ups = g.db.query(SubmissionOptionVote).filter_by(option_id=option_id).options( + joinedload(SubmissionOptionVote.user) + ).all() + + return render_template("poll_votes.html", + v=v, + thing=option, + ups=ups) + + + +@app.post("/vote/comment/option/") +@is_not_permabanned +def api_vote_option_comment(option_id, v): + + option_id = int(option_id) + + option = g.db.get(CommentOption, option_id) + + if not option: abort(404) + + if option.exclusive: + vote = g.db.query(CommentOptionVote).join(CommentOption).filter( + CommentOptionVote.user_id==v.id, + CommentOptionVote.comment_id==option.comment_id, + CommentOption.exclusive==True).one_or_none() + if vote: + g.db.delete(vote) + + existing = g.db.query(CommentOptionVote).filter_by(option_id=option_id, user_id=v.id).one_or_none() + if not existing: + vote = CommentOptionVote( + option_id=option_id, + user_id=v.id, + comment_id=option.comment_id, + ) + g.db.add(vote) + elif existing: + g.db.delete(existing) + + return "", 204 + +@app.get("/votes/comment/option/") +@auth_required +def option_votes_comment(option_id, v): + + option_id = int(option_id) + + option = g.db.get(CommentOption, option_id) + + if not option: abort(404) + + ups = g.db.query(CommentOptionVote).filter_by(option_id=option_id).options( + joinedload(CommentOptionVote.user) + ).all() + + return render_template("poll_votes.html", + v=v, + thing=option, + ups=ups) \ No newline at end of file diff --git a/files/routes/posts.py b/files/routes/posts.py index 45a7d2c46..1a14d9daa 100644 --- a/files/routes/posts.py +++ b/files/routes/posts.py @@ -158,7 +158,7 @@ def post_id(pid, anything=None, v=None, sub=None): if not (v and v.shadowbanned) and not (v and v.admin_level >= 2): comments = comments.join(User, User.id == Comment.author_id).filter(User.shadowbanned == None) - comments=comments.filter(Comment.parent_submission == post.id, Comment.author_id.notin_(poll_bots)).join( + comments=comments.filter(Comment.parent_submission == post.id).join( votes, votes.c.comment_id == Comment.id, isouter=True @@ -170,7 +170,13 @@ def post_id(pid, anything=None, v=None, sub=None): blocked, blocked.c.user_id == Comment.author_id, isouter=True - ).options(joinedload(Comment.flags), joinedload(Comment.awards), joinedload(Comment.author)) + ).options( + joinedload(Comment.flags), + joinedload(Comment.awards), + joinedload(Comment.author), + joinedload(Comment.options), + joinedload(Comment.options, CommentOption.votes) + ) output = [] for c in comments.all(): @@ -192,7 +198,7 @@ def post_id(pid, anything=None, v=None, sub=None): else: pinned = g.db.query(Comment).filter(Comment.parent_submission == post.id, Comment.stickied != None).all() - comments = g.db.query(Comment).join(User, User.id == Comment.author_id).filter(User.shadowbanned == None, Comment.parent_submission == post.id, Comment.author_id.notin_(poll_bots), Comment.level == 1, Comment.stickied == None) + comments = g.db.query(Comment).join(User, User.id == Comment.author_id).filter(User.shadowbanned == None, Comment.parent_submission == post.id, Comment.level == 1, Comment.stickied == None) comments = sort_comments(sort, comments) @@ -268,7 +274,7 @@ def viewmore(v, pid, sort, offset): votes.c.vote_type, blocking.c.target_id, blocked.c.target_id, - ).filter(Comment.parent_submission == pid, Comment.author_id.notin_(poll_bots), Comment.stickied == None, Comment.id.notin_(ids)) + ).filter(Comment.parent_submission == pid, Comment.stickied == None, Comment.id.notin_(ids)) if not (v and v.shadowbanned) and not (v and v.admin_level >= 2): comments = comments.join(User, User.id == Comment.author_id).filter(User.shadowbanned == None) @@ -303,7 +309,7 @@ def viewmore(v, pid, sort, offset): second = [c[0] for c in comments.filter(or_(Comment.slots_result != None, Comment.blackjack_result != None, Comment.wordle_result != None), func.length(Comment.body_html) <= 100).all()] comments = first + second else: - comments = g.db.query(Comment).join(User, User.id == Comment.author_id).filter(User.shadowbanned == None, Comment.parent_submission == pid, Comment.author_id.notin_(poll_bots), Comment.level == 1, Comment.stickied == None, Comment.id.notin_(ids)) + comments = g.db.query(Comment).join(User, User.id == Comment.author_id).filter(User.shadowbanned == None, Comment.parent_submission == pid, Comment.level == 1, Comment.stickied == None, Comment.id.notin_(ids)) comments = sort_comments(sort, comments) @@ -427,27 +433,22 @@ def edit_post(pid, v): for i in poll_regex.finditer(body): body = body.replace(i.group(0), "") - c = Comment(author_id=AUTOPOLLER_ID, - parent_submission=p.id, - level=1, + option = SubmissionOption( + submission_id=p.id, body_html=filter_emojis_only(i.group(1)), - upvotes=0, - is_bot=True, - ghost=p.ghost - ) - g.db.add(c) + exclusive = False + ) + g.db.add(option) for i in choice_regex.finditer(body): body = body.replace(i.group(0), "") - c = Comment(author_id=AUTOCHOICE_ID, - parent_submission=p.id, - level=1, + option = SubmissionOption( + submission_id=p.id, body_html=filter_emojis_only(i.group(1)), - upvotes=0, - is_bot=True, - ghost=p.ghost - ) - g.db.add(c) + exclusive = True + ) + g.db.add(option) + body_html = sanitize(body, edit=True) @@ -974,26 +975,20 @@ def submit_post(v, sub=None): g.db.add(bet_option) for option in options: - c = Comment(author_id=AUTOPOLLER_ID, - parent_submission=post.id, - level=1, + option = SubmissionOption( + submission_id=post.id, body_html=filter_emojis_only(option), - upvotes=0, - is_bot=True, - ghost=post.ghost - ) - g.db.add(c) + exclusive=False + ) + g.db.add(option) for choice in choices: - c = Comment(author_id=AUTOCHOICE_ID, - parent_submission=post.id, - level=1, + choice = SubmissionOption( + submission_id=post.id, body_html=filter_emojis_only(choice), - upvotes=0, - is_bot=True, - ghost=post.ghost - ) - g.db.add(c) + exclusive=True + ) + g.db.add(choice) vote = Vote(user_id=v.id, vote_type=1, diff --git a/files/routes/users.py b/files/routes/users.py index e04320817..3209d45c5 100644 --- a/files/routes/users.py +++ b/files/routes/users.py @@ -317,7 +317,7 @@ def upvoting(v, username): votes = g.db.query(Submission.author_id, func.count(Submission.author_id)).join(Vote, Vote.submission_id==Submission.id).filter(Submission.ghost == False, Submission.is_banned == False, Submission.deleted_utc == 0, Vote.vote_type==1, Vote.user_id==id).group_by(Submission.author_id).order_by(func.count(Submission.author_id).desc()).all() - votes2 = g.db.query(Comment.author_id, func.count(Comment.author_id)).join(CommentVote, CommentVote.comment_id==Comment.id).filter(Comment.ghost == False, Comment.is_banned == False, Comment.deleted_utc == 0, CommentVote.vote_type==1, CommentVote.user_id==id, Comment.author_id.notin_(poll_bots)).group_by(Comment.author_id).order_by(func.count(Comment.author_id).desc()).all() + votes2 = g.db.query(Comment.author_id, func.count(Comment.author_id)).join(CommentVote, CommentVote.comment_id==Comment.id).filter(Comment.ghost == False, Comment.is_banned == False, Comment.deleted_utc == 0, CommentVote.vote_type==1, CommentVote.user_id==id).group_by(Comment.author_id).order_by(func.count(Comment.author_id).desc()).all() votes = Counter(dict(votes)) + Counter(dict(votes2)) diff --git a/files/routes/votes.py b/files/routes/votes.py index e57586a1d..9d67a6699 100644 --- a/files/routes/votes.py +++ b/files/routes/votes.py @@ -6,12 +6,9 @@ from flask import * from files.__main__ import app, limiter, cache from os import environ -@app.get("/votes") +@app.get("/votes/") @auth_required -def admin_vote_info_get(v): - link = request.values.get("link") - if not link: return render_template("votes.html", v=v) - +def vote_info_get(v, link): try: if "t2_" in link: thing = get_post(int(link.split("t2_")[1]), v=v) elif "t3_" in link: thing = get_comment(int(link.split("t3_")[1]), v=v) @@ -20,8 +17,6 @@ def admin_vote_info_get(v): if thing.ghost and v.id != AEVANN_ID: abort(403) - if not thing.author: - print(thing.id, flush=True) if isinstance(thing, Submission): if thing.author.shadowbanned and not (v and v.admin_level): thing_id = g.db.query(Submission.id).filter_by(upvotes=thing.upvotes, downvotes=thing.downvotes).order_by(Submission.id).first()[0] @@ -151,8 +146,6 @@ def api_vote_comment(comment_id, new, v): except: abort(404) comment = get_comment(comment_id) - - if new == 1 and comment.author_id in poll_bots: return {"error": "forbidden."}, 403 existing = g.db.query(CommentVote).filter_by(user_id=v.id, comment_id=comment.id).one_or_none() @@ -207,100 +200,4 @@ def api_vote_comment(comment_id, new, v): comment.realupvotes = g.db.query(CommentVote).filter_by(comment_id=comment.id, real=True).count() if comment.author.progressivestack: comment.realupvotes *= 2 g.db.add(comment) - return "", 204 - - -@app.post("/vote/poll/") -@is_not_permabanned -def api_vote_poll(comment_id, v): - - vote = request.values.get("vote") - if vote == "true": new = 1 - elif vote == "false": new = 0 - else: abort(400) - - comment_id = int(comment_id) - comment = get_comment(comment_id) - - existing = g.db.query(CommentVote).filter_by(user_id=v.id, comment_id=comment.id).one_or_none() - - if existing and existing.vote_type == new: return "", 204 - - if existing: - if new == 1: - existing.vote_type = new - g.db.add(existing) - else: g.db.delete(existing) - elif new == 1: - vote = CommentVote(user_id=v.id, vote_type=new, comment_id=comment.id) - g.db.add(vote) - - g.db.flush() - comment.upvotes = g.db.query(CommentVote).filter_by(comment_id=comment.id, vote_type=1).count() - g.db.add(comment) - return "", 204 - - -@app.post("/bet/") -@limiter.limit("1/second;30/minute;200/hour;1000/day") -@limiter.limit("1/second;30/minute;200/hour;1000/day", key_func=lambda:f'{request.host}-{session.get("lo_user")}') -@is_not_permabanned -def bet(comment_id, v): - if not v.can_gamble: return {"error": "You have gambling disabled!"} - - if v.coins < 200: return {"error": "You don't have 200 coins!"} - - vote = request.values.get("vote") - comment_id = int(comment_id) - comment = get_comment(comment_id) - - option_ids = map(lambda x: x.id, comment.post.bet_options) - existing = g.db.query(CommentVote).filter_by(user_id=v.id) \ - .filter(CommentVote.comment_id.in_(option_ids)).one_or_none() - if existing: return "", 204 - - vote = CommentVote(user_id=v.id, vote_type=1, comment_id=comment.id) - g.db.add(vote) - - comment.upvotes += 1 - g.db.add(comment) - - v.coins -= 200 - g.db.add(v) - autobetter = get_account(AUTOBETTER_ID) - autobetter.coins += 200 - g.db.add(autobetter) - - return "", 204 - -@app.post("/vote/choice/") -@is_not_permabanned -def api_vote_choice(comment_id, v): - - comment_id = int(comment_id) - comment = get_comment(comment_id) - - existing = g.db.query(CommentVote).filter_by(user_id=v.id, comment_id=comment.id).one_or_none() - - if existing and existing.vote_type == 1: return "", 204 - - if existing: - existing.vote_type = 1 - g.db.add(existing) - else: - vote = CommentVote(user_id=v.id, vote_type=1, comment_id=comment.id) - g.db.add(vote) - - if comment.parent_comment: parent = comment.parent_comment - else: parent = comment.post - - vote = parent.total_choice_voted(v) - if vote: - vote.comment.upvotes = g.db.query(CommentVote).filter_by(comment_id=vote.comment.id, vote_type=1).count() - 1 - g.db.add(vote.comment) - g.db.delete(vote) - - g.db.flush() - comment.upvotes = g.db.query(CommentVote).filter_by(comment_id=comment.id, vote_type=1).count() - g.db.add(comment) - return "", 204 + return "", 204 \ No newline at end of file diff --git a/files/templates/comments.html b/files/templates/comments.html index 969bce620..0f26349da 100644 --- a/files/templates/comments.html +++ b/files/templates/comments.html @@ -443,7 +443,7 @@ {% endif %} - {% if not c.ghost or v.id == AEVANN_ID %}Votes{% endif %} + {% if not c.ghost or v.id == AEVANN_ID %}Votes{% endif %} Context @@ -646,7 +646,7 @@