12
12
users = Blueprint ('users' , __name__ )
13
13
14
14
15
+ def extract_rooms_or_global (req , admin = True ):
16
+ """
17
+ Extracts the rooms / global parameters from the request body checking them for validity and
18
+ expanding them as appropriate.
19
+
20
+ Throws a flask abort on failure, returns (rooms, global) which will be either ([list of Rooms],
21
+ None) for a room operation or (None, True) for a global operation.
22
+
23
+ admin specifies whether we require admin permission (if True) or just moderator permission,
24
+ either in all rooms specified, or globally. (Similarly it affects what `rooms=['*']` expands
25
+ to).
26
+ """
27
+
28
+ room_tokens , global_ = req .get ('rooms' ), req .get ('global' , False )
29
+
30
+ if room_tokens and not isinstance (room_tokens , list ):
31
+ app .logger .warning ("Invalid request: rooms must be a list" )
32
+ abort (http .BAD_REQUEST )
33
+
34
+ if room_tokens and global_ :
35
+ app .logger .warning ("Invalid moderator request: cannot specify both 'rooms' and 'global'" )
36
+ abort (http .BAD_REQUEST )
37
+
38
+ if not room_tokens and not global_ :
39
+ app .logger .warning ("Invalid moderator request: neither 'rooms' nor 'global' specified" )
40
+ abort (http .BAD_REQUEST )
41
+
42
+ if room_tokens :
43
+ if len (room_tokens ) > 1 and '*' in room_tokens :
44
+ app .logger .warning ("Invalid moderator request: room '*' must be the only rooms value" )
45
+ abort (http .BAD_REQUEST )
46
+
47
+ if room_tokens == ['*' ]:
48
+ room_tokens = None
49
+
50
+ try :
51
+ rooms = mroom .get_rooms_with_permission (
52
+ g .user , tokens = room_tokens , moderator = True , admin = admin
53
+ )
54
+ except Exception as e :
55
+ # This is almost certainly a bad room token passed in:
56
+ app .logger .warning (f"Cannot get rooms for adding a moderator: { e } " )
57
+ abort (http .NOT_FOUND )
58
+
59
+ if room_tokens :
60
+ if len (rooms ) != len (room_tokens ):
61
+ abort (http .FORBIDDEN )
62
+ elif not rooms :
63
+ abort (http .FORBIDDEN )
64
+
65
+ return (rooms , None )
66
+
67
+ if not g .user .global_moderator or (admin and not g .user .global_admin ):
68
+ abort (http .FORBIDDEN )
69
+
70
+ return (None , True )
71
+
72
+
15
73
@users .post ("/user/<SessionID:sid>/moderator" )
16
74
@auth .user_required
17
75
def set_mod (sid ):
18
76
19
77
user = User (session_id = sid )
20
78
21
79
req = request .json
22
- room_tokens , global_mod = req .get ('rooms' ), req .get ('global' , False )
23
80
24
- if room_tokens and not isinstance (room_tokens , list ):
25
- app .logger .warning ("Invalid request: room_tokens must be a list" )
26
- abort (http .BAD_REQUEST )
81
+ rooms , global_mod = extract_rooms_or_global (req )
27
82
28
83
mod , admin , visible = (
29
84
None if arg is None else bool (arg )
@@ -51,39 +106,11 @@ def set_mod(sid):
51
106
# (False, True) -- removes admin, adds mod
52
107
# (False, None) -- removes admin
53
108
54
- with db .transaction ():
55
- if room_tokens :
56
- if visible is None :
57
- visible = True
58
-
59
- if global_mod :
60
- app .logger .warning (
61
- "Invalid moderator request: cannot specify both 'rooms' and 'global'"
62
- )
63
- abort (http .BAD_REQUEST )
64
-
65
- if len (room_tokens ) > 1 and '*' in room_tokens :
66
- app .logger .warning (
67
- "Invalid moderator request: room '*' must be the only rooms value"
68
- )
69
- abort (http .BAD_REQUEST )
70
-
71
- if room_tokens == ['*' ]:
72
- room_tokens = None
73
-
74
- try :
75
- rooms = mroom .get_rooms_with_permission (g .user , tokens = room_tokens , admin = True )
76
- except Exception as e :
77
- # This is almost certainly a bad room token passed in:
78
- app .logger .warning (f"Cannot get rooms for adding a moderator: { e } " )
79
- abort (http .BAD_REQUEST )
80
-
81
- if room_tokens is not None :
82
- if len (rooms ) != len (room_tokens ):
83
- abort (http .FORBIDDEN )
84
- elif not rooms :
85
- abort (http .FORBIDDEN )
109
+ if rooms :
110
+ if visible is None :
111
+ visible = True
86
112
113
+ with db .transaction ():
87
114
for room in rooms :
88
115
if (admin , mod ) in ((True , None ), (None , True )):
89
116
room .set_moderator (user , added_by = g .user , admin = admin , visible = visible )
@@ -98,18 +125,63 @@ def set_mod(sid):
98
125
app .logger .error ("Internal error: unhandled mod/admin room case" )
99
126
raise RuntimeError ("Internal error: unhandled mod/admin room case" )
100
127
101
- else : # global mod
102
- if visible is None :
103
- visible = False
104
-
105
- if (admin , mod ) in ((True , None ), (None , True )):
106
- user .set_moderator (added_by = g .user , admin = admin , visible = visible )
107
- elif (admin , mod ) == (None , False ):
108
- user .remove_moderator (removed_by = g .user )
109
- elif (admin , mod ) == (False , None ):
110
- user .remove_moderator (removed_by = g .user , remove_admin_only = True )
111
- elif (admin , mod ) == (False , True ):
128
+ else : # global mod
129
+ if visible is None :
130
+ visible = False
131
+
132
+ if (admin , mod ) in ((True , None ), (None , True )):
133
+ user .set_moderator (added_by = g .user , admin = admin , visible = visible )
134
+ elif (admin , mod ) == (None , False ):
135
+ user .remove_moderator (removed_by = g .user )
136
+ elif (admin , mod ) == (False , None ):
137
+ user .remove_moderator (removed_by = g .user , remove_admin_only = True )
138
+ elif (admin , mod ) == (False , True ):
139
+ with db .transaction ():
112
140
user .remove_moderator (removed_by = g .user , remove_admin_only = True )
113
141
user .set_moderator (added_by = g .user , admin = bool (admin ), visible = visible )
114
142
115
143
return jsonify ({})
144
+
145
+
146
+ @users .post ("/user/<SessionID:sid>/ban" )
147
+ @auth .user_required
148
+ def ban_user (sid ):
149
+
150
+ user = User (session_id = sid )
151
+ req = request .json
152
+ rooms , global_ban = extract_rooms_or_global (req , admin = False )
153
+
154
+ timeout = req .get ('timeout' )
155
+ if timeout is not None and not isinstance (timeout , int ) and not isinstance (timeout , float ):
156
+ app .logger .warning ("Invalid ban request: timeout must be numeric" )
157
+ abort (http .BAD_REQUEST )
158
+
159
+ if timeout and global_ban :
160
+ app .logger .warning ("Invalid ban request: global server bans do not support timeouts" )
161
+ abort (http .BAD_REQUEST )
162
+
163
+ if rooms :
164
+ with db .transaction ():
165
+ for room in rooms :
166
+ room .ban_user (to_ban = user , mod = g .user , timeout = timeout )
167
+ else :
168
+ user .ban (banned_by = g .user )
169
+
170
+ return {}
171
+
172
+
173
+ @users .post ("/user/<SessionID:sid>/unban" )
174
+ @auth .user_required
175
+ def unban_user (sid ):
176
+
177
+ user = User (session_id = sid )
178
+ rooms , global_ban = extract_rooms_or_global (request .json , admin = False )
179
+
180
+ if rooms :
181
+ with db .transaction ():
182
+ for room in rooms :
183
+ room .unban_user (to_unban = user , mod = g .user )
184
+ else :
185
+ user .unban (unbanned_by = g .user )
186
+
187
+ return {}
0 commit comments