2022-05-04 23:09:46 +00:00
import time
2022-11-15 09:19:08 +00:00
from urllib . parse import quote , urlencode
2023-01-23 12:40:44 +00:00
from math import floor
2022-11-15 09:19:08 +00:00
2022-12-10 04:46:19 +00:00
from sqlalchemy import nullslast
2022-12-25 04:02:33 +00:00
from sqlalchemy . exc import IntegrityError
from psycopg2 . errors import UniqueViolation
2022-12-10 04:46:19 +00:00
2022-11-15 09:19:08 +00:00
from files . __main__ import app , cache , limiter
from files . classes import *
from files . helpers . actions import *
2022-05-04 23:09:46 +00:00
from files . helpers . alerts import *
2022-11-15 09:19:08 +00:00
from files . helpers . cloudflare import *
2022-12-11 23:44:34 +00:00
from files . helpers . config . const import *
2022-05-04 23:09:46 +00:00
from files . helpers . get import *
2022-05-22 16:13:19 +00:00
from files . helpers . media import *
2022-11-15 09:19:08 +00:00
from files . helpers . sanitize import *
from files . helpers . security import *
2022-11-30 17:37:35 +00:00
from files . helpers . settings import get_settings , toggle_setting
2022-11-01 23:46:56 +00:00
from files . helpers . useractions import *
2022-11-15 09:19:08 +00:00
from files . routes . routehelpers import check_for_alts
from files . routes . wrappers import *
2022-12-24 16:53:13 +00:00
from files . routes . routehelpers import get_alt_graph , get_alt_graph_ids
2022-11-15 09:19:08 +00:00
2022-05-04 23:09:46 +00:00
from . front import frontlist
2022-11-15 09:19:08 +00:00
2022-05-25 20:16:26 +00:00
@app.get ( ' /admin/loggedin ' )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 03:29:14 +00:00
@admin_level_required ( PERMS [ ' VIEW_ACTIVE_USERS ' ] )
2022-05-25 20:16:26 +00:00
def loggedin_list ( v ) :
2022-06-20 20:25:03 +00:00
ids = [ x for x , val in cache . get ( f ' { SITE } _loggedin ' ) . items ( ) if time . time ( ) - val < LOGGEDIN_ACTIVE_TIME ]
2022-11-07 07:03:58 +00:00
users = g . db . query ( User ) . filter ( User . id . in_ ( ids ) ) . order_by ( User . admin_level . desc ( ) , User . truescore . desc ( ) ) . all ( )
2022-11-15 19:08:41 +00:00
return render_template ( " admin/loggedin.html " , v = v , users = users )
2022-05-25 20:16:26 +00:00
2022-05-26 20:31:08 +00:00
@app.get ( ' /admin/loggedout ' )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 03:29:14 +00:00
@admin_level_required ( PERMS [ ' VIEW_ACTIVE_USERS ' ] )
2022-05-26 20:31:08 +00:00
def loggedout_list ( v ) :
2022-06-20 20:25:03 +00:00
users = sorted ( [ val [ 1 ] for x , val in cache . get ( f ' { SITE } _loggedout ' ) . items ( ) if time . time ( ) - val [ 0 ] < LOGGEDIN_ACTIVE_TIME ] )
2022-11-15 19:08:41 +00:00
return render_template ( " admin/loggedout.html " , v = v , users = users )
2022-05-04 23:09:46 +00:00
2023-01-22 08:04:49 +00:00
# @app.get('/admin/move/<int:old_id>/<int:new_id>')
# @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID)
# @admin_level_required(PERMS['USER_MERGE'])
# def move_acc(v:User, new_id, old_id):
# if time.time() - session.get('verified', 0) > 10:
# session.pop("lo_user", None)
# path = request.path
# qs = urlencode(dict(request.values))
# argval = quote(f"{path}?{qs}", safe='')
# return redirect(f"/login?redirect={argval}")
# old_id = int(old_id)
# new_id = int(new_id)
# olduser = g.db.get(User, old_id)
# newuser = g.db.get(User, new_id)
# attrs = {
# 'coins',
# 'coins_spent',
# 'coins_spent_on_hats',
# 'comment_count',
# 'currently_held_lottery_tickets',
# 'lootboxes_bought',
# 'marseybux',
# 'post_count',
# 'received_award_count',
# 'total_held_lottery_tickets',
# 'total_lottery_winnings',
# 'truescore',
# }
# for attr in attrs:
# amount = getattr(newuser, attr) + getattr(olduser, attr)
# setattr(newuser, attr, amount)
# if newuser.created_utc > olduser.created_utc:
# newuser.created_utc = olduser.created_utc
# g.db.add(newuser)
# g.db.commit()
# classes = {
# (AwardRelationship, "user_id"),
# (Badge, "user_id"),
# (CasinoGame, "user_id"),
# (Hat, "user_id"),
# (HatDef, "author_id"),
# (Lottery, "winner_id"),
# (Marsey, "author_id"),
# (Media, "user_id"),
# (Notification, "user_id"),
# (PushSubscription, "user_id"),
# #mod actions
# (ModAction, "user_id"),
# (ModAction, "target_user_id"),
# (SubAction, "user_id"),
# (SubAction, "target_user_id"),
# #holes
# (Mod, "user_id"),
# (Exile, "exiler_id"),
# (Exile, "user_id"),
# (SubBlock, "user_id"),
# (SubJoin, "user_id"),
# (SubSubscription, "user_id"),
# (Subscription, "user_id"),
# #other users
# (User, "is_banned"),
# (User, "referred_by"),
# (User, "shadowbanned"),
# (Follow, "target_id"),
# (Follow, "user_id"),
# (UserBlock, "user_id"),
# (UserBlock, "target_id"),
# (ViewerRelationship, "user_id"),
# (ViewerRelationship, "viewer_id"),
# #posts and comments
# (Submission, "author_id"),
# (Submission, "is_approved"),
# (Comment, "author_id"),
# (Comment, "is_approved"),
# (Comment, "sentto"),
# (Comment, "wall_user_id"),
# (Vote, "user_id"),
# (CommentVote, "user_id"),
# (Flag, "user_id"),
# (CommentFlag, "user_id"),
# (SaveRelationship, "user_id"),
# (CommentSaveRelationship, "user_id"),
# (SubmissionOptionVote, "user_id"),
# (CommentOptionVote, "user_id"),
# }
# for cls, attr in classes:
# items = g.db.query(cls).filter(getattr(cls, attr) == olduser.id)
# for item in items:
# setattr(item, attr, newuser.id)
# g.db.add(item)
# try: g.db.commit()
# except IntegrityError as e:
# if isinstance(e.orig, UniqueViolation):
# g.db.rollback()
# g.db.delete(item)
# g.db.commit()
# else:
# print(e, flush=True)
# abort(500, str(e))
# newuser.stored_subscriber_count = g.db.query(Follow).filter_by(target_id=newuser.id).count()
# g.db.add(newuser)
# update_statement = f'''
# update submissions set body_html=replace(body_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where body_html like '%<a href="/id/{olduser.id}">%';
# update comments set body_html=replace(body_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where body_html like '%<a href="/id/{olduser.id}">%';
# update subs set sidebar_html=replace(sidebar_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where sidebar_html like '%<a href="/id/{olduser.id}">%';
# update users set bio_html=replace(bio_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where bio_html like '%<a href="/id/{olduser.id}">%';
# update users set sig_html=replace(sig_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where sig_html like '%<a href="/id/{olduser.id}">%';
# update users set friends_html=replace(friends_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where friends_html like '%<a href="/id/{olduser.id}">%';
# update users set enemies_html=replace(enemies_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where enemies_html like '%<a href="/id/{olduser.id}">%';
# update submissions set body_html=replace(body_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where body_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%';
# update comments set body_html=replace(body_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where body_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%';
# update subs set sidebar_html=replace(sidebar_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where sidebar_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%';
# update users set bio_html=replace(bio_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where bio_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%';
# update users set sig_html=replace(sig_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where sig_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%';
# update users set friends_html=replace(friends_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where friends_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%';
# update users set enemies_html=replace(enemies_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where enemies_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%'; '''
# g.db.execute(update_statement)
# g.db.delete(olduser)
# g.db.commit()
# stats = cache.get(f'{SITE}_stats')
# online = cache.get(CHAT_ONLINE_CACHE_KEY)
# cache.clear()
# cache.set(f'{SITE}_stats', stats)
# cache.set(CHAT_ONLINE_CACHE_KEY, online)
# return redirect(f"/@{olduser.username}")
2022-05-04 23:09:46 +00:00
2023-01-23 09:58:38 +00:00
@app.get ( ' /admin/dm_images ' )
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
@admin_level_required ( PERMS [ ' VIEW_DM_IMAGES ' ] )
def dm_images ( v ) :
with open ( f " { LOG_DIRECTORY } /dm_images.log " , " r " , encoding = " utf-8 " ) as f :
return f . read ( )
2022-12-05 05:22:08 +00:00
@app.get ( ' /admin/edit_rules ' )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-12-05 05:22:08 +00:00
@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 )
@app.post ( ' /admin/edit_rules ' )
@limiter.limit ( " 1/second;30/minute;200/hour;1000/day " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( " 1/second;30/minute;200/hour;1000/day " , key_func = get_ID )
2022-12-05 05:22:08 +00:00
@admin_level_required ( PERMS [ ' EDIT_RULES ' ] )
def edit_rules_post ( v ) :
rules = request . values . get ( ' rules ' , ' ' ) . strip ( )
rules = sanitize ( rules , sidebar = True )
with open ( f ' files/templates/rules_ { SITE_NAME } .html ' , ' w+ ' , encoding = " utf-8 " ) as f :
f . write ( rules )
ma = ModAction (
kind = " edit_rules " ,
user_id = v . id ,
)
g . db . add ( ma )
return render_template ( ' admin/edit_rules.html ' , v = v , rules = rules , msg = ' Rules edited successfully! ' )
2022-05-04 23:09:46 +00:00
@app.post ( " /@<username>/make_admin " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 03:37:18 +00:00
@admin_level_required ( PERMS [ ' ADMIN_ADD ' ] )
2022-12-11 23:44:34 +00:00
def make_admin ( v : User , username ) :
2022-11-11 13:52:18 +00:00
if SITE == ' rdrama.net ' : abort ( 403 )
2022-05-29 18:36:51 +00:00
2022-05-04 23:09:46 +00:00
user = get_user ( username )
2022-09-01 21:44:40 +00:00
2022-10-06 03:37:18 +00:00
user . admin_level = PERMS [ ' ADMIN_ADD_PERM_LEVEL ' ]
2022-05-04 23:09:46 +00:00
g . db . add ( user )
ma = ModAction (
kind = " make_admin " ,
user_id = v . id ,
target_user_id = user . id
)
g . db . add ( ma )
2022-12-21 14:38:02 +00:00
send_repeatable_notification ( user . id , f " @ { v . username } added you as an admin! " )
2022-09-11 14:32:00 +00:00
return { " message " : f " @ { user . username } has been made admin! " }
2022-05-04 23:09:46 +00:00
@app.post ( " /@<username>/remove_admin " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 03:37:18 +00:00
@admin_level_required ( PERMS [ ' ADMIN_REMOVE ' ] )
2022-12-11 23:44:34 +00:00
def remove_admin ( v : User , username ) :
2022-12-27 04:01:57 +00:00
if SITE == ' devrama.net ' :
abort ( 403 , " You can ' t remove admins on devrama! " )
2022-05-04 23:09:46 +00:00
user = get_user ( username )
2022-12-09 05:58:44 +00:00
2023-01-20 01:31:51 +00:00
if user . admin_level > v . admin_level :
abort ( 403 )
2022-12-16 20:17:03 +00:00
if user . admin_level :
user . admin_level = 0
g . db . add ( user )
2022-05-04 23:09:46 +00:00
2022-12-16 20:17:03 +00:00
ma = ModAction (
kind = " remove_admin " ,
user_id = v . id ,
target_user_id = user . id
)
g . db . add ( ma )
2022-05-04 23:09:46 +00:00
2022-12-21 14:38:02 +00:00
send_repeatable_notification ( user . id , f " @ { v . username } removed you as an admin! " )
2022-09-11 14:32:00 +00:00
return { " message " : f " @ { user . username } has been removed as admin! " }
2022-05-04 23:09:46 +00:00
2022-12-29 10:39:10 +00:00
@app.post ( " /distribute/<int:option_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-12-02 22:08:46 +00:00
@admin_level_required ( PERMS [ ' POST_BETS_DISTRIBUTE ' ] )
2022-12-11 23:44:34 +00:00
def distribute ( v : User , option_id ) :
2022-08-26 21:53:17 +00:00
autojanny = get_account ( AUTOJANNY_ID )
2022-10-11 13:01:39 +00:00
if autojanny . coins == 0 : abort ( 400 , " @AutoJanny has 0 coins " )
2022-08-26 21:53:17 +00:00
try : option_id = int ( option_id )
except : abort ( 400 )
try : option = g . db . get ( SubmissionOption , option_id )
except : abort ( 404 )
2022-09-08 18:25:45 +00:00
if option . exclusive != 2 : abort ( 403 )
option . exclusive = 3
g . db . add ( option )
2022-08-26 21:53:17 +00:00
post = option . post
pool = 0
for o in post . options :
2022-09-30 15:38:47 +00:00
if o . exclusive > = 2 : pool + = o . upvotes
2022-10-05 06:07:53 +00:00
pool * = POLL_BET_COINS
2022-08-26 21:53:17 +00:00
2022-10-12 16:33:00 +00:00
autojanny . charge_account ( ' coins ' , pool )
2022-08-26 21:53:17 +00:00
if autojanny . coins < 0 : autojanny . coins = 0
g . db . add ( autojanny )
votes = option . votes
coinsperperson = int ( pool / len ( votes ) )
cid = notif_comment ( f " You won { coinsperperson } coins betting on [ { post . title } ]( { post . shortlink } ) :marseyparty: " )
for vote in votes :
u = vote . user
2022-11-20 10:50:02 +00:00
u . pay_account ( ' coins ' , coinsperperson )
2022-08-26 21:53:17 +00:00
add_notif ( cid , u . id )
2022-10-05 06:07:53 +00:00
cid = notif_comment ( f " You lost the { POLL_BET_COINS } coins you bet on [ { post . title } ]( { post . shortlink } ) :marseylaugh: " )
2022-08-26 21:53:17 +00:00
losing_voters = [ ]
for o in post . options :
2022-09-23 12:09:33 +00:00
if o . exclusive == 2 :
2022-08-26 21:53:17 +00:00
losing_voters . extend ( [ x . user_id for x in o . votes ] )
for uid in losing_voters :
add_notif ( cid , uid )
2023-01-01 11:36:20 +00:00
2022-08-26 21:53:17 +00:00
ma = ModAction (
kind = " distribute " ,
user_id = v . id ,
target_submission_id = post . id
)
g . db . add ( ma )
return { " message " : f " Each winner has received { coinsperperson } coins! " }
2022-05-04 23:09:46 +00:00
2022-10-08 04:07:44 +00:00
@app.post ( " /@<username>/revert_actions " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-10-08 04:07:44 +00:00
@admin_level_required ( PERMS [ ' ADMIN_ACTIONS_REVERT ' ] )
2022-12-11 23:44:34 +00:00
def revert_actions ( v : User , username ) :
2022-12-28 09:47:30 +00:00
revertee = get_user ( username )
2022-10-08 04:07:44 +00:00
2023-01-20 01:31:51 +00:00
if revertee . admin_level > v . admin_level :
abort ( 403 )
2022-10-08 04:07:44 +00:00
ma = ModAction (
kind = " revert " ,
user_id = v . id ,
2022-12-28 09:47:30 +00:00
target_user_id = revertee . id
2022-10-08 04:07:44 +00:00
)
g . db . add ( ma )
cutoff = int ( time . time ( ) ) - 86400
2022-12-28 09:47:30 +00:00
posts = [ x [ 0 ] for x in g . db . query ( ModAction . target_submission_id ) . filter ( ModAction . user_id == revertee . id , ModAction . created_utc > cutoff , ModAction . kind == ' ban_post ' ) . all ( ) ]
2022-10-08 04:07:44 +00:00
posts = g . db . query ( Submission ) . filter ( Submission . id . in_ ( posts ) ) . all ( )
2022-12-28 09:47:30 +00:00
comments = [ x [ 0 ] for x in g . db . query ( ModAction . target_comment_id ) . filter ( ModAction . user_id == revertee . id , ModAction . created_utc > cutoff , ModAction . kind == ' ban_comment ' ) . all ( ) ]
2022-10-08 04:07:44 +00:00
comments = g . db . query ( Comment ) . filter ( Comment . id . in_ ( comments ) ) . all ( )
for item in posts + comments :
item . is_banned = False
item . ban_reason = None
item . is_approved = v . id
g . db . add ( item )
2022-12-28 09:47:30 +00:00
users = ( x [ 0 ] for x in g . db . query ( ModAction . target_user_id ) . filter ( ModAction . user_id == revertee . id , ModAction . created_utc > cutoff , ModAction . kind . in_ ( ( ' shadowban ' , ' ban_user ' ) ) ) . all ( ) )
2022-10-08 04:07:44 +00:00
users = g . db . query ( User ) . filter ( User . id . in_ ( users ) ) . all ( )
for user in users :
user . shadowbanned = None
user . unban_utc = 0
user . ban_reason = None
if user . is_banned :
2022-12-13 22:02:53 +00:00
user . is_banned = None
2022-12-13 17:11:26 +00:00
send_repeatable_notification ( user . id , f " @ { v . username } (a site admin) has unbanned you! " )
2022-10-08 04:07:44 +00:00
g . db . add ( user )
2022-12-22 20:44:37 +00:00
for u in get_alt_graph ( user . id ) :
2022-10-08 04:07:44 +00:00
u . shadowbanned = None
u . unban_utc = 0
u . ban_reason = None
if u . is_banned :
2022-12-13 22:02:53 +00:00
u . is_banned = None
2022-12-13 17:11:26 +00:00
send_repeatable_notification ( u . id , f " @ { v . username } (a site admin) has unbanned you! " )
2022-10-08 04:07:44 +00:00
g . db . add ( u )
2022-12-28 09:47:30 +00:00
return { " message " : f " @ { revertee . username } ' s admin actions have been reverted! " }
2022-10-08 04:07:44 +00:00
2022-05-04 23:09:46 +00:00
@app.get ( " /admin/shadowbanned " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-12 06:53:32 +00:00
@admin_level_required ( PERMS [ ' USER_SHADOWBAN ' ] )
2022-05-04 23:09:46 +00:00
def shadowbanned ( v ) :
2022-12-10 04:46:19 +00:00
users = g . db . query ( User ) \
2022-12-10 08:23:56 +00:00
. filter (
User . shadowbanned != None ,
) \
2023-01-21 05:50:48 +00:00
. order_by ( User . ban_reason ) . all ( )
2022-12-10 08:23:56 +00:00
2022-11-15 19:08:41 +00:00
return render_template ( " admin/shadowbanned.html " , v = v , users = users )
2022-05-04 23:09:46 +00:00
@app.get ( " /admin/image_posts " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 00:57:08 +00:00
@admin_level_required ( PERMS [ ' POST_COMMENT_MODERATION ' ] )
2022-05-04 23:09:46 +00:00
def image_posts_listing ( v ) :
try : page = int ( request . values . get ( ' page ' , 1 ) )
except : page = 1
posts = g . db . query ( Submission ) . order_by ( Submission . id . desc ( ) )
2022-10-29 03:20:48 +00:00
firstrange = PAGE_SIZE * ( page - 1 )
secondrange = firstrange + PAGE_SIZE + 1
2022-05-04 23:09:46 +00:00
posts = [ x . id for x in posts if x . is_image ] [ firstrange : secondrange ]
2022-10-29 03:20:48 +00:00
next_exists = ( len ( posts ) > PAGE_SIZE )
posts = get_posts ( posts [ : PAGE_SIZE ] , v = v )
2022-05-04 23:09:46 +00:00
return render_template ( " admin/image_posts.html " , v = v , listing = posts , next_exists = next_exists , page = page , sort = " new " )
@app.get ( " /admin/reported/posts " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 00:57:08 +00:00
@admin_level_required ( PERMS [ ' POST_COMMENT_MODERATION ' ] )
2022-05-04 23:09:46 +00:00
def reported_posts ( v ) :
2022-11-07 21:34:40 +00:00
try : page = max ( 1 , int ( request . values . get ( " page " , 1 ) ) )
except : abort ( 400 , " Invalid page input! " )
2022-05-04 23:09:46 +00:00
listing = g . db . query ( Submission ) . filter_by (
is_approved = None ,
2022-10-23 16:24:17 +00:00
is_banned = False ,
deleted_utc = 0
2022-10-29 03:20:48 +00:00
) . join ( Submission . flags ) . order_by ( Submission . id . desc ( ) ) . offset ( PAGE_SIZE * ( page - 1 ) ) . limit ( PAGE_SIZE + 1 )
2022-05-04 23:09:46 +00:00
listing = [ p . id for p in listing ]
2022-10-29 03:20:48 +00:00
next_exists = len ( listing ) > PAGE_SIZE
listing = listing [ : PAGE_SIZE ]
2022-05-04 23:09:46 +00:00
listing = get_posts ( listing , v = v )
return render_template ( " admin/reported_posts.html " ,
2022-09-04 23:15:37 +00:00
next_exists = next_exists , listing = listing , page = page , v = v )
2022-05-04 23:09:46 +00:00
@app.get ( " /admin/reported/comments " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 00:57:08 +00:00
@admin_level_required ( PERMS [ ' POST_COMMENT_MODERATION ' ] )
2022-05-04 23:09:46 +00:00
def reported_comments ( v ) :
2022-11-07 21:34:40 +00:00
try : page = max ( 1 , int ( request . values . get ( " page " , 1 ) ) )
except : abort ( 400 , " Invalid page input! " )
2022-05-04 23:09:46 +00:00
listing = g . db . query ( Comment
2022-09-04 23:15:37 +00:00
) . filter_by (
2022-05-04 23:09:46 +00:00
is_approved = None ,
2022-10-23 16:24:17 +00:00
is_banned = False ,
deleted_utc = 0
2022-10-29 03:20:48 +00:00
) . join ( Comment . flags ) . order_by ( Comment . id . desc ( ) ) . offset ( PAGE_SIZE * ( page - 1 ) ) . limit ( PAGE_SIZE + 1 ) . all ( )
2022-05-04 23:09:46 +00:00
listing = [ c . id for c in listing ]
2022-10-29 03:20:48 +00:00
next_exists = len ( listing ) > PAGE_SIZE
listing = listing [ : PAGE_SIZE ]
2022-05-04 23:09:46 +00:00
listing = get_comments ( listing , v = v )
return render_template ( " admin/reported_comments.html " ,
2022-09-04 23:15:37 +00:00
next_exists = next_exists ,
listing = listing ,
page = page ,
v = v ,
standalone = True )
2022-05-04 23:09:46 +00:00
@app.get ( " /admin " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 05:54:48 +00:00
@admin_level_required ( PERMS [ ' ADMIN_HOME_VISIBLE ' ] )
2022-05-04 23:09:46 +00:00
def admin_home ( v ) :
2022-07-01 18:19:21 +00:00
under_attack = False
2022-10-13 06:12:35 +00:00
if v . admin_level > = PERMS [ ' SITE_SETTINGS_UNDER_ATTACK ' ] :
2022-11-15 09:19:08 +00:00
under_attack = ( get_security_level ( ) or ' high ' ) == ' under_attack '
2022-05-04 23:09:46 +00:00
2023-01-01 11:36:20 +00:00
return render_template ( " admin/admin_home.html " , v = v ,
2022-12-30 13:32:58 +00:00
under_attack = under_attack )
2022-05-04 23:09:46 +00:00
@app.post ( " /admin/site_settings/<setting> " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 04:26:15 +00:00
@admin_level_required ( PERMS [ ' SITE_SETTINGS ' ] )
2022-12-11 23:44:34 +00:00
def change_settings ( v : User , setting ) :
2022-12-27 13:35:14 +00:00
if SITE == ' devrama.net ' :
2022-12-27 05:25:29 +00:00
abort ( 403 , " Can ' t change this shit in devrama! " )
2022-11-30 17:37:35 +00:00
if setting not in get_settings ( ) . keys ( ) :
abort ( 404 , f " Setting ' { setting } ' not found " )
2022-11-15 09:19:08 +00:00
val = toggle_setting ( setting )
if val : word = ' enable '
2022-05-04 23:09:46 +00:00
else : word = ' disable '
2023-01-24 05:48:27 +00:00
if setting != ' login_required ' :
ma = ModAction (
kind = f " { word } _ { setting } " ,
user_id = v . id ,
)
g . db . add ( ma )
2022-11-30 17:37:35 +00:00
return { ' message ' : f " { setting . replace ( ' _ ' , ' ' ) . title ( ) } { word } d successfully! " }
2022-05-04 23:09:46 +00:00
2022-11-06 05:28:44 +00:00
@app.post ( " /admin/clear_cloudflare_cache " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 06:21:04 +00:00
@admin_level_required ( PERMS [ ' SITE_CACHE_PURGE_CDN ' ] )
2022-11-06 05:28:44 +00:00
def clear_cloudflare_cache ( v ) :
2022-11-15 09:19:08 +00:00
if not clear_entire_cache ( ) :
2022-11-06 05:28:44 +00:00
abort ( 400 , ' Failed to clear cloudflare cache! ' )
2022-05-04 23:09:46 +00:00
ma = ModAction (
2022-11-06 05:28:44 +00:00
kind = " clear_cloudflare_cache " ,
2022-05-04 23:09:46 +00:00
user_id = v . id
)
g . db . add ( ma )
2022-11-06 05:28:44 +00:00
return { " message " : " Cloudflare cache cleared! " }
2022-05-04 23:09:46 +00:00
@app.post ( " /admin/under_attack " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 04:26:15 +00:00
@admin_level_required ( PERMS [ ' SITE_SETTINGS_UNDER_ATTACK ' ] )
2022-05-04 23:09:46 +00:00
def under_attack ( v ) :
2022-11-15 09:19:08 +00:00
response = get_security_level ( )
2022-10-13 07:27:56 +00:00
if not response :
abort ( 400 , ' Could not retrieve the current security level ' )
old_under_attack_mode = response == ' under_attack '
enable_disable_str = ' disable ' if old_under_attack_mode else ' enable '
new_security_level = ' high ' if old_under_attack_mode else ' under_attack '
2022-11-15 09:19:08 +00:00
if not set_security_level ( new_security_level ) :
2022-10-13 07:27:56 +00:00
abort ( 400 , f ' Failed to { enable_disable_str } under attack mode ' )
ma = ModAction (
kind = f " { enable_disable_str } _under_attack " ,
user_id = v . id ,
)
g . db . add ( ma )
2022-10-13 07:54:30 +00:00
return { " message " : f " Under attack mode { enable_disable_str } d! " }
2022-05-04 23:09:46 +00:00
2022-11-27 22:02:18 +00:00
def admin_badges_grantable_list ( v ) :
2022-11-27 21:49:20 +00:00
query = g . db . query ( BadgeDef )
2022-11-30 21:15:07 +00:00
2023-01-22 08:04:49 +00:00
if BADGE_BLACKLIST and v . admin_level < PERMS [ ' IGNORE_BADGE_BLACKLIST ' ] :
2022-12-07 19:03:06 +00:00
query = query . filter ( BadgeDef . id . notin_ ( BADGE_BLACKLIST ) )
2022-11-30 21:15:07 +00:00
2022-11-27 21:49:20 +00:00
badge_types = query . order_by ( BadgeDef . id ) . all ( )
2022-11-27 22:02:18 +00:00
return badge_types
@app.get ( " /admin/badge_grant " )
@app.get ( " /admin/badge_remove " )
@feature_required ( ' BADGES ' )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-11-27 22:02:18 +00:00
@admin_level_required ( PERMS [ ' USER_BADGES ' ] )
def badge_grant_get ( v ) :
grant = request . url . endswith ( " grant " )
badge_types = admin_badges_grantable_list ( v )
2022-11-27 21:49:20 +00:00
return render_template ( " admin/badge_admin.html " , v = v ,
badge_types = badge_types , grant = grant )
2022-05-04 23:09:46 +00:00
@app.post ( " /admin/badge_grant " )
2022-11-14 15:11:05 +00:00
@feature_required ( ' BADGES ' )
2022-12-19 13:55:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-10-06 03:50:02 +00:00
@admin_level_required ( PERMS [ ' USER_BADGES ' ] )
2022-05-04 23:09:46 +00:00
def badge_grant_post ( v ) :
2022-11-27 22:02:18 +00:00
badges = admin_badges_grantable_list ( v )
2022-05-04 23:09:46 +00:00
2022-12-18 17:01:06 +00:00
user = get_user ( request . values . get ( " username " ) , graceful = True )
2022-05-04 23:09:46 +00:00
if not user :
2022-10-29 06:08:29 +00:00
return render_template ( " admin/badge_admin.html " , v = v , badge_types = badges , grant = True , error = " User not found. " )
2022-05-04 23:09:46 +00:00
try : badge_id = int ( request . values . get ( " badge_id " ) )
except : abort ( 400 )
2022-11-27 22:02:18 +00:00
if badge_id not in [ b . id for b in badges ] :
2022-12-23 01:01:24 +00:00
abort ( 403 , " You can ' t grant this badge! " )
2022-05-04 23:09:46 +00:00
2022-12-23 01:01:24 +00:00
description = request . values . get ( " description " )
2022-05-04 23:09:46 +00:00
url = request . values . get ( " url " )
2022-12-23 01:01:24 +00:00
2022-11-26 01:45:20 +00:00
if url :
if ' \\ ' in url : abort ( 400 )
if url . startswith ( SITE_FULL ) :
url = url . split ( SITE_FULL , 1 ) [ 1 ]
2022-12-11 18:56:04 +00:00
elif url . startswith ( BAN_EVASION_FULL ) :
url = url . split ( BAN_EVASION_FULL , 1 ) [ 1 ]
2022-12-23 01:01:24 +00:00
existing = user . has_badge ( badge_id )
if existing :
if url or description :
existing . url = url
existing . description = description
g . db . add ( existing )
return render_template ( " admin/badge_admin.html " , v = v , badge_types = badges , grant = True , msg = " Badge attributes edited successfully! " )
return render_template ( " admin/badge_admin.html " , v = v , badge_types = badges , grant = True , error = " User already has that badge. " )
new_badge = Badge (
badge_id = badge_id ,
user_id = user . id ,
url = url ,
description = description
)
2022-05-04 23:09:46 +00:00
g . db . add ( new_badge )
2022-08-17 17:57:32 +00:00
g . db . flush ( )
2022-05-04 23:09:46 +00:00
if v . id != user . id :
2022-12-13 17:11:26 +00:00
text = f " @ { v . username } (a site admin) has given you the following profile badge: \n \n ![]( { new_badge . path } ) \n \n ** { new_badge . name } ** \n \n { new_badge . badge . description } "
2022-09-13 10:27:09 +00:00
send_repeatable_notification ( user . id , text )
2023-01-01 11:36:20 +00:00
2022-05-04 23:09:46 +00:00
ma = ModAction (
kind = " badge_grant " ,
user_id = v . id ,
target_user_id = user . id ,
_note = new_badge . name
)
g . db . add ( ma )
2022-12-23 01:01:24 +00:00
2022-10-29 06:08:29 +00:00
return render_template ( " admin/badge_admin.html " , v = v , badge_types = badges , grant = True , msg = f " { new_badge . name } Badge granted to @ { user . username } successfully! " )
2022-05-04 23:09:46 +00:00
@app.post ( " /admin/badge_remove " )
2022-11-14 15:11:05 +00:00
@feature_required ( ' BADGES ' )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-10-06 03:50:02 +00:00
@admin_level_required ( PERMS [ ' USER_BADGES ' ] )
2022-05-04 23:09:46 +00:00
def badge_remove_post ( v ) :
2022-11-27 22:02:18 +00:00
badges = admin_badges_grantable_list ( v )
2022-05-04 23:09:46 +00:00
2022-12-18 17:01:06 +00:00
user = get_user ( request . values . get ( " username " ) , graceful = True )
2022-05-04 23:09:46 +00:00
if not user :
2022-10-29 06:08:29 +00:00
return render_template ( " admin/badge_admin.html " , v = v , badge_types = badges , grant = False , error = " User not found. " )
2022-05-04 23:09:46 +00:00
try : badge_id = int ( request . values . get ( " badge_id " ) )
except : abort ( 400 )
2022-11-27 22:02:18 +00:00
if badge_id not in [ b . id for b in badges ] :
2022-10-14 17:11:39 +00:00
abort ( 403 )
2022-05-04 23:09:46 +00:00
badge = user . has_badge ( badge_id )
if not badge :
2022-10-29 06:08:29 +00:00
return render_template ( " admin/badge_admin.html " , v = v , badge_types = badges , grant = False , error = " User doesn ' t have that badge. " )
2022-05-04 23:09:46 +00:00
2022-09-13 10:27:09 +00:00
if v . id != user . id :
2022-12-13 17:11:26 +00:00
text = f " @ { v . username } (a site admin) has removed the following profile badge from you: \n \n ![]( { badge . path } ) \n \n ** { badge . name } ** \n \n { badge . badge . description } "
2022-09-13 10:27:09 +00:00
send_repeatable_notification ( user . id , text )
2022-05-04 23:09:46 +00:00
ma = ModAction (
kind = " badge_remove " ,
user_id = v . id ,
target_user_id = user . id ,
_note = badge . name
)
g . db . add ( ma )
g . db . delete ( badge )
2022-10-29 06:08:29 +00:00
return render_template ( " admin/badge_admin.html " , v = v , badge_types = badges , grant = False , msg = f " { badge . name } Badge removed from @ { user . username } successfully! " )
2022-05-04 23:09:46 +00:00
@app.get ( " /admin/alt_votes " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 05:37:50 +00:00
@admin_level_required ( PERMS [ ' VIEW_ALT_VOTES ' ] )
2022-05-04 23:09:46 +00:00
def alt_votes_get ( v ) :
u1 = request . values . get ( " u1 " )
u2 = request . values . get ( " u2 " )
if not u1 or not u2 :
return render_template ( " admin/alt_votes.html " , v = v )
u1 = get_user ( u1 )
u2 = get_user ( u2 )
u1_post_ups = g . db . query (
Vote . submission_id ) . filter_by (
user_id = u1 . id ,
vote_type = 1 ) . all ( )
u1_post_downs = g . db . query (
Vote . submission_id ) . filter_by (
user_id = u1 . id ,
vote_type = - 1 ) . all ( )
u1_comment_ups = g . db . query (
CommentVote . comment_id ) . filter_by (
user_id = u1 . id ,
vote_type = 1 ) . all ( )
u1_comment_downs = g . db . query (
CommentVote . comment_id ) . filter_by (
user_id = u1 . id ,
vote_type = - 1 ) . all ( )
u2_post_ups = g . db . query (
Vote . submission_id ) . filter_by (
user_id = u2 . id ,
vote_type = 1 ) . all ( )
u2_post_downs = g . db . query (
Vote . submission_id ) . filter_by (
user_id = u2 . id ,
vote_type = - 1 ) . all ( )
u2_comment_ups = g . db . query (
CommentVote . comment_id ) . filter_by (
user_id = u2 . id ,
vote_type = 1 ) . all ( )
u2_comment_downs = g . db . query (
CommentVote . comment_id ) . filter_by (
user_id = u2 . id ,
vote_type = - 1 ) . all ( )
data = { }
data [ ' u1_only_post_ups ' ] = len (
[ x for x in u1_post_ups if x not in u2_post_ups ] )
data [ ' u2_only_post_ups ' ] = len (
[ x for x in u2_post_ups if x not in u1_post_ups ] )
data [ ' both_post_ups ' ] = len ( list ( set ( u1_post_ups ) & set ( u2_post_ups ) ) )
data [ ' u1_only_post_downs ' ] = len (
[ x for x in u1_post_downs if x not in u2_post_downs ] )
data [ ' u2_only_post_downs ' ] = len (
[ x for x in u2_post_downs if x not in u1_post_downs ] )
data [ ' both_post_downs ' ] = len (
list ( set ( u1_post_downs ) & set ( u2_post_downs ) ) )
data [ ' u1_only_comment_ups ' ] = len (
[ x for x in u1_comment_ups if x not in u2_comment_ups ] )
data [ ' u2_only_comment_ups ' ] = len (
[ x for x in u2_comment_ups if x not in u1_comment_ups ] )
data [ ' both_comment_ups ' ] = len (
list ( set ( u1_comment_ups ) & set ( u2_comment_ups ) ) )
data [ ' u1_only_comment_downs ' ] = len (
[ x for x in u1_comment_downs if x not in u2_comment_downs ] )
data [ ' u2_only_comment_downs ' ] = len (
[ x for x in u2_comment_downs if x not in u1_comment_downs ] )
data [ ' both_comment_downs ' ] = len (
list ( set ( u1_comment_downs ) & set ( u2_comment_downs ) ) )
data [ ' u1_post_ups_unique ' ] = 100 * \
data [ ' u1_only_post_ups ' ] / / len ( u1_post_ups ) if u1_post_ups else 0
data [ ' u2_post_ups_unique ' ] = 100 * \
data [ ' u2_only_post_ups ' ] / / len ( u2_post_ups ) if u2_post_ups else 0
data [ ' u1_post_downs_unique ' ] = 100 * \
data [ ' u1_only_post_downs ' ] / / len (
u1_post_downs ) if u1_post_downs else 0
data [ ' u2_post_downs_unique ' ] = 100 * \
data [ ' u2_only_post_downs ' ] / / len (
u2_post_downs ) if u2_post_downs else 0
data [ ' u1_comment_ups_unique ' ] = 100 * \
data [ ' u1_only_comment_ups ' ] / / len (
u1_comment_ups ) if u1_comment_ups else 0
data [ ' u2_comment_ups_unique ' ] = 100 * \
data [ ' u2_only_comment_ups ' ] / / len (
u2_comment_ups ) if u2_comment_ups else 0
data [ ' u1_comment_downs_unique ' ] = 100 * \
data [ ' u1_only_comment_downs ' ] / / len (
u1_comment_downs ) if u1_comment_downs else 0
data [ ' u2_comment_downs_unique ' ] = 100 * \
data [ ' u2_only_comment_downs ' ] / / len (
u2_comment_downs ) if u2_comment_downs else 0
return render_template ( " admin/alt_votes.html " ,
2022-09-04 23:15:37 +00:00
u1 = u1 ,
u2 = u2 ,
v = v ,
data = data
)
2022-05-04 23:09:46 +00:00
2022-11-14 17:32:13 +00:00
@app.get ( " /admin/alts/ " )
@app.get ( " /@<username>/alts/ " )
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-11-14 17:32:13 +00:00
@admin_level_required ( PERMS [ ' USER_LINK ' ] )
2022-12-11 23:44:34 +00:00
def admin_view_alts ( v : User , username = None ) :
2023-01-22 08:20:38 +00:00
u = get_user ( username or request . values . get ( ' username ' ) )
return render_template ( ' admin/alts.html ' , v = v , u = u , alts = u . alts )
2022-05-04 23:09:46 +00:00
2022-11-14 17:32:13 +00:00
@app.post ( ' /@<username>/alts/ ' )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-10-06 05:37:50 +00:00
@admin_level_required ( PERMS [ ' USER_LINK ' ] )
2022-12-11 23:44:34 +00:00
def admin_add_alt ( v : User , username ) :
2022-11-14 17:32:13 +00:00
user1 = get_user ( username )
user2 = get_user ( request . values . get ( ' other_username ' ) )
if user1 . id == user2 . id : abort ( 400 , " Can ' t add the same account as alts of each other " )
deleted = request . values . get ( ' deleted ' , False , bool ) or False
ids = [ user1 . id , user2 . id ]
a = g . db . query ( Alt ) . filter ( Alt . user1 . in_ ( ids ) , Alt . user2 . in_ ( ids ) ) . one_or_none ( )
if a : abort ( 409 , f " @ { user1 . username } and @ { user2 . username } are already known { ' linked ' if not a . deleted else ' delinked ' } alts " )
a = Alt (
user1 = user1 . id ,
user2 = user2 . id ,
2022-11-15 09:19:08 +00:00
is_manual = True ,
2022-11-14 17:32:13 +00:00
deleted = deleted
)
g . db . add ( a )
g . db . flush ( )
2022-05-04 23:09:46 +00:00
2022-12-24 16:53:13 +00:00
cache . delete_memoized ( get_alt_graph_ids , user1 . id )
cache . delete_memoized ( get_alt_graph_ids , user2 . id )
2022-12-22 21:24:36 +00:00
2022-11-14 17:32:13 +00:00
check_for_alts ( user1 , include_current_session = False )
check_for_alts ( user2 , include_current_session = False )
2022-05-04 23:09:46 +00:00
2022-11-14 17:32:13 +00:00
word = ' Delinked ' if deleted else ' Linked '
ma_word = ' delink ' if deleted else ' link '
2023-01-21 05:54:29 +00:00
note = f ' from @ { user2 . username } ' if deleted else f ' with @ { user2 . username } '
2022-11-14 17:32:13 +00:00
ma = ModAction (
kind = f " { ma_word } _accounts " ,
user_id = v . id ,
target_user_id = user1 . id ,
_note = note
)
g . db . add ( ma )
return { " message " : f " { word } @ { user1 . username } and @ { user2 . username } successfully! " }
2022-09-23 12:33:58 +00:00
2022-11-14 17:32:13 +00:00
@app.route ( ' /@<username>/alts/<int:other>/deleted ' , methods = [ " PUT " , " DELETE " ] )
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-11-14 17:32:13 +00:00
@admin_level_required ( PERMS [ ' USER_LINK ' ] )
2022-12-11 23:44:34 +00:00
def admin_delink_relink_alt ( v : User , username , other ) :
2022-11-14 17:32:13 +00:00
is_delinking = request . method == ' PUT ' # we're adding the 'deleted' state if a PUT request
user1 = get_user ( username )
user2 = get_account ( other )
ids = [ user1 . id , user2 . id ]
a = g . db . query ( Alt ) . filter ( Alt . user1 . in_ ( ids ) , Alt . user2 . in_ ( ids ) ) . one_or_none ( )
if not a : abort ( 404 )
a . deleted = is_delinking
g . db . add ( a )
g . db . flush ( )
check_for_alts ( user1 , include_current_session = False )
check_for_alts ( user2 , include_current_session = False )
word = ' Delinked ' if is_delinking else ' Relinked '
ma_word = ' delink ' if is_delinking else ' link '
2023-01-21 05:54:29 +00:00
note = f ' from @ { user2 . username } ' if is_delinking else f ' with @ { user2 . username } (relinked) '
2022-05-04 23:09:46 +00:00
ma = ModAction (
2022-11-14 17:32:13 +00:00
kind = f " { ma_word } _accounts " ,
2022-05-04 23:09:46 +00:00
user_id = v . id ,
2022-11-14 17:32:13 +00:00
target_user_id = user1 . id ,
_note = note
2022-05-04 23:09:46 +00:00
)
g . db . add ( ma )
2022-11-14 17:32:13 +00:00
return { " message " : f " { word } @ { user1 . username } and @ { user2 . username } successfully! " }
2022-05-04 23:09:46 +00:00
@app.get ( " /admin/removed/posts " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 00:57:08 +00:00
@admin_level_required ( PERMS [ ' POST_COMMENT_MODERATION ' ] )
2022-05-04 23:09:46 +00:00
def admin_removed ( v ) :
try : page = int ( request . values . get ( " page " , 1 ) )
except : page = 1
if page < 1 : abort ( 400 )
2022-10-29 03:20:48 +00:00
ids = g . db . query ( Submission . id ) . join ( Submission . author ) . filter ( or_ ( Submission . is_banned == True , User . shadowbanned != None ) ) . order_by ( Submission . id . desc ( ) ) . offset ( PAGE_SIZE * ( page - 1 ) ) . limit ( PAGE_SIZE + 1 ) . all ( )
2022-05-04 23:09:46 +00:00
ids = [ x [ 0 ] for x in ids ]
2022-10-29 03:20:48 +00:00
next_exists = len ( ids ) > PAGE_SIZE
ids = ids [ : PAGE_SIZE ]
2022-05-04 23:09:46 +00:00
posts = get_posts ( ids , v = v )
return render_template ( " admin/removed_posts.html " ,
2022-09-04 23:15:37 +00:00
v = v ,
listing = posts ,
page = page ,
next_exists = next_exists
)
2022-05-04 23:09:46 +00:00
@app.get ( " /admin/removed/comments " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 00:57:08 +00:00
@admin_level_required ( PERMS [ ' POST_COMMENT_MODERATION ' ] )
2022-05-04 23:09:46 +00:00
def admin_removed_comments ( v ) :
try : page = int ( request . values . get ( " page " , 1 ) )
except : page = 1
2023-01-01 11:36:20 +00:00
2022-11-27 00:19:50 +00:00
ids = g . db . query ( Comment . id ) . join ( Comment . author ) . filter ( or_ ( Comment . is_banned == True , User . shadowbanned != None ) ) . order_by ( Comment . id . desc ( ) ) . offset ( PAGE_SIZE * ( page - 1 ) ) . limit ( PAGE_SIZE + 1 ) . all ( )
2022-05-04 23:09:46 +00:00
ids = [ x [ 0 ] for x in ids ]
2022-10-29 03:20:48 +00:00
next_exists = len ( ids ) > PAGE_SIZE
ids = ids [ : PAGE_SIZE ]
2022-05-04 23:09:46 +00:00
comments = get_comments ( ids , v = v )
return render_template ( " admin/removed_comments.html " ,
2022-09-04 23:15:37 +00:00
v = v ,
listing = comments ,
page = page ,
next_exists = next_exists
)
2022-05-04 23:09:46 +00:00
2022-12-30 16:22:57 +00:00
@app.post ( " /unagendaposter/<id> " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 03:04:38 +00:00
@admin_level_required ( PERMS [ ' USER_AGENDAPOSTER ' ] )
2022-12-30 16:22:57 +00:00
def unagendaposter ( id , v ) :
if id . startswith ( ' p_ ' ) :
post_id = id . split ( ' p_ ' ) [ 1 ]
post = g . db . get ( Submission , post_id )
user = post . author
elif id . startswith ( ' c_ ' ) :
comment_id = id . split ( ' c_ ' ) [ 1 ]
comment = g . db . get ( Comment , comment_id )
user = comment . author
else :
user = get_account ( id )
2022-05-04 23:09:46 +00:00
2022-12-26 02:38:32 +00:00
if not user . chudded_by :
abort ( 403 , " Jannies can ' t undo chud awards anymore! " )
2022-05-04 23:09:46 +00:00
user . agendaposter = 0
g . db . add ( user )
ma = ModAction (
2022-11-07 01:47:27 +00:00
kind = " unchud " ,
2022-05-04 23:09:46 +00:00
user_id = v . id ,
target_user_id = user . id
)
g . db . add ( ma )
badge = user . has_badge ( 28 )
if badge : g . db . delete ( badge )
2022-12-13 17:11:26 +00:00
send_repeatable_notification ( user . id , f " @ { v . username } (a site admin) has unchudded you. " )
2022-05-04 23:09:46 +00:00
2022-11-05 02:01:45 +00:00
return { " message " : f " @ { user . username } has been unchudded! " }
2022-05-04 23:09:46 +00:00
2022-12-29 10:39:10 +00:00
@app.post ( " /shadowban/<int:user_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-10-06 03:04:38 +00:00
@admin_level_required ( PERMS [ ' USER_SHADOWBAN ' ] )
2022-05-04 23:09:46 +00:00
def shadowban ( user_id , v ) :
2022-06-24 13:19:53 +00:00
user = get_account ( user_id )
2022-11-05 02:16:39 +00:00
if user . admin_level > v . admin_level :
abort ( 403 )
2022-12-13 18:50:38 +00:00
user . shadowbanned = v . id
2022-12-28 09:31:27 +00:00
reason = request . values . get ( " reason " , " " ) . strip ( ) [ : 256 ]
if not reason :
abort ( 400 , " You need to submit a reason for shadowbanning! " )
2022-12-27 04:24:25 +00:00
reason = filter_emojis_only ( reason )
2022-09-29 06:36:59 +00:00
user . ban_reason = reason
2022-05-04 23:09:46 +00:00
g . db . add ( user )
2022-11-22 15:51:04 +00:00
check_for_alts ( user , False )
2022-05-04 23:09:46 +00:00
ma = ModAction (
kind = " shadowban " ,
user_id = v . id ,
target_user_id = user . id ,
2022-09-29 06:36:59 +00:00
_note = f ' reason: " { reason } " '
2022-05-04 23:09:46 +00:00
)
g . db . add ( ma )
2023-01-01 11:36:20 +00:00
2022-05-04 23:09:46 +00:00
cache . delete_memoized ( frontlist )
2022-11-07 06:08:50 +00:00
return { " message " : f " @ { user . username } has been shadowbanned! " }
2022-05-04 23:09:46 +00:00
2022-12-29 10:39:10 +00:00
@app.post ( " /unshadowban/<int:user_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-10-06 03:04:38 +00:00
@admin_level_required ( PERMS [ ' USER_SHADOWBAN ' ] )
2022-05-04 23:09:46 +00:00
def unshadowban ( user_id , v ) :
2022-06-24 13:19:53 +00:00
user = get_account ( user_id )
2022-05-04 23:09:46 +00:00
user . shadowbanned = None
2022-09-29 06:36:59 +00:00
if not user . is_banned : user . ban_reason = None
2022-05-04 23:09:46 +00:00
g . db . add ( user )
2022-12-22 20:03:40 +00:00
2022-12-22 20:44:37 +00:00
for alt in get_alt_graph ( user . id ) :
2022-05-04 23:09:46 +00:00
alt . shadowbanned = None
2022-09-29 06:36:59 +00:00
if not alt . is_banned : alt . ban_reason = None
2022-05-04 23:09:46 +00:00
g . db . add ( alt )
ma = ModAction (
kind = " unshadowban " ,
user_id = v . id ,
target_user_id = user . id ,
)
g . db . add ( ma )
2023-01-01 11:36:20 +00:00
2022-05-04 23:09:46 +00:00
cache . delete_memoized ( frontlist )
2022-11-05 02:16:39 +00:00
return { " message " : f " @ { user . username } has been unshadowbanned! " }
2022-05-04 23:09:46 +00:00
2022-12-29 10:39:10 +00:00
@app.post ( " /admin/title_change/<int:user_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-10-06 05:45:44 +00:00
@admin_level_required ( PERMS [ ' USER_TITLE_CHANGE ' ] )
2022-05-04 23:09:46 +00:00
def admin_title_change ( user_id , v ) :
2022-06-24 13:19:53 +00:00
user = get_account ( user_id )
2022-05-04 23:09:46 +00:00
new_name = request . values . get ( " title " ) . strip ( ) [ : 256 ]
user . customtitleplain = new_name
new_name = filter_emojis_only ( new_name )
2022-11-02 03:22:16 +00:00
new_name = censor_slurs ( new_name , None )
2022-05-04 23:09:46 +00:00
2022-06-24 13:19:53 +00:00
user = get_account ( user . id )
2022-05-04 23:09:46 +00:00
user . customtitle = new_name
if request . values . get ( " locked " ) : user . flairchanged = int ( time . time ( ) ) + 2629746
else :
user . flairchanged = None
badge = user . has_badge ( 96 )
if badge : g . db . delete ( badge )
g . db . add ( user )
if user . flairchanged : kind = " set_flair_locked "
else : kind = " set_flair_notlocked "
2023-01-01 11:36:20 +00:00
2022-05-04 23:09:46 +00:00
ma = ModAction (
kind = kind ,
user_id = v . id ,
target_user_id = user . id ,
2022-12-27 06:11:44 +00:00
_note = f ' " { new_name } " '
2022-05-04 23:09:46 +00:00
)
g . db . add ( ma )
2022-11-07 06:26:41 +00:00
return { " message " : f " @ { user . username } ' s flair has been changed! " }
2022-05-04 23:09:46 +00:00
2022-12-30 16:22:57 +00:00
@app.post ( " /ban_user/<id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-10-06 01:58:43 +00:00
@admin_level_required ( PERMS [ ' USER_BAN ' ] )
2022-12-30 16:22:57 +00:00
def ban_user ( id , v ) :
if id . startswith ( ' p_ ' ) :
post_id = id . split ( ' p_ ' ) [ 1 ]
post = g . db . get ( Submission , post_id )
user = post . author
elif id . startswith ( ' c_ ' ) :
comment_id = id . split ( ' c_ ' ) [ 1 ]
comment = g . db . get ( Comment , comment_id )
user = comment . author
else :
user = get_account ( id )
2022-05-04 23:09:46 +00:00
2022-10-11 13:48:49 +00:00
if user . admin_level > v . admin_level :
abort ( 403 )
2022-05-04 23:09:46 +00:00
2022-10-15 11:02:02 +00:00
days = 0.0
try :
days = float ( request . values . get ( " days " ) )
except :
pass
2022-05-04 23:09:46 +00:00
2023-01-01 00:58:37 +00:00
if days < 0 :
abort ( 400 , " You can ' t bans people for negative days! " )
2022-12-28 09:31:27 +00:00
reason = request . values . get ( " reason " , " " ) . strip ( ) [ : 256 ]
if not reason :
abort ( 400 , " You need to submit a reason for banning! " )
2022-05-04 23:09:46 +00:00
2022-12-27 04:32:53 +00:00
reason = filter_emojis_only ( reason )
2022-12-30 16:10:29 +00:00
reason = reason_regex . sub ( r ' <a href= " \ 1 " > \ 1</a> ' , reason )
2022-05-30 02:55:51 +00:00
user . ban ( admin = v , reason = reason , days = days )
2022-05-04 23:09:46 +00:00
if request . values . get ( " alts " ) :
2022-12-22 20:44:37 +00:00
for x in get_alt_graph ( user . id ) :
2022-10-11 13:48:49 +00:00
if x . admin_level > v . admin_level :
continue
2022-05-30 02:55:51 +00:00
x . ban ( admin = v , reason = reason , days = days )
2022-05-04 23:09:46 +00:00
2022-10-15 11:02:02 +00:00
duration = " permanently "
2022-05-04 23:09:46 +00:00
if days :
2022-11-05 03:06:33 +00:00
days_txt = str ( days )
if days_txt . endswith ( ' .0 ' ) : days_txt = days_txt [ : - 2 ]
2022-10-15 11:02:02 +00:00
duration = f " for { days_txt } day "
if days != 1 : duration + = " s "
2022-12-13 17:11:26 +00:00
if reason : text = f " @ { v . username } (a site admin) has banned you for ** { days_txt } ** days for the following reason: \n \n > { reason } "
else : text = f " @ { v . username } (a site admin) has banned you for ** { days_txt } ** days. "
2022-05-04 23:09:46 +00:00
else :
2022-12-13 17:11:26 +00:00
if reason : text = f " @ { v . username } (a site admin) has banned you permanently for the following reason: \n \n > { reason } "
else : text = f " @ { v . username } (a site admin) has banned you permanently. "
2022-05-04 23:09:46 +00:00
send_repeatable_notification ( user . id , text )
2022-11-05 02:48:02 +00:00
note = f ' duration: { duration } , reason: " { reason } " '
2022-05-04 23:09:46 +00:00
ma = ModAction (
kind = " ban_user " ,
user_id = v . id ,
target_user_id = user . id ,
_note = note
)
g . db . add ( ma )
if ' reason ' in request . values :
2022-06-02 23:18:10 +00:00
if request . values [ " reason " ] . startswith ( " /post/ " ) :
2022-07-28 14:23:38 +00:00
try : post = int ( request . values [ " reason " ] . split ( " /post/ " ) [ 1 ] . split ( None , 1 ) [ 0 ] )
except : abort ( 400 )
2022-06-25 00:11:00 +00:00
post = get_post ( post )
2022-06-28 00:59:08 +00:00
post . bannedfor = f ' { duration } by @ { v . username } '
2022-06-25 00:11:00 +00:00
g . db . add ( post )
2022-06-02 23:18:10 +00:00
elif request . values [ " reason " ] . startswith ( " /comment/ " ) :
2022-07-28 14:23:38 +00:00
try : comment = int ( request . values [ " reason " ] . split ( " /comment/ " ) [ 1 ] . split ( None , 1 ) [ 0 ] )
except : abort ( 400 )
2022-06-25 00:11:00 +00:00
comment = get_comment ( comment )
2022-06-28 00:59:08 +00:00
comment . bannedfor = f ' { duration } by @ { v . username } '
2022-06-25 00:11:00 +00:00
g . db . add ( comment )
2022-05-04 23:09:46 +00:00
2022-12-24 22:45:01 +00:00
return { " message " : f " @ { user . username } has been banned { duration } ! " }
2022-05-04 23:09:46 +00:00
2022-12-30 16:22:57 +00:00
@app.post ( " /agendaposter/<id> " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-11-05 02:12:17 +00:00
@admin_level_required ( PERMS [ ' USER_AGENDAPOSTER ' ] )
2022-12-30 16:22:57 +00:00
def agendaposter ( id , v ) :
if id . startswith ( ' p_ ' ) :
post_id = id . split ( ' p_ ' ) [ 1 ]
post = g . db . get ( Submission , post_id )
user = post . author
elif id . startswith ( ' c_ ' ) :
comment_id = id . split ( ' c_ ' ) [ 1 ]
comment = g . db . get ( Comment , comment_id )
user = comment . author
else :
user = get_account ( id )
2022-11-05 02:12:17 +00:00
if user . admin_level > v . admin_level :
abort ( 403 )
days = 0.0
try :
days = float ( request . values . get ( " days " ) )
except :
pass
2023-01-01 00:58:37 +00:00
if days < 0 :
abort ( 400 , " You can ' t chud people for negative days! " )
2022-11-05 02:12:17 +00:00
reason = request . values . get ( " reason " , " " ) . strip ( )
2022-12-27 04:32:53 +00:00
reason = filter_emojis_only ( reason )
2022-12-30 16:10:29 +00:00
reason = reason_regex . sub ( r ' <a href= " \ 1 " > \ 1</a> ' , reason )
2022-11-05 02:12:17 +00:00
duration = " permanently "
if days :
2022-11-08 03:37:14 +00:00
user . agendaposter = int ( time . time ( ) ) + ( days * 86400 )
2022-11-05 03:06:33 +00:00
days_txt = str ( days )
if days_txt . endswith ( ' .0 ' ) : days_txt = days_txt [ : - 2 ]
2022-11-05 02:12:17 +00:00
duration = f " for { days_txt } day "
if days != 1 : duration + = " s "
2022-12-13 17:11:26 +00:00
if reason : text = f " @ { v . username } (a site admin) has chudded you for ** { days_txt } ** days for the following reason: \n \n > { reason } "
else : text = f " @ { v . username } (a site admin) has chudded you for ** { days_txt } ** days. "
2022-11-05 02:12:17 +00:00
else :
2022-11-08 03:37:14 +00:00
user . agendaposter = 1
2022-12-13 17:11:26 +00:00
if reason : text = f " @ { v . username } (a site admin) has chudded you permanently for the following reason: \n \n > { reason } "
else : text = f " @ { v . username } (a site admin) has chudded you permanently. "
2022-11-05 02:12:17 +00:00
2022-12-26 02:38:32 +00:00
user . chudded_by = v . id
2022-11-08 03:37:14 +00:00
g . db . add ( user )
2022-11-05 02:12:17 +00:00
send_repeatable_notification ( user . id , text )
2022-11-05 02:48:02 +00:00
note = f ' duration: { duration } '
if reason : note + = f ' , reason: " { reason } " '
2022-11-05 02:12:17 +00:00
ma = ModAction (
2022-11-07 01:47:27 +00:00
kind = " chud " ,
2022-11-05 02:12:17 +00:00
user_id = v . id ,
target_user_id = user . id ,
_note = note
)
g . db . add ( ma )
2022-11-07 05:43:25 +00:00
badge_grant ( user = user , badge_id = 28 )
2022-11-05 02:12:17 +00:00
if ' reason ' in request . values :
if request . values [ " reason " ] . startswith ( " /post/ " ) :
try : post = int ( request . values [ " reason " ] . split ( " /post/ " ) [ 1 ] . split ( None , 1 ) [ 0 ] )
except : abort ( 400 )
post = get_post ( post )
2022-12-10 13:06:30 +00:00
if post . sub == ' chudrama ' :
abort ( 403 , " You can ' t chud people in /h/chudrama " )
2022-11-05 02:12:17 +00:00
post . chuddedfor = f ' { duration } by @ { v . username } '
g . db . add ( post )
elif request . values [ " reason " ] . startswith ( " /comment/ " ) :
try : comment = int ( request . values [ " reason " ] . split ( " /comment/ " ) [ 1 ] . split ( None , 1 ) [ 0 ] )
except : abort ( 400 )
comment = get_comment ( comment )
2022-12-10 13:06:30 +00:00
if comment . post . sub == ' chudrama ' :
abort ( 403 , " You can ' t chud people in /h/chudrama " )
2022-11-05 02:12:17 +00:00
comment . chuddedfor = f ' { duration } by @ { v . username } '
g . db . add ( comment )
2022-12-24 22:45:01 +00:00
return { " message " : f " @ { user . username } has been chudded { duration } ! " }
2022-11-05 02:12:17 +00:00
2022-12-30 16:22:57 +00:00
@app.post ( " /unban_user/<id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-10-06 01:58:43 +00:00
@admin_level_required ( PERMS [ ' USER_BAN ' ] )
2022-12-30 16:22:57 +00:00
def unban_user ( id , v ) :
if id . startswith ( ' p_ ' ) :
post_id = id . split ( ' p_ ' ) [ 1 ]
post = g . db . get ( Submission , post_id )
user = post . author
elif id . startswith ( ' c_ ' ) :
comment_id = id . split ( ' c_ ' ) [ 1 ]
comment = g . db . get ( Comment , comment_id )
user = comment . author
else :
user = get_account ( id )
2022-09-01 21:44:40 +00:00
if not user . is_banned :
abort ( 400 )
2022-05-04 23:09:46 +00:00
2022-11-19 14:24:32 +00:00
if FEATURES [ ' AWARDS ' ] and user . ban_reason and user . ban_reason . startswith ( ' 1-Day ban award ' ) :
2022-10-31 23:05:02 +00:00
abort ( 403 , " You can ' t undo a ban award! " )
2022-12-13 22:02:53 +00:00
user . is_banned = None
2022-05-04 23:09:46 +00:00
user . unban_utc = 0
user . ban_reason = None
2022-12-13 17:11:26 +00:00
send_repeatable_notification ( user . id , f " @ { v . username } (a site admin) has unbanned you! " )
2022-05-04 23:09:46 +00:00
g . db . add ( user )
2022-12-22 20:44:37 +00:00
for x in get_alt_graph ( user . id ) :
2022-12-13 17:11:26 +00:00
if x . is_banned : send_repeatable_notification ( x . id , f " @ { v . username } (a site admin) has unbanned you! " )
2022-12-13 22:02:53 +00:00
x . is_banned = None
2022-05-04 23:09:46 +00:00
x . unban_utc = 0
x . ban_reason = None
g . db . add ( x )
ma = ModAction (
kind = " unban_user " ,
user_id = v . id ,
target_user_id = user . id ,
)
g . db . add ( ma )
2022-11-05 02:07:29 +00:00
return { " message " : f " @ { user . username } has been unbanned! " }
2022-05-04 23:09:46 +00:00
2022-11-12 09:11:31 +00:00
@app.post ( " /mute_user/<int:user_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-10-06 01:58:43 +00:00
@admin_level_required ( PERMS [ ' USER_BAN ' ] )
2022-12-11 23:44:34 +00:00
def mute_user ( v : User , user_id ) :
2022-09-01 21:29:27 +00:00
user = get_account ( user_id )
2022-11-12 09:11:31 +00:00
if not user . is_muted :
2022-09-01 21:29:27 +00:00
user . is_muted = True
2022-11-12 09:11:31 +00:00
ma = ModAction (
kind = ' mod_mute_user ' ,
user_id = v . id ,
target_user_id = user . id ,
)
g . db . add ( user )
g . db . add ( ma )
2023-01-24 04:53:07 +00:00
check_for_alts ( user )
2022-11-12 09:11:31 +00:00
return { " message " : f " @ { user . username } has been muted! " }
@app.post ( " /unmute_user/<int:user_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-11-12 09:11:31 +00:00
@admin_level_required ( PERMS [ ' USER_BAN ' ] )
2022-12-11 23:44:34 +00:00
def unmute_user ( v : User , user_id ) :
2022-11-12 09:11:31 +00:00
user = get_account ( user_id )
if user . is_muted :
2022-09-01 21:29:27 +00:00
user . is_muted = False
2022-11-12 09:11:31 +00:00
ma = ModAction (
kind = ' mod_unmute_user ' ,
user_id = v . id ,
target_user_id = user . id ,
)
g . db . add ( user )
g . db . add ( ma )
2022-09-01 21:29:27 +00:00
2022-11-12 09:11:31 +00:00
return { " message " : f " @ { user . username } has been unmuted! " }
2022-09-01 21:29:27 +00:00
2023-01-23 12:40:44 +00:00
@app.post ( " /admin/progstack/<int:post_id> " )
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
@admin_level_required ( PERMS [ ' PROGSTACK ' ] )
def progstack ( post_id , v ) :
post = get_post ( post_id )
post . is_approved = PROGSTACK_ID
2023-01-23 12:44:30 +00:00
post . realupvotes = floor ( post . realupvotes * PROGSTACK_MUL )
2023-01-23 12:40:44 +00:00
g . db . add ( post )
cache . delete_memoized ( frontlist )
return { " message " : " Progressive stack applied! " }
2022-05-04 23:09:46 +00:00
2022-12-29 10:39:10 +00:00
@app.post ( " /remove_post/<int:post_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-10-06 00:57:08 +00:00
@admin_level_required ( PERMS [ ' POST_COMMENT_MODERATION ' ] )
2022-08-11 04:04:41 +00:00
def remove_post ( post_id , v ) :
2022-06-24 13:19:53 +00:00
post = get_post ( post_id )
2022-05-04 23:09:46 +00:00
post . is_banned = True
post . is_approved = None
2022-11-19 14:24:32 +00:00
if not FEATURES [ ' AWARDS ' ] or not post . stickied or not post . stickied . endswith ( PIN_AWARD_TEXT ) :
2022-10-25 15:32:32 +00:00
post . stickied = None
2022-10-24 17:43:14 +00:00
post . is_pinned = False
2022-05-04 23:09:46 +00:00
post . ban_reason = v . username
g . db . add ( post )
ma = ModAction (
kind = " ban_post " ,
user_id = v . id ,
target_submission_id = post . id ,
)
g . db . add ( ma )
cache . delete_memoized ( frontlist )
2022-11-20 10:50:02 +00:00
v . pay_account ( ' coins ' , 1 )
2022-05-04 23:09:46 +00:00
g . db . add ( v )
2022-11-15 09:19:08 +00:00
purge_files_in_cache ( f " https:// { SITE } / " )
2022-05-04 23:09:46 +00:00
return { " message " : " Post removed! " }
2022-12-29 10:39:10 +00:00
@app.post ( " /approve_post/<int:post_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-10-06 00:57:08 +00:00
@admin_level_required ( PERMS [ ' POST_COMMENT_MODERATION ' ] )
2022-08-11 04:04:41 +00:00
def approve_post ( post_id , v ) :
2022-06-24 13:19:53 +00:00
post = get_post ( post_id )
2022-05-04 23:09:46 +00:00
2022-08-19 22:20:25 +00:00
if post . author . id == v . id and post . author . agendaposter and AGENDAPOSTER_PHRASE not in post . body . lower ( ) and post . sub != ' chudrama ' :
2022-10-11 13:01:39 +00:00
abort ( 400 , " You can ' t bypass the chud award! " )
2022-05-09 14:07:29 +00:00
2022-05-04 23:09:46 +00:00
if post . is_banned :
ma = ModAction (
kind = " unban_post " ,
user_id = v . id ,
target_submission_id = post . id ,
)
g . db . add ( ma )
post . is_banned = False
post . ban_reason = None
post . is_approved = v . id
g . db . add ( post )
cache . delete_memoized ( frontlist )
2022-10-12 16:33:00 +00:00
v . charge_account ( ' coins ' , 1 )
2022-05-04 23:09:46 +00:00
g . db . add ( v )
return { " message " : " Post approved! " }
2022-12-29 10:39:10 +00:00
@app.post ( " /distinguish/<int:post_id> " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 04:19:11 +00:00
@admin_level_required ( PERMS [ ' POST_COMMENT_DISTINGUISH ' ] )
2022-08-11 04:05:23 +00:00
def distinguish_post ( post_id , v ) :
2022-06-24 13:19:53 +00:00
post = get_post ( post_id )
2022-05-04 23:09:46 +00:00
if post . distinguish_level :
post . distinguish_level = 0
kind = ' undistinguish_post '
else :
post . distinguish_level = v . admin_level
kind = ' distinguish_post '
g . db . add ( post )
ma = ModAction (
kind = kind ,
user_id = v . id ,
target_submission_id = post . id
)
g . db . add ( ma )
if post . distinguish_level : return { " message " : " Post distinguished! " }
else : return { " message " : " Post undistinguished! " }
2022-12-29 10:39:10 +00:00
@app.post ( " /sticky/<int:post_id> " )
2022-10-11 07:29:24 +00:00
@feature_required ( ' PINS ' )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-11-14 15:11:05 +00:00
@admin_level_required ( PERMS [ ' POST_COMMENT_MODERATION ' ] )
2022-05-04 23:09:46 +00:00
def sticky_post ( post_id , v ) :
2022-10-23 21:36:38 +00:00
post = get_post ( post_id )
2022-10-23 22:17:49 +00:00
if post . is_banned : abort ( 403 , " Can ' t sticky removed posts! " )
2022-11-19 14:24:32 +00:00
if FEATURES [ ' AWARDS ' ] and post . stickied and post . stickied . endswith ( PIN_AWARD_TEXT ) :
2022-10-23 21:36:38 +00:00
abort ( 403 , " Can ' t pin award pins! " )
2022-10-14 18:28:20 +00:00
pins = g . db . query ( Submission ) . filter ( Submission . stickied != None , Submission . is_banned == False ) . count ( )
2022-10-10 09:51:29 +00:00
2022-10-14 18:28:20 +00:00
if not post . stickied_utc :
2022-11-19 15:36:34 +00:00
post . stickied_utc = int ( time . time ( ) ) + 3600
2022-10-14 18:28:20 +00:00
pin_time = ' for 1 hour '
2022-11-19 15:36:34 +00:00
code = 200
2022-10-14 18:35:13 +00:00
if v . id != post . author_id :
2022-12-13 17:11:26 +00:00
send_repeatable_notification ( post . author_id , f " @ { v . username } (a site admin) has pinned [ { post . title } ](/post/ { post_id } ) " )
2022-10-14 18:28:20 +00:00
else :
2022-11-19 15:36:34 +00:00
if pins > = PIN_LIMIT + 1 :
abort ( 403 , f " Can ' t exceed { PIN_LIMIT } pinned posts limit! " )
post . stickied_utc = None
2022-10-14 18:28:46 +00:00
pin_time = ' permanently '
2022-11-19 15:36:34 +00:00
code = 201
2022-10-14 18:28:20 +00:00
post . stickied = v . username
g . db . add ( post )
2022-05-04 23:09:46 +00:00
2022-10-14 18:28:20 +00:00
ma = ModAction (
kind = " pin_post " ,
user_id = v . id ,
target_submission_id = post . id ,
_note = pin_time
)
g . db . add ( ma )
cache . delete_memoized ( frontlist )
2022-05-04 23:09:46 +00:00
2022-11-19 15:36:34 +00:00
return { " message " : f " Post pinned { pin_time } ! " } , code
2022-05-04 23:09:46 +00:00
2022-12-29 10:39:10 +00:00
@app.post ( " /unsticky/<int:post_id> " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 00:57:08 +00:00
@admin_level_required ( PERMS [ ' POST_COMMENT_MODERATION ' ] )
2022-05-04 23:09:46 +00:00
def unsticky_post ( post_id , v ) :
2022-06-24 13:19:53 +00:00
post = get_post ( post_id )
2022-09-30 22:40:02 +00:00
if post . stickied :
2022-11-19 14:24:32 +00:00
if FEATURES [ ' AWARDS ' ] and post . stickied . endswith ( PIN_AWARD_TEXT ) : abort ( 403 , " Can ' t unpin award pins! " )
2022-10-23 18:28:51 +00:00
if post . author_id == LAWLZ_ID and post . stickied_utc and SITE_NAME == ' rDrama ' : abort ( 403 , " Can ' t unpin lawlzposts! " )
2023-01-01 11:36:20 +00:00
2022-05-04 23:09:46 +00:00
post . stickied = None
post . stickied_utc = None
g . db . add ( post )
ma = ModAction (
kind = " unpin_post " ,
user_id = v . id ,
target_submission_id = post . id
)
g . db . add ( ma )
if v . id != post . author_id :
2022-12-13 17:11:26 +00:00
send_repeatable_notification ( post . author_id , f " @ { v . username } (a site admin) has unpinned [ { post . title } ](/post/ { post_id } ) " )
2022-05-04 23:09:46 +00:00
cache . delete_memoized ( frontlist )
return { " message " : " Post unpinned! " }
2022-12-29 10:39:10 +00:00
@app.post ( " /sticky_comment/<int:cid> " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 00:57:08 +00:00
@admin_level_required ( PERMS [ ' POST_COMMENT_MODERATION ' ] )
2022-05-04 23:09:46 +00:00
def sticky_comment ( cid , v ) :
comment = get_comment ( cid , v = v )
2023-01-24 10:23:19 +00:00
if comment . is_banned :
abort ( 403 , " Can ' t sticky removed comments! " )
2022-05-04 23:09:46 +00:00
2022-05-26 23:08:23 +00:00
if not comment . stickied :
comment . stickied = v . username
2022-05-04 23:09:46 +00:00
g . db . add ( comment )
ma = ModAction (
kind = " pin_comment " ,
user_id = v . id ,
target_comment_id = comment . id
)
g . db . add ( ma )
if v . id != comment . author_id :
2022-12-13 17:11:26 +00:00
message = f " @ { v . username } (a site admin) has pinned your [comment]( { comment . shortlink } ) "
2022-05-04 23:09:46 +00:00
send_repeatable_notification ( comment . author_id , message )
2022-11-26 04:01:20 +00:00
c = comment
while c . level > 2 :
c = c . parent_comment
c . stickied_child_id = comment . id
g . db . add ( c )
2022-05-04 23:09:46 +00:00
return { " message " : " Comment pinned! " }
2023-01-01 11:36:20 +00:00
2022-05-04 23:09:46 +00:00
2022-12-29 10:39:10 +00:00
@app.post ( " /unsticky_comment/<int:cid> " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 00:57:08 +00:00
@admin_level_required ( PERMS [ ' POST_COMMENT_MODERATION ' ] )
2022-05-04 23:09:46 +00:00
def unsticky_comment ( cid , v ) :
comment = get_comment ( cid , v = v )
2023-01-01 11:36:20 +00:00
2022-05-26 23:08:23 +00:00
if comment . stickied :
2022-11-19 14:24:32 +00:00
if FEATURES [ ' AWARDS ' ] and comment . stickied . endswith ( PIN_AWARD_TEXT ) : abort ( 403 , " Can ' t unpin award pins! " )
2022-05-04 23:09:46 +00:00
2022-05-26 23:08:23 +00:00
comment . stickied = None
2022-05-04 23:09:46 +00:00
g . db . add ( comment )
ma = ModAction (
kind = " unpin_comment " ,
user_id = v . id ,
target_comment_id = comment . id
)
g . db . add ( ma )
if v . id != comment . author_id :
2022-12-13 17:11:26 +00:00
message = f " @ { v . username } (a site admin) has unpinned your [comment]( { comment . shortlink } ) "
2022-05-04 23:09:46 +00:00
send_repeatable_notification ( comment . author_id , message )
2022-11-26 04:01:20 +00:00
cleanup = g . db . query ( Comment ) . filter_by ( stickied_child_id = comment . id ) . all ( )
for c in cleanup :
c . stickied_child_id = None
g . db . add ( c )
2022-05-04 23:09:46 +00:00
return { " message " : " Comment unpinned! " }
2022-12-29 10:39:10 +00:00
@app.post ( " /remove_comment/<int:c_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-10-06 00:57:08 +00:00
@admin_level_required ( PERMS [ ' POST_COMMENT_MODERATION ' ] )
2022-08-11 04:05:23 +00:00
def remove_comment ( c_id , v ) :
2022-06-24 13:19:53 +00:00
comment = get_comment ( c_id )
2022-05-04 23:09:46 +00:00
comment . is_banned = True
comment . is_approved = None
comment . ban_reason = v . username
g . db . add ( comment )
ma = ModAction (
kind = " ban_comment " ,
user_id = v . id ,
target_comment_id = comment . id ,
)
g . db . add ( ma )
2022-05-30 03:01:03 +00:00
2022-05-04 23:09:46 +00:00
return { " message " : " Comment removed! " }
2022-12-29 10:39:10 +00:00
@app.post ( " /approve_comment/<int:c_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-10-06 00:57:08 +00:00
@admin_level_required ( PERMS [ ' POST_COMMENT_MODERATION ' ] )
2022-08-11 04:05:23 +00:00
def approve_comment ( c_id , v ) :
2022-06-24 13:19:53 +00:00
comment = get_comment ( c_id )
2023-01-01 11:36:20 +00:00
2022-12-05 03:08:06 +00:00
if comment . author . id == v . id and comment . author . agendaposter and AGENDAPOSTER_PHRASE not in comment . body . lower ( ) and not ( comment . parent_submission and comment . post . sub == ' chudrama ' ) :
2022-10-11 13:01:39 +00:00
abort ( 400 , " You can ' t bypass the chud award! " )
2022-05-04 23:09:46 +00:00
if comment . is_banned :
ma = ModAction (
kind = " unban_comment " ,
user_id = v . id ,
target_comment_id = comment . id ,
)
g . db . add ( ma )
comment . is_banned = False
comment . ban_reason = None
comment . is_approved = v . id
g . db . add ( comment )
return { " message " : " Comment approved! " }
2022-12-29 10:39:10 +00:00
@app.post ( " /distinguish_comment/<int:c_id> " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 04:19:11 +00:00
@admin_level_required ( PERMS [ ' POST_COMMENT_DISTINGUISH ' ] )
2022-05-04 23:09:46 +00:00
def admin_distinguish_comment ( c_id , v ) :
comment = get_comment ( c_id , v = v )
if comment . distinguish_level :
comment . distinguish_level = 0
kind = ' undistinguish_comment '
else :
comment . distinguish_level = v . admin_level
kind = ' distinguish_comment '
g . db . add ( comment )
ma = ModAction (
kind = kind ,
user_id = v . id ,
target_comment_id = comment . id
)
g . db . add ( ma )
if comment . distinguish_level : return { " message " : " Comment distinguished! " }
else : return { " message " : " Comment undistinguished! " }
@app.get ( " /admin/banned_domains/ " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 04:26:15 +00:00
@admin_level_required ( PERMS [ ' DOMAINS_BAN ' ] )
2022-05-04 23:09:46 +00:00
def admin_banned_domains ( v ) :
2022-11-29 21:24:13 +00:00
banned_domains = g . db . query ( BannedDomain ) \
. order_by ( BannedDomain . reason ) . all ( )
return render_template ( " admin/banned_domains.html " , v = v ,
banned_domains = banned_domains )
2022-05-04 23:09:46 +00:00
2022-12-30 16:24:20 +00:00
@app.post ( " /admin/ban_domain " )
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-12-30 16:24:20 +00:00
@admin_level_required ( PERMS [ ' DOMAINS_BAN ' ] )
def ban_domain ( v ) :
2022-05-04 23:09:46 +00:00
2022-12-30 16:24:20 +00:00
domain = request . values . get ( " domain " , " " ) . strip ( ) . lower ( )
if not domain : abort ( 400 )
2022-05-04 23:09:46 +00:00
2022-12-30 16:24:20 +00:00
reason = request . values . get ( " reason " , " " ) . strip ( )
if not reason : abort ( 400 , ' Reason is required! ' )
2022-12-27 05:18:46 +00:00
2022-12-30 16:24:20 +00:00
if len ( reason ) > 100 :
abort ( 400 , ' Reason is too long (max 100 characters)! ' )
2022-12-27 05:18:46 +00:00
2022-12-30 16:24:20 +00:00
if len ( reason ) > 100 :
abort ( 400 , ' Reason is too long! ' )
2022-12-27 05:02:14 +00:00
2022-12-30 16:24:20 +00:00
existing = g . db . get ( BannedDomain , domain )
if not existing :
d = BannedDomain ( domain = domain , reason = reason )
g . db . add ( d )
ma = ModAction (
kind = " ban_domain " ,
user_id = v . id ,
_note = filter_emojis_only ( f ' { domain } , reason: { reason } ' )
)
g . db . add ( ma )
2022-05-04 23:09:46 +00:00
2022-12-30 16:24:20 +00:00
return redirect ( " /admin/banned_domains/ " )
2022-05-04 23:09:46 +00:00
2022-10-20 22:14:25 +00:00
2022-12-30 16:24:20 +00:00
@app.post ( " /admin/unban_domain/<path:domain> " )
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-12-30 16:24:20 +00:00
@admin_level_required ( PERMS [ ' DOMAINS_BAN ' ] )
def unban_domain ( v : User , domain ) :
existing = g . db . get ( BannedDomain , domain )
if not existing : abort ( 400 , ' Domain is not banned! ' )
2023-01-01 11:36:20 +00:00
2022-12-30 16:24:20 +00:00
g . db . delete ( existing )
ma = ModAction (
kind = " unban_domain " ,
user_id = v . id ,
_note = filter_emojis_only ( domain )
)
g . db . add ( ma )
return { " message " : f " { domain } has been unbanned! " }
2022-10-20 22:14:25 +00:00
2022-05-04 23:09:46 +00:00
@app.post ( " /admin/nuke_user " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-10-06 01:58:43 +00:00
@admin_level_required ( PERMS [ ' POST_COMMENT_MODERATION ' ] )
2022-05-04 23:09:46 +00:00
def admin_nuke_user ( v ) :
user = get_user ( request . values . get ( " user " ) )
for post in g . db . query ( Submission ) . filter_by ( author_id = user . id ) . all ( ) :
if post . is_banned :
continue
2023-01-01 11:36:20 +00:00
2022-05-04 23:09:46 +00:00
post . is_banned = True
post . ban_reason = v . username
g . db . add ( post )
for comment in g . db . query ( Comment ) . filter_by ( author_id = user . id ) . all ( ) :
if comment . is_banned :
continue
comment . is_banned = True
comment . ban_reason = v . username
g . db . add ( comment )
ma = ModAction (
kind = " nuke_user " ,
user_id = v . id ,
target_user_id = user . id ,
)
g . db . add ( ma )
2022-11-07 06:26:41 +00:00
return { " message " : f " @ { user . username } ' s content has been removed! " }
2022-05-04 23:09:46 +00:00
@app.post ( " /admin/unnuke_user " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER , key_func = get_ID )
2022-10-06 01:58:43 +00:00
@admin_level_required ( PERMS [ ' POST_COMMENT_MODERATION ' ] )
2022-05-04 23:09:46 +00:00
def admin_nunuke_user ( v ) :
user = get_user ( request . values . get ( " user " ) )
for post in g . db . query ( Submission ) . filter_by ( author_id = user . id ) . all ( ) :
if not post . is_banned :
continue
2023-01-01 11:36:20 +00:00
2022-05-04 23:09:46 +00:00
post . is_banned = False
post . ban_reason = None
2022-07-12 20:00:19 +00:00
post . is_approved = v . id
2022-05-04 23:09:46 +00:00
g . db . add ( post )
for comment in g . db . query ( Comment ) . filter_by ( author_id = user . id ) . all ( ) :
if not comment . is_banned :
continue
comment . is_banned = False
comment . ban_reason = None
2022-07-12 20:00:19 +00:00
comment . is_approved = v . id
2022-05-04 23:09:46 +00:00
g . db . add ( comment )
ma = ModAction (
kind = " unnuke_user " ,
user_id = v . id ,
target_user_id = user . id ,
)
g . db . add ( ma )
2022-11-07 06:26:41 +00:00
return { " message " : f " @ { user . username } ' s content has been approved! " }