2023-02-24 06:31:06 +00:00
from files . classes import *
from files . helpers . alerts import *
from files . helpers . regex import *
from files . helpers . get import *
from files . routes . wrappers import *
from files . __main__ import app , limiter
@app.get ( " /ping_groups " )
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-02-24 06:31:06 +00:00
@auth_required
2023-07-30 00:42:06 +00:00
def ping_groups ( v ) :
2023-03-16 06:27:58 +00:00
groups = g . db . query ( Group ) . order_by ( Group . created_utc ) . all ( )
2023-08-11 21:50:23 +00:00
return render_template ( ' groups.html ' , v = v , groups = groups , cost = GROUP_COST )
2023-02-24 06:31:06 +00:00
@app.post ( " /create_group " )
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-09-14 16:49:46 +00:00
@auth_required
2023-02-24 06:31:06 +00:00
def create_group ( v ) :
name = request . values . get ( ' name ' )
if not name : abort ( 400 )
name = name . strip ( ) . lower ( )
2023-04-29 21:27:45 +00:00
if name . startswith ( ' slots ' ) or name . startswith ( ' remindme ' ) :
2023-08-11 21:50:23 +00:00
abort ( 400 , " You can ' t make a group with that name! " )
2023-03-04 21:45:12 +00:00
2023-09-08 22:31:18 +00:00
if not hole_group_name_regex . fullmatch ( name ) :
2023-08-11 21:50:23 +00:00
abort ( 400 , " Name does not match the required format! " )
2023-02-24 06:31:06 +00:00
2023-11-04 21:28:44 +00:00
if name in { ' everyone ' , ' jannies ' , ' holejannies ' , ' followers ' , ' commenters ' } or g . db . get ( Group , name ) :
2023-08-11 21:50:23 +00:00
abort ( 400 , " This group already exists! " )
2023-03-02 19:21:38 +00:00
2024-01-12 08:12:35 +00:00
if not v . charge_account ( ' coins/marseybux ' , GROUP_COST ) [ 0 ] :
2023-08-11 21:50:23 +00:00
abort ( 403 , " You don ' t have enough coins or marseybux! " )
2023-03-02 19:21:38 +00:00
2023-03-16 06:27:58 +00:00
g . db . add ( v )
2023-03-02 19:21:38 +00:00
if v . shadowbanned : abort ( 500 )
group = Group ( name = name )
2023-03-16 06:27:58 +00:00
g . db . add ( group )
2023-03-02 19:21:38 +00:00
group_membership = GroupMembership (
user_id = v . id ,
group_name = group . name ,
created_utc = time . time ( ) ,
approved_utc = time . time ( )
)
2023-03-16 06:27:58 +00:00
g . db . add ( group_membership )
2023-03-02 19:21:38 +00:00
2023-10-12 18:57:35 +00:00
g . db . flush ( ) #Necessary, to make linkfying the ping group in the notification work
2024-02-08 03:35:37 +00:00
text = f " :!marseyparty: ! { group } has been created by @ { v . username } :marseyparty: "
2024-02-10 15:34:45 +00:00
alert_active_users ( text , v . id , User . group_creation_notifs == True )
2023-02-24 06:31:06 +00:00
2023-08-11 21:50:23 +00:00
return { " message " : f " ! { group } created successfully! " }
2023-02-24 06:31:06 +00:00
2023-02-24 19:29:07 +00:00
@app.post ( " /!<group_name>/apply " )
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-02-24 06:31:06 +00:00
@auth_required
2023-07-30 00:42:06 +00:00
def join_group ( v , group_name ) :
2023-03-07 18:55:17 +00:00
group_name = group_name . strip ( ) . lower ( )
2023-08-01 22:18:57 +00:00
if group_name == ' verifiedrich ' :
if not v . patron :
abort ( 403 , f " Only { patron } s can join !verifiedrich " )
join = GroupMembership (
user_id = v . id ,
group_name = group_name ,
approved_utc = time . time ( )
)
g . db . add ( join )
return { " message " : " You have joined !verifiedrich successfully! " }
2023-08-01 21:56:13 +00:00
2023-03-16 06:27:58 +00:00
group = g . db . get ( Group , group_name )
2023-02-24 06:31:06 +00:00
if not group : abort ( 404 )
2023-08-01 22:18:57 +00:00
2023-03-16 06:27:58 +00:00
existing = g . db . query ( GroupMembership ) . filter_by ( user_id = v . id , group_name = group_name ) . one_or_none ( )
2023-02-24 06:31:06 +00:00
if not existing :
join = GroupMembership ( user_id = v . id , group_name = group_name )
2023-03-16 06:27:58 +00:00
g . db . add ( join )
2024-02-11 11:00:37 +00:00
send_notification ( group . owner_id , f " @ { v . username } has applied to join ! { group } . You can approve or reject the application [here](/! { group } ). " )
2023-02-24 06:31:06 +00:00
2023-02-24 19:29:07 +00:00
return { " message " : f " Application submitted to ! { group } ' s owner (@ { group . owner . username } ) successfully! " }
2023-02-24 06:31:06 +00:00
2023-02-24 19:29:07 +00:00
@app.post ( " /!<group_name>/leave " )
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-02-24 06:31:06 +00:00
@auth_required
2023-07-30 00:42:06 +00:00
def leave_group ( v , group_name ) :
2023-03-07 18:55:17 +00:00
group_name = group_name . strip ( ) . lower ( )
2023-03-16 06:27:58 +00:00
group = g . db . get ( Group , group_name )
2023-02-24 06:31:06 +00:00
if not group : abort ( 404 )
2023-03-16 06:27:58 +00:00
existing = g . db . query ( GroupMembership ) . filter_by ( user_id = v . id , group_name = group_name ) . one_or_none ( )
2023-02-24 19:29:07 +00:00
if existing :
if existing . approved_utc :
text = f " @ { v . username } has left ! { group } "
msg = f " You have left ! { group } successfully! "
else :
text = f " @ { v . username } has cancelled their application to ! { group } "
msg = f " You have cancelled your application to ! { group } successfully! "
2024-02-11 11:00:37 +00:00
send_notification ( group . owner_id , text )
2023-03-16 06:27:58 +00:00
g . db . delete ( existing )
2023-05-05 21:45:25 +00:00
2023-02-25 21:44:02 +00:00
return { " message " : msg }
2023-02-24 19:29:07 +00:00
2023-02-24 19:43:27 +00:00
return { " message " : ' ' }
2023-02-24 19:29:07 +00:00
2023-02-25 22:06:43 +00:00
@app.get ( " /!<group_name> " )
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-02-24 19:29:07 +00:00
@auth_required
2023-07-30 00:42:06 +00:00
def memberships ( v , group_name ) :
2023-03-07 18:55:17 +00:00
group_name = group_name . strip ( ) . lower ( )
2023-03-16 06:27:58 +00:00
group = g . db . get ( Group , group_name )
2023-02-24 19:29:07 +00:00
if not group : abort ( 404 )
2023-02-24 19:53:40 +00:00
2023-03-16 06:27:58 +00:00
members = g . db . query ( GroupMembership ) . filter (
2023-02-25 21:44:02 +00:00
GroupMembership . group_name == group_name ,
GroupMembership . approved_utc != None
) . order_by ( GroupMembership . approved_utc ) . all ( )
2023-02-24 19:53:40 +00:00
2023-03-16 06:27:58 +00:00
applications = g . db . query ( GroupMembership ) . filter (
2023-02-25 21:44:02 +00:00
GroupMembership . group_name == group_name ,
GroupMembership . approved_utc == None
) . order_by ( GroupMembership . created_utc ) . all ( )
return render_template ( ' group_memberships.html ' , v = v , group = group , members = members , applications = applications )
2023-02-24 06:31:06 +00:00
@app.post ( " /!<group_name>/<user_id>/approve " )
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-02-24 06:31:06 +00:00
@auth_required
2023-07-30 00:42:06 +00:00
def group_approve ( v , group_name , user_id ) :
2023-03-07 18:55:17 +00:00
group_name = group_name . strip ( ) . lower ( )
2023-03-16 06:27:58 +00:00
group = g . db . get ( Group , group_name )
2023-02-24 06:31:06 +00:00
if not group : abort ( 404 )
2023-05-05 21:45:25 +00:00
2023-08-08 18:08:29 +00:00
if not v . mods_group ( group ) :
abort ( 403 , f " Only the group owner and its mods can approve applications! " )
2023-05-05 21:45:25 +00:00
2023-03-16 06:27:58 +00:00
application = g . db . query ( GroupMembership ) . filter_by ( user_id = user_id , group_name = group . name ) . one_or_none ( )
2023-02-24 06:31:06 +00:00
if not application :
abort ( 404 , " There is no application to approve! " )
2023-12-07 18:45:19 +00:00
if not application . approved_utc :
2023-02-24 06:31:06 +00:00
application . approved_utc = time . time ( )
2023-03-16 06:27:58 +00:00
g . db . add ( application )
2023-12-07 18:45:19 +00:00
if v . id != application . user_id :
send_repeatable_notification ( application . user_id , f " @ { v . username } (! { group } ' s owner) has approved your application! " )
2023-02-24 06:31:06 +00:00
2023-02-24 19:41:25 +00:00
return { " message " : f ' You have approved @ { application . user . username } successfully! ' }
2023-02-24 06:31:06 +00:00
@app.post ( " /!<group_name>/<user_id>/reject " )
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-02-24 06:31:06 +00:00
@auth_required
2023-07-30 00:42:06 +00:00
def group_reject ( v , group_name , user_id ) :
2023-03-07 18:55:17 +00:00
group_name = group_name . strip ( ) . lower ( )
2023-03-16 06:27:58 +00:00
group = g . db . get ( Group , group_name )
2023-02-24 06:31:06 +00:00
if not group : abort ( 404 )
2023-05-05 21:45:25 +00:00
2023-08-08 18:08:29 +00:00
if not v . mods_group ( group ) :
abort ( 403 , f " Only the group owner and its mods can reject memberships! " )
2023-02-24 19:41:25 +00:00
2023-03-16 06:27:58 +00:00
membership = g . db . query ( GroupMembership ) . filter_by ( user_id = user_id , group_name = group . name ) . one_or_none ( )
2023-02-24 19:41:25 +00:00
if not membership :
abort ( 404 , " There is no membership to reject! " )
2023-02-24 06:31:06 +00:00
2023-12-06 20:54:42 +00:00
if v . id != membership . user_id : #implies kicking and not leaving
2024-02-11 11:00:37 +00:00
if membership . user_id == group . owner_id :
2023-12-06 20:54:42 +00:00
abort ( 403 , " You can ' t kick the group owner! " )
2024-02-11 11:00:37 +00:00
if v . id != group . owner_id and membership . is_mod :
2023-12-06 20:54:42 +00:00
abort ( 403 , " Only the group owner can kick mods! " )
2023-08-10 10:17:27 +00:00
2023-05-16 10:40:57 +00:00
if v . id == membership . user_id :
msg = f " You have left ! { group } successfully! "
2023-02-24 19:41:25 +00:00
else :
2023-05-16 10:40:57 +00:00
if membership . approved_utc :
text = f " @ { v . username } (! { group } ' s owner) has kicked you from the group! "
msg = f " You have kicked @ { membership . user . username } successfully! "
else :
text = f " @ { v . username } (! { group } ' s owner) has rejected your application! "
msg = f " You have rejected @ { membership . user . username } successfully! "
2023-05-16 10:28:50 +00:00
send_repeatable_notification ( membership . user_id , text )
2023-02-24 19:41:25 +00:00
2023-03-16 06:27:58 +00:00
g . db . delete ( membership )
2023-02-24 19:43:27 +00:00
2023-08-20 03:03:07 +00:00
g . db . flush ( )
2023-07-07 00:37:17 +00:00
count = g . db . query ( GroupMembership ) . filter_by ( group_name = group . name ) . count ( )
if not count :
g . db . commit ( ) #need it to fix "Dependency rule tried to blank-out primary key column 'group_memberships.group_name' on instance"
g . db . delete ( group )
2023-02-24 19:41:25 +00:00
return { " message " : msg }
2023-08-08 18:08:29 +00:00
@app.post ( " /!<group_name>/<user_id>/add_mod " )
@limiter.limit ( ' 1/second ' , scope = rpath )
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
@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 )
@auth_required
def group_add_mod ( v , group_name , user_id ) :
group_name = group_name . strip ( ) . lower ( )
group = g . db . get ( Group , group_name )
if not group : abort ( 404 )
2024-02-11 11:00:37 +00:00
if v . id != group . owner_id :
2023-08-08 18:08:29 +00:00
abort ( 403 , f " Only the group owner (@ { group . owner . username } ) can add mods! " )
membership = g . db . query ( GroupMembership ) . filter_by ( user_id = user_id , group_name = group . name ) . one_or_none ( )
if not membership :
abort ( 404 , " The user is not a member of the group! " )
membership . is_mod = True
g . db . add ( membership )
send_repeatable_notification ( membership . user_id , f " @ { v . username } (! { group } ' s owner) has added you as a mod! " )
return { " message " : f ' You have added @ { membership . user . username } as a mod successfully! ' }
@app.post ( " /!<group_name>/<user_id>/remove_mod " )
@limiter.limit ( ' 1/second ' , scope = rpath )
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
@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 )
@auth_required
def group_remove_mod ( v , group_name , user_id ) :
group_name = group_name . strip ( ) . lower ( )
group = g . db . get ( Group , group_name )
if not group : abort ( 404 )
2024-02-11 11:00:37 +00:00
if v . id != group . owner_id :
2023-08-08 18:08:29 +00:00
abort ( 403 , f " Only the group owner (@ { group . owner . username } ) can remove mods! " )
membership = g . db . query ( GroupMembership ) . filter_by ( user_id = user_id , group_name = group . name ) . one_or_none ( )
if not membership :
abort ( 404 , " The user is not a member of the group! " )
membership . is_mod = False
g . db . add ( membership )
send_repeatable_notification ( membership . user_id , f " @ { v . username } (! { group } ' s owner) has removed you as a mod! " )
return { " message " : f ' You have removed @ { membership . user . username } as a mod successfully! ' }
2024-02-11 11:31:46 +00:00
@app.post ( " /!<group_name>/usurp " )
@limiter.limit ( ' 1/second ' , scope = rpath )
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
@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 )
@auth_required
def group_usurp ( v , group_name ) :
group_name = group_name . strip ( ) . lower ( )
group = g . db . get ( Group , group_name )
if not group : abort ( 404 )
if not v . is_member_of_group ( group ) :
abort ( 403 , " Only members of groups can usurp them! " )
search_html = f ''' %src= " /pp/ { group . owner_id } " >@%</a> (<a href= " /! { group . name } " rel= " nofollow " >! { group . name } </a> ' s owner) has % your application!</p>% '''
one_month_ago = time . time ( ) - 2629800
is_active = g . db . query ( Comment . id ) . filter (
Comment . author_id == AUTOJANNY_ID ,
Comment . parent_post == None ,
Comment . body_html . like ( search_html ) ,
Comment . created_utc > one_month_ago ,
) . first ( )
2024-02-11 11:57:17 +00:00
month_old_applications = g . db . query ( GroupMembership . user_id ) . filter_by (
GroupMembership . group_name == group . name ,
GroupMembership . approved_utc == None ,
GroupMembership . created_utc < one_month_ago ,
2024-02-11 11:53:30 +00:00
) . first ( )
2024-02-11 11:57:17 +00:00
if is_active or not month_old_applications :
abort ( 403 , f " @ { group . owner . username } has reviewed a membership application in the past month, so you can ' t usurp them! " )
2024-02-11 11:53:30 +00:00
2024-02-11 11:31:46 +00:00
send_repeatable_notification ( group . owner_id , f " @ { v . username } has usurped control of ! { group . name } from you. This was possible because you spent more than a month not reviewing membership applications. Be active next time sweaty :!marseycheeky: " )
group . owner_id = v . id
g . db . add ( group )
return { " message " : f ' You have usurped control of ! { group . name } successfully! ' }