forked from rDrama/rDrama
cache get_alt_graph for 1 hour
parent
8554317588
commit
92cbe64ac0
|
@ -1,6 +1,6 @@
|
|||
import random
|
||||
from operator import *
|
||||
from typing import Callable, Union
|
||||
from typing import Union
|
||||
|
||||
import pyotp
|
||||
from sqlalchemy import Column, ForeignKey
|
||||
|
@ -470,46 +470,6 @@ class User(Base):
|
|||
def age(self):
|
||||
return int(time.time()) - self.created_utc
|
||||
|
||||
@lazy
|
||||
def get_alt_graph(self, db:scoped_session, alt_filter:Optional[Callable[[Query], Query]]=None, **kwargs) -> Query:
|
||||
'''
|
||||
Gets the full graph of alts (optionally filtering `Alt` objects by criteria using a callable,
|
||||
such as by a date to only get alts from a certain date) as a query of users that can be filtered
|
||||
further. This function filters alts marked as deleted by default, pass `include_deleted=True` to
|
||||
disable this behavior and include delinked alts.
|
||||
'''
|
||||
if not alt_filter:
|
||||
alt_filter = lambda q:q
|
||||
|
||||
if not kwargs.get('include_deleted', False):
|
||||
deleted_filter = lambda q:q.filter(Alt.deleted == False)
|
||||
else:
|
||||
deleted_filter = lambda q:q
|
||||
|
||||
combined_filter = lambda q:deleted_filter(alt_filter(q))
|
||||
|
||||
alt_graph_cte = db.query(literal(self.id).label('user_id')).select_from(Alt).cte('alt_graph', recursive=True)
|
||||
|
||||
alt_graph_cte_inner = combined_filter(db.query(
|
||||
case(
|
||||
(Alt.user1 == alt_graph_cte.c.user_id, Alt.user2),
|
||||
(Alt.user2 == alt_graph_cte.c.user_id, Alt.user1),
|
||||
)
|
||||
).select_from(Alt, alt_graph_cte).filter(
|
||||
or_(alt_graph_cte.c.user_id == Alt.user1, alt_graph_cte.c.user_id == Alt.user2)
|
||||
))
|
||||
|
||||
alt_graph_cte = alt_graph_cte.union(alt_graph_cte_inner)
|
||||
return db.query(User).filter(User.id == alt_graph_cte.c.user_id)
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def alts_patron(self):
|
||||
for u in self.get_alt_graph(g.db):
|
||||
if not u._deleted and u.patron: return True
|
||||
return False
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def follow_count(self):
|
||||
return g.db.query(Follow).filter_by(user_id=self.id).count()
|
||||
|
|
|
@ -17,6 +17,7 @@ from files.helpers.settings import get_settings, toggle_setting
|
|||
from files.helpers.useractions import *
|
||||
from files.routes.routehelpers import check_for_alts
|
||||
from files.routes.wrappers import *
|
||||
from files.routes.routehelpers import get_alt_graph
|
||||
|
||||
from .front import frontlist
|
||||
|
||||
|
@ -261,7 +262,7 @@ def revert_actions(v:User, username):
|
|||
send_repeatable_notification(user.id, f"@{v.username} (a site admin) has unbanned you!")
|
||||
g.db.add(user)
|
||||
|
||||
for u in user.get_alt_graph(g.db):
|
||||
for u in get_alt_graph(user.id):
|
||||
u.shadowbanned = None
|
||||
u.unban_utc = 0
|
||||
u.ban_reason = None
|
||||
|
@ -678,7 +679,7 @@ def alt_votes_get(v):
|
|||
@admin_level_required(PERMS['USER_LINK'])
|
||||
def admin_view_alts(v:User, username=None):
|
||||
u = get_user(username or request.values.get('username'), graceful=True)
|
||||
return render_template('admin/alts.html', v=v, u=u, alts=u.get_alt_graph(g.db) if u else None)
|
||||
return render_template('admin/alts.html', v=v, u=u, alts=get_alt_graph(u.id) if u else None)
|
||||
|
||||
@app.post('/@<username>/alts/')
|
||||
@limiter.limit(DEFAULT_RATELIMIT_SLOWER)
|
||||
|
@ -843,7 +844,7 @@ def unshadowban(user_id, v):
|
|||
if not user.is_banned: user.ban_reason = None
|
||||
g.db.add(user)
|
||||
|
||||
for alt in user.get_alt_graph(g.db):
|
||||
for alt in get_alt_graph(user.id):
|
||||
alt.shadowbanned = None
|
||||
if not alt.is_banned: alt.ban_reason = None
|
||||
g.db.add(alt)
|
||||
|
@ -920,7 +921,7 @@ def ban_user(user_id, v):
|
|||
user.ban(admin=v, reason=reason, days=days)
|
||||
|
||||
if request.values.get("alts"):
|
||||
for x in user.get_alt_graph(g.db):
|
||||
for x in get_alt_graph(user.id):
|
||||
if x.admin_level > v.admin_level:
|
||||
continue
|
||||
x.ban(admin=v, reason=reason, days=days)
|
||||
|
@ -1052,7 +1053,7 @@ def unban_user(user_id, v):
|
|||
send_repeatable_notification(user.id, f"@{v.username} (a site admin) has unbanned you!")
|
||||
g.db.add(user)
|
||||
|
||||
for x in user.get_alt_graph(g.db):
|
||||
for x in get_alt_graph(user.id):
|
||||
if x.is_banned: send_repeatable_notification(x.id, f"@{v.username} (a site admin) has unbanned you!")
|
||||
x.is_banned = None
|
||||
x.unban_utc = 0
|
||||
|
|
|
@ -12,6 +12,7 @@ from files.helpers.assetcache import assetcache_path
|
|||
from files.helpers.config.const import *
|
||||
from files.helpers.settings import get_settings
|
||||
from files.helpers.sorting_and_time import make_age_string
|
||||
from files.routes.routehelpers import get_alt_graph
|
||||
from files.routes.routehelpers import get_formkey
|
||||
from files.__main__ import app, cache
|
||||
|
||||
|
@ -95,5 +96,5 @@ def inject_constants():
|
|||
"HOUSE_JOIN_COST":HOUSE_JOIN_COST, "HOUSE_SWITCH_COST":HOUSE_SWITCH_COST, "IMAGE_FORMATS":IMAGE_FORMATS,
|
||||
"PAGE_SIZES":PAGE_SIZES, "THEMES":THEMES, "COMMENT_SORTS":COMMENT_SORTS, "SORTS":SORTS,
|
||||
"TIME_FILTERS":TIME_FILTERS, "HOUSES":HOUSES, "TIERS_ID_TO_NAME":TIERS_ID_TO_NAME,
|
||||
"DEFAULT_CONFIG_VALUE":DEFAULT_CONFIG_VALUE, "IS_LOCALHOST":IS_LOCALHOST, "BACKGROUND_CATEGORIES":BACKGROUND_CATEGORIES, "PAGE_SIZE":PAGE_SIZE, "TAGLINE":TAGLINE, "HOLIDAY_EVENT":HOLIDAY_EVENT
|
||||
"DEFAULT_CONFIG_VALUE":DEFAULT_CONFIG_VALUE, "IS_LOCALHOST":IS_LOCALHOST, "BACKGROUND_CATEGORIES":BACKGROUND_CATEGORIES, "PAGE_SIZE":PAGE_SIZE, "TAGLINE":TAGLINE, "HOLIDAY_EVENT":HOLIDAY_EVENT, "get_alt_graph":get_alt_graph
|
||||
}
|
||||
|
|
|
@ -2,13 +2,17 @@ import time
|
|||
import secrets
|
||||
|
||||
from random import randint
|
||||
from typing import Optional, Union
|
||||
from typing import Optional, Union, Callable
|
||||
from sqlalchemy.orm import aliased, deferred, Query
|
||||
from sqlalchemy.sql import case, literal
|
||||
from sqlalchemy.sql.expression import or_
|
||||
|
||||
from flask import g, session
|
||||
|
||||
from files.classes import Alt, Comment, User, Submission
|
||||
from files.helpers.config.const import *
|
||||
from files.helpers.security import generate_hash, validate_hash
|
||||
from files.__main__ import cache
|
||||
|
||||
def get_raw_formkey(u:User):
|
||||
if not session.get("session_id"):
|
||||
|
@ -25,6 +29,38 @@ def validate_formkey(u:User, formkey:Optional[str]) -> bool:
|
|||
if not formkey: return False
|
||||
return validate_hash(get_raw_formkey(u), formkey)
|
||||
|
||||
@cache.memoize(timeout=3600)
|
||||
def get_alt_graph(uid:int, alt_filter:Optional[Callable[[Query], Query]]=None, **kwargs) -> Query:
|
||||
'''
|
||||
Gets the full graph of alts (optionally filtering `Alt` objects by criteria using a callable,
|
||||
such as by a date to only get alts from a certain date) as a query of users that can be filtered
|
||||
further. This function filters alts marked as deleted by default, pass `include_deleted=True` to
|
||||
disable this behavior and include delinked alts.
|
||||
'''
|
||||
if not alt_filter:
|
||||
alt_filter = lambda q:q
|
||||
|
||||
if not kwargs.get('include_deleted', False):
|
||||
deleted_filter = lambda q:q.filter(Alt.deleted == False)
|
||||
else:
|
||||
deleted_filter = lambda q:q
|
||||
|
||||
combined_filter = lambda q:deleted_filter(alt_filter(q))
|
||||
|
||||
alt_graph_cte = g.db.query(literal(uid).label('user_id')).select_from(Alt).cte('alt_graph', recursive=True)
|
||||
|
||||
alt_graph_cte_inner = combined_filter(g.db.query(
|
||||
case(
|
||||
(Alt.user1 == alt_graph_cte.c.user_id, Alt.user2),
|
||||
(Alt.user2 == alt_graph_cte.c.user_id, Alt.user1),
|
||||
)
|
||||
).select_from(Alt, alt_graph_cte).filter(
|
||||
or_(alt_graph_cte.c.user_id == Alt.user1, alt_graph_cte.c.user_id == Alt.user2)
|
||||
))
|
||||
|
||||
alt_graph_cte = alt_graph_cte.union(alt_graph_cte_inner)
|
||||
return g.db.query(User).filter(User.id == alt_graph_cte.c.user_id, User.id != uid).order_by(User.username).all()
|
||||
|
||||
def check_for_alts(current:User, include_current_session=True):
|
||||
current_id = current.id
|
||||
ids = [x[0] for x in g.db.query(User.id).all()]
|
||||
|
@ -65,7 +101,7 @@ def check_for_alts(current:User, include_current_session=True):
|
|||
if include_current_session:
|
||||
session["history"] = list(past_accs)
|
||||
g.db.flush()
|
||||
for u in current.get_alt_graph(g.db):
|
||||
for u in get_alt_graph(current.id):
|
||||
if u._alt_deleted: continue
|
||||
if u.shadowbanned and current.id not in DONT_SHADOWBAN:
|
||||
current.shadowbanned = u.shadowbanned
|
||||
|
|
|
@ -312,7 +312,7 @@ def transfer_currency(v:User, username:str, currency_name:Literal['coins', 'mars
|
|||
if amount is None or amount <= 0: abort(400, f"Invalid number of {currency_name}")
|
||||
if amount < MIN_CURRENCY_TRANSFER: abort(400, f"You have to gift at least {MIN_CURRENCY_TRANSFER} {currency_name}")
|
||||
tax = 0
|
||||
if apply_tax and not v.patron and not receiver.patron and not v.alts_patron and not receiver.alts_patron:
|
||||
if apply_tax and not v.patron and not receiver.patron:
|
||||
tax = math.ceil(amount*TAX_PCT)
|
||||
|
||||
reason = request.values.get("reason", "").strip()
|
||||
|
|
|
@ -89,6 +89,8 @@ def vote_post_comment(target_id, new, v, cls, vote_cls):
|
|||
if v.id == target.author.id:
|
||||
coin_delta = 0
|
||||
|
||||
v_alts_id = [x.id for x in v.get_alt_graph(self.id) if not x._alt_deleted]
|
||||
|
||||
alt = False
|
||||
if target.author.id in v.alt_ids or v.id in target.author.alt_ids:
|
||||
coin_delta = -1
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
{% if v.admin_level >= PERMS['USER_LINK'] %}
|
||||
<h2>Link Accounts</h2>
|
||||
|
||||
{% if u2 in u1.get_alt_graph(g.db) %}
|
||||
{% if u2 in get_alt_graph(u.id) %}
|
||||
<p>Accounts are <a href="/@{{u1.username}}/alts">known alts</a> of each other.</p>
|
||||
{% else %}
|
||||
|
||||
|
|
|
@ -225,7 +225,7 @@
|
|||
<span id="profile--alts">Alts:</span>
|
||||
{% endif %}
|
||||
<ul id="profile--alts-list">
|
||||
{% for account in u.get_alt_graph(g.db) if not account._alt_deleted and (v.can_see_shadowbanned or not account.shadowbanned) %}
|
||||
{% for account in get_alt_graph(u.id) if not account._alt_deleted and (v.can_see_shadowbanned or not account.shadowbanned) %}
|
||||
<li><a href="{{account.url}}">@{{account.username}}</a>{% if account._is_manual %} [m]{% endif %}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
@ -489,7 +489,7 @@
|
|||
<span id="profile-mobile--alts">Alts:</span>
|
||||
{% endif %}
|
||||
<ul id="profile-mobile--alts-list">
|
||||
{% for account in u.get_alt_graph(g.db) if not account._alt_deleted and (v.can_see_shadowbanned or not account.shadowbanned) %}
|
||||
{% for account in get_alt_graph(u.id) if not account._alt_deleted and (v.can_see_shadowbanned or not account.shadowbanned) %}
|
||||
<li><a href="{{account.url}}">@{{account.username}}</a>{% if account._is_manual %} [m]{% endif %}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
{% endif %}
|
||||
|
||||
{% if v %}
|
||||
<div id='tax' class="d-none">{% if v.patron or u.patron or v.alts_patron or u.alts_patron %}0{% else %}0.03{% endif %}</div>
|
||||
<div id='tax' class="d-none">{% if v.patron or u.patron %}0{% else %}0.03{% endif %}</div>
|
||||
<script defer src="{{'js/userpage_v.js' | asset}}"></script>
|
||||
<div id="username" class="d-none">{{u.username}}</div>
|
||||
{% endif %}
|
||||
|
|
Loading…
Reference in New Issue