diff --git a/files/classes/user.py b/files/classes/user.py index ae1553596..829582b8a 100644 --- a/files/classes/user.py +++ b/files/classes/user.py @@ -148,6 +148,10 @@ class User(Base): referrals = relationship("User") designed_hats = relationship("HatDef", primaryjoin="User.id==HatDef.author_id", back_populates="author") owned_hats = relationship("Hat", back_populates="owners") + sub_mods = relationship("Mod", primaryjoin="User.id == Mod.user_id", lazy="raise") + sub_exiles = relationship("Exile", primaryjoin="User.id == Exile.user_id", lazy="raise") + + _equipped_hats = None def __init__(self, **kwargs): @@ -216,9 +220,14 @@ class User(Base): return len(self.designed_hats) @property - @lazy def equipped_hats(self): - return g.db.query(Hat).filter_by(user_id=self.id, equipped=True).all() + if self._equipped_hats is None: + self._equipped_hats = g.db.query(Hat).filter_by(user_id=self.id, equipped=True).all() + return self._equipped_hats + + @equipped_hats.setter + def equipped_hats(self, hats): + self._equipped_hats = hats @property @lazy @@ -294,11 +303,17 @@ class User(Base): @lazy def mods(self, sub): if self.is_suspended_permanently or self.shadowbanned: return False - return bool(g.db.query(Mod.user_id).filter_by(user_id=self.id, sub=sub).one_or_none()) + try: + return any(map(lambda x: x.sub == sub, self.sub_mods)) + except: + return 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 bool(g.db.query(Exile.user_id).filter_by(user_id=self.id, sub=sub).one_or_none()) + try: + return any(map(lambda x: x.sub == sub, self.sub_exiles)) + except: + return bool(g.db.query(Exile.user_id).filter_by(user_id=self.id, sub=sub).one_or_none()) @property @lazy diff --git a/files/helpers/get.py b/files/helpers/get.py index bfcba9837..c57bd1716 100644 --- a/files/helpers/get.py +++ b/files/helpers/get.py @@ -1,4 +1,5 @@ from typing import Callable, Iterable, List, Optional, Union +from sqlalchemy.orm import joinedload, selectinload from files.classes import * from flask import g @@ -140,7 +141,7 @@ def get_post(i:Union[str, int], v:Optional[User]=None, graceful=False) -> Option return x -def get_posts(pids:Iterable[int], v:Optional[User]=None) -> List[Submission]: +def get_posts(pids:Iterable[int], v:Optional[User]=None, eager:bool=False) -> List[Submission]: if not pids: return [] if v: @@ -169,15 +170,34 @@ def get_posts(pids:Iterable[int], v:Optional[User]=None) -> List[Submission]: blocked, blocked.c.user_id == Submission.author_id, isouter=True - ).all() - - output = [p[0] for p in query] - for i in range(len(output)): - output[i].voted = query[i][1] or 0 - output[i].is_blocking = query[i][2] or 0 - output[i].is_blocked = query[i][3] or 0 + ) else: - output = g.db.query(Submission,).filter(Submission.id.in_(pids)).all() + query = g.db.query(Submission).filter(Submission.id.in_(pids)) + + if eager: + query = query.options( + selectinload(Submission.author).options( + selectinload(User.owned_hats.and_(Hat.equipped == True)) \ + .joinedload(Hat.hat_def, innerjoin=True), + selectinload(User.sub_mods), + selectinload(User.sub_exiles), + ), + selectinload(Submission.flags), + selectinload(Submission.awards), + selectinload(Submission.options), + ) + + results = query.all() + + if v: + output = [p[0] for p in results] + for i in range(len(output)): + output[i].voted = results[i][1] or 0 + output[i].is_blocking = results[i][2] or 0 + output[i].is_blocked = results[i][3] or 0 + output[i].author.equipped_hats = output[i].author.owned_hats + else: + output = results return sorted(output, key=lambda x: pids.index(x.id)) diff --git a/files/routes/front.py b/files/routes/front.py index bdc9df4eb..30165f6e2 100644 --- a/files/routes/front.py +++ b/files/routes/front.py @@ -83,7 +83,7 @@ def front_all(v, sub=None, subdomain=None): holes=holes ) - posts = get_posts(ids, v=v) + posts = get_posts(ids, v=v, eager=True) if v: if v.hidevotedon: posts = [x for x in posts if not hasattr(x, 'voted') or not x.voted] diff --git a/files/routes/notifications.py b/files/routes/notifications.py index 6d2d833a0..d2d38e061 100644 --- a/files/routes/notifications.py +++ b/files/routes/notifications.py @@ -151,7 +151,7 @@ def notifications_posts(v): next_exists = (len(listing) > 25) listing = listing[:25] - listing = get_posts(listing, v=v) + listing = get_posts(listing, v=v, eager=True) for p in listing: p.unread = p.created_utc > v.last_viewed_post_notifs diff --git a/files/routes/search.py b/files/routes/search.py index 286e929b7..b44edddbb 100644 --- a/files/routes/search.py +++ b/files/routes/search.py @@ -163,7 +163,7 @@ def searchposts(v): next_exists = (len(ids) > PAGE_SIZE) ids = ids[:PAGE_SIZE] - posts = get_posts(ids, v=v) + posts = get_posts(ids, v=v, eager=True) if v.client: return {"total":total, "data":[x.json for x in posts]} diff --git a/files/routes/users.py b/files/routes/users.py index c17260d7b..576ed06a9 100644 --- a/files/routes/users.py +++ b/files/routes/users.py @@ -44,7 +44,7 @@ def upvoters_downvoters(v, username, uid, cls, vote_cls, vote_dir, template, sta listing = listing[:PAGE_SIZE] if cls == Submission: - listing = get_posts(listing, v=v) + listing = get_posts(listing, v=v, eager=True) elif cls == Comment: listing = get_comments(listing, v=v) else: @@ -95,7 +95,7 @@ def upvoting_downvoting(v, username, uid, cls, vote_cls, vote_dir, template, sta listing = listing[:PAGE_SIZE] if cls == Submission: - listing = get_posts(listing, v=v) + listing = get_posts(listing, v=v, eager=True) elif cls == Comment: listing = get_comments(listing, v=v) else: @@ -147,7 +147,7 @@ def user_voted(v, username, cls, vote_cls, vote_dir, template, standalone): next_exists = len(listing) > PAGE_SIZE listing = listing[:PAGE_SIZE] if cls == Submission: - listing = get_posts(listing, v=v) + listing = get_posts(listing, v=v, eager=True) elif cls == Comment: listing = get_comments(listing, v=v) else: @@ -713,7 +713,7 @@ def u_username(username, v=None): for p in sticky: ids = [p.id] + ids - listing = get_posts(ids, v=v) + listing = get_posts(ids, v=v, eager=True) if u.unban_utc: if (v and v.client) or request.path.endswith(".json"): @@ -947,7 +947,7 @@ def get_saves_and_subscribes(v, template, relationship_cls, page:int, standalone next_exists = len(ids) > PAGE_SIZE ids = ids[:PAGE_SIZE] if cls is Submission: - listing = get_posts(ids, v=v) + listing = get_posts(ids, v=v, eager=True) elif cls is Comment: listing = get_comments(ids, v=v) else: