2022-05-04 23:09:46 +00:00
import time
2022-11-15 09:19:08 +00:00
from urllib . parse import quote , urlencode
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 ' )
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 ' )
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
2022-12-25 06:12:49 +00:00
@app.get ( ' /admin/move/<old_id>/<new_id> ' )
@admin_level_required ( PERMS [ ' USER_MERGE ' ] )
def move_acc ( v : User , new_id , old_id ) :
if v . id != AEVANN_ID : abort ( 403 )
2022-05-04 23:09:46 +00:00
2022-12-25 06:12:49 +00:00
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 )
2022-12-25 04:02:33 +00:00
attrs = {
' coins ' ,
' coins_spent ' ,
' coins_spent_on_hats ' ,
2022-12-25 05:54:34 +00:00
' comment_count ' ,
2022-12-25 04:02:33 +00:00
' currently_held_lottery_tickets ' ,
' lootboxes_bought ' ,
' marseybux ' ,
2022-12-25 05:54:34 +00:00
' post_count ' ,
2022-12-25 04:02:33 +00:00
' 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 )
setattr ( olduser , attr , 0 )
if newuser . created_utc > olduser . created_utc :
newuser . created_utc = olduser . created_utc
2022-12-25 06:12:49 +00:00
g . db . add ( newuser )
g . db . add ( olduser )
2022-12-25 04:02:33 +00:00
2022-12-25 06:12:49 +00:00
g . db . commit ( )
2022-12-25 04:02:33 +00:00
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 :
2022-12-25 06:12:49 +00:00
items = g . db . query ( cls ) . filter ( getattr ( cls , attr ) == olduser . id )
2022-12-25 04:02:33 +00:00
for item in items :
setattr ( item , attr , newuser . id )
2022-12-25 06:12:49 +00:00
g . db . add ( item )
try : g . db . commit ( )
2022-12-25 04:02:33 +00:00
except IntegrityError as e :
if isinstance ( e . orig , UniqueViolation ) :
2022-12-25 06:12:49 +00:00
g . db . rollback ( )
g . db . delete ( item )
g . db . commit ( )
2022-12-25 04:02:33 +00:00
else :
print ( e , flush = True )
abort ( 500 , str ( e ) )
2022-09-01 23:59:56 +00:00
2022-12-25 06:12:49 +00:00
olduser . stored_subscriber_count = g . db . query ( Follow ) . filter_by ( target_id = olduser . id ) . count ( )
newuser . stored_subscriber_count = g . db . query ( Follow ) . filter_by ( target_id = newuser . id ) . count ( )
2022-12-25 05:54:34 +00:00
2022-12-25 06:12:49 +00:00
g . db . add ( newuser )
g . db . add ( olduser )
2022-12-25 05:54:34 +00:00
2022-12-25 04:53:12 +00:00
update_statement = f ''' update submissions set body_html=replace(body_html, ' <a href= " /id/ { old_id } " > ' , ' <a href= " /id/ { new_id } " > ' ) where body_html like ' %<a href= " /id/ { old_id } " >% ' ;
update comments set body_html = replace ( body_html , ' <a href= " /id/ {old_id} " > ' , ' <a href= " /id/ {new_id} " > ' ) where body_html like ' % <a href= " /id/ {old_id} " > % ' ;
update subs set sidebar_html = replace ( sidebar_html , ' <a href= " /id/ {old_id} " > ' , ' <a href= " /id/ {new_id} " > ' ) where sidebar_html like ' % <a href= " /id/ {old_id} " > % ' ;
update users set bio_html = replace ( bio_html , ' <a href= " /id/ {old_id} " > ' , ' <a href= " /id/ {new_id} " > ' ) where bio_html like ' % <a href= " /id/ {old_id} " > % ' ;
update users set sig_html = replace ( sig_html , ' <a href= " /id/ {old_id} " > ' , ' <a href= " /id/ {new_id} " > ' ) where sig_html like ' % <a href= " /id/ {old_id} " > % ' ;
update users set friends_html = replace ( friends_html , ' <a href= " /id/ {old_id} " > ' , ' <a href= " /id/ {new_id} " > ' ) where friends_html like ' % <a href= " /id/ {old_id} " > % ' ;
update users set enemies_html = replace ( enemies_html , ' <a href= " /id/ {old_id} " > ' , ' <a href= " /id/ {new_id} " > ' ) where enemies_html like ' % <a href= " /id/ {old_id} " > % ' ;
'''
2022-12-25 06:12:49 +00:00
g . db . execute ( update_statement )
g . db . delete ( olduser )
2022-12-25 04:53:12 +00:00
2022-11-29 21:49:06 +00:00
online = cache . get ( CHAT_ONLINE_CACHE_KEY )
2022-05-04 23:09:46 +00:00
cache . clear ( )
2022-11-29 21:49:06 +00:00
cache . set ( CHAT_ONLINE_CACHE_KEY , online )
2022-09-01 23:59:56 +00:00
2022-12-25 06:12:49 +00:00
g . db . commit ( )
2022-12-25 04:25:47 +00:00
2022-12-25 04:37:29 +00:00
return redirect ( f " /id/ { old_id } " )
2022-05-04 23:09:46 +00:00
2022-12-05 05:22:08 +00:00
@app.get ( ' /admin/edit_rules ' )
@admin_level_required ( PERMS [ ' EDIT_RULES ' ] )
def edit_rules_get ( v ) :
try :
with open ( f ' files/templates/rules_ { SITE_NAME } .html ' , ' r ' , encoding = " utf-8 " ) as f :
rules = f . read ( )
except :
rules = None
return render_template ( ' admin/edit_rules.html ' , v = v , rules = rules )
@app.post ( ' /admin/edit_rules ' )
@limiter.limit ( " 1/second;30/minute;200/hour;1000/day " )
@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 " )
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 " )
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-05-04 23:09:46 +00:00
user = get_user ( username )
2022-12-09 05:58:44 +00:00
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-08-26 21:53:17 +00:00
@app.post ( " /distribute/<option_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
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 )
2022-05-04 23:09:46 +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 )
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-10-08 04:07:44 +00:00
user = get_user ( username )
ma = ModAction (
kind = " revert " ,
user_id = v . id ,
target_user_id = user . id
)
g . db . add ( ma )
cutoff = int ( time . time ( ) ) - 86400
posts = [ x [ 0 ] for x in g . db . query ( ModAction . target_submission_id ) . filter ( ModAction . user_id == user . id , ModAction . created_utc > cutoff , ModAction . kind == ' ban_post ' ) . all ( ) ]
posts = g . db . query ( Submission ) . filter ( Submission . id . in_ ( posts ) ) . all ( )
comments = [ x [ 0 ] for x in g . db . query ( ModAction . target_comment_id ) . filter ( ModAction . user_id == user . id , ModAction . created_utc > cutoff , ModAction . kind == ' ban_comment ' ) . all ( ) ]
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 )
users = ( x [ 0 ] for x in g . db . query ( ModAction . target_user_id ) . filter ( ModAction . user_id == user . id , ModAction . created_utc > cutoff , ModAction . kind . in_ ( ( ' shadowban ' , ' ban_user ' ) ) ) . all ( ) )
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-10-08 06:08:45 +00:00
return { " message " : f " @ { user . 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 " )
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 ,
) \
2022-12-15 18:31:51 +00:00
. order_by ( User . truescore . desc ( ) ) . 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 " )
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 " )
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 " )
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 " )
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
2022-05-05 08:46:20 +00:00
gitref = admin_git_head ( )
return render_template ( " admin/admin_home.html " , v = v ,
2022-07-01 18:19:21 +00:00
under_attack = under_attack ,
2022-05-05 08:46:20 +00:00
gitref = gitref )
def admin_git_head ( ) :
short_len = 12
# Note: doing zero sanitization. Git branch names are extremely permissive.
# However, they forbid '..', so I don't see an obvious dir traversal attack.
# Also, a malicious branch name would mean someone already owned the server
# or repo, so I think this isn't a weak link.
try :
2022-06-17 22:19:18 +00:00
with open ( ' .git/HEAD ' , encoding = ' utf_8 ' ) as head_f :
2022-05-05 08:46:20 +00:00
head_txt = head_f . read ( )
2022-07-06 11:49:13 +00:00
head_path = git_regex . match ( head_txt ) . group ( 1 )
2022-06-17 22:19:18 +00:00
with open ( ' .git/ ' + head_path , encoding = ' utf_8 ' ) as ref_f :
2022-05-05 08:46:20 +00:00
gitref = ref_f . read ( ) [ 0 : short_len ]
except :
2022-11-18 19:05:47 +00:00
return ' <unable to read> ' , ' '
return ( gitref , head_txt )
2022-05-04 23:09:46 +00:00
@app.post ( " /admin/site_settings/<setting> " )
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 " )
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 '
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 " )
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 " )
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
2022-12-07 19:03:06 +00:00
if BADGE_BLACKLIST and v . id not in { AEVANN_ID , SNAKES_ID } :
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 ' )
@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 )
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 )
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 )
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/users " )
2022-10-06 05:37:50 +00:00
@admin_level_required ( PERMS [ ' VIEW_ALL_USERS ' ] )
2022-05-04 23:09:46 +00:00
def users_list ( v ) :
try : page = int ( request . values . get ( " page " , 1 ) )
except : page = 1
2022-10-29 03:20:48 +00:00
users = g . db . query ( User ) . order_by ( User . id . desc ( ) ) . offset ( PAGE_SIZE * ( page - 1 ) ) . limit ( PAGE_SIZE + 1 ) . all ( )
2022-05-04 23:09:46 +00:00
2022-10-29 03:20:48 +00:00
next_exists = ( len ( users ) > PAGE_SIZE )
users = users [ : PAGE_SIZE ]
2022-05-04 23:09:46 +00:00
2022-09-05 20:23:35 +00:00
return render_template ( " user_cards.html " ,
2022-09-04 23:15:37 +00:00
v = v ,
users = users ,
next_exists = next_exists ,
page = page ,
2022-11-21 08:52:22 +00:00
user_cards_title = " Users Feed " ,
2022-09-04 23:15:37 +00:00
)
2022-05-04 23:09:46 +00:00
@app.get ( " /admin/alt_votes " )
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 )
@admin_level_required ( PERMS [ ' USER_LINK ' ] )
2022-12-11 23:44:34 +00:00
def admin_view_alts ( v : User , username = None ) :
2022-11-14 17:32:13 +00:00
u = get_user ( username or request . values . get ( ' username ' ) , graceful = True )
2022-12-22 20:44:37 +00:00
return render_template ( ' admin/alts.html ' , v = v , u = u , alts = get_alt_graph ( u . id ) if u else None )
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 )
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 '
note = f ' from { user2 . id } ' if deleted else f ' with { user2 . id } '
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 )
@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 '
note = f ' from { user2 . id } ' if is_delinking else f ' with { user2 . id } (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 " )
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 " )
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
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
@app.post ( " /unagendaposter/<user_id> " )
2022-10-06 03:04:38 +00:00
@admin_level_required ( PERMS [ ' USER_AGENDAPOSTER ' ] )
2022-05-04 23:09:46 +00:00
def unagendaposter ( 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 . 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
@app.post ( " /shadowban/<user_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
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-09-29 06:36:59 +00:00
reason = request . values . get ( " reason " ) . strip ( ) [ : 256 ]
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 )
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
@app.post ( " /unshadowban/<user_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
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 )
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
@app.post ( " /admin/title_change/<user_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
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 "
ma = ModAction (
kind = kind ,
user_id = v . id ,
target_user_id = user . id ,
_note = f ' " { user . customtitleplain } " '
)
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
@app.post ( " /ban_user/<user_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2022-10-06 01:58:43 +00:00
@admin_level_required ( PERMS [ ' USER_BAN ' ] )
2022-05-04 23:09:46 +00:00
def ban_user ( user_id , v ) :
2022-06-24 13:19:53 +00:00
user = get_account ( user_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
2022-09-29 06:36:59 +00:00
reason = request . values . get ( " reason " ) . strip ( ) [ : 256 ]
2022-05-30 02:55:51 +00:00
reason = filter_emojis_only ( reason )
2022-05-04 23:09:46 +00:00
2022-05-30 02:55:51 +00:00
if reason . startswith ( " / " ) and ' \\ ' not in reason :
reason = f ' <a href= " { reason . split ( ) [ 0 ] } " > { reason } </a> '
2022-05-04 23:09:46 +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 " ) :
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-11-05 02:12:17 +00:00
@app.post ( " /agendaposter/<user_id> " )
@admin_level_required ( PERMS [ ' USER_AGENDAPOSTER ' ] )
def agendaposter ( user_id , v ) :
user = get_account ( user_id )
if user . admin_level > v . admin_level :
abort ( 403 )
days = 0.0
try :
days = float ( request . values . get ( " days " ) )
except :
pass
reason = request . values . get ( " reason " , " " ) . strip ( )
if reason and reason . startswith ( " / " ) and ' \\ ' not in reason :
reason = f ' <a href= " { reason . split ( ) [ 0 ] } " > { reason } </a> '
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-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-05-04 23:09:46 +00:00
@app.post ( " /unban_user/<user_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2022-10-06 01:58:43 +00:00
@admin_level_required ( PERMS [ ' USER_BAN ' ] )
2022-05-04 23:09:46 +00:00
def unban_user ( user_id , v ) :
2022-06-24 13:19:53 +00:00
user = get_account ( user_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 )
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 )
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 )
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
2022-05-04 23:09:46 +00:00
2022-08-11 04:04:41 +00:00
@app.post ( " /remove_post/<post_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
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-08-11 04:04:41 +00:00
@app.post ( " /approve_post/<post_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
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! " }
@app.post ( " /distinguish/<post_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! " }
@app.post ( " /sticky/<post_id> " )
2022-10-11 07:29:24 +00:00
@feature_required ( ' PINS ' )
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
@app.post ( " /unsticky/<post_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! " )
2022-10-23 17:01:00 +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! " }
@app.post ( " /sticky_comment/<cid> " )
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 )
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! " }
@app.post ( " /unsticky_comment/<cid> " )
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 )
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-08-11 04:04:41 +00:00
@app.post ( " /remove_comment/<c_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
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-08-11 04:04:41 +00:00
@app.post ( " /approve_comment/<c_id> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
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 )
2022-05-04 23:09:46 +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! " }
@app.post ( " /distinguish_comment/<c_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/ " )
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-10-20 22:14:25 +00:00
@app.post ( " /admin/ban_domain " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2022-10-06 04:26:15 +00:00
@admin_level_required ( PERMS [ ' DOMAINS_BAN ' ] )
2022-10-20 22:14:25 +00:00
def ban_domain ( v ) :
2022-05-04 23:09:46 +00:00
2022-10-31 14:33:11 +00:00
domain = request . values . get ( " domain " , " " ) . strip ( ) . lower ( )
2022-05-04 23:09:46 +00:00
if not domain : abort ( 400 )
2022-09-29 06:36:59 +00:00
reason = request . values . get ( " reason " ) . strip ( )
2022-10-20 22:14:25 +00:00
if not reason : abort ( 400 , ' Reason is required! ' )
2022-05-04 23:09:46 +00:00
2022-10-20 22:14:25 +00:00
existing = g . db . get ( BannedDomain , domain )
if not existing :
2022-05-04 23:09:46 +00:00
d = BannedDomain ( domain = domain , reason = reason )
g . db . add ( d )
ma = ModAction (
kind = " ban_domain " ,
user_id = v . id ,
_note = f ' { domain } , reason: { reason } '
)
g . db . add ( ma )
return redirect ( " /admin/banned_domains/ " )
2022-10-20 22:14:25 +00:00
2022-12-21 16:17:09 +00:00
@app.post ( " /admin/unban_domain/<path:domain> " )
2022-11-13 06:43:35 +00:00
@limiter.limit ( DEFAULT_RATELIMIT_SLOWER )
2022-10-20 22:14:25 +00:00
@admin_level_required ( PERMS [ ' DOMAINS_BAN ' ] )
2022-12-11 23:44:34 +00:00
def unban_domain ( v : User , domain ) :
2022-10-20 22:14:25 +00:00
existing = g . db . get ( BannedDomain , domain )
if not existing : abort ( 400 , ' Domain is not banned! ' )
g . db . delete ( existing )
ma = ModAction (
kind = " unban_domain " ,
user_id = v . id ,
_note = domain
)
g . db . add ( ma )
return { " message " : f " { domain } has been unbanned! " }
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 )
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
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 )
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
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! " }