diff --git a/files/routes/admin.py b/files/routes/admin.py index 9e085f88a..a28da9aea 100644 --- a/files/routes/admin.py +++ b/files/routes/admin.py @@ -689,6 +689,9 @@ def admin_add_alt(v:User, username): g.db.add(a) g.db.flush() + cache.delete_memoized(get_alt_graph, user1.id) + cache.delete_memoized(get_alt_graph, user2.id) + check_for_alts(user1, include_current_session=False) check_for_alts(user2, include_current_session=False) diff --git a/files/routes/routehelpers.py b/files/routes/routehelpers.py index 4b4e87cc6..a0307dc08 100644 --- a/files/routes/routehelpers.py +++ b/files/routes/routehelpers.py @@ -2,8 +2,8 @@ import time import secrets from random import randint -from typing import Optional, Union, Callable -from sqlalchemy.orm import aliased, deferred, Query +from typing import Optional, Union, Callable, List +from sqlalchemy.orm import aliased, deferred from sqlalchemy.sql import case, literal from sqlalchemy.sql.expression import or_ @@ -29,51 +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)) - +@cache.memoize(timeout=604800) +def get_alt_graph(uid:int) -> List[User]: + print(uid, flush=True) 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( + alt_graph_cte_inner = 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 add_alt(user1:int, user2:int): + li = [user1, user2] + existing = g.db.query(Alt).filter(Alt.user1.in_(li), Alt.user2.in_(li)).one_or_none() + if not existing: + new_alt = Alt(user1=user1, user2=user2) + g.db.add(new_alt) + g.db.flush() + cache.delete_memoized(get_alt_graph, user1) + cache.delete_memoized(get_alt_graph, user2) + 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()] past_accs = set(session.get("history", [])) if include_current_session else set() - def add_alt(user1:int, user2:int): - li = [user1, user2] - existing = g.db.query(Alt).filter(Alt.user1.in_(li), Alt.user2.in_(li)).one_or_none() - if not existing: - new_alt = Alt(user1=user1, user2=user2) - g.db.add(new_alt) - g.db.flush() - for past_id in list(past_accs): if past_id not in ids: past_accs.remove(past_id) diff --git a/files/routes/users.py b/files/routes/users.py index dcef6667b..9e5c4853e 100644 --- a/files/routes/users.py +++ b/files/routes/users.py @@ -21,7 +21,7 @@ from files.helpers.mail import * from files.helpers.sanitize import * from files.helpers.sorting_and_time import * from files.helpers.useractions import badge_grant -from files.routes.routehelpers import check_for_alts +from files.routes.routehelpers import check_for_alts, add_alt from files.routes.wrappers import * from files.__main__ import app, cache, limiter @@ -1168,11 +1168,10 @@ def fp(v:User, fp): li = [v.id, u.id] existing = g.db.query(Alt).filter(Alt.user1.in_(li), Alt.user2.in_(li)).one_or_none() if existing: continue - new_alt = Alt(user1=v.id, user2=u.id) - g.db.add(new_alt) - g.db.flush() + add_alt(user1=v.id, user2=u.id) print(v.username + ' + ' + u.username, flush=True) - check_for_alts(v) + + check_for_alts(v) g.db.add(v) return '', 204