2022-05-18 19:29:07 +00:00
import os
2022-11-15 09:19:08 +00:00
from shutil import copyfile
2023-01-28 08:25:19 +00:00
from sqlalchemy import func
2022-11-15 09:19:08 +00:00
from files . helpers . media import process_files
2022-06-07 12:31:24 +00:00
import files . helpers . stats as statshelper
2022-11-15 09:19:08 +00:00
from files . classes . award import AWARDS
from files . classes . badges import Badge , BadgeDef
2022-12-11 23:44:34 +00:00
from files . classes . mod_logs import ModAction
2022-11-15 09:19:08 +00:00
from files . classes . userblock import UserBlock
from files . helpers . actions import *
from files . helpers . alerts import *
2022-12-11 23:44:34 +00:00
from files . helpers . config . const import *
2023-01-25 16:06:27 +00:00
from files . helpers . config . modaction_types import *
2022-11-15 09:19:08 +00:00
from files . routes . wrappers import *
from files . __main__ import app , cache , limiter
2022-05-04 23:09:46 +00:00
2022-09-29 04:26:50 +00:00
2022-12-29 10:39:10 +00:00
@app.get ( " /r/drama/comments/<int:id>/<title> " )
@app.get ( " /r/Drama/comments/<int:id>/<title> " )
2022-05-04 23:09:46 +00:00
def rdrama ( id , title ) :
id = ' ' . join ( f ' { x } / ' for x in id )
return redirect ( f ' /archives/drama/comments/ { id } { title } .html ' )
2022-11-28 22:12:39 +00:00
@app.get ( " /r/<subreddit> " )
@auth_desired
def subreddit ( subreddit , v ) :
reddit = v . reddit if v else " old.reddit.com "
return redirect ( f ' https:// { reddit } /r/ { subreddit } ' )
2022-05-04 23:09:46 +00:00
2022-11-28 23:48:16 +00:00
@app.get ( " /reddit/<subreddit>/comments/<path:path> " )
2022-11-29 03:08:26 +00:00
@app.get ( " /r/<subreddit>/comments/<path:path> " )
2022-11-28 23:45:52 +00:00
@auth_desired
def reddit_post ( subreddit , v , path ) :
post_id = path . rsplit ( " / " , 1 ) [ 0 ] . replace ( ' / ' , ' ' )
reddit = v . reddit if v else " old.reddit.com "
return redirect ( f ' https:// { reddit } / { post_id } ' )
2022-05-04 23:09:46 +00:00
@app.get ( " /marseys " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-05-04 23:09:46 +00:00
@auth_required
2022-11-26 21:00:03 +00:00
def marseys ( v : User ) :
2022-11-28 04:59:35 +00:00
2022-11-29 03:22:57 +00:00
marseys = get_marseys ( g . db )
authors = get_accounts_dict ( [ m . author_id for m in marseys ] , v = v , graceful = True , include_shadowbanned = False )
original = os . listdir ( " /asset_submissions/marseys/original " )
for marsey in marseys :
marsey . user = authors . get ( marsey . author_id )
for x in IMAGE_FORMATS :
if f ' { marsey . name } . { x } ' in original :
marsey . og = f ' { marsey . name } . { x } '
break
2022-05-04 23:09:46 +00:00
return render_template ( " marseys.html " , v = v , marseys = marseys )
2022-11-27 16:59:36 +00:00
@app.get ( " /emojis " )
def emoji_list ( ) :
2022-12-29 10:42:08 +00:00
return get_emojis ( g . db )
2022-11-27 16:59:36 +00:00
@cache.cached ( timeout = 86400 , key_prefix = MARSEYS_CACHE_KEY )
def get_marseys ( db : scoped_session ) :
if not FEATURES [ ' MARSEYS ' ] : return [ ]
marseys = [ ]
for marsey , author in db . query ( Marsey , User ) . join ( User , Marsey . author_id == User . id ) . filter ( Marsey . submitter_id == None ) . order_by ( Marsey . count . desc ( ) ) :
2022-11-29 03:17:28 +00:00
marsey . author = author . username if FEATURES [ ' ASSET_SUBMISSIONS ' ] else None
2022-11-27 16:59:36 +00:00
setattr ( marsey , " class " , " Marsey " )
marseys . append ( marsey )
return marseys
@cache.cached ( timeout = 600 , key_prefix = EMOJIS_CACHE_KEY )
def get_emojis ( db : scoped_session ) :
emojis = [ m . json ( ) for m in get_marseys ( db ) ]
2022-07-09 04:32:48 +00:00
for src in EMOJI_SRCS :
with open ( src , " r " , encoding = " utf-8 " ) as f :
emojis = emojis + json . load ( f )
2022-11-27 16:59:36 +00:00
return emojis
2022-05-04 23:09:46 +00:00
@app.get ( ' /sidebar ' )
2022-10-06 06:26:10 +00:00
@auth_desired
2022-11-26 21:00:03 +00:00
def sidebar ( v : Optional [ User ] ) :
2022-05-04 23:09:46 +00:00
return render_template ( ' sidebar.html ' , v = v )
2022-12-20 00:42:39 +00:00
@app.get ( " /stats " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-12-20 00:42:39 +00:00
@auth_required
def participation_stats ( v : User ) :
2022-12-20 02:26:23 +00:00
stats = cache . get ( f ' { SITE } _stats ' ) or { }
if v . client : return stats
return render_template ( " stats.html " , v = v , title = " Content Statistics " , data = stats )
2022-05-04 23:09:46 +00:00
@app.get ( " /chart " )
def chart ( ) :
return redirect ( ' /weekly_chart ' )
@app.get ( " /weekly_chart " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-05-04 23:09:46 +00:00
@auth_required
2022-11-26 21:00:03 +00:00
def weekly_chart ( v : User ) :
2022-06-07 12:31:24 +00:00
return send_file ( statshelper . chart_path ( kind = " weekly " , site = SITE ) )
2022-05-04 23:09:46 +00:00
@app.get ( " /daily_chart " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-05-04 23:09:46 +00:00
@auth_required
2022-11-26 21:00:03 +00:00
def daily_chart ( v : User ) :
2022-06-07 12:31:24 +00:00
return send_file ( statshelper . chart_path ( kind = " daily " , site = SITE ) )
2022-05-04 23:09:46 +00:00
@app.get ( " /patrons " )
@app.get ( " /paypigs " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-10-06 05:48:55 +00:00
@admin_level_required ( PERMS [ ' VIEW_PATRONS ' ] )
2022-05-04 23:09:46 +00:00
def patrons ( v ) :
users = g . db . query ( User ) . filter ( User . patron > 0 ) . order_by ( User . patron . desc ( ) , User . id ) . all ( )
2023-01-22 08:04:49 +00:00
return render_template ( " admin/patrons.html " , v = v , users = users , benefactor_def = AWARDS [ ' benefactor ' ] )
2022-05-04 23:09:46 +00:00
@app.get ( " /admins " )
@app.get ( " /badmins " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-05-04 23:09:46 +00:00
@auth_required
2022-11-26 21:00:03 +00:00
def admins ( v : User ) :
2022-11-26 01:15:39 +00:00
admins = g . db . query ( User ) . filter ( User . admin_level > = PERMS [ ' ADMIN_MOP_VISIBLE ' ] ) . order_by ( User . truescore . desc ( ) ) . all ( )
2022-05-04 23:09:46 +00:00
return render_template ( " admins.html " , v = v , admins = admins )
@app.get ( " /log " )
@app.get ( " /modlog " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-05-04 23:09:46 +00:00
@auth_required
2022-11-26 21:00:03 +00:00
def log ( v : User ) :
2022-05-04 23:09:46 +00:00
try : page = max ( int ( request . values . get ( " page " , 1 ) ) , 1 )
except : page = 1
admin = request . values . get ( " admin " )
2022-10-01 05:15:56 +00:00
if admin : admin_id = get_id ( admin )
2022-05-04 23:09:46 +00:00
else : admin_id = 0
kind = request . values . get ( " kind " )
2023-01-26 05:45:38 +00:00
if v and v . admin_level > = PERMS [ ' USER_SHADOWBAN ' ] :
if v and v . admin_level > = PERMS [ ' PROGSTACK ' ] :
types = MODACTION_TYPES
else :
types = MODACTION_TYPES__FILTERED
2022-12-11 23:44:34 +00:00
else : types = MODACTION_TYPES_FILTERED
2022-05-04 23:09:46 +00:00
2022-06-13 16:41:46 +00:00
if kind and kind not in types :
kind = None
actions = [ ]
else :
actions = g . db . query ( ModAction )
2023-01-01 11:36:20 +00:00
if not ( v and v . admin_level > = PERMS [ ' USER_SHADOWBAN ' ] ) :
2022-12-11 23:44:34 +00:00
actions = actions . filter ( ModAction . kind . notin_ ( MODACTION_PRIVILEGED_TYPES ) )
2023-01-25 16:06:27 +00:00
if not ( v and v . admin_level > = PERMS [ ' PROGSTACK ' ] ) :
2023-01-25 16:52:16 +00:00
actions = actions . filter ( ModAction . kind . notin_ ( MODACTION_PRIVILEGED__TYPES ) )
2022-06-13 16:41:46 +00:00
if admin_id :
actions = actions . filter_by ( user_id = admin_id )
kinds = set ( [ x . kind for x in actions ] )
2022-10-02 07:50:59 +00:00
kinds . add ( kind )
2022-06-13 16:41:46 +00:00
types2 = { }
for k , val in types . items ( ) :
if k in kinds : types2 [ k ] = val
types = types2
if kind : actions = actions . filter_by ( kind = kind )
2022-10-29 03:20:48 +00:00
actions = actions . order_by ( ModAction . id . desc ( ) ) . offset ( PAGE_SIZE * ( page - 1 ) ) . limit ( PAGE_SIZE + 1 ) . all ( )
2023-01-01 11:36:20 +00:00
2022-10-29 03:20:48 +00:00
next_exists = len ( actions ) > PAGE_SIZE
actions = actions [ : PAGE_SIZE ]
2022-10-06 05:25:45 +00:00
admins = [ x [ 0 ] for x in g . db . query ( User . username ) . filter ( User . admin_level > = PERMS [ ' ADMIN_MOP_VISIBLE ' ] ) . order_by ( User . username ) . all ( ) ]
2022-05-04 23:09:46 +00:00
2022-11-04 23:51:42 +00:00
return render_template ( " log.html " , v = v , admins = admins , types = types , admin = admin , type = kind , actions = actions , next_exists = next_exists , page = page , single_user_url = ' admin ' )
2022-05-04 23:09:46 +00:00
2022-12-29 10:39:10 +00:00
@app.get ( " /log/<int:id> " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-05-04 23:09:46 +00:00
@auth_required
def log_item ( id , v ) :
try : id = int ( id )
except : abort ( 404 )
2022-06-18 00:57:23 +00:00
action = g . db . get ( ModAction , id )
2022-05-04 23:09:46 +00:00
if not action : abort ( 404 )
2022-10-06 05:25:45 +00:00
admins = [ x [ 0 ] for x in g . db . query ( User . username ) . filter ( User . admin_level > = PERMS [ ' ADMIN_MOP_VISIBLE ' ] ) . all ( ) ]
2022-05-04 23:09:46 +00:00
2023-01-26 05:45:38 +00:00
if v and v . admin_level > = PERMS [ ' USER_SHADOWBAN ' ] :
if v and v . admin_level > = PERMS [ ' PROGSTACK ' ] :
types = MODACTION_TYPES
else :
types = MODACTION_TYPES__FILTERED
2022-12-11 23:44:34 +00:00
else : types = MODACTION_TYPES_FILTERED
2022-05-04 23:09:46 +00:00
2022-11-04 23:51:42 +00:00
return render_template ( " log.html " , v = v , actions = [ action ] , next_exists = False , page = 1 , action = action , admins = admins , types = types , single_user_url = ' admin ' )
2022-05-04 23:09:46 +00:00
2022-06-15 07:27:04 +00:00
@app.get ( " /directory " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-09-20 00:54:10 +00:00
@auth_required
2022-11-26 21:00:03 +00:00
def static_megathread_index ( v : User ) :
2022-06-15 07:27:04 +00:00
return render_template ( " megathread_index.html " , v = v )
2022-05-04 23:09:46 +00:00
2022-11-26 21:04:39 +00:00
@app.get ( " /api " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-11-26 21:04:39 +00:00
@auth_required
def api ( v ) :
return render_template ( " api.html " , v = v )
2022-05-04 23:09:46 +00:00
@app.get ( " /contact " )
2022-09-09 09:13:50 +00:00
@app.get ( " /contactus " )
@app.get ( " /contact_us " )
2022-05-04 23:09:46 +00:00
@app.get ( " /press " )
@app.get ( " /media " )
2022-10-01 10:14:46 +00:00
@auth_desired
2022-11-26 21:00:03 +00:00
def contact ( v : Optional [ User ] ) :
2023-01-27 09:41:32 +00:00
return render_template ( " contact.html " , v = v , msg = get_msg ( ) )
2022-05-04 23:09:46 +00:00
@app.post ( " /send_admin " )
2022-11-13 02:37:33 +00:00
@limiter.limit ( " 1/second;1/2 minutes;10/day " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( " 1/second;1/2 minutes;10/day " , key_func = get_ID )
2022-05-04 23:09:46 +00:00
@auth_required
def submit_contact ( v ) :
body = request . values . get ( " message " )
if not body : abort ( 400 )
2022-09-01 21:29:27 +00:00
if v . is_muted :
abort ( 403 )
2022-11-17 16:00:49 +00:00
body = f ' This message has been sent automatically to all admins via [/contact](/contact) \n \n Message: \n \n { body } '
2022-11-15 09:19:08 +00:00
body + = process_files ( request . files , v )
2022-06-18 17:41:24 +00:00
body = body . strip ( )
body_html = sanitize ( body )
2022-05-04 23:09:46 +00:00
2022-11-14 03:48:52 +00:00
execute_antispam_duplicate_comment_check ( v , body_html )
2022-11-13 02:48:33 +00:00
2022-05-04 23:09:46 +00:00
new_comment = Comment ( author_id = v . id ,
2022-09-04 23:15:37 +00:00
parent_submission = None ,
level = 1 ,
body_html = body_html ,
2022-11-17 22:50:06 +00:00
sentto = MODMAIL_ID
2022-09-04 23:15:37 +00:00
)
2022-05-04 23:09:46 +00:00
g . db . add ( new_comment )
g . db . flush ( )
2022-11-14 02:43:26 +00:00
execute_blackjack ( v , new_comment , new_comment . body_html , ' modmail ' )
2022-11-30 17:37:35 +00:00
execute_under_siege ( v , new_comment , new_comment . body_html , ' modmail ' )
2022-05-04 23:09:46 +00:00
new_comment . top_comment_id = new_comment . id
2023-01-01 11:36:20 +00:00
2022-11-25 20:56:11 +00:00
admins = g . db . query ( User ) . filter ( User . admin_level > = PERMS [ ' NOTIFICATIONS_MODMAIL ' ] , User . id != AEVANN_ID )
2022-09-21 19:38:29 +00:00
for admin in admins . all ( ) :
2022-05-04 23:09:46 +00:00
notif = Notification ( comment_id = new_comment . id , user_id = admin . id )
g . db . add ( notif )
2023-01-27 09:26:59 +00:00
return redirect ( " /contact?msg=Your message has been sent to the admins! " )
2022-05-04 23:09:46 +00:00
@app.get ( ' /archives ' )
def archivesindex ( ) :
return redirect ( " /archives/index.html " )
no = ( 21 , 22 , 23 , 24 , 25 , 26 , 27 )
@cache.memoize ( timeout = 3600 )
def badge_list ( site ) :
badges = g . db . query ( BadgeDef ) . filter ( BadgeDef . id . notin_ ( no ) ) . order_by ( BadgeDef . id ) . all ( )
counts_raw = g . db . query ( Badge . badge_id , func . count ( ) ) . group_by ( Badge . badge_id ) . all ( )
2022-05-09 11:21:49 +00:00
users = g . db . query ( User ) . count ( )
2022-05-04 23:09:46 +00:00
counts = { }
for c in counts_raw :
counts [ c [ 0 ] ] = ( c [ 1 ] , float ( c [ 1 ] ) * 100 / max ( users , 1 ) )
2023-01-01 11:36:20 +00:00
2022-05-04 23:09:46 +00:00
return badges , counts
@app.get ( " /badges " )
2022-10-11 07:29:24 +00:00
@feature_required ( ' BADGES ' )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-11-14 15:11:05 +00:00
@auth_required
2022-11-26 21:00:03 +00:00
def badges ( v : User ) :
2022-05-04 23:09:46 +00:00
badges , counts = badge_list ( SITE )
return render_template ( " badges.html " , v = v , badges = badges , counts = counts )
@app.get ( " /blocks " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-07-18 07:17:45 +00:00
@admin_level_required ( PERMS [ ' USER_BLOCKS_VISIBLE ' ] )
2022-05-04 23:09:46 +00:00
def blocks ( v ) :
blocks = g . db . query ( UserBlock ) . all ( )
users = [ ]
targets = [ ]
for x in blocks :
2022-06-13 03:03:36 +00:00
acc_user = get_account ( x . user_id )
2022-09-04 23:15:37 +00:00
acc_tgt = get_account ( x . target_id )
2022-06-13 03:03:36 +00:00
if acc_user . shadowbanned or acc_tgt . shadowbanned : continue
users . append ( acc_user )
targets . append ( acc_tgt )
2022-05-04 23:09:46 +00:00
return render_template ( " blocks.html " , v = v , users = users , targets = targets )
@app.get ( " /formatting " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-05-04 23:09:46 +00:00
@auth_required
2022-11-26 21:00:03 +00:00
def formatting ( v : User ) :
2022-05-04 23:09:46 +00:00
return render_template ( " formatting.html " , v = v )
2022-11-19 22:04:08 +00:00
@app.get ( " /app " )
@auth_desired
2022-11-26 21:00:03 +00:00
def mobile_app ( v : Optional [ User ] ) :
2022-11-19 22:04:08 +00:00
return render_template ( " app.html " , v = v )
2022-05-04 23:09:46 +00:00
@app.post ( " /dismiss_mobile_tip " )
def dismiss_mobile_tip ( ) :
session [ " tooltip_last_dismissed " ] = int ( time . time ( ) )
return " " , 204
2022-07-13 15:20:10 +00:00
2022-12-29 10:39:10 +00:00
@app.get ( " /transfers/<int:id> " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-07-13 15:20:10 +00:00
@auth_required
def transfers_id ( id , v ) :
try : id = int ( id )
except : abort ( 404 )
transfer = g . db . get ( Comment , id )
if not transfer : abort ( 404 )
return render_template ( " transfers.html " , v = v , page = 1 , comments = [ transfer ] , standalone = True , next_exists = False )
@app.get ( " /transfers " )
2023-01-21 04:39:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , key_func = get_ID )
2022-07-13 15:20:10 +00:00
@auth_required
2022-11-26 21:00:03 +00:00
def transfers ( v : User ) :
2022-07-13 15:20:10 +00:00
comments = g . db . query ( Comment ) . filter ( Comment . author_id == AUTOJANNY_ID , Comment . parent_submission == None , Comment . body_html . like ( " % </a> has transferred % " ) ) . order_by ( Comment . id . desc ( ) )
try : page = max ( int ( request . values . get ( " page " , 1 ) ) , 1 )
except : page = 1
2022-10-29 03:20:48 +00:00
comments = comments . offset ( PAGE_SIZE * ( page - 1 ) ) . limit ( PAGE_SIZE + 1 ) . all ( )
next_exists = len ( comments ) > PAGE_SIZE
comments = comments [ : PAGE_SIZE ]
2022-09-10 00:30:25 +00:00
2022-10-15 09:11:36 +00:00
if v . client :
2022-11-15 09:28:39 +00:00
return { " data " : [ x . json ( g . db ) for x in comments ] }
2022-09-10 00:30:25 +00:00
else :
return render_template ( " transfers.html " , v = v , page = page , comments = comments , standalone = True , next_exists = next_exists )
2022-07-18 08:39:21 +00:00
2022-09-19 23:59:24 +00:00
if not os . path . exists ( f ' files/templates/donate_ { SITE_NAME } .html ' ) :
2022-11-17 16:00:49 +00:00
copyfile ( ' files/templates/donate_rDrama.html ' , f ' files/templates/donate_ { SITE_NAME } .html ' )
2022-09-19 23:59:24 +00:00
@app.get ( ' /donate ' )
2022-10-30 18:43:06 +00:00
@auth_desired_with_logingate
2022-09-19 23:59:24 +00:00
def donate ( v ) :
2022-09-22 02:17:02 +00:00
return render_template ( f ' donate_ { SITE_NAME } .html ' , v = v )
2022-12-27 01:22:39 +00:00
2022-12-28 10:25:52 +00:00
items_we_want = ( ' blocked-uri ' , ' document-uri ' , ' effective-directive ' , ' source-file ' , ' violated-directive ' )
2022-12-27 01:22:39 +00:00
@app.post ( ' /csp_violations ' )
@limiter.limit ( " 10/minute;50/day " )
def csp_violations ( ) :
2022-12-28 10:25:52 +00:00
content = json . dumps ( request . get_json ( ) )
if content [ " source-file " ] . startswith ( SITE_FULL ) :
print ( ' -------- ' , flush = True )
for i in items_we_want :
print ( f " { i } : { content [ ' i ' ] } " )
2022-12-27 01:22:39 +00:00
return ' '