
Ported in from upstream with adjustments for TheMotte, most notably universal default to 'new' and fixes to 'hot'. Lumped into this PR because eager comment loading uses it.
648 lines
20 KiB
Python
648 lines
20 KiB
Python
from sqlalchemy.orm import deferred, aliased
|
|
from secrets import token_hex
|
|
import pyotp
|
|
from files.helpers.images import *
|
|
from files.helpers.const import *
|
|
from .alts import Alt
|
|
from .saves import *
|
|
from .notifications import Notification
|
|
from .award import AwardRelationship
|
|
from .follows import *
|
|
from .subscriptions import *
|
|
from .userblock import *
|
|
from .badges import *
|
|
from .clients import *
|
|
from .mod_logs import *
|
|
from .mod import *
|
|
from .exiles import *
|
|
from .sub_block import *
|
|
from files.__main__ import app, Base, cache
|
|
from files.helpers.security import *
|
|
from files.helpers.assetcache import assetcache_path
|
|
from files.helpers.contentsorting import apply_time_filter, sort_objects
|
|
import random
|
|
from datetime import datetime
|
|
from os import environ, remove, path
|
|
|
|
|
|
defaulttheme = "TheMotte"
|
|
defaulttimefilter = environ.get("DEFAULT_TIME_FILTER", "all").strip()
|
|
cardview = bool(int(environ.get("CARD_VIEW", 1)))
|
|
|
|
class User(Base):
|
|
__tablename__ = "users"
|
|
__table_args__ = (
|
|
UniqueConstraint('bannerurl', name='one_banner'),
|
|
UniqueConstraint('id', name='uid_unique'),
|
|
UniqueConstraint('original_username', name='users_original_username_key'),
|
|
UniqueConstraint('username', name='users_username_key'),
|
|
)
|
|
id = Column(Integer, primary_key=True)
|
|
username = Column(String(length=255), nullable=False)
|
|
namecolor = Column(String(length=6), default=DEFAULT_COLOR, nullable=False)
|
|
background = Column(String)
|
|
customtitle = Column(String)
|
|
customtitleplain = deferred(Column(String))
|
|
titlecolor = Column(String(length=6), default=DEFAULT_COLOR, nullable=False)
|
|
theme = Column(String, default=defaulttheme, nullable=False)
|
|
themecolor = Column(String, default=DEFAULT_COLOR, nullable=False)
|
|
cardview = Column(Boolean, default=cardview, nullable=False)
|
|
song = Column(String)
|
|
highres = Column(String)
|
|
profileurl = Column(String)
|
|
bannerurl = Column(String)
|
|
house = Column(String)
|
|
patron = Column(Integer, default=0, nullable=False)
|
|
patron_utc = Column(Integer, default=0, nullable=False)
|
|
verified = Column(String)
|
|
verifiedcolor = Column(String)
|
|
winnings = Column(Integer, default=0, nullable=False)
|
|
email = deferred(Column(String))
|
|
css = deferred(Column(String))
|
|
profilecss = deferred(Column(String))
|
|
passhash = deferred(Column(String, nullable=False))
|
|
post_count = Column(Integer, default=0, nullable=False)
|
|
comment_count = Column(Integer, default=0, nullable=False)
|
|
received_award_count = Column(Integer, default=0, nullable=False)
|
|
created_utc = Column(Integer, nullable=False)
|
|
admin_level = Column(Integer, default=0, nullable=False)
|
|
coins_spent = Column(Integer, default=0, nullable=False)
|
|
lootboxes_bought = Column(Integer, default=0, nullable=False)
|
|
agendaposter = Column(Integer, default=0, nullable=False)
|
|
changelogsub = Column(Boolean, default=False, nullable=False)
|
|
is_activated = Column(Boolean, default=False, nullable=False)
|
|
shadowbanned = Column(String)
|
|
over_18 = Column(Boolean, default=False, nullable=False)
|
|
hidevotedon = Column(Boolean, default=False, nullable=False)
|
|
highlightcomments = Column(Boolean, default=True, nullable=False)
|
|
slurreplacer = Column(Boolean, default=True, nullable=False)
|
|
flairchanged = Column(Integer)
|
|
newtab = Column(Boolean, default=False, nullable=False)
|
|
newtabexternal = Column(Boolean, default=True, nullable=False)
|
|
reddit = Column(String, default='old.reddit.com', nullable=False)
|
|
nitter = Column(Boolean)
|
|
frontsize = Column(Integer, default=25, nullable=False)
|
|
controversial = Column(Boolean, default=False, nullable=False)
|
|
bio = deferred(Column(String))
|
|
bio_html = Column(String)
|
|
fp = Column(String)
|
|
friends = deferred(Column(String))
|
|
friends_html = deferred(Column(String))
|
|
enemies = deferred(Column(String))
|
|
enemies_html = deferred(Column(String))
|
|
is_banned = Column(Integer, default=0, nullable=False)
|
|
unban_utc = Column(Integer, default=0, nullable=False)
|
|
ban_reason = deferred(Column(String))
|
|
club_allowed = Column(Boolean)
|
|
login_nonce = Column(Integer, default=0, nullable=False)
|
|
reserved = deferred(Column(String))
|
|
coins = Column(Integer, default=0, nullable=False)
|
|
truecoins = Column(Integer, default=0, nullable=False)
|
|
procoins = Column(Integer, default=0, nullable=False)
|
|
mfa_secret = deferred(Column(String))
|
|
is_private = Column(Boolean, default=False, nullable=False)
|
|
stored_subscriber_count = Column(Integer, default=0, nullable=False)
|
|
defaultsortingcomments = Column(String, default="new", nullable=False)
|
|
defaultsorting = Column(String, default="new", nullable=False)
|
|
defaulttime = Column(String, default=defaulttimefilter, nullable=False)
|
|
is_nofollow = Column(Boolean, default=False, nullable=False)
|
|
custom_filter_list = Column(String)
|
|
ban_evade = Column(Integer, default=0, nullable=False)
|
|
original_username = deferred(Column(String))
|
|
referred_by = Column(Integer, ForeignKey("users.id"))
|
|
subs_created = Column(Integer, default=0, nullable=False)
|
|
|
|
Index(
|
|
'users_original_username_trgm_idx',
|
|
original_username,
|
|
postgresql_using='gin',
|
|
postgresql_ops={'description':'gin_trgm_ops'}
|
|
)
|
|
Index(
|
|
'users_username_trgm_idx',
|
|
username,
|
|
postgresql_using='gin',
|
|
postgresql_ops={'description':'gin_trgm_ops'}
|
|
)
|
|
|
|
Index('fki_user_referrer_fkey', referred_by)
|
|
Index('user_banned_idx', is_banned)
|
|
Index('user_private_idx', is_private)
|
|
Index('users_created_utc_index', created_utc)
|
|
Index('users_subs_idx', stored_subscriber_count)
|
|
Index('users_unbanutc_idx', unban_utc.desc())
|
|
|
|
badges = relationship("Badge", 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)
|
|
notes = relationship("UserNote", foreign_keys='UserNote.reference_user', back_populates="user")
|
|
|
|
def __init__(self, **kwargs):
|
|
|
|
if "password" in kwargs:
|
|
kwargs["passhash"] = self.hash_password(kwargs["password"])
|
|
kwargs.pop("password")
|
|
|
|
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())
|
|
|
|
super().__init__(**kwargs)
|
|
|
|
|
|
def can_manage_reports(self):
|
|
return self.admin_level > 1
|
|
|
|
def should_comments_be_filtered(self):
|
|
if self.admin_level > 0:
|
|
return False
|
|
site_settings = app.config['SETTINGS']
|
|
minComments = site_settings.get('FilterCommentsMinComments', 0)
|
|
minKarma = site_settings.get('FilterCommentsMinKarma', 0)
|
|
minAge = site_settings.get('FilterCommentsMinAgeDays', 0)
|
|
accountAgeDays = (datetime.now() - datetime.fromtimestamp(self.created_utc)).days
|
|
return self.comment_count < minComments or accountAgeDays < minAge or self.truecoins < minKarma
|
|
|
|
@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())
|
|
|
|
@lazy
|
|
def exiled_from(self, sub):
|
|
return self.admin_level < 2 and bool(g.db.query(Exile.user_id).filter_by(user_id=self.id, sub=sub).one_or_none())
|
|
|
|
@property
|
|
@lazy
|
|
def all_blocks(self):
|
|
return [x[0] for x in g.db.query(SubBlock.sub).filter_by(user_id=self.id).all()]
|
|
|
|
@lazy
|
|
def blocks(self, sub):
|
|
return g.db.query(SubBlock).filter_by(user_id=self.id, sub=sub).one_or_none()
|
|
|
|
@lazy
|
|
def mod_date(self, sub):
|
|
if self.id == OWNER_ID: return 1
|
|
mod = g.db.query(Mod).filter_by(user_id=self.id, sub=sub).one_or_none()
|
|
if not mod: return None
|
|
return mod.created_utc
|
|
|
|
@property
|
|
@lazy
|
|
def csslazy(self):
|
|
return self.css
|
|
|
|
@property
|
|
@lazy
|
|
def created_date(self):
|
|
|
|
return time.strftime("%d %b %Y", time.gmtime(self.created_utc))
|
|
|
|
@property
|
|
@lazy
|
|
def discount(self):
|
|
if self.patron == 1: discount = 0.90
|
|
elif self.patron == 2: discount = 0.85
|
|
elif self.patron == 3: discount = 0.80
|
|
elif self.patron == 4: discount = 0.75
|
|
elif self.patron == 5: discount = 0.70
|
|
elif self.patron == 6: discount = 0.65
|
|
else: discount = 1
|
|
|
|
for badge in [69,70,71,72,73]:
|
|
if self.has_badge(badge): discount -= discounts[badge]
|
|
|
|
return discount
|
|
|
|
|
|
@property
|
|
@lazy
|
|
def user_awards(self):
|
|
|
|
return_value = list(AWARDS2.values())
|
|
|
|
user_awards = g.db.query(AwardRelationship).filter_by(user_id=self.id)
|
|
|
|
for val in return_value: val['owned'] = user_awards.filter_by(kind=val['kind'], submission_id=None, comment_id=None).count()
|
|
|
|
return return_value
|
|
|
|
@property
|
|
def referral_count(self):
|
|
return len(self.referrals)
|
|
|
|
def is_blocking(self, target):
|
|
return g.db.query(UserBlock).filter_by(user_id=self.id, target_id=target.id).one_or_none()
|
|
|
|
@property
|
|
@lazy
|
|
def paid_dues(self):
|
|
return not self.shadowbanned and not (self.is_banned and not self.unban_utc) and (self.admin_level or self.club_allowed or (self.club_allowed != False and self.truecoins > dues))
|
|
|
|
@lazy
|
|
def any_block_exists(self, other):
|
|
|
|
return g.db.query(UserBlock).filter(
|
|
or_(and_(UserBlock.user_id == self.id, UserBlock.target_id == other.id), and_(
|
|
UserBlock.user_id == other.id, UserBlock.target_id == self.id))).first()
|
|
|
|
def validate_2fa(self, token):
|
|
|
|
x = pyotp.TOTP(self.mfa_secret)
|
|
return x.verify(token, valid_window=1)
|
|
|
|
@property
|
|
@lazy
|
|
def age(self):
|
|
return int(time.time()) - self.created_utc
|
|
|
|
@property
|
|
@lazy
|
|
def ban_reason_link(self):
|
|
if self.ban_reason:
|
|
if self.ban_reason.startswith("/post/"): return self.ban_reason.split(None, 1)[0]
|
|
if self.ban_reason.startswith("/comment/"): return self.ban_reason.split(None, 1)[0] + "?context=8#context"
|
|
|
|
@property
|
|
@lazy
|
|
def alts_unique(self):
|
|
alts = []
|
|
for u in self.alts:
|
|
if u not in alts: alts.append(u)
|
|
return alts
|
|
|
|
@property
|
|
@lazy
|
|
def alts_patron(self):
|
|
for u in self.alts_unique:
|
|
if u.patron: return True
|
|
return False
|
|
|
|
@cache.memoize(timeout=86400)
|
|
def userpagelisting(self, site=None, v=None, page=1, sort="new", t="all"):
|
|
|
|
if self.shadowbanned and not (v and (v.admin_level > 1 or v.id == self.id)): return []
|
|
|
|
posts = g.db.query(Submission.id).filter_by(author_id=self.id, is_pinned=False)
|
|
|
|
if not (v and (v.admin_level > 1 or v.id == self.id)):
|
|
posts = posts.filter_by(deleted_utc=0, is_banned=False, private=False, ghost=False)
|
|
|
|
posts = apply_time_filter(posts, t, Submission)
|
|
posts = sort_objects(posts, sort, Submission)
|
|
|
|
posts = posts.offset(25 * (page - 1)).limit(26).all()
|
|
|
|
return [x[0] for x in posts]
|
|
|
|
@property
|
|
@lazy
|
|
def follow_count(self):
|
|
return g.db.query(Follow.target_id).filter_by(user_id=self.id).count()
|
|
|
|
@property
|
|
@lazy
|
|
def bio_html_eager(self):
|
|
if self.bio_html == None: return ''
|
|
return self.bio_html.replace('data-src', 'src').replace('src="/assets/images/loading.webp"', '')
|
|
|
|
@property
|
|
@lazy
|
|
def fullname(self):
|
|
return f"t1_{self.id}"
|
|
|
|
@property
|
|
@lazy
|
|
def banned_by(self):
|
|
if not self.is_suspended: return None
|
|
return g.db.query(User).filter_by(id=self.is_banned).one_or_none()
|
|
|
|
def has_badge(self, badge_id):
|
|
return g.db.query(Badge).filter_by(user_id=self.id, badge_id=badge_id).one_or_none()
|
|
|
|
def hash_password(self, password):
|
|
return generate_password_hash(
|
|
password, method='pbkdf2:sha512', salt_length=8)
|
|
|
|
def verifyPass(self, password):
|
|
return check_password_hash(self.passhash, password)
|
|
|
|
@property
|
|
@lazy
|
|
def formkey(self):
|
|
|
|
msg = f"{session['session_id']}+{self.id}+{self.login_nonce}"
|
|
|
|
return generate_hash(msg)
|
|
|
|
def validate_formkey(self, formkey):
|
|
|
|
return validate_hash(f"{session['session_id']}+{self.id}+{self.login_nonce}", formkey)
|
|
|
|
@property
|
|
@lazy
|
|
def url(self):
|
|
return f"/@{self.username}"
|
|
|
|
def __repr__(self):
|
|
return f"<User(id={self.id})>"
|
|
|
|
@property
|
|
@lazy
|
|
def unban_string(self):
|
|
if self.unban_utc == 0:
|
|
return "permanently banned"
|
|
|
|
wait = self.unban_utc - int(time.time())
|
|
|
|
if wait < 60:
|
|
text = f"{wait}s"
|
|
else:
|
|
days = wait//(24*60*60)
|
|
wait -= days*24*60*60
|
|
|
|
hours = wait//(60*60)
|
|
wait -= hours*60*60
|
|
|
|
mins = wait//60
|
|
|
|
text = f"{days}d {hours:02d}h {mins:02d}m"
|
|
|
|
return f"Unban in {text}"
|
|
|
|
|
|
@property
|
|
@lazy
|
|
def received_awards(self):
|
|
|
|
awards = {}
|
|
|
|
posts_idlist = [x[0] for x in g.db.query(Submission.id).filter_by(author_id=self.id).all()]
|
|
comments_idlist = [x[0] for x in g.db.query(Comment.id).filter_by(author_id=self.id).all()]
|
|
|
|
post_awards = g.db.query(AwardRelationship).filter(AwardRelationship.submission_id.in_(posts_idlist)).all()
|
|
comment_awards = g.db.query(AwardRelationship).filter(AwardRelationship.comment_id.in_(comments_idlist)).all()
|
|
|
|
total_awards = post_awards + comment_awards
|
|
|
|
for a in total_awards:
|
|
if a.kind in awards:
|
|
awards[a.kind]['count'] += 1
|
|
else:
|
|
awards[a.kind] = a.type
|
|
awards[a.kind]['count'] = 1
|
|
|
|
return sorted(list(awards.values()), key=lambda x: x['kind'], reverse=True)
|
|
|
|
@property
|
|
@lazy
|
|
def modaction_num(self):
|
|
if self.admin_level < 2: return 0
|
|
return g.db.query(ModAction.id).filter_by(user_id=self.id).count()
|
|
|
|
@property
|
|
@lazy
|
|
def notifications_count(self):
|
|
notifs = g.db.query(Notification.user_id).join(Comment).filter(Notification.user_id == self.id, Notification.read == False, Comment.is_banned == False, Comment.deleted_utc == 0)
|
|
|
|
if not self.shadowbanned and self.admin_level < 3:
|
|
notifs = notifs.join(User, User.id == Comment.author_id).filter(User.shadowbanned == None)
|
|
|
|
return notifs.count()
|
|
|
|
@property
|
|
@lazy
|
|
def post_notifications_count(self):
|
|
return g.db.query(Notification.user_id).join(Comment).filter(Notification.user_id == self.id, Notification.read == False, Comment.author_id == AUTOJANNY_ID).count()
|
|
|
|
@property
|
|
@lazy
|
|
def reddit_notifications_count(self):
|
|
return g.db.query(Notification.user_id).join(Comment).filter(Notification.user_id == self.id, Notification.read == False, Comment.is_banned == False, Comment.deleted_utc == 0, Comment.body_html.like('%<p>New site mention: <a href="https://old.reddit.com/r/%'), Comment.parent_submission == None, Comment.author_id == NOTIFICATIONS_ID).count()
|
|
|
|
@property
|
|
@lazy
|
|
def normal_count(self):
|
|
return self.notifications_count - self.post_notifications_count - self.reddit_notifications_count
|
|
|
|
@property
|
|
@lazy
|
|
def do_posts(self):
|
|
return self.post_notifications_count and self.notifications_count-self.reddit_notifications_count == self.post_notifications_count
|
|
|
|
@property
|
|
@lazy
|
|
def do_reddit(self):
|
|
return self.notifications_count == self.reddit_notifications_count
|
|
|
|
@property
|
|
@lazy
|
|
def alts(self):
|
|
|
|
subq = g.db.query(Alt).filter(
|
|
or_(
|
|
Alt.user1 == self.id,
|
|
Alt.user2 == self.id
|
|
)
|
|
).subquery()
|
|
|
|
data = g.db.query(
|
|
User,
|
|
aliased(Alt, alias=subq)
|
|
).join(
|
|
subq,
|
|
or_(
|
|
subq.c.user1 == User.id,
|
|
subq.c.user2 == User.id
|
|
)
|
|
).filter(
|
|
User.id != self.id
|
|
).order_by(User.username).all()
|
|
|
|
data = [x for x in data]
|
|
output = []
|
|
for x in data:
|
|
user = x[0]
|
|
user._is_manual = x[1].is_manual
|
|
output.append(user)
|
|
|
|
return output
|
|
|
|
@property
|
|
@lazy
|
|
def moderated_subs(self):
|
|
modded_subs = g.db.query(Mod.sub).filter_by(user_id=self.id).all()
|
|
return modded_subs
|
|
|
|
def has_follower(self, user):
|
|
|
|
return g.db.query(Follow).filter_by(target_id=self.id, user_id=user.id).one_or_none()
|
|
|
|
@property
|
|
@lazy
|
|
def banner_url(self):
|
|
if self.bannerurl:
|
|
return self.bannerurl
|
|
return assetcache_path(f'images/{SITE_ID}/site_preview.webp')
|
|
|
|
@property
|
|
@lazy
|
|
def profile_url(self):
|
|
if self.profileurl:
|
|
if self.profileurl.startswith('/'):
|
|
return SITE_FULL + self.profileurl
|
|
return self.profileurl
|
|
return assetcache_path('images/default-profile-pic.webp')
|
|
|
|
@lazy
|
|
def json_popover(self, v):
|
|
data = {'username': self.username,
|
|
'url': self.url,
|
|
'id': self.id,
|
|
'profile_url': self.profile_url,
|
|
'bannerurl': self.banner_url,
|
|
'bio_html': self.bio_html_eager,
|
|
'post_count': 0 if self.shadowbanned and not (v and (v.shadowbanned or v.admin_level > 1)) else self.post_count,
|
|
'comment_count': 0 if self.shadowbanned and not (v and (v.shadowbanned or v.admin_level > 1)) else self.comment_count,
|
|
'badges': [x.path for x in self.badges],
|
|
}
|
|
|
|
return data
|
|
|
|
@lazy
|
|
def json_notes(self, v):
|
|
data = {'username': self.username,
|
|
'url': self.url,
|
|
'id': self.id,
|
|
'notes': [x.json() for x in self.notes]
|
|
}
|
|
|
|
return data
|
|
|
|
@property
|
|
@lazy
|
|
def json_raw(self):
|
|
data = {'username': self.username,
|
|
'url': self.url,
|
|
'is_banned': bool(self.is_banned),
|
|
'created_utc': self.created_utc,
|
|
'id': self.id,
|
|
'is_private': self.is_private,
|
|
'profile_url': self.profile_url,
|
|
'bannerurl': self.banner_url,
|
|
'bio': self.bio,
|
|
'bio_html': self.bio_html_eager,
|
|
'flair': self.customtitle
|
|
}
|
|
|
|
return data
|
|
|
|
@property
|
|
@lazy
|
|
def json_core(self):
|
|
|
|
now = int(time.time())
|
|
if self.is_suspended:
|
|
return {'username': self.username,
|
|
'url': self.url,
|
|
'is_banned': True,
|
|
'is_permanent_ban': not bool(self.unban_utc),
|
|
'ban_reason': self.ban_reason,
|
|
'id': self.id
|
|
}
|
|
return self.json_raw
|
|
|
|
@property
|
|
@lazy
|
|
def json(self):
|
|
data = self.json_core
|
|
|
|
data["badges"] = [x.json for x in self.badges]
|
|
data['coins'] = self.coins
|
|
data['post_count'] = self.post_count
|
|
data['comment_count'] = self.comment_count
|
|
|
|
return data
|
|
|
|
|
|
def ban(self, admin=None, reason=None, days=0):
|
|
if days:
|
|
self.unban_utc = int(time.time()) + (days * 86400)
|
|
g.db.add(self)
|
|
|
|
self.is_banned = admin.id if admin else AUTOJANNY_ID
|
|
if reason: self.ban_reason = reason
|
|
|
|
|
|
|
|
@property
|
|
def is_suspended(self):
|
|
return (self.is_banned and (self.unban_utc == 0 or self.unban_utc > time.time()))
|
|
|
|
@property
|
|
def is_suspended_permanently(self):
|
|
return (self.is_banned and self.unban_utc == 0)
|
|
|
|
@property
|
|
@lazy
|
|
def applications(self):
|
|
return g.db.query(OauthApp).filter_by(author_id=self.id).order_by(OauthApp.id)
|
|
|
|
@property
|
|
@lazy
|
|
def created_datetime(self):
|
|
return str(time.strftime("%d/%B/%Y %H:%M:%S UTC", time.gmtime(self.created_utc)))
|
|
|
|
@lazy
|
|
def subscribed_idlist(self, page=1):
|
|
posts = g.db.query(Subscription.submission_id).filter_by(user_id=self.id).all()
|
|
return [x[0] for x in posts]
|
|
|
|
@property
|
|
@lazy
|
|
def userblocks(self):
|
|
return [x[0] for x in g.db.query(UserBlock.target_id).filter_by(user_id=self.id).all()] + [x[0] for x in g.db.query(UserBlock.user_id).filter_by(target_id=self.id).all()]
|
|
|
|
@lazy
|
|
def saved_idlist(self, page=1):
|
|
|
|
saved = [x[0] for x in g.db.query(SaveRelationship.submission_id).filter_by(user_id=self.id).all()]
|
|
posts = g.db.query(Submission.id).filter(Submission.id.in_(saved), Submission.is_banned == False, Submission.deleted_utc == 0)
|
|
|
|
if self.admin_level < 2:
|
|
posts = posts.filter(Submission.author_id.notin_(self.userblocks))
|
|
|
|
return [x[0] for x in posts.order_by(Submission.created_utc.desc()).offset(25 * (page - 1)).all()]
|
|
|
|
@lazy
|
|
def saved_comment_idlist(self, page=1):
|
|
|
|
saved = [x[0] for x in g.db.query(CommentSaveRelationship.comment_id).filter_by(user_id=self.id).all()]
|
|
comments = g.db.query(Comment.id).filter(Comment.id.in_(saved), Comment.is_banned == False, Comment.deleted_utc == 0)
|
|
|
|
if self.admin_level < 2:
|
|
comments = comments.filter(Comment.author_id.notin_(self.userblocks))
|
|
|
|
return [x[0] for x in comments.order_by(Comment.created_utc.desc()).offset(25 * (page - 1)).all()]
|
|
|
|
@property
|
|
@lazy
|
|
def saved_count(self):
|
|
return len(self.saved_idlist())
|
|
|
|
@property
|
|
@lazy
|
|
def saved_comment_count(self):
|
|
return len(self.saved_comment_idlist())
|
|
|
|
@property
|
|
@lazy
|
|
def filter_words(self):
|
|
l = [i.strip() for i in self.custom_filter_list.split('\n')] if self.custom_filter_list else []
|
|
l = [i for i in l if i]
|
|
return l
|