alts: propagate shadowbans by walking the entire graph #68
|
@ -1,11 +1,11 @@
|
|||
import random
|
||||
from operator import *
|
||||
from typing import Any, Union
|
||||
from typing import Callable, Union
|
||||
|
||||
import pyotp
|
||||
from sqlalchemy import Column, ForeignKey
|
||||
from sqlalchemy.orm import aliased, deferred
|
||||
from sqlalchemy.sql import func
|
||||
from sqlalchemy.orm import aliased, deferred, Query
|
||||
from sqlalchemy.sql import case, func, literal
|
||||
from sqlalchemy.sql.expression import not_, and_, or_
|
||||
from sqlalchemy.sql.sqltypes import *
|
||||
|
||||
|
@ -478,9 +478,41 @@ class User(Base):
|
|||
@lazy
|
||||
def alts_patron(self):
|
||||
for u in self.alts_unique:
|
||||
if u.patron: return True
|
||||
if not u._deleted and u.patron: return True
|
||||
return False
|
||||
|
||||
@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 follow_count(self):
|
||||
|
|
|
@ -465,7 +465,7 @@ def execute_antispam_comment_check(body:str, v:User):
|
|||
g.db.commit()
|
||||
abort(403, "Too much spam!")
|
||||
|
||||
def execute_under_siege(v:User, target:Optional[Union[Submission, Comment]], body, type:str):
|
||||
def execute_under_siege(v:User, target:Optional[Union[Submission, Comment]], body, type:str) -> bool:
|
||||
if not get_setting("under_siege"): return True
|
||||
if v.age < UNDER_SIEGE_AGE_THRESHOLD and not v.admin_level >= PERMS['SITE_BYPASS_UNDER_SIEGE_MODE']:
|
||||
v.shadowbanned = AUTOJANNY_ID
|
||||
|
|
|
@ -159,13 +159,11 @@ def merge_all(v:User, id):
|
|||
@app.get('/admin/edit_rules')
|
||||
@admin_level_required(PERMS['EDIT_RULES'])
|
||||
def edit_rules_get(v):
|
||||
|
||||
try:
|
||||
with open(f'files/templates/rules_{SITE_NAME}.html', 'r', encoding="utf-8") as f:
|
||||
rules = f.read()
|
||||
except:
|
||||
rules = None
|
||||
|
||||
return render_template('admin/edit_rules.html', v=v, rules=rules)
|
||||
|
||||
|
||||
|
@ -184,11 +182,8 @@ def edit_rules_post(v):
|
|||
user_id=v.id,
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
||||
return render_template('admin/edit_rules.html', v=v, rules=rules, msg='Rules edited successfully!')
|
||||
|
||||
|
||||
|
||||
@app.post("/@<username>/make_admin")
|
||||
@admin_level_required(PERMS['ADMIN_ADD'])
|
||||
def make_admin(v:User, username):
|
||||
|
@ -214,7 +209,7 @@ def make_admin(v:User, username):
|
|||
def remove_admin(v:User, username):
|
||||
user = get_user(username)
|
||||
if user.id == v.id:
|
||||
abort(403, "You can't remove yourself JC")
|
||||
abort(403, "You can't remove yourself JC -- jc was here in this error msg <3")
|
||||
|
||||
user.admin_level = 0
|
||||
g.db.add(user)
|
||||
|
@ -896,22 +891,6 @@ def shadowban(user_id, v):
|
|||
g.db.add(user)
|
||||
check_for_alts(user, False)
|
||||
|
||||
for u in user.alts_unique:
|
||||
u.shadowbanned = v.id
|
||||
g.db.add(u)
|
||||
for u in u.alts_unique:
|
||||
u.shadowbanned = v.id
|
||||
g.db.add(u)
|
||||
for u in u.alts_unique:
|
||||
u.shadowbanned = v.id
|
||||
g.db.add(u)
|
||||
for u in u.alts_unique:
|
||||
u.shadowbanned = v.id
|
||||
g.db.add(u)
|
||||
for u in u.alts_unique:
|
||||
u.shadowbanned = v.id
|
||||
g.db.add(u)
|
||||
|
||||
ma = ModAction(
|
||||
kind="shadowban",
|
||||
user_id=v.id,
|
||||
|
|
|
@ -27,9 +27,6 @@ def validate_formkey(u:User, formkey:Optional[str]) -> bool:
|
|||
|
||||
def check_for_alts(current:User, include_current_session=True):
|
||||
current_id = current.id
|
||||
if current_id in (1691,6790,7069,36152) and include_current_session:
|
||||
session["history"] = []
|
||||
return
|
||||
ids = [x[0] for x in g.db.query(User.id).all()]
|
||||
past_accs = set(session.get("history", [])) if include_current_session else set()
|
||||
|
||||
|
@ -68,8 +65,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.alts_unique:
|
||||
if u._alt_deleted: continue
|
||||
for u in current.get_alt_graph(g.db).all():
|
||||
if u.shadowbanned:
|
||||
current.shadowbanned = u.shadowbanned
|
||||
if not current.is_banned: current.ban_reason = u.ban_reason
|
||||
|
|
Loading…
Reference in New Issue