2022-11-15 09:19:08 +00:00
from os import path , rename
from shutil import copyfile , move
2022-09-10 07:38:23 +00:00
2023-03-18 13:34:04 +00:00
from files . classes . emoji import *
2022-11-15 09:19:08 +00:00
from files . classes . hats import Hat , HatDef
from files . classes . mod_logs import ModAction
2023-09-15 00:07:17 +00:00
from files . helpers . cloudflare import purge_files_in_cloudflare_cache
2022-12-11 23:44:34 +00:00
from files . helpers . config . const import *
2022-09-13 18:00:11 +00:00
from files . helpers . get import *
2022-11-15 09:19:08 +00:00
from files . helpers . media import *
from files . helpers . useractions import *
from files . routes . wrappers import *
from files . __main__ import app , cache , limiter
2023-03-18 13:34:04 +00:00
ASSET_TYPES = ( Emoji , HatDef )
2022-11-15 09:19:08 +00:00
2024-01-23 11:23:34 +00:00
def delete_unnecessary_tags ( tags , name ) :
new_tags = [ ]
for tag in tags . split ( ' ' ) :
2024-02-01 17:34:22 +00:00
if tag not in name and tag not in new_tags :
2024-01-23 11:23:34 +00:00
new_tags . append ( tag )
2024-02-01 17:36:35 +00:00
if not new_tags : abort ( 400 , " Invalid tags! " )
2024-01-23 11:23:34 +00:00
return ' ' . join ( new_tags )
2023-03-18 14:54:01 +00:00
@app.get ( " /submit/marseys " )
2023-10-24 19:04:40 +00:00
@feature_required ( ' EMOJI_SUBMISSIONS ' )
2023-03-18 14:54:01 +00:00
def submit_marseys_redirect ( ) :
return redirect ( " /submit/emojis " )
2023-03-18 13:34:04 +00:00
@app.get ( " /submit/emojis " )
2023-10-24 19:04:40 +00:00
@feature_required ( ' EMOJI_SUBMISSIONS ' )
2023-07-13 13:50:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 )
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 , key_func = get_ID )
2022-11-15 09:19:08 +00:00
@auth_required
2023-07-30 00:42:06 +00:00
def submit_emojis ( v ) :
2023-09-05 12:30:16 +00:00
emojis = g . db . query ( Emoji ) . filter ( Emoji . submitter_id != None )
2022-12-08 15:05:17 +00:00
2023-03-18 14:39:26 +00:00
emojis = emojis . order_by ( Emoji . created_utc . desc ( ) ) . all ( )
2022-11-15 09:19:08 +00:00
2023-03-18 14:39:26 +00:00
for emoji in emojis :
emoji . author = g . db . query ( User . username ) . filter_by ( id = emoji . author_id ) . one ( ) [ 0 ]
emoji . submitter = g . db . query ( User . username ) . filter_by ( id = emoji . submitter_id ) . one ( ) [ 0 ]
2022-11-15 09:19:08 +00:00
2023-08-11 21:50:23 +00:00
return render_template ( " submit_emojis.html " , v = v , emojis = emojis )
2022-11-15 09:19:08 +00:00
2024-02-14 17:47:53 +00:00
emoji_modifiers = ( ' pat ' , ' talking ' , ' genocide ' , ' love ' , ' typing ' )
2023-08-17 15:28:14 +00:00
2023-03-18 13:34:04 +00:00
@app.post ( " /submit/emojis " )
2023-10-24 19:04:40 +00:00
@feature_required ( ' EMOJI_SUBMISSIONS ' )
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-07-13 13:50:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 )
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 , key_func = get_ID )
2022-11-15 09:19:08 +00:00
@auth_required
2023-07-30 00:42:06 +00:00
def submit_emoji ( v ) :
2023-10-26 14:53:20 +00:00
if SITE_NAME == ' WPD ' and v . blacklisted_by :
abort ( 403 )
2022-11-15 09:19:08 +00:00
file = request . files [ " image " ]
name = request . values . get ( ' name ' , ' ' ) . lower ( ) . strip ( )
2023-10-26 18:17:48 +00:00
tags = request . values . get ( ' tags ' , ' ' ) . lower ( ) . strip ( ) . replace ( ' ' , ' ' )
2024-01-23 11:23:34 +00:00
tags = delete_unnecessary_tags ( tags , name )
2022-11-15 09:19:08 +00:00
username = request . values . get ( ' author ' , ' ' ) . lower ( ) . strip ( )
2023-03-18 13:34:04 +00:00
kind = request . values . get ( ' kind ' , ' ' ) . strip ( )
2023-10-05 10:19:50 +00:00
nsfw = bool ( request . values . get ( " nsfw " ) )
2023-03-18 13:34:04 +00:00
2023-08-17 15:28:14 +00:00
for modifier in emoji_modifiers :
if name . endswith ( modifier ) :
abort ( 400 , f ' Submitted emoji names should NOT end with the word " { modifier } " ' )
2023-03-21 16:50:22 +00:00
if kind not in EMOJI_KINDS :
2023-08-11 21:50:23 +00:00
abort ( 400 , " Invalid emoji kind! " )
2023-03-18 15:21:20 +00:00
2024-01-23 18:26:48 +00:00
if kind in { " Tay " , " Platy " , " Wolf " , " Carp " , " Capy " } and not name . startswith ( kind . lower ( ) ) :
2023-08-11 21:50:23 +00:00
abort ( 400 , f ' The name of this emoji should start with the word " { kind . lower ( ) } " ' )
2023-03-18 15:21:20 +00:00
2023-07-07 23:25:07 +00:00
if kind == " Marsey " and not name . startswith ( " marsey " ) and not name . startswith ( " marcus " ) :
2023-08-11 21:50:23 +00:00
abort ( 400 , ' The name of this emoji should start with the word " Marsey " or " Marcus " ' )
2023-07-07 23:25:07 +00:00
2023-03-18 15:21:20 +00:00
if kind == " Marsey Flags " and not name . startswith ( " marseyflag " ) :
2023-08-11 21:50:23 +00:00
abort ( 400 , ' The name of this emoji should start with the word " marseyflag " ' )
2023-03-18 15:21:20 +00:00
2022-11-15 09:19:08 +00:00
if g . is_tor :
2024-02-28 22:34:26 +00:00
abort ( 400 , " File uploads are not allowed through TOR! " )
2022-11-15 09:19:08 +00:00
if not file or not file . content_type . startswith ( ' image/ ' ) :
2023-08-11 21:50:23 +00:00
abort ( 400 , " You need to submit an image! " )
2022-11-15 09:19:08 +00:00
2023-03-18 14:53:00 +00:00
if not emoji_name_regex . fullmatch ( name ) :
2023-08-11 21:50:23 +00:00
abort ( 400 , " Invalid name! " )
2022-11-15 09:19:08 +00:00
2023-03-18 13:34:04 +00:00
existing = g . db . query ( Emoji . name ) . filter_by ( name = name ) . one_or_none ( )
2022-11-15 09:19:08 +00:00
if existing :
2023-08-11 21:50:23 +00:00
abort ( 400 , " Someone already submitted an emoji with this name! " )
2022-11-15 09:19:08 +00:00
if not tags_regex . fullmatch ( tags ) :
2023-08-11 21:50:23 +00:00
abort ( 400 , " Invalid tags! " )
2022-11-15 09:19:08 +00:00
2023-09-06 18:13:32 +00:00
author = get_user ( username , v = v )
2022-11-15 09:19:08 +00:00
2023-03-21 14:16:18 +00:00
highquality = f ' /asset_submissions/emojis/ { name } '
2022-11-15 09:19:08 +00:00
file . save ( highquality )
2023-09-14 22:40:25 +00:00
process_image ( highquality , v ) #to ensure not malware
2022-11-15 09:19:08 +00:00
2023-03-21 14:16:18 +00:00
filename = f ' /asset_submissions/emojis/ { name } .webp '
2022-11-15 09:19:08 +00:00
copyfile ( highquality , filename )
2023-09-23 17:58:04 +00:00
process_image ( filename , v , resize = 300 , trim = True )
2022-11-15 09:19:08 +00:00
2023-09-29 07:15:29 +00:00
emoji = Emoji (
name = name ,
kind = kind ,
author_id = author . id ,
tags = tags ,
count = 0 ,
submitter_id = v . id ,
2023-10-05 10:19:50 +00:00
nsfw = nsfw ,
2023-09-29 07:15:29 +00:00
)
2023-03-18 14:53:00 +00:00
g . db . add ( emoji )
2022-11-15 09:19:08 +00:00
2023-08-11 21:50:23 +00:00
return { " message " : f " ' { name } ' submitted successfully! " }
2022-11-15 09:19:08 +00:00
2023-07-30 00:42:06 +00:00
def verify_permissions_and_get_asset ( cls , asset_type , v , name , make_lower = False ) :
2022-11-15 09:19:08 +00:00
if cls not in ASSET_TYPES : raise Exception ( " not a valid asset type " )
name = name . strip ( )
if make_lower : name = name . lower ( )
asset = None
if cls == HatDef :
2023-03-16 06:27:58 +00:00
asset = g . db . query ( cls ) . filter_by ( name = name ) . one_or_none ( )
2022-11-15 09:19:08 +00:00
else :
2023-03-16 06:27:58 +00:00
asset = g . db . get ( cls , name )
2022-11-15 09:19:08 +00:00
if not asset :
abort ( 404 , f " This { asset } ' { name } ' doesn ' t exist! " )
return asset
2023-03-18 13:34:04 +00:00
@app.post ( " /admin/approve/emoji/<name> " )
2023-10-24 19:04:40 +00:00
@feature_required ( ' EMOJI_SUBMISSIONS ' )
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-07-13 13:50:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 )
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 , key_func = get_ID )
2023-01-22 08:04:49 +00:00
@admin_level_required ( PERMS [ ' MODERATE_PENDING_SUBMITTED_ASSETS ' ] )
2023-03-18 14:53:00 +00:00
def approve_emoji ( v , name ) :
2024-03-05 19:07:13 +00:00
comment = request . values . get ( " comment " , " " ) . strip ( )
2023-03-18 14:53:00 +00:00
emoji = verify_permissions_and_get_asset ( Emoji , " emoji " , v , name , True )
2023-10-26 18:17:48 +00:00
tags = request . values . get ( ' tags ' ) . lower ( ) . strip ( ) . replace ( ' ' , ' ' )
2022-11-15 09:19:08 +00:00
if not tags :
abort ( 400 , " You need to include tags! " )
new_name = request . values . get ( ' name ' ) . lower ( ) . strip ( )
if not new_name :
abort ( 400 , " You need to include name! " )
2024-01-23 11:23:34 +00:00
tags = delete_unnecessary_tags ( tags , new_name )
2023-03-18 13:34:04 +00:00
new_kind = request . values . get ( ' kind ' ) . strip ( )
if not new_kind :
abort ( 400 , " You need to include kind! " )
2022-11-15 09:19:08 +00:00
2023-03-18 14:53:00 +00:00
if not emoji_name_regex . fullmatch ( new_name ) :
2022-11-15 09:19:08 +00:00
abort ( 400 , " Invalid name! " )
2023-03-18 13:34:04 +00:00
2022-11-15 09:19:08 +00:00
if not tags_regex . fullmatch ( tags ) :
abort ( 400 , " Invalid tags! " )
2023-03-21 16:50:22 +00:00
if new_kind not in EMOJI_KINDS :
2023-03-18 13:34:04 +00:00
abort ( 400 , " Invalid kind! " )
2023-10-05 10:19:50 +00:00
nsfw = request . values . get ( " nsfw " ) == ' true '
2022-11-15 09:19:08 +00:00
2024-02-16 17:02:43 +00:00
author = request . values . get ( ' author ' ) . strip ( )
author = get_user ( author )
2023-10-26 13:32:04 +00:00
old_name = emoji . name
2023-03-18 14:53:00 +00:00
emoji . name = new_name
emoji . kind = new_kind
emoji . tags = tags
2023-10-05 10:19:50 +00:00
emoji . nsfw = nsfw
2024-02-16 17:02:43 +00:00
emoji . author_id = author . id
2023-03-18 14:53:00 +00:00
g . db . add ( emoji )
2022-11-15 09:19:08 +00:00
2023-03-18 15:13:36 +00:00
if emoji . kind == " Marsey " :
2023-06-06 21:39:38 +00:00
all_by_author = g . db . query ( Emoji ) . filter_by ( kind = " Marsey " , author_id = author . id ) . count ( )
2023-03-18 15:25:56 +00:00
2023-08-20 02:00:35 +00:00
if all_by_author > = 99 :
2023-03-18 15:13:36 +00:00
badge_grant ( badge_id = 143 , user = author )
2023-08-20 02:00:35 +00:00
elif all_by_author > = 9 :
2023-03-18 15:13:36 +00:00
badge_grant ( badge_id = 16 , user = author )
else :
2023-03-18 15:25:56 +00:00
badge_grant ( badge_id = 17 , user = author )
2023-06-22 16:19:05 +00:00
elif emoji . kind == " Capy " :
all_by_author = g . db . query ( Emoji ) . filter_by ( kind = " Capy " , author_id = author . id ) . count ( )
2023-08-20 02:00:35 +00:00
if all_by_author > = 9 :
2023-06-22 16:19:05 +00:00
badge_grant ( badge_id = 115 , user = author )
badge_grant ( badge_id = 114 , user = author )
2023-06-23 16:34:29 +00:00
elif emoji . kind == " Carp " :
all_by_author = g . db . query ( Emoji ) . filter_by ( kind = " Carp " , author_id = author . id ) . count ( )
2023-08-20 02:00:35 +00:00
if all_by_author > = 9 :
2023-06-30 23:10:50 +00:00
badge_grant ( badge_id = 288 , user = author )
badge_grant ( badge_id = 287 , user = author )
2023-03-18 15:13:36 +00:00
elif emoji . kind == " Wolf " :
all_by_author = g . db . query ( Emoji ) . filter_by ( kind = " Wolf " , author_id = author . id ) . count ( )
2023-08-20 02:00:35 +00:00
if all_by_author > = 9 :
2023-03-18 15:13:36 +00:00
badge_grant ( badge_id = 111 , user = author )
2023-08-06 07:35:30 +00:00
badge_grant ( badge_id = 110 , user = author )
2023-03-18 15:13:36 +00:00
elif emoji . kind == " Platy " :
all_by_author = g . db . query ( Emoji ) . filter_by ( kind = " Platy " , author_id = author . id ) . count ( )
2023-08-20 02:00:35 +00:00
if all_by_author > = 9 :
2023-03-18 15:13:36 +00:00
badge_grant ( badge_id = 113 , user = author )
2023-08-06 07:35:30 +00:00
badge_grant ( badge_id = 112 , user = author )
2023-05-05 21:45:25 +00:00
2023-10-26 13:32:04 +00:00
move ( f " /asset_submissions/emojis/ { old_name } .webp " , f " files/assets/images/emojis/ { emoji . name } .webp " )
2022-11-15 09:19:08 +00:00
2023-10-26 13:32:04 +00:00
highquality = f " /asset_submissions/emojis/ { old_name } "
2022-11-15 09:19:08 +00:00
with Image . open ( highquality ) as i :
2023-10-22 20:21:38 +00:00
new_path = f ' /asset_submissions/emojis/original/ { emoji . name } . { i . format . lower ( ) } '
2022-11-15 09:19:08 +00:00
rename ( highquality , new_path )
2023-10-19 19:22:39 +00:00
if ' pkmn ' in emoji . tags : amount = 500
else : amount = 250
2024-03-06 02:04:25 +00:00
pay_reason = f ' Reward for making <img loading= " lazy " data-bs-toggle= " tooltip " alt= " : { emoji . name } : " title= " : { emoji . name } : " src= " { SITE_FULL_IMAGES } /e/ { emoji . name } .webp " > '
author . pay_account ( ' coins ' , amount , pay_reason )
2023-03-16 06:27:58 +00:00
g . db . add ( author )
2022-11-15 09:19:08 +00:00
if v . id != author . id :
2024-02-18 16:10:24 +00:00
msg = f " @ { v . username } (a site admin) has approved an emoji you made: : { emoji . name } : \n \n You have received { amount } coins as a reward! "
2023-10-02 03:40:30 +00:00
if comment :
msg + = f " \n Comment: ` { comment } ` "
2022-11-15 09:19:08 +00:00
send_repeatable_notification ( author . id , msg )
2023-03-18 14:53:00 +00:00
if v . id != emoji . submitter_id and author . id != emoji . submitter_id :
2024-02-18 16:10:24 +00:00
msg = f " @ { v . username } (a site admin) has approved an emoji you submitted: : { emoji . name } : "
2023-10-02 03:40:30 +00:00
if comment :
msg + = f " \n Comment: ` { comment } ` "
2023-03-18 14:53:00 +00:00
send_repeatable_notification ( emoji . submitter_id , msg )
2022-11-15 09:19:08 +00:00
2023-03-18 14:53:00 +00:00
emoji . submitter_id = None
2022-11-15 09:19:08 +00:00
2024-03-05 19:18:13 +00:00
note = f ' <img loading= " lazy " data-bs-toggle= " tooltip " alt= " : { emoji . name } : " title= " : { emoji . name } : " src= " { SITE_FULL_IMAGES } /e/ { emoji . name } .webp " > '
2024-03-04 23:54:15 +00:00
if comment :
note + = f ' - Comment: " { comment } " '
2023-02-18 21:34:39 +00:00
ma = ModAction (
2023-03-18 14:53:00 +00:00
kind = " approve_emoji " ,
2023-02-18 21:34:39 +00:00
user_id = v . id ,
2024-03-04 23:54:15 +00:00
target_user_id = emoji . author_id ,
2024-03-05 19:18:13 +00:00
_note = note
2023-02-18 21:34:39 +00:00
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2023-02-18 21:34:39 +00:00
2023-10-05 10:19:50 +00:00
if emoji . nsfw :
2023-12-25 01:18:48 +00:00
NSFW_EMOJIS . append ( emoji . name )
2023-09-29 07:15:29 +00:00
2023-10-27 15:58:37 +00:00
g . db . commit ( )
2023-10-20 15:42:32 +00:00
cache . delete ( " emojis_True " )
cache . delete ( f " emoji_list_ { emoji . kind } _True " )
if not emoji . nsfw :
cache . delete ( " emojis_False " )
cache . delete ( f " emoji_list_ { emoji . kind } _False " )
2023-10-20 15:39:10 +00:00
2023-10-27 15:58:37 +00:00
cache . delete ( " emoji_count " )
2023-10-27 09:22:44 +00:00
2023-10-20 15:39:10 +00:00
purge_files_in_cloudflare_cache ( f " { SITE_FULL_IMAGES } /e/ { emoji . name } /webp " )
2023-03-18 14:53:00 +00:00
return { " message " : f " ' { emoji . name } ' approved! " }
2022-11-15 09:19:08 +00:00
2023-07-30 00:42:06 +00:00
def remove_asset ( cls , type_name , v , name ) :
2024-03-05 19:07:13 +00:00
comment = request . values . get ( " comment " , " " ) . strip ( )
2022-11-15 09:19:08 +00:00
if cls not in ASSET_TYPES : raise Exception ( " not a valid asset type " )
2023-03-18 14:02:03 +00:00
should_make_lower = cls == Emoji
2022-11-15 09:19:08 +00:00
if should_make_lower : name = name . lower ( )
name = name . strip ( )
if not name :
abort ( 400 , f " You need to specify a { type_name } ! " )
asset = None
if cls == HatDef :
2023-03-16 06:27:58 +00:00
asset = g . db . query ( cls ) . filter_by ( name = name ) . one_or_none ( )
2022-11-15 09:19:08 +00:00
else :
2023-03-16 06:27:58 +00:00
asset = g . db . get ( cls , name )
2022-11-15 09:19:08 +00:00
if not asset :
abort ( 404 , f " This { type_name } ' { name } ' doesn ' t exist! " )
2023-01-22 08:04:49 +00:00
if v . id != asset . submitter_id and v . admin_level < PERMS [ ' MODERATE_PENDING_SUBMITTED_ASSETS ' ] :
abort ( 403 )
2022-11-15 09:19:08 +00:00
name = asset . name
2023-02-28 17:15:49 +00:00
2022-11-15 09:19:08 +00:00
if v . id != asset . submitter_id :
2024-03-04 22:46:03 +00:00
msg = f " @ { v . username } (a site admin) has rejected a { type_name } you submitted: ` ' { name } ' ` "
2023-10-02 03:40:30 +00:00
if comment :
msg + = f " \n Comment: ` { comment } ` "
2022-11-15 09:19:08 +00:00
send_repeatable_notification ( asset . submitter_id , msg )
2023-02-28 17:15:49 +00:00
2024-03-04 23:54:15 +00:00
note = name
if comment :
note + = f ' - Comment: " { comment } " '
2023-02-28 17:15:49 +00:00
ma = ModAction (
kind = f " reject_ { type_name } " ,
user_id = v . id ,
2024-03-04 23:54:15 +00:00
target_user_id = asset . author_id ,
2024-03-05 19:18:13 +00:00
_note = note
2023-02-28 17:15:49 +00:00
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2023-02-28 17:15:49 +00:00
2023-03-16 06:27:58 +00:00
g . db . delete ( asset )
2023-03-18 14:56:34 +00:00
2023-03-25 15:07:12 +00:00
os . remove ( f " /asset_submissions/ { type_name } s/ { name } .webp " )
os . remove ( f " /asset_submissions/ { type_name } s/ { name } " )
2023-02-18 21:34:39 +00:00
2022-11-15 09:19:08 +00:00
return { " message " : f " ' { name } ' removed! " }
2023-03-18 13:34:04 +00:00
@app.post ( " /remove/emoji/<name> " )
2023-10-24 19:04:40 +00:00
@feature_required ( ' EMOJI_SUBMISSIONS ' )
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-07-13 13:50:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 )
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 , key_func = get_ID )
2022-11-15 09:19:08 +00:00
@auth_required
2023-07-30 00:42:06 +00:00
def remove_emoji ( v , name ) :
2023-03-18 14:53:00 +00:00
return remove_asset ( Emoji , " emoji " , v , name )
2022-11-15 09:19:08 +00:00
@app.get ( " /submit/hats " )
2023-10-24 19:04:40 +00:00
@feature_required ( ' HAT_SUBMISSIONS ' )
2023-07-13 13:50:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 )
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 , key_func = get_ID )
2022-11-15 09:19:08 +00:00
@auth_required
2023-07-30 00:42:06 +00:00
def submit_hats ( v ) :
2023-08-16 23:20:31 +00:00
hats = g . db . query ( HatDef ) . filter ( HatDef . submitter_id != None ) . order_by ( HatDef . created_utc . desc ( ) ) . all ( )
2023-03-18 13:34:04 +00:00
2023-08-11 21:50:23 +00:00
return render_template ( " submit_hats.html " , v = v , hats = hats )
2022-11-15 09:19:08 +00:00
@app.post ( " /submit/hats " )
2023-10-24 19:04:40 +00:00
@feature_required ( ' HAT_SUBMISSIONS ' )
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-07-13 13:50:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 )
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 , key_func = get_ID )
2022-11-15 09:19:08 +00:00
@auth_required
2023-07-30 00:42:06 +00:00
def submit_hat ( v ) :
2022-11-15 09:19:08 +00:00
name = request . values . get ( ' name ' , ' ' ) . strip ( )
description = request . values . get ( ' description ' , ' ' ) . strip ( )
username = request . values . get ( ' author ' , ' ' ) . strip ( )
if g . is_tor :
2024-02-28 22:34:26 +00:00
abort ( 400 , " File uploads are not allowed through TOR! " )
2022-09-10 07:38:23 +00:00
2022-11-15 09:19:08 +00:00
file = request . files [ " image " ]
if not file or not file . content_type . startswith ( ' image/ ' ) :
2023-08-11 21:50:23 +00:00
abort ( 400 , " You need to submit an image! " )
2022-09-10 07:38:23 +00:00
2023-10-17 17:22:05 +00:00
if not hat_name_regex . fullmatch ( name ) :
2023-08-11 21:50:23 +00:00
abort ( 400 , " Invalid name! " )
2022-09-10 07:38:23 +00:00
2023-03-16 06:27:58 +00:00
existing = g . db . query ( HatDef . name ) . filter_by ( name = name ) . one_or_none ( )
2022-11-15 09:19:08 +00:00
if existing :
2023-08-11 21:50:23 +00:00
abort ( 400 , " A hat with this name already exists! " )
2022-09-10 07:38:23 +00:00
2022-11-15 09:19:08 +00:00
if not description_regex . fullmatch ( description ) :
2023-08-11 21:50:23 +00:00
abort ( 400 , " Invalid description! " )
2022-09-10 07:38:23 +00:00
2023-09-06 18:13:32 +00:00
author = get_user ( username , v = v )
2022-09-10 07:38:23 +00:00
2022-11-15 09:19:08 +00:00
highquality = f ' /asset_submissions/hats/ { name } '
file . save ( highquality )
2023-09-14 22:40:25 +00:00
process_image ( highquality , v ) #to ensure not malware
2022-11-15 09:19:08 +00:00
with Image . open ( highquality ) as i :
2024-03-09 11:51:51 +00:00
if i . width != 100 or i . height != 130 :
2023-03-25 15:07:12 +00:00
os . remove ( highquality )
2023-08-11 21:50:23 +00:00
abort ( 400 , " Images must be 100x130 " )
2022-11-15 09:19:08 +00:00
if len ( list ( Iterator ( i ) ) ) > 1 : price = 1000
else : price = 500
filename = f ' /asset_submissions/hats/ { name } .webp '
copyfile ( highquality , filename )
process_image ( filename , v , resize = 100 )
hat = HatDef ( name = name , author_id = author . id , description = description , price = price , submitter_id = v . id )
2023-03-16 06:27:58 +00:00
g . db . add ( hat )
2022-11-15 09:19:08 +00:00
2023-08-11 21:50:23 +00:00
return { " message " : f " ' { name } ' submitted successfully! " }
2022-11-15 09:19:08 +00:00
@app.post ( " /admin/approve/hat/<name> " )
2023-10-24 19:04:40 +00:00
@feature_required ( ' HAT_SUBMISSIONS ' )
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-07-13 13:50:46 +00:00
@limiter.limit ( " 120/minute;200/hour;1000/day " , deduct_when = lambda response : response . status_code < 400 )
@limiter.limit ( " 120/minute;200/hour;1000/day " , deduct_when = lambda response : response . status_code < 400 , key_func = get_ID )
2023-01-22 08:04:49 +00:00
@admin_level_required ( PERMS [ ' MODERATE_PENDING_SUBMITTED_ASSETS ' ] )
2022-11-15 09:19:08 +00:00
def approve_hat ( v , name ) :
2024-03-05 19:07:13 +00:00
comment = request . values . get ( " comment " , " " ) . strip ( )
2022-11-15 09:19:08 +00:00
hat = verify_permissions_and_get_asset ( HatDef , " hat " , v , name , False )
description = request . values . get ( ' description ' ) . strip ( )
if not description : abort ( 400 , " You need to include a description! " )
new_name = request . values . get ( ' name ' ) . strip ( )
if not new_name : abort ( 400 , " You need to include a name! " )
2023-10-17 17:22:05 +00:00
if not hat_name_regex . fullmatch ( new_name ) : abort ( 400 , " Invalid name! " )
2022-11-15 09:19:08 +00:00
if not description_regex . fullmatch ( description ) : abort ( 400 , " Invalid description! " )
try :
hat . price = int ( request . values . get ( ' price ' ) )
if hat . price < 0 : raise ValueError ( " Invalid hat price " )
except :
abort ( 400 , " Invalid hat price " )
2023-10-26 13:33:36 +00:00
old_name = hat . name
2022-11-15 09:19:08 +00:00
hat . name = new_name
hat . description = description
2023-03-16 06:27:58 +00:00
g . db . add ( hat )
2022-11-15 09:19:08 +00:00
author = hat . author
2023-03-16 06:27:58 +00:00
all_by_author = g . db . query ( HatDef ) . filter_by ( author_id = author . id ) . count ( )
2022-11-15 09:19:08 +00:00
2023-08-20 02:00:35 +00:00
if all_by_author > = 249 :
2022-11-15 09:19:08 +00:00
badge_grant ( badge_id = 166 , user = author )
2023-08-20 02:00:35 +00:00
elif all_by_author > = 99 :
2022-11-15 09:19:08 +00:00
badge_grant ( badge_id = 165 , user = author )
2023-08-20 02:00:35 +00:00
elif all_by_author > = 49 :
2022-11-15 09:19:08 +00:00
badge_grant ( badge_id = 164 , user = author )
2023-08-20 02:00:35 +00:00
elif all_by_author > = 9 :
2022-11-15 09:19:08 +00:00
badge_grant ( badge_id = 163 , user = author )
hat_copy = Hat (
user_id = author . id ,
hat_id = hat . id
)
2023-03-16 06:27:58 +00:00
g . db . add ( hat_copy )
2022-11-15 09:19:08 +00:00
if v . id != author . id :
2024-02-18 16:10:24 +00:00
msg = f " @ { v . username } (a site admin) has approved a hat you made: ` ' { hat . name } ' ` "
2023-10-02 03:40:30 +00:00
if comment :
msg + = f " \n Comment: ` { comment } ` "
2022-11-15 09:19:08 +00:00
send_repeatable_notification ( author . id , msg )
if v . id != hat . submitter_id and author . id != hat . submitter_id :
2024-02-18 16:10:24 +00:00
msg = f " @ { v . username } (a site admin) has approved a hat you submitted: ` ' { hat . name } ' ` "
2023-10-02 03:40:30 +00:00
if comment :
msg + = f " \n Comment: ` { comment } ` "
2022-11-15 09:19:08 +00:00
send_repeatable_notification ( hat . submitter_id , msg )
hat . submitter_id = None
2023-10-26 13:33:36 +00:00
move ( f " /asset_submissions/hats/ { old_name } .webp " , f " files/assets/images/hats/ { hat . name } .webp " )
2022-11-15 09:19:08 +00:00
2023-10-26 13:33:36 +00:00
highquality = f " /asset_submissions/hats/ { old_name } "
2022-11-15 09:19:08 +00:00
with Image . open ( highquality ) as i :
2023-10-22 20:21:38 +00:00
new_path = f ' /asset_submissions/hats/original/ { hat . name } . { i . format . lower ( ) } '
2022-11-15 09:19:08 +00:00
rename ( highquality , new_path )
2024-03-05 19:18:13 +00:00
note = f ' <a href= " { SITE_FULL_IMAGES } /i/hats/ { hat . name } .webp " > { hat . name } </a> '
2024-03-04 23:54:15 +00:00
if comment :
note + = f ' - Comment: " { comment } " '
2023-02-18 21:34:39 +00:00
ma = ModAction (
kind = " approve_hat " ,
user_id = v . id ,
2024-03-04 23:54:15 +00:00
target_user_id = hat . author_id ,
2024-03-05 19:18:13 +00:00
_note = note
2023-02-18 21:34:39 +00:00
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2023-02-18 21:34:39 +00:00
2022-11-15 09:19:08 +00:00
return { " message " : f " ' { hat . name } ' approved! " }
@app.post ( " /remove/hat/<name> " )
2023-10-24 19:04:40 +00:00
@feature_required ( ' HAT_SUBMISSIONS ' )
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-07-13 13:50:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 )
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 , key_func = get_ID )
2022-11-15 09:19:08 +00:00
@auth_required
2023-07-30 00:42:06 +00:00
def remove_hat ( v , name ) :
2022-11-15 09:19:08 +00:00
return remove_asset ( HatDef , ' hat ' , v , name )
2023-03-18 13:34:04 +00:00
@app.get ( " /admin/update/emojis " )
2023-07-13 13:50:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 )
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 , key_func = get_ID )
2023-01-22 08:04:49 +00:00
@admin_level_required ( PERMS [ ' UPDATE_ASSETS ' ] )
2023-03-18 14:53:00 +00:00
def update_emojis ( v ) :
2023-03-21 17:03:11 +00:00
return render_template ( " admin/update_assets.html " , v = v , type = " Emoji " )
2022-09-10 07:38:23 +00:00
2023-03-18 13:34:04 +00:00
@app.post ( " /admin/update/emojis " )
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-07-13 13:50:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 )
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 , key_func = get_ID )
2023-01-22 08:04:49 +00:00
@admin_level_required ( PERMS [ ' UPDATE_ASSETS ' ] )
2023-03-18 14:53:00 +00:00
def update_emoji ( v ) :
2022-11-15 09:19:08 +00:00
name = request . values . get ( ' name ' , ' ' ) . lower ( ) . strip ( )
2023-10-17 17:04:38 +00:00
file = request . files [ " image " ]
2023-03-21 16:50:22 +00:00
kind = request . values . get ( ' kind ' , ' ' ) . strip ( )
2023-12-02 23:24:35 +00:00
new_name = request . values . get ( ' new_name ' , ' ' ) . lower ( ) . strip ( )
2023-10-26 18:17:48 +00:00
tags = request . values . get ( ' tags ' , ' ' ) . lower ( ) . strip ( ) . replace ( ' ' , ' ' )
2024-01-23 11:23:34 +00:00
2023-10-17 17:04:38 +00:00
nsfw = request . values . get ( ' nsfw ' , ' ' ) . strip ( )
2022-09-10 07:38:23 +00:00
2023-03-18 13:34:04 +00:00
existing = g . db . get ( Emoji , name )
2022-11-15 09:19:08 +00:00
if not existing :
2023-08-11 21:50:23 +00:00
abort ( 400 , " An emoji with this name doesn ' t exist! " )
2023-03-18 13:34:04 +00:00
2023-10-31 22:57:18 +00:00
if SITE in { ' rdrama.net ' , ' watchpeopledie.tv ' } and existing . author_id == 2 :
abort ( 403 , f " This emoji was submitted through { OTHER_SITE_NAME } , so you can only update it there! " )
2023-03-18 13:34:04 +00:00
updated = False
2022-09-18 17:38:53 +00:00
2023-10-17 17:11:16 +00:00
if new_name and existing . name != new_name :
if not emoji_name_regex . fullmatch ( new_name ) :
abort ( 400 , " Invalid new name! " )
2023-10-17 17:21:50 +00:00
2023-10-17 17:11:16 +00:00
old_path = f " files/assets/images/emojis/ { existing . name } .webp "
new_path = f " files/assets/images/emojis/ { new_name } .webp "
copyfile ( old_path , new_path )
2023-10-17 17:21:50 +00:00
for x in IMAGE_FORMATS :
original_old_path = f ' /asset_submissions/emojis/original/ { existing . name } . { x } '
original_new_path = f ' /asset_submissions/emojis/original/ { new_name } . { x } '
if path . isfile ( original_old_path ) :
rename ( original_old_path , original_new_path )
2023-10-17 17:11:16 +00:00
existing . name = new_name
updated = True
name = existing . name
2022-11-15 09:19:08 +00:00
if file :
if g . is_tor :
2024-02-28 22:34:26 +00:00
abort ( 400 , " File uploads are not allowed through TOR! " )
2022-11-15 09:19:08 +00:00
if not file . content_type . startswith ( ' image/ ' ) :
2023-08-11 21:50:23 +00:00
abort ( 400 , " You need to submit an image! " )
2023-01-01 11:36:20 +00:00
2022-11-15 09:19:08 +00:00
for x in IMAGE_FORMATS :
2023-03-21 14:16:18 +00:00
if path . isfile ( f ' /asset_submissions/emojis/original/ { name } . { x } ' ) :
2023-03-25 15:07:12 +00:00
os . remove ( f ' /asset_submissions/emojis/original/ { name } . { x } ' )
2022-10-08 01:00:27 +00:00
2023-03-21 14:16:18 +00:00
highquality = f " /asset_submissions/emojis/ { name } "
2022-10-08 01:00:27 +00:00
file . save ( highquality )
2023-09-14 22:40:25 +00:00
process_image ( highquality , v ) #to ensure not malware
2022-10-08 01:00:27 +00:00
with Image . open ( highquality ) as i :
format = i . format . lower ( )
2023-03-21 14:16:18 +00:00
new_path = f ' /asset_submissions/emojis/original/ { name } . { format } '
2022-10-08 01:00:27 +00:00
rename ( highquality , new_path )
2022-09-18 17:38:53 +00:00
2022-11-15 09:19:08 +00:00
filename = f " files/assets/images/emojis/ { name } .webp "
2022-10-08 01:00:27 +00:00
copyfile ( new_path , filename )
2023-09-23 17:58:04 +00:00
process_image ( filename , v , resize = 300 , trim = True )
2023-09-15 00:07:17 +00:00
purge_files_in_cloudflare_cache ( [ f " { SITE_FULL_IMAGES } /e/ { name } .webp " , f " { SITE_FULL_IMAGES } /asset_submissions/emojis/original/ { name } . { format } " ] )
2023-03-18 13:34:04 +00:00
updated = True
2023-10-17 17:04:38 +00:00
if kind and existing . kind != kind :
if kind not in EMOJI_KINDS :
abort ( 400 , " Invalid kind! " )
existing . kind = kind
updated = True
if tags and existing . tags != tags :
2024-03-23 20:13:43 +00:00
existing . tags + = f " { tags } "
existing . tags = delete_unnecessary_tags ( existing . tags , new_name )
2023-03-18 13:34:04 +00:00
if not tags_regex . fullmatch ( tags ) :
abort ( 400 , " Invalid tags! " )
2023-03-21 16:50:22 +00:00
updated = True
2023-10-17 17:04:38 +00:00
if nsfw :
nsfw = ( nsfw == ' NSFW ' )
if existing . nsfw != nsfw :
existing . nsfw = nsfw
updated = True
2023-03-18 13:34:04 +00:00
if not updated :
2023-08-11 21:50:23 +00:00
abort ( 400 , " You need to actually update something! " )
2022-11-15 09:19:08 +00:00
2023-03-21 16:50:22 +00:00
g . db . add ( existing )
2022-11-15 09:19:08 +00:00
ma = ModAction (
2023-03-18 14:53:00 +00:00
kind = " update_emoji " ,
2022-11-15 09:19:08 +00:00
user_id = v . id ,
2024-03-02 21:01:29 +00:00
_note = f ' <img loading= " lazy " data-bs-toggle= " tooltip " alt= " : { name } : " title= " : { name } : " src= " { SITE_FULL_IMAGES } /e/ { name } .webp " > '
2022-11-15 09:19:08 +00:00
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2023-03-21 16:50:22 +00:00
2023-10-27 15:58:37 +00:00
g . db . commit ( )
2023-10-20 15:42:32 +00:00
cache . delete ( " emojis_True " )
cache . delete ( f " emoji_list_ { existing . kind } _True " )
if not existing . nsfw :
cache . delete ( " emojis_False " )
cache . delete ( f " emoji_list_ { existing . kind } _False " )
2023-03-21 16:50:22 +00:00
2023-08-11 21:50:23 +00:00
return { " message " : f " ' { name } ' updated successfully! " }
2022-11-15 09:19:08 +00:00
@app.get ( " /admin/update/hats " )
2023-07-13 13:50:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 )
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 , key_func = get_ID )
2023-01-22 08:04:49 +00:00
@admin_level_required ( PERMS [ ' UPDATE_ASSETS ' ] )
2022-11-15 09:19:08 +00:00
def update_hats ( v ) :
2023-10-31 23:01:52 +00:00
if SITE == ' watchpeopledie.tv ' :
2023-10-31 23:03:19 +00:00
abort ( 403 , " You can only update hats on rdrama.net (the changes will propagate to WPD automatically) " )
2023-03-04 18:55:07 +00:00
return render_template ( " admin/update_assets.html " , v = v , type = " Hat " )
2022-11-15 09:19:08 +00:00
@app.post ( " /admin/update/hats " )
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-07-13 13:50:46 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 )
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 , key_func = get_ID )
2023-01-22 08:04:49 +00:00
@admin_level_required ( PERMS [ ' UPDATE_ASSETS ' ] )
2022-11-15 09:19:08 +00:00
def update_hat ( v ) :
name = request . values . get ( ' name ' , ' ' ) . strip ( )
2023-10-17 17:22:05 +00:00
file = request . files [ " image " ]
new_name = request . values . get ( ' new_name ' , ' ' ) . strip ( )
2022-11-15 09:19:08 +00:00
2023-10-17 17:22:05 +00:00
existing = g . db . query ( HatDef ) . filter_by ( name = name ) . one_or_none ( )
2022-11-15 09:19:08 +00:00
if not existing :
2023-08-11 21:50:23 +00:00
abort ( 400 , " A hat with this name doesn ' t exist! " )
2022-11-15 09:19:08 +00:00
2023-10-17 17:22:05 +00:00
updated = False
2022-11-15 09:19:08 +00:00
2023-10-17 17:22:05 +00:00
if new_name and existing . name != new_name :
if not hat_name_regex . fullmatch ( new_name ) :
abort ( 400 , " Invalid new name! " )
2022-11-15 09:19:08 +00:00
2023-10-17 17:22:05 +00:00
old_path = f " files/assets/images/hats/ { existing . name } .webp "
new_path = f " files/assets/images/hats/ { new_name } .webp "
rename ( old_path , new_path )
2022-11-15 09:19:08 +00:00
2023-10-17 17:22:05 +00:00
for x in IMAGE_FORMATS :
original_old_path = f ' /asset_submissions/hats/original/ { existing . name } . { x } '
original_new_path = f ' /asset_submissions/hats/original/ { new_name } . { x } '
if path . isfile ( original_old_path ) :
rename ( original_old_path , original_new_path )
2022-11-15 09:19:08 +00:00
2023-10-17 17:22:05 +00:00
existing . name = new_name
updated = True
name = existing . name
if file :
if g . is_tor :
2024-02-28 22:34:26 +00:00
abort ( 400 , " File uploads are not allowed through TOR! " )
2023-10-17 17:22:05 +00:00
if not file . content_type . startswith ( ' image/ ' ) :
abort ( 400 , " You need to submit an image! " )
highquality = f " /asset_submissions/hats/ { name } "
file . save ( highquality )
process_image ( highquality , v ) #to ensure not malware
with Image . open ( highquality ) as i :
if i . width > 100 or i . height > 130 :
os . remove ( highquality )
abort ( 400 , " Images must be 100x130 " )
format = i . format . lower ( )
new_path = f ' /asset_submissions/hats/original/ { name } . { format } '
for x in IMAGE_FORMATS :
if path . isfile ( f ' /asset_submissions/hats/original/ { name } . { x } ' ) :
os . remove ( f ' /asset_submissions/hats/original/ { name } . { x } ' )
rename ( highquality , new_path )
filename = f " files/assets/images/hats/ { name } .webp "
copyfile ( new_path , filename )
process_image ( filename , v , resize = 100 )
purge_files_in_cloudflare_cache ( [ f " { SITE_FULL_IMAGES } /i/hats/ { name } .webp " , f " { SITE_FULL_IMAGES } /asset_submissions/hats/original/ { name } . { format } " ] )
updated = True
if not updated :
abort ( 400 , " You need to actually update something! " )
g . db . add ( existing )
2022-11-15 09:19:08 +00:00
ma = ModAction (
kind = " update_hat " ,
user_id = v . id ,
2024-03-02 21:01:29 +00:00
_note = f ' <a href= " { SITE_FULL_IMAGES } /i/hats/ { name } .webp " > { name } </a> '
2022-11-15 09:19:08 +00:00
)
2023-03-16 06:27:58 +00:00
g . db . add ( ma )
2023-10-17 17:22:05 +00:00
2023-08-11 21:50:23 +00:00
return { " message " : f " ' { name } ' updated successfully! " }