529 lines
16 KiB
Python
529 lines
16 KiB
Python
from flask import render_template, request, g
|
|
from sqlalchemy import *
|
|
from sqlalchemy.orm import relationship, deferred
|
|
import re, random
|
|
from urllib.parse import urlparse
|
|
from .mix_ins import *
|
|
from drama.helpers.base36 import *
|
|
from drama.helpers.lazy import lazy
|
|
from drama.__main__ import Base
|
|
|
|
class SubmissionAux(Base):
|
|
|
|
__tablename__ = "submissions_aux"
|
|
|
|
# we don't care about this ID
|
|
key_id = Column(BigInteger, primary_key=True)
|
|
id = Column(BigInteger, ForeignKey("submissions.id"))
|
|
title = Column(String(500))
|
|
title_html = Column(String(500))
|
|
url = Column(String(500))
|
|
body = Column(String(10000), default="")
|
|
body_html = Column(String(20000), default="")
|
|
ban_reason = Column(String(128), default="")
|
|
embed_url = Column(String(256), default="")
|
|
meta_title=Column(String(512), default="")
|
|
meta_description=Column(String(1024), default="")
|
|
|
|
|
|
class Submission(Base, Stndrd, Age_times, Scores, Fuzzing):
|
|
|
|
__tablename__ = "submissions"
|
|
|
|
id = Column(BigInteger, primary_key=True)
|
|
submission_aux = relationship(
|
|
"SubmissionAux",
|
|
lazy="joined",
|
|
uselist=False,
|
|
innerjoin=True,
|
|
primaryjoin="Submission.id==SubmissionAux.id")
|
|
gm_distinguish = Column(Integer, default=0)
|
|
author_id = Column(BigInteger, ForeignKey("users.id"))
|
|
repost_id = Column(BigInteger, ForeignKey("submissions.id"), default=0)
|
|
edited_utc = Column(BigInteger, default=0)
|
|
created_utc = Column(BigInteger, default=0)
|
|
thumburl = Column(String)
|
|
is_banned = Column(Boolean, default=False)
|
|
views = Column(Integer, default=0)
|
|
deleted_utc = Column(Integer, default=0)
|
|
banaward = Column(String)
|
|
purged_utc = Column(Integer, default=0)
|
|
distinguish_level = Column(Integer, default=0)
|
|
created_str = Column(String(255))
|
|
stickied = Column(Boolean, default=False)
|
|
is_pinned = Column(Boolean, default=False)
|
|
private = Column(Boolean, default=False)
|
|
_comments = relationship(
|
|
"Comment",
|
|
lazy="dynamic",
|
|
primaryjoin="Comment.parent_submission==Submission.id",
|
|
backref="submissions")
|
|
domain_ref = Column(Integer, ForeignKey("domains.id"))
|
|
domain_obj = relationship("Domain")
|
|
flags = relationship("Flag", backref="submission")
|
|
is_approved = Column(Integer, ForeignKey("users.id"), default=0)
|
|
approved_utc = Column(Integer, default=0)
|
|
over_18 = Column(Boolean, default=False)
|
|
creation_ip = Column(String(64), default="")
|
|
mod_approved = Column(Integer)
|
|
accepted_utc = Column(Integer, default=0)
|
|
has_thumb = Column(Boolean, default=False)
|
|
post_public = Column(Boolean, default=True)
|
|
score_hot = Column(Float, default=0)
|
|
score_top = Column(Float, default=1)
|
|
score_activity = Column(Float, default=0)
|
|
author = relationship(
|
|
"User",
|
|
lazy="joined",
|
|
innerjoin=True,
|
|
primaryjoin="Submission.author_id==User.id")
|
|
is_pinned = Column(Boolean, default=False)
|
|
score_best = Column(Float, default=0)
|
|
reports = relationship("Report", backref="submission")
|
|
is_bot = Column(Boolean, default=False)
|
|
|
|
upvotes = Column(Integer, default=1)
|
|
downvotes = Column(Integer, default=0)
|
|
creation_region=Column(String(2))
|
|
|
|
app_id=Column(Integer, ForeignKey("oauth_apps.id"))
|
|
oauth_app=relationship("OauthApp")
|
|
|
|
approved_by = relationship(
|
|
"User",
|
|
uselist=False,
|
|
primaryjoin="Submission.is_approved==User.id")
|
|
|
|
# not sure if we need this
|
|
reposts = relationship("Submission", lazy="joined", remote_side=[id])
|
|
|
|
# These are virtual properties handled as postgres functions server-side
|
|
# There is no difference to SQLAlchemy, but they cannot be written to
|
|
|
|
ups = deferred(Column(Integer, server_default=FetchedValue()))
|
|
downs = deferred(Column(Integer, server_default=FetchedValue()))
|
|
comment_count = Column(Integer, server_default=FetchedValue())
|
|
score = deferred(Column(Float, server_default=FetchedValue()))
|
|
|
|
#awards = relationship("AwardRelationship", lazy="joined")
|
|
|
|
rank_hot = deferred(Column(Float, server_default=FetchedValue()))
|
|
rank_fiery = deferred(Column(Float, server_default=FetchedValue()))
|
|
rank_activity = deferred(Column(Float, server_default=FetchedValue()))
|
|
rank_best = deferred(Column(Float, server_default=FetchedValue()))
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
if "created_utc" not in kwargs:
|
|
kwargs["created_utc"] = int(time.time())
|
|
kwargs["created_str"] = time.strftime(
|
|
"%I:%M %p on %d %b %Y", time.gmtime(
|
|
kwargs["created_utc"]))
|
|
|
|
kwargs["creation_ip"] = request.remote_addr
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
def __repr__(self):
|
|
return f"<Submission(id={self.id})>"
|
|
|
|
@property
|
|
@lazy
|
|
def hotscore(self):
|
|
return 10000000*(self.upvotes - self.downvotes + 1)/(((self.age+3600)/1000)**(1.35))
|
|
|
|
@property
|
|
@lazy
|
|
def score_disputed(self):
|
|
return (self.upvotes+1) * (self.downvotes+1)
|
|
|
|
@property
|
|
def is_repost(self):
|
|
return bool(self.repost_id)
|
|
|
|
@property
|
|
def is_archived(self):
|
|
return false
|
|
|
|
@property
|
|
@lazy
|
|
def fullname(self):
|
|
return f"t2_{self.base36id}"
|
|
|
|
@property
|
|
@lazy
|
|
def permalink(self):
|
|
|
|
output = self.title.lower()
|
|
|
|
output = re.sub('&\w{2,3};', '', output)
|
|
|
|
output = [re.sub('\W', '', word) for word in output.split()]
|
|
output = [x for x in output if x][0:6]
|
|
|
|
output = '-'.join(output)
|
|
|
|
if not output:
|
|
output = '-'
|
|
|
|
return f"/post/{self.id}/{output}"
|
|
|
|
@property
|
|
def is_archived(self):
|
|
|
|
now = int(time.time())
|
|
|
|
cutoff = now - (60 * 60 * 24 * 180)
|
|
|
|
return self.created_utc < cutoff
|
|
|
|
def rendered_page(self, sort=None, comment=None, comment_info=None, v=None):
|
|
|
|
# check for banned
|
|
if v and v.admin_level >= 3:
|
|
template = "submission.html"
|
|
elif self.is_banned:
|
|
template = "submission_banned.html"
|
|
else:
|
|
template = "submission.html"
|
|
|
|
# load and tree comments
|
|
# calling this function with a comment object will do a comment
|
|
# permalink thing
|
|
if "replies" not in self.__dict__ and "_preloaded_comments" in self.__dict__:
|
|
self.tree_comments(comment=comment)
|
|
|
|
return render_template(template,
|
|
v=v,
|
|
p=self,
|
|
sort=sort,
|
|
linked_comment=comment,
|
|
comment_info=comment_info,
|
|
render_replies=True,
|
|
)
|
|
|
|
@property
|
|
@lazy
|
|
def domain(self):
|
|
|
|
if not self.url:
|
|
return "text post"
|
|
domain = urlparse(self.url).netloc
|
|
if domain.startswith("www."):
|
|
domain = domain.split("www.")[1]
|
|
return domain.replace("old.reddit.com", "reddit.com")
|
|
|
|
def tree_comments(self, comment=None, v=None):
|
|
|
|
comments = self.__dict__.get('_preloaded_comments',[])
|
|
if not comments:
|
|
return
|
|
|
|
pinned_comment=[]
|
|
|
|
index = {}
|
|
for c in comments:
|
|
|
|
if c.is_pinned and c.parent_fullname==self.fullname:
|
|
pinned_comment+=[c]
|
|
continue
|
|
|
|
if c.parent_fullname in index:
|
|
index[c.parent_fullname].append(c)
|
|
else:
|
|
index[c.parent_fullname] = [c]
|
|
|
|
for c in comments:
|
|
c.__dict__["replies"] = index.get(c.fullname, [])
|
|
|
|
if comment:
|
|
self.__dict__["replies"] = [comment]
|
|
else:
|
|
self.__dict__["replies"] = pinned_comment + index.get(self.fullname, [])
|
|
|
|
@property
|
|
def active_flags(self):
|
|
if self.is_approved:
|
|
return 0
|
|
else:
|
|
return len(self.flags)
|
|
|
|
@property
|
|
#@lazy
|
|
def thumb_url(self):
|
|
|
|
if self.over_18: return f"/assets/images/nsfw.png"
|
|
elif self.has_thumb:
|
|
if self.thumburl: return self.thumburl
|
|
else: return f"https://s3.eu-central-1.amazonaws.com/i.ruqqus.ga/posts/{self.base36id}/thumb.png"
|
|
elif self.is_image:
|
|
return self.url
|
|
else:
|
|
return None
|
|
|
|
@property
|
|
|
|
def json_raw(self):
|
|
data = {'author_name': self.author.username,
|
|
'permalink': self.permalink,
|
|
'is_banned': bool(self.is_banned),
|
|
'deleted_utc': self.deleted_utc,
|
|
'created_utc': self.created_utc,
|
|
'id': self.base36id,
|
|
'fullname': self.fullname,
|
|
'title': self.title,
|
|
'is_nsfw': self.over_18,
|
|
'is_bot': self.is_bot,
|
|
'thumb_url': self.thumb_url,
|
|
'domain': self.domain,
|
|
'is_archived': self.is_archived,
|
|
'url': self.url,
|
|
'body': self.body,
|
|
'body_html': self.body_html,
|
|
'created_utc': self.created_utc,
|
|
'edited_utc': self.edited_utc or 0,
|
|
'comment_count': self.comment_count,
|
|
'score': self.score_fuzzed,
|
|
'upvotes': self.upvotes_fuzzed,
|
|
'downvotes': self.downvotes_fuzzed,
|
|
#'award_count': self.award_count,
|
|
'meta_title': self.meta_title,
|
|
'meta_description': self.meta_description,
|
|
'voted': self.voted
|
|
}
|
|
if self.ban_reason:
|
|
data["ban_reason"]=self.ban_reason
|
|
|
|
return data
|
|
|
|
@property
|
|
def json_core(self):
|
|
|
|
if self.is_banned:
|
|
return {'is_banned': True,
|
|
'deleted_utc': self.deleted_utc,
|
|
'ban_reason': self.ban_reason,
|
|
'id': self.base36id,
|
|
'title': self.title,
|
|
'permalink': self.permalink,
|
|
}
|
|
elif self.deleted_utc:
|
|
return {'is_banned': bool(self.is_banned),
|
|
'deleted_utc': True,
|
|
'id': self.base36id,
|
|
'title': self.title,
|
|
'permalink': self.permalink,
|
|
}
|
|
|
|
return self.json_raw
|
|
|
|
@property
|
|
def json(self):
|
|
|
|
data=self.json_core
|
|
|
|
if self.deleted_utc > 0 or self.is_banned:
|
|
return data
|
|
|
|
data["author"]=self.author.json_core
|
|
data["comment_count"]=self.comment_count
|
|
|
|
|
|
if "replies" in self.__dict__:
|
|
data["replies"]=[x.json_core for x in self.replies]
|
|
|
|
if "_voted" in self.__dict__:
|
|
data["voted"] = self._voted
|
|
|
|
return data
|
|
|
|
@property
|
|
def voted(self):
|
|
return self._voted if "_voted" in self.__dict__ else 0
|
|
|
|
@property
|
|
def user_title(self):
|
|
return self._title if "_title" in self.__dict__ else self.author.title
|
|
|
|
@property
|
|
def title(self):
|
|
return self.submission_aux.title
|
|
|
|
@title.setter
|
|
def title(self, x):
|
|
self.submission_aux.title = x
|
|
g.db.add(self.submission_aux)
|
|
|
|
@property
|
|
def url(self):
|
|
return self.submission_aux.url
|
|
|
|
@url.setter
|
|
def url(self, x):
|
|
self.submission_aux.url = x
|
|
g.db.add(self.submission_aux)
|
|
|
|
def realurl(self, v):
|
|
if v and v.agendaposter and random.randint(1, 10) < 4:
|
|
return 'https://secure.actblue.com/donate/ms_blm_homepage_2019'
|
|
elif self.url:
|
|
if v and not v.oldreddit: return self.url.replace("old.reddit.com", "reddit.com")
|
|
if self.url: return self.url
|
|
return ""
|
|
|
|
@property
|
|
def body(self):
|
|
return self.submission_aux.body
|
|
|
|
@body.setter
|
|
def body(self, x):
|
|
self.submission_aux.body = x
|
|
g.db.add(self.submission_aux)
|
|
|
|
@property
|
|
def body_html(self):
|
|
return self.submission_aux.body_html
|
|
|
|
@body_html.setter
|
|
def body_html(self, x):
|
|
self.submission_aux.body_html = x
|
|
g.db.add(self.submission_aux)
|
|
|
|
def realbody(self, v):
|
|
body = self.submission_aux.body_html
|
|
if not v or v.slurreplacer: body = body.replace(" nigger"," 🏀").replace(" Nigger"," 🏀").replace(" NIGGER"," 🏀").replace(" pedo"," libertarian").replace(" Pedo"," Libertarian ").replace(" PEDO"," LIBERTARIAN ").replace(" tranny"," 🚄").replace(" Tranny"," 🚄").replace(" TRANNY"," 🚄").replace(" fag"," cute twink").replace(" Fag"," Cute twink").replace(" FAG"," CUTE TWINK").replace(" faggot"," cute twink").replace(" Faggot"," Cute twink").replace(" FAGGOT"," CUTE TWINK").replace(" trump"," DDR").replace(" Trump"," DDR").replace(" TRUMP"," DDR").replace(" biden"," DDD").replace(" Biden"," DDD").replace(" BIDEN"," DDD").replace(" steve akins"," penny verity oaken").replace(" Steve Akins"," Penny Verity Oaken").replace(" STEVE AKINS"," PENNY VERITY OAKEN").replace(" RETARD"," RSLUR").replace(" rapist"," male feminist").replace(" Rapist"," Male feminist").replace(" RAPIST"," MALE FEMINIST").replace(" RETARD"," RSLUR").replace(" rapist"," male feminist").replace(" Rapist"," Male feminist").replace(" RAPIST"," MALE FEMINIST").replace(" RETARD"," RSLUR").replace(" rapist"," male feminist").replace(" Rapist"," Male feminist").replace(" RAPIST"," MALE FEMINIST").replace(" kill yourself"," keep yourself safe").replace(" KILL YOURSELF"," KEEP YOURSELF SAFE")
|
|
if v and not v.oldreddit: body = body.replace("old.reddit.com", "reddit.com")
|
|
return body
|
|
|
|
@property
|
|
def title_html(self):
|
|
return self.submission_aux.title_html
|
|
|
|
@title_html.setter
|
|
def title_html(self, x):
|
|
self.submission_aux.title_html = x
|
|
g.db.add(self.submission_aux)
|
|
|
|
def realtitle(self, v):
|
|
if self.title_html: title = self.title_html
|
|
else: title = self.title
|
|
if not v or v.slurreplacer: title = title.replace(" nigger"," 🏀").replace(" Nigger"," 🏀").replace(" NIGGER"," 🏀").replace(" pedo"," libertarian").replace(" Pedo"," Libertarian ").replace(" PEDO"," LIBERTARIAN ").replace(" tranny"," 🚄").replace(" Tranny"," 🚄").replace(" TRANNY"," 🚄").replace(" fag"," cute twink").replace(" Fag"," Cute twink").replace(" FAG"," CUTE TWINK").replace(" faggot"," cute twink").replace(" Faggot"," Cute twink").replace(" FAGGOT"," CUTE TWINK").replace(" trump"," DDR").replace(" Trump"," DDR").replace(" TRUMP"," DDR").replace(" biden"," DDD").replace(" Biden"," DDD").replace(" BIDEN"," DDD").replace(" steve akins"," penny verity oaken").replace(" Steve Akins"," Penny Verity Oaken").replace(" STEVE AKINS"," PENNY VERITY OAKEN").replace(" RETARD"," RSLUR").replace(" rapist"," male feminist").replace(" Rapist"," Male feminist").replace(" RAPIST"," MALE FEMINIST").replace(" RETARD"," RSLUR").replace(" rapist"," male feminist").replace(" Rapist"," Male feminist").replace(" RAPIST"," MALE FEMINIST").replace(" RETARD"," RSLUR").replace(" rapist"," male feminist").replace(" Rapist"," Male feminist").replace(" RAPIST"," MALE FEMINIST").replace(" kill yourself"," keep yourself safe").replace(" KILL YOURSELF"," KEEP YOURSELF SAFE")
|
|
return title
|
|
|
|
@property
|
|
def ban_reason(self):
|
|
return self.submission_aux.ban_reason
|
|
|
|
@ban_reason.setter
|
|
def ban_reason(self, x):
|
|
self.submission_aux.ban_reason = x
|
|
g.db.add(self.submission_aux)
|
|
|
|
@property
|
|
def embed_url(self):
|
|
return self.submission_aux.embed_url
|
|
|
|
@embed_url.setter
|
|
def embed_url(self, x):
|
|
self.submission_aux.embed_url = x
|
|
g.db.add(self.submission_aux)
|
|
|
|
@property
|
|
def meta_title(self):
|
|
return self.submission_aux.meta_title
|
|
|
|
@meta_title.setter
|
|
def meta_title(self, x):
|
|
self.submission_aux.meta_title=x
|
|
g.db.add(self.submission_aux)
|
|
|
|
@property
|
|
def meta_description(self):
|
|
return self.submission_aux.meta_description
|
|
|
|
@meta_description.setter
|
|
def meta_description(self, x):
|
|
self.submission_aux.meta_description=x
|
|
g.db.add(self.submission_aux)
|
|
|
|
@property
|
|
def is_blocked(self):
|
|
return self.__dict__.get('_is_blocked', False)
|
|
|
|
@property
|
|
def is_blocking(self):
|
|
return self.__dict__.get('_is_blocking', False)
|
|
|
|
@property
|
|
def flag_count(self):
|
|
return len(self.flags)
|
|
|
|
@property
|
|
def report_count(self):
|
|
return len(self.reports)
|
|
|
|
#@property
|
|
#def award_count(self):
|
|
#return len(self.awards)
|
|
|
|
@property
|
|
def embed_template(self):
|
|
return f"site_embeds/{self.domain_obj.embed_template}.html"
|
|
|
|
@property
|
|
def flagged_by(self):
|
|
return [x.user for x in self.flags]
|
|
|
|
@property
|
|
def is_image(self):
|
|
if self.url: return self.url.endswith('jpg') or self.url.endswith('png') or self.url.endswith('.gif') or self.url.endswith('jpeg') or self.url.endswith('?maxwidth=9999') or self.url.endswith('?maxwidth=8888')
|
|
else: return False
|
|
|
|
@property
|
|
def self_download_json(self):
|
|
|
|
#This property should never be served to anyone but author and admin
|
|
if not self.is_banned and self.deleted_utc == 0:
|
|
return self.json_core
|
|
|
|
data= {
|
|
"title":self.title,
|
|
"author": self.author.username,
|
|
"url": self.url,
|
|
"body": self.body,
|
|
"body_html": self.body_html,
|
|
"is_banned": bool(self.is_banned),
|
|
"deleted_utc": self.deleted_utc,
|
|
'created_utc': self.created_utc,
|
|
'id': self.base36id,
|
|
'fullname': self.fullname,
|
|
'comment_count': self.comment_count,
|
|
'permalink': self.permalink
|
|
}
|
|
|
|
return data
|
|
|
|
@property
|
|
def json_admin(self):
|
|
|
|
data=self.json_raw
|
|
|
|
data["creation_ip"]=self.creation_ip
|
|
data["creation_region"]=self.creation_region
|
|
|
|
return data
|
|
|
|
@property
|
|
def is_exiled_for(self):
|
|
return self.__dict__.get('_is_exiled_for', None)
|
|
|
|
|
|
|
|
class SaveRelationship(Base, Stndrd):
|
|
|
|
__tablename__="save_relationship"
|
|
|
|
id=Column(Integer, primary_key=true)
|
|
user_id=Column(Integer, ForeignKey("users.id"))
|
|
submission_id=Column(Integer, ForeignKey("submissions.id"))
|
|
type=Column(Integer)
|