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
2023-02-19 19:31:26 +00:00
import os
2022-11-15 09:19:08 +00:00
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 *
2023-01-25 02:51:48 +00:00
from files . routes . routehelpers import get_alt_graph , get_alt_graph_ids
2022-11-15 09:19:08 +00:00
2023-01-25 11:35:37 +00:00
from . front import frontlist , comment_idlist
2022-11-15 09:19:08 +00:00
2022-05-25 20:16:26 +00:00
@app.get ( ' /admin/loggedin ' )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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 ) :
2023-03-25 20:57:27 +00:00
ids = [ x for x , val in cache . get ( ' loggedin ' ) . items ( ) if time . time ( ) - val < LOGGEDIN_ACTIVE_TIME ]
2023-03-16 06:27: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-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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 ) :
2023-03-25 20:57:27 +00:00
users = sorted ( [ val [ 1 ] for x , val in cache . get ( ' 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-23 09:58:38 +00:00
@app.get ( ' /admin/dm_images ' )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-01-23 09:58:38 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2023-03-25 21:13:47 +00:00
@admin_level_required ( PERMS [ ' ENABLE_DM_IMAGES ' ] )
2023-01-23 09:58:38 +00:00
def dm_images ( v ) :
with open ( f " { LOG_DIRECTORY } /dm_images.log " , " r " , encoding = " utf-8 " ) as f :
2023-01-27 12:24:39 +00:00
items = f . read ( ) . split ( " \n " ) [ : - 1 ]
items = [ x . split ( " , " ) for x in items ]
2023-02-22 14:36:52 +00:00
items . reverse ( )
2023-01-27 12:24:39 +00:00
2023-02-22 14:36:52 +00:00
try : page = int ( request . values . get ( ' page ' , 1 ) )
except : page = 1
firstrange = PAGE_SIZE * ( page - 1 )
secondrange = firstrange + PAGE_SIZE + 1
2023-02-22 14:43:39 +00:00
items = items [ firstrange : secondrange ]
next_exists = ( len ( items ) > PAGE_SIZE )
2023-02-22 14:36:52 +00:00
return render_template ( " admin/dm_images.html " , v = v , items = items , next_exists = next_exists , page = page )
2022-12-05 05:22:08 +00:00
@app.get ( ' /admin/edit_rules ' )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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 ' )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 01:42:39 +00:00
@limiter.limit ( " 30/minute;200/hour;1000/day " )
@limiter.limit ( " 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 ( )
2023-02-07 03:31:49 +00:00
rules = sanitize ( rules , blackjack = " rules " , showmore = False )
2022-12-05 05:22:08 +00:00
with open ( f ' files/templates/rules_ { SITE_NAME } .html ' , ' w+ ' , encoding = " utf-8 " ) as f :
f . write ( rules )
2023-03-23 20:22:46 +00:00
# ma = ModAction(
# kind="edit_rules",
# user_id=v.id,
# )
# g.db.add(ma)
2022-12-05 05:22:08 +00:00
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-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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-05-04 23:09:46 +00:00
user = get_user ( username )
2022-09-01 21:44:40 +00:00
2023-01-29 08:28:29 +00:00
user . admin_level = 1
2023-03-16 06:27:58 +00:00
g . db . add ( user )
2022-05-04 23:09:46 +00:00
ma = ModAction (
kind = " make_admin " ,
user_id = v . id ,
target_user_id = user . id
)
2023-03-16 06:27:58 +00:00
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 } 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-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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
2023-03-16 06:27:58 +00:00
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
)
2023-03-16 06:27:58 +00:00
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
2023-03-12 17:36:35 +00:00
@app.post ( " /distribute/<kind>/<int:option_id> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-12-02 22:08:46 +00:00
@admin_level_required ( PERMS [ ' POST_BETS_DISTRIBUTE ' ] )
2023-03-12 17:36:35 +00:00
def distribute ( v : User , kind , 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 )
2023-03-12 17:36:35 +00:00
if kind == ' post ' : cls = SubmissionOption
else : cls = CommentOption
2023-03-16 06:27:58 +00:00
option = g . db . get ( cls , option_id )
2022-08-26 21:53:17 +00:00
2022-09-08 18:25:45 +00:00
if option . exclusive != 2 : abort ( 403 )
option . exclusive = 3
2023-03-16 06:27:58 +00:00
g . db . add ( option )
2022-09-08 18:25:45 +00:00
2023-03-12 17:36:35 +00:00
parent = option . parent
2022-08-26 21:53:17 +00:00
pool = 0
2023-03-12 17:36:35 +00:00
for o in parent . 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
2023-03-16 06:27:58 +00:00
g . db . add ( autojanny )
2022-08-26 21:53:17 +00:00
votes = option . votes
coinsperperson = int ( pool / len ( votes ) )
2023-03-12 17:36:35 +00:00
text = f " You won { coinsperperson } coins betting on { parent . permalink } :marseyparty: "
2023-02-24 02:28:10 +00:00
cid = notif_comment ( text )
2022-08-26 21:53:17 +00:00
for vote in votes :
u = vote . user
2022-11-20 10:50:02 +00:00
u . pay_account ( ' coins ' , coinsperperson )
2023-02-24 02:28:10 +00:00
add_notif ( cid , u . id , text )
2022-08-26 21:53:17 +00:00
2023-03-12 17:36:35 +00:00
text = f " You lost the { POLL_BET_COINS } coins you bet on { parent . permalink } :marseylaugh: "
2023-02-24 02:28:10 +00:00
cid = notif_comment ( text )
2022-08-26 21:53:17 +00:00
losing_voters = [ ]
2023-03-12 17:36:35 +00:00
for o in parent . 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 :
2023-02-24 02:28:10 +00:00
add_notif ( cid , uid , text )
2023-01-01 11:36:20 +00:00
2023-03-12 17:36:35 +00:00
if isinstance ( parent , Submission ) :
ma = ModAction (
kind = " distribute " ,
user_id = v . id ,
target_submission_id = parent . id
)
else :
ma = ModAction (
kind = " distribute " ,
user_id = v . id ,
target_comment_id = parent . id
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-08-26 21:53:17 +00:00
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 " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , 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
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-10-08 04:07:44 +00:00
cutoff = int ( time . time ( ) ) - 86400
2023-03-16 06:27:58 +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 ( ) ]
posts = g . db . query ( Submission ) . filter ( Submission . id . in_ ( posts ) ) . all ( )
2022-10-08 04:07:44 +00:00
2023-03-16 06:27:58 +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 ( ) ]
comments = g . db . query ( Comment ) . filter ( Comment . id . in_ ( comments ) ) . all ( )
2022-10-08 04:07:44 +00:00
for item in posts + comments :
item . is_banned = False
item . ban_reason = None
item . is_approved = v . id
2023-03-16 06:27:58 +00:00
g . db . add ( item )
2022-10-08 04:07:44 +00:00
2023-03-16 06:27:58 +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 ( ) )
users = g . db . query ( User ) . filter ( User . id . in_ ( users ) ) . all ( )
2022-10-08 04:07:44 +00:00
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! " )
2023-03-16 06:27:58 +00:00
g . db . add ( user )
2022-10-08 04:07:44 +00:00
2023-01-25 02:51:48 +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! " )
2023-03-16 06:27:58 +00:00
g . db . add ( u )
2022-10-08 04:07:44 +00:00
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-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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 ) :
2023-03-16 06:27:58 +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-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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
2023-03-16 06:27:58 +00:00
posts = g . db . query ( Submission ) . order_by ( Submission . id . desc ( ) )
2022-05-04 23:09:46 +00:00
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-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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
2023-03-16 06:27:58 +00:00
listing = g . db . query ( Submission ) . 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 ( 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-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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
2023-03-16 06:27:58 +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-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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 ) :
2023-02-09 03:50:30 +00:00
return render_template ( " admin/admin_home.html " , v = v )
2022-05-04 23:09:46 +00:00
@app.post ( " /admin/site_settings/<setting> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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-11-30 17:37:35 +00:00
if setting not in get_settings ( ) . keys ( ) :
abort ( 404 , f " Setting ' { setting } ' not found " )
2023-03-25 21:35:13 +00:00
if setting == " offline_mode " and v . admin_level < PERMS [ " SITE_OFFLINE_MODE " ] :
abort ( 403 , " You can ' t change this setting! " )
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
2023-02-09 03:50:30 +00:00
if setting == " under_attack " :
new_security_level = ' under_attack ' if val else ' high '
if not set_security_level ( new_security_level ) :
2023-02-09 04:00:37 +00:00
abort ( 400 , f ' Failed to { word } under attack mode ' )
2023-02-09 03:50:30 +00:00
2023-03-01 20:45:42 +00:00
ma = ModAction (
kind = f " { word } _ { setting } " ,
user_id = v . id ,
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2023-01-24 05:48:27 +00:00
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-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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
)
2023-03-16 06:27:58 +00:00
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
2022-11-27 22:02:18 +00:00
def admin_badges_grantable_list ( v ) :
2023-03-16 06:27:58 +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-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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 ' )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , 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 :
2023-03-17 17:59:55 +00:00
error = " User not found! "
if v . client : return { " error " : error }
return render_template ( " admin/badge_admin.html " , v = v , badge_types = badges , grant = True , error = error )
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-23 01:01:24 +00:00
existing = user . has_badge ( badge_id )
if existing :
if url or description :
existing . url = url
existing . description = description
2023-03-16 06:27:58 +00:00
g . db . add ( existing )
2023-03-17 17:59:55 +00:00
msg = " Badge attributes edited successfully! "
if v . client : return { " message " : msg }
return render_template ( " admin/badge_admin.html " , v = v , badge_types = badges , grant = True , msg = msg )
error = " User already has that badge! "
if v . client : return { " error " : error }
return render_template ( " admin/badge_admin.html " , v = v , badge_types = badges , grant = True , error = error )
2022-12-23 01:01:24 +00:00
new_badge = Badge (
badge_id = badge_id ,
user_id = user . id ,
url = url ,
description = description
)
2022-05-04 23:09:46 +00:00
2023-03-16 06:27:58 +00:00
g . db . add ( new_badge )
g . db . flush ( )
2022-05-04 23:09:46 +00:00
if v . id != user . id :
2023-03-12 13:02:31 +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
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-12-23 01:01:24 +00:00
2023-03-16 13:38:18 +00:00
msg = f " { new_badge . name } Badge granted to @ { user . username } successfully! "
if v . client : return { " message " : msg }
return render_template ( " admin/badge_admin.html " , v = v , badge_types = badges , grant = True , msg = msg )
2022-05-04 23:09:46 +00:00
@app.post ( " /admin/badge_remove " )
2022-11-14 15:11:05 +00:00
@feature_required ( ' BADGES ' )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , 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 :
2023-01-27 11:57: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 :
2023-01-27 11:57: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 :
2023-03-12 13:02:31 +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
)
2023-03-16 06:27:58 +00:00
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-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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 )
2023-03-16 06:27:58 +00:00
u1_post_ups = g . db . query (
2022-05-04 23:09:46 +00:00
Vote . submission_id ) . filter_by (
user_id = u1 . id ,
vote_type = 1 ) . all ( )
2023-03-16 06:27:58 +00:00
u1_post_downs = g . db . query (
2022-05-04 23:09:46 +00:00
Vote . submission_id ) . filter_by (
user_id = u1 . id ,
vote_type = - 1 ) . all ( )
2023-03-16 06:27:58 +00:00
u1_comment_ups = g . db . query (
2022-05-04 23:09:46 +00:00
CommentVote . comment_id ) . filter_by (
user_id = u1 . id ,
vote_type = 1 ) . all ( )
2023-03-16 06:27:58 +00:00
u1_comment_downs = g . db . query (
2022-05-04 23:09:46 +00:00
CommentVote . comment_id ) . filter_by (
user_id = u1 . id ,
vote_type = - 1 ) . all ( )
2023-03-16 06:27:58 +00:00
u2_post_ups = g . db . query (
2022-05-04 23:09:46 +00:00
Vote . submission_id ) . filter_by (
user_id = u2 . id ,
vote_type = 1 ) . all ( )
2023-03-16 06:27:58 +00:00
u2_post_downs = g . db . query (
2022-05-04 23:09:46 +00:00
Vote . submission_id ) . filter_by (
user_id = u2 . id ,
vote_type = - 1 ) . all ( )
2023-03-16 06:27:58 +00:00
u2_comment_ups = g . db . query (
2022-05-04 23:09:46 +00:00
CommentVote . comment_id ) . filter_by (
user_id = u2 . id ,
vote_type = 1 ) . all ( )
2023-03-16 06:27:58 +00:00
u2_comment_downs = g . db . query (
2022-05-04 23:09:46 +00:00
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/ " )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , 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-24 10:32:06 +00:00
u = get_user ( username or request . values . get ( ' username ' ) , graceful = True )
return render_template ( ' admin/alts.html ' , v = v , u = u , alts = u . alts if u else None )
2022-05-04 23:09:46 +00:00
2022-11-14 17:32:13 +00:00
@app.post ( ' /@<username>/alts/ ' )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , 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 " )
ids = [ user1 . id , user2 . id ]
2023-03-16 06:27:58 +00:00
a = g . db . query ( Alt ) . filter ( Alt . user1 . in_ ( ids ) , Alt . user2 . in_ ( ids ) ) . one_or_none ( )
2023-02-18 15:19:14 +00:00
if a : abort ( 409 , f " @ { user1 . username } and @ { user2 . username } are already known alts! " )
2022-11-14 17:32:13 +00:00
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
)
2023-03-16 06:27:58 +00:00
g . db . add ( a )
g . db . flush ( )
2022-05-04 23:09:46 +00:00
2023-01-25 02:51:48 +00:00
cache . delete_memoized ( get_alt_graph_ids , user1 . id )
cache . delete_memoized ( get_alt_graph_ids , user2 . id )
2023-01-25 02:53:52 +00:00
check_for_alts ( user1 )
check_for_alts ( user2 )
2022-05-04 23:09:46 +00:00
2022-11-14 17:32:13 +00:00
ma = ModAction (
2023-02-18 15:19:14 +00:00
kind = f " link_accounts " ,
2022-11-14 17:32:13 +00:00
user_id = v . id ,
target_user_id = user1 . id ,
2023-02-18 15:19:14 +00:00
_note = f ' with @ { user2 . username } '
2022-11-14 17:32:13 +00:00
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2023-02-18 15:19:14 +00:00
return { " message " : f " Linked @ { user1 . username } and @ { user2 . username } successfully! " }
2022-09-23 12:33:58 +00:00
2023-02-18 14:55:18 +00:00
@app.post ( ' /@<username>/alts/<int:other>/deleted ' )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , 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
user1 = get_user ( username )
user2 = get_account ( other )
ids = [ user1 . id , user2 . id ]
2023-03-16 06:27:58 +00:00
a = g . db . query ( Alt ) . filter ( Alt . user1 . in_ ( ids ) , Alt . user2 . in_ ( ids ) ) . one_or_none ( )
2022-11-14 17:32:13 +00:00
if not a : abort ( 404 )
2023-03-16 06:27:58 +00:00
g . db . delete ( a )
2022-05-04 23:09:46 +00:00
ma = ModAction (
2023-02-18 14:55:18 +00:00
kind = f " delink_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 ,
2023-02-18 14:55:18 +00:00
_note = f ' from @ { user2 . username } '
2022-05-04 23:09:46 +00:00
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-05-04 23:09:46 +00:00
2023-02-18 14:55:18 +00:00
return { " message " : f " Delinked @ { user1 . username } and @ { user2 . username } successfully! " }
2022-05-04 23:09:46 +00:00
@app.get ( " /admin/removed/posts " )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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 )
2023-03-16 06:27:58 +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-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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
2023-03-16 06:27:58 +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
2023-03-17 14:37:13 +00:00
@app.post ( " /unchud_user/<id> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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 ]
2023-03-16 06:27:58 +00:00
post = g . db . get ( Submission , post_id )
2022-12-30 16:22:57 +00:00
user = post . author
elif id . startswith ( ' c_ ' ) :
comment_id = id . split ( ' c_ ' ) [ 1 ]
2023-03-16 06:27:58 +00:00
comment = g . db . get ( Comment , comment_id )
2022-12-30 16:22:57 +00:00
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
2023-03-19 17:13:45 +00:00
user . agendaposter_phrase = None
2023-02-19 13:23:08 +00:00
user . chudded_by = None
2023-03-16 06:27:58 +00:00
g . db . add ( user )
2022-05-04 23:09:46 +00:00
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
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-05-04 23:09:46 +00:00
badge = user . has_badge ( 28 )
2023-03-16 06:27:58 +00:00
if badge : g . db . delete ( badge )
2022-05-04 23:09:46 +00:00
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> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , 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 )
2023-02-21 14:30:31 +00:00
if len ( reason ) > 256 :
abort ( 400 , " Ban reason too long! " )
2022-09-29 06:36:59 +00:00
user . ban_reason = reason
2023-03-16 06:27:58 +00:00
g . db . add ( user )
2023-01-25 02:53:52 +00:00
check_for_alts ( user )
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
)
2023-03-16 06:27:58 +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> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , 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
2023-03-16 06:27:58 +00:00
g . db . add ( user )
2022-12-22 20:03:40 +00:00
2023-01-25 02:51:48 +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
2023-03-16 06:27:58 +00:00
g . db . add ( alt )
2022-05-04 23:09:46 +00:00
ma = ModAction (
kind = " unshadowban " ,
user_id = v . id ,
target_user_id = user . id ,
)
2023-03-16 06:27:58 +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-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> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , 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 )
2023-03-16 06:27:58 +00:00
if badge : g . db . delete ( badge )
2022-05-04 23:09:46 +00:00
2023-03-16 06:27:58 +00:00
g . db . add ( user )
2022-05-04 23:09:46 +00:00
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
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-05-04 23:09:46 +00:00
2023-02-22 17:00:38 +00:00
if user . flairchanged :
message = f " @ { v . username } (a site admin) has locked your flair to ` { user . customtitleplain } `. "
else :
message = f " @ { v . username } (a site admin) has changed your flair to ` { user . customtitleplain } `. You can change it back in the settings. "
2023-02-22 17:27:33 +00:00
2023-02-22 17:00:38 +00:00
send_repeatable_notification ( user . id , message )
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> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , 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 ]
2023-03-16 06:27:58 +00:00
post = g . db . get ( Submission , post_id )
2022-12-30 16:22:57 +00:00
user = post . author
elif id . startswith ( ' c_ ' ) :
comment_id = id . split ( ' c_ ' ) [ 1 ]
2023-03-16 06:27:58 +00:00
comment = g . db . get ( Comment , comment_id )
2022-12-30 16:22:57 +00:00
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
2023-02-22 17:11:29 +00:00
if user . is_suspended_permanently :
abort ( 403 , f " @ { user . username } is already banned permanently! " )
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 )
2023-02-21 14:30:31 +00:00
if len ( reason ) > 256 :
abort ( 400 , " Ban reason too long! " )
2022-12-27 04:32:53 +00:00
2023-02-07 02:34:11 +00:00
reason = reason_regex_post . sub ( r ' <a href= " \ 1 " > \ 1</a> ' , reason )
reason = reason_regex_comment . sub ( r ' <a href= " \ 1#context " > \ 1</a> ' , reason )
2022-12-30 16:10:29 +00:00
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 " ) :
2023-01-25 02:51:48 +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
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-05-04 23:09:46 +00:00
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 )
2023-03-15 02:13:39 +00:00
if post . sub != ' chudrama ' :
post . bannedfor = f ' { duration } by @ { v . username } '
2023-03-16 06:27:58 +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 } '
2023-03-16 06:27:58 +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
2023-03-17 14:37:13 +00:00
@app.post ( " /chud_user/<id> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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 ]
2023-03-16 06:27:58 +00:00
post = g . db . get ( Submission , post_id )
2022-12-30 16:22:57 +00:00
user = post . author
elif id . startswith ( ' c_ ' ) :
comment_id = id . split ( ' c_ ' ) [ 1 ]
2023-03-16 06:27:58 +00:00
comment = g . db . get ( Comment , comment_id )
2022-12-30 16:22:57 +00:00
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 )
2023-02-22 17:11:29 +00:00
if user . agendaposter == 1 :
abort ( 403 , f " @ { user . username } is already chudded permanently! " )
2022-11-05 02:12:17 +00:00
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 )
2023-02-07 02:34:11 +00:00
reason = reason_regex_post . sub ( r ' <a href= " \ 1 " > \ 1</a> ' , reason )
reason = reason_regex_comment . sub ( r ' <a href= " \ 1#context " > \ 1</a> ' , reason )
2022-12-30 16:10:29 +00:00
2022-11-05 02:12:17 +00:00
if days :
2023-02-19 13:23:08 +00:00
if user . agendaposter :
user . agendaposter + = days * 86400
else :
user . agendaposter = int ( time . time ( ) ) + ( days * 86400 )
2023-03-24 11:51:25 +00:00
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 "
else :
2022-11-08 03:37:14 +00:00
user . agendaposter = 1
2023-03-24 11:51:25 +00:00
duration = " permanently "
2022-11-05 02:12:17 +00:00
2023-03-21 11:03:27 +00:00
user . agendaposter_phrase = " trans lives matter "
2023-03-24 11:51:25 +00:00
text = f " @ { v . username } (a site admin) has chudded you ** { duration } ** "
if reason : text + = f " for the following reason: \n \n > { reason } "
text + = f " \n \n **You now have to say this phrase in all posts and comments you make { duration } :** \n \n > { user . agendaposter_phrase } "
2023-03-23 18:53:07 +00:00
2022-12-26 02:38:32 +00:00
user . chudded_by = v . id
2023-03-16 06:27:58 +00:00
g . db . add ( user )
2022-11-08 03:37:14 +00:00
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
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-11-05 02:12:17 +00:00
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 } '
2023-03-16 06:27:58 +00:00
g . db . add ( post )
2022-11-05 02:12:17 +00:00
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 } '
2023-03-16 06:27:58 +00:00
g . db . add ( comment )
2022-11-05 02:12:17 +00:00
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> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , 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 ]
2023-03-16 06:27:58 +00:00
post = g . db . get ( Submission , post_id )
2022-12-30 16:22:57 +00:00
user = post . author
elif id . startswith ( ' c_ ' ) :
comment_id = id . split ( ' c_ ' ) [ 1 ]
2023-03-16 06:27:58 +00:00
comment = g . db . get ( Comment , comment_id )
2022-12-30 16:22:57 +00:00
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! " )
2023-03-16 06:27:58 +00:00
g . db . add ( user )
2022-05-04 23:09:46 +00:00
2023-01-25 02:51:48 +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
2023-03-16 06:27:58 +00:00
g . db . add ( x )
2022-05-04 23:09:46 +00:00
ma = ModAction (
kind = " unban_user " ,
user_id = v . id ,
target_user_id = user . id ,
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-05-04 23:09:46 +00:00
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> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , 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 ,
)
2023-03-16 06:27:58 +00:00
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> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , 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 ,
)
2023-03-16 06:27:58 +00:00
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-25 11:35:37 +00:00
@app.post ( " /admin/progstack/post/<int:post_id> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2023-01-23 12:40:44 +00:00
@admin_level_required ( PERMS [ ' PROGSTACK ' ] )
2023-01-25 11:35:37 +00:00
def progstack_post ( post_id , v ) :
2023-01-23 12:40:44 +00:00
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-03-16 06:27:58 +00:00
g . db . add ( post )
2023-01-25 11:35:37 +00:00
ma = ModAction (
kind = " progstack_post " ,
user_id = v . id ,
target_submission_id = post . id ,
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2023-01-25 11:35:37 +00:00
2023-01-23 12:40:44 +00:00
cache . delete_memoized ( frontlist )
2023-01-25 11:35:37 +00:00
return { " message " : " Progressive stack applied on post! " }
2023-02-19 14:02:30 +00:00
@app.post ( " /admin/unprogstack/post/<int:post_id> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2023-02-19 14:02:30 +00:00
@admin_level_required ( PERMS [ ' PROGSTACK ' ] )
def unprogstack_post ( post_id , v ) :
post = get_post ( post_id )
post . is_approved = None
2023-03-16 06:27:58 +00:00
g . db . add ( post )
2023-02-19 14:02:30 +00:00
ma = ModAction (
kind = " unprogstack_post " ,
user_id = v . id ,
target_submission_id = post . id ,
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2023-02-19 14:02:30 +00:00
return { " message " : " Progressive stack removed from post! " }
2023-01-25 11:35:37 +00:00
@app.post ( " /admin/progstack/comment/<int:comment_id> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2023-01-25 11:35:37 +00:00
@admin_level_required ( PERMS [ ' PROGSTACK ' ] )
def progstack_comment ( comment_id , v ) :
comment = get_comment ( comment_id )
comment . is_approved = PROGSTACK_ID
comment . realupvotes = floor ( comment . realupvotes * PROGSTACK_MUL )
2023-03-16 06:27:58 +00:00
g . db . add ( comment )
2023-01-25 11:35:37 +00:00
ma = ModAction (
kind = " progstack_comment " ,
user_id = v . id ,
target_comment_id = comment . id ,
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2023-01-25 11:35:37 +00:00
cache . delete_memoized ( comment_idlist )
return { " message " : " Progressive stack applied on comment! " }
2022-05-04 23:09:46 +00:00
2023-02-19 14:02:30 +00:00
@app.post ( " /admin/unprogstack/comment/<int:comment_id> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2023-02-19 14:02:30 +00:00
@admin_level_required ( PERMS [ ' PROGSTACK ' ] )
def unprogstack_comment ( comment_id , v ) :
comment = get_comment ( comment_id )
comment . is_approved = None
2023-03-16 06:27:58 +00:00
g . db . add ( comment )
2023-02-19 14:02:30 +00:00
ma = ModAction (
kind = " unprogstack_comment " ,
user_id = v . id ,
target_comment_id = comment . id ,
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2023-02-19 14:02:30 +00:00
return { " message " : " Progressive stack removed from comment! " }
2022-12-29 10:39:10 +00:00
@app.post ( " /remove_post/<int:post_id> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +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-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
2023-03-16 06:27:58 +00:00
g . db . add ( post )
2022-05-04 23:09:46 +00:00
ma = ModAction (
kind = " ban_post " ,
user_id = v . id ,
target_submission_id = post . id ,
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-05-04 23:09:46 +00:00
cache . delete_memoized ( frontlist )
2022-11-20 10:50:02 +00:00
v . pay_account ( ' coins ' , 1 )
2023-03-16 06:27:58 +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> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +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-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
2023-03-23 12:50:01 +00:00
if not complies_with_chud ( post ) :
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 ,
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-05-04 23:09:46 +00:00
post . is_banned = False
post . ban_reason = None
post . is_approved = v . id
2023-03-16 06:27:58 +00:00
g . db . add ( post )
2022-05-04 23:09:46 +00:00
cache . delete_memoized ( frontlist )
2022-10-12 16:33:00 +00:00
v . charge_account ( ' coins ' , 1 )
2023-03-16 06:27:58 +00:00
g . db . add ( v )
2022-05-04 23:09:46 +00:00
return { " message " : " Post approved! " }
2022-12-29 10:39:10 +00:00
@app.post ( " /distinguish/<int:post_id> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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 '
2023-03-16 06:27:58 +00:00
g . db . add ( post )
2022-05-04 23:09:46 +00:00
ma = ModAction (
kind = kind ,
user_id = v . id ,
target_submission_id = post . id
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-05-04 23:09:46 +00:00
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-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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 )
2023-01-24 10:24:27 +00:00
if post . is_banned :
abort ( 403 , " Can ' t sticky removed posts! " )
2023-01-25 01:07:49 +00:00
if FEATURES [ ' AWARDS ' ] and post . stickied and post . stickied . endswith ( PIN_AWARD_TEXT ) and v . admin_level < PERMS [ " UNDO_AWARD_PINS " ] :
2022-10-23 21:36:38 +00:00
abort ( 403 , " Can ' t pin award pins! " )
2023-03-16 06:27:58 +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
2023-03-16 06:27:58 +00:00
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
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-10-14 18:28:20 +00:00
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-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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 :
2023-01-25 01:07:49 +00:00
if FEATURES [ ' AWARDS ' ] and post . stickied . endswith ( PIN_AWARD_TEXT ) and v . admin_level < PERMS [ " UNDO_AWARD_PINS " ] :
2023-01-24 10:24:27 +00:00
abort ( 403 , " Can ' t unpin award pins! " )
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
2023-03-16 06:27:58 +00:00
g . db . add ( post )
2022-05-04 23:09:46 +00:00
ma = ModAction (
kind = " unpin_post " ,
user_id = v . id ,
target_submission_id = post . id
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-05-04 23:09:46 +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 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-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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:24:27 +00:00
2023-01-24 10:23:19 +00:00
if comment . is_banned :
abort ( 403 , " Can ' t sticky removed comments! " )
2023-01-25 01:07:49 +00:00
if FEATURES [ ' AWARDS ' ] and comment . stickied and comment . stickied . endswith ( PIN_AWARD_TEXT ) and v . admin_level < PERMS [ " UNDO_AWARD_PINS " ] :
2023-01-24 10:24:27 +00:00
abort ( 403 , " Can ' t pin award pins! " )
2022-05-04 23:09:46 +00:00
2022-05-26 23:08:23 +00:00
if not comment . stickied :
comment . stickied = v . username
2023-03-16 06:27:58 +00:00
g . db . add ( comment )
2022-05-04 23:09:46 +00:00
ma = ModAction (
kind = " pin_comment " ,
user_id = v . id ,
target_comment_id = comment . id
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-05-04 23:09:46 +00:00
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
2023-03-16 06:27:58 +00:00
g . db . add ( c )
2022-11-26 04:01:20 +00:00
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-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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 :
2023-01-25 01:07:49 +00:00
if FEATURES [ ' AWARDS ' ] and comment . stickied . endswith ( PIN_AWARD_TEXT ) and v . admin_level < PERMS [ " UNDO_AWARD_PINS " ] :
2023-01-24 10:24:27 +00:00
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
2023-03-16 06:27:58 +00:00
g . db . add ( comment )
2022-05-04 23:09:46 +00:00
ma = ModAction (
kind = " unpin_comment " ,
user_id = v . id ,
target_comment_id = comment . id
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-05-04 23:09:46 +00:00
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 )
2023-03-16 06:27:58 +00:00
cleanup = g . db . query ( Comment ) . filter_by ( stickied_child_id = comment . id ) . all ( )
2022-11-26 04:01:20 +00:00
for c in cleanup :
c . stickied_child_id = None
2023-03-16 06:27:58 +00:00
g . db . add ( c )
2022-11-26 04:01:20 +00:00
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> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +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-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
2023-03-16 06:27:58 +00:00
g . db . add ( comment )
2022-05-04 23:09:46 +00:00
ma = ModAction (
kind = " ban_comment " ,
user_id = v . id ,
target_comment_id = comment . id ,
)
2023-03-16 06:27:58 +00:00
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> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +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-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
2023-03-23 12:50:01 +00:00
if not complies_with_chud ( comment ) :
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 ,
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-05-04 23:09:46 +00:00
comment . is_banned = False
comment . ban_reason = None
comment . is_approved = v . id
2023-03-16 06:27:58 +00:00
g . db . add ( comment )
2022-05-04 23:09:46 +00:00
return { " message " : " Comment approved! " }
2022-12-29 10:39:10 +00:00
@app.post ( " /distinguish_comment/<int:c_id> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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 '
2023-03-16 06:27:58 +00:00
g . db . add ( comment )
2022-05-04 23:09:46 +00:00
ma = ModAction (
kind = kind ,
user_id = v . id ,
target_comment_id = comment . id
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-05-04 23:09:46 +00:00
if comment . distinguish_level : return { " message " : " Comment distinguished! " }
else : return { " message " : " Comment undistinguished! " }
@app.get ( " /admin/banned_domains/ " )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
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 ) :
2023-03-16 06:27:58 +00:00
banned_domains = g . db . query ( BannedDomain ) \
2022-11-29 21:24:13 +00:00
. 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 " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , 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
2023-03-16 06:27:58 +00:00
existing = g . db . get ( BannedDomain , domain )
2022-12-30 16:24:20 +00:00
if not existing :
d = BannedDomain ( domain = domain , reason = reason )
2023-03-16 06:27:58 +00:00
g . db . add ( d )
2022-12-30 16:24:20 +00:00
ma = ModAction (
kind = " ban_domain " ,
user_id = v . id ,
_note = filter_emojis_only ( f ' { domain } , reason: { reason } ' )
)
2023-03-16 06:27:58 +00:00
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> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-12-30 16:24:20 +00:00
@admin_level_required ( PERMS [ ' DOMAINS_BAN ' ] )
def unban_domain ( v : User , domain ) :
2023-03-16 06:27:58 +00:00
existing = g . db . get ( BannedDomain , domain )
2022-12-30 16:24:20 +00:00
if not existing : abort ( 400 , ' Domain is not banned! ' )
2023-01-01 11:36:20 +00:00
2023-03-16 06:27:58 +00:00
g . db . delete ( existing )
2022-12-30 16:24:20 +00:00
ma = ModAction (
kind = " unban_domain " ,
user_id = v . id ,
_note = filter_emojis_only ( domain )
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-12-30 16:24:20 +00:00
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 " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , 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 " ) )
2023-03-16 06:27:58 +00:00
for post in g . db . query ( Submission ) . filter_by ( author_id = user . id ) . all ( ) :
2022-05-04 23:09:46 +00:00
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
2023-03-16 06:27:58 +00:00
g . db . add ( post )
2022-05-04 23:09:46 +00:00
2023-03-16 06:27:58 +00:00
for comment in g . db . query ( Comment ) . filter_by ( author_id = user . id ) . all ( ) :
2022-05-04 23:09:46 +00:00
if comment . is_banned :
continue
comment . is_banned = True
comment . ban_reason = v . username
2023-03-16 06:27:58 +00:00
g . db . add ( comment )
2022-05-04 23:09:46 +00:00
ma = ModAction (
kind = " nuke_user " ,
user_id = v . id ,
target_user_id = user . id ,
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-05-04 23:09:46 +00:00
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 " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , 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 " ) )
2023-03-16 06:27:58 +00:00
for post in g . db . query ( Submission ) . filter_by ( author_id = user . id ) . all ( ) :
2022-05-04 23:09:46 +00:00
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
2023-03-16 06:27:58 +00:00
g . db . add ( post )
2022-05-04 23:09:46 +00:00
2023-03-16 06:27:58 +00:00
for comment in g . db . query ( Comment ) . filter_by ( author_id = user . id ) . all ( ) :
2022-05-04 23:09:46 +00:00
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
2023-03-16 06:27:58 +00:00
g . db . add ( comment )
2022-05-04 23:09:46 +00:00
ma = ModAction (
kind = " unnuke_user " ,
user_id = v . id ,
target_user_id = user . id ,
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2022-05-04 23:09:46 +00:00
2022-11-07 06:26:41 +00:00
return { " message " : f " @ { user . username } ' s content has been approved! " }
2023-01-25 15:41:46 +00:00
@app.post ( " /blacklist/<int:user_id> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2023-01-25 15:41:46 +00:00
@admin_level_required ( PERMS [ ' USER_BLACKLIST ' ] )
def blacklist_user ( user_id , v ) :
user = get_account ( user_id )
if user . admin_level > v . admin_level :
abort ( 403 )
user . blacklisted_by = v . id
2023-03-16 06:27:58 +00:00
g . db . add ( user )
2023-01-25 15:41:46 +00:00
check_for_alts ( user )
ma = ModAction (
kind = " blacklist_user " ,
user_id = v . id ,
target_user_id = user . id
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2023-01-25 15:41:46 +00:00
return { " message " : f " @ { user . username } has been blacklisted from restricted holes! " }
@app.post ( " /unblacklist/<int:user_id> " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-26 01:42:39 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2023-01-25 15:41:46 +00:00
@admin_level_required ( PERMS [ ' USER_BLACKLIST ' ] )
def unblacklist_user ( user_id , v ) :
user = get_account ( user_id )
user . blacklisted_by = None
2023-03-16 06:27:58 +00:00
g . db . add ( user )
2023-01-25 15:41:46 +00:00
for alt in get_alt_graph ( user . id ) :
alt . blacklisted_by = None
2023-03-16 06:27:58 +00:00
g . db . add ( alt )
2023-01-25 15:41:46 +00:00
ma = ModAction (
kind = " unblacklist_user " ,
user_id = v . id ,
target_user_id = user . id
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2023-01-25 15:41:46 +00:00
return { " message " : f " @ { user . username } has been unblacklisted from restricted holes! " }
2023-02-19 19:31:26 +00:00
@app.get ( ' /admin/delete_media ' )
2023-02-26 08:41:04 +00:00
@limiter.limit ( DEFAULT_RATELIMIT )
2023-02-19 19:31:26 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
@admin_level_required ( PERMS [ ' DELETE_MEDIA ' ] )
def delete_media_get ( v ) :
return render_template ( " admin/delete_media.html " , v = v )
@app.post ( " /admin/delete_media " )
2023-02-27 05:33:45 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
2023-04-02 06:52:26 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2023-03-09 20:50:12 +00:00
@limiter.limit ( " 50/day " )
@limiter.limit ( " 50/day " , key_func = get_ID )
2023-02-19 19:31:26 +00:00
@admin_level_required ( PERMS [ ' DELETE_MEDIA ' ] )
def delete_media_post ( v ) :
url = request . values . get ( " url " )
if not url :
return render_template ( " admin/delete_media.html " , v = v , url = url , error = " No url provided! " )
2023-03-25 15:07:12 +00:00
if not image_link_regex . fullmatch ( url ) and not video_link_regex . fullmatch ( url ) :
2023-02-19 19:31:26 +00:00
return render_template ( " admin/delete_media.html " , v = v , url = url , error = " Invalid url! " )
2023-03-25 15:07:12 +00:00
path = url . split ( SITE ) [ 1 ]
2023-02-19 19:31:26 +00:00
if not os . path . isfile ( path ) :
return render_template ( " admin/delete_media.html " , v = v , url = url , error = " File not found on the server! " )
2023-03-25 15:07:12 +00:00
os . remove ( path )
2023-02-19 19:31:26 +00:00
ma = ModAction (
kind = " delete_media " ,
user_id = v . id ,
_note = url ,
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2023-02-19 19:31:26 +00:00
purge_files_in_cache ( url )
return render_template ( " admin/delete_media.html " , v = v , msg = " Media deleted successfully! " )