@@ -940,6 +940,8 @@ def set_moderator(self, user: User, *, added_by: User, admin=False, visible=True
940
940
Sets `user` as a moderator or admin of this room. Replaces current admin/moderator/visible
941
941
status with the new values if the user is already a moderator/admin of the room.
942
942
943
+ `admin` can be specified as None to not touch the current admin permission on the room.
944
+
943
945
added_by is the user performing the update and must have admin permission.
944
946
"""
945
947
@@ -951,12 +953,13 @@ def set_moderator(self, user: User, *, added_by: User, admin=False, visible=True
951
953
raise BadPermission ()
952
954
953
955
query (
954
- """
955
- INSERT INTO user_permission_overrides (room, "user", moderator, admin, visible_mod)
956
- VALUES (:r, :u, TRUE, :admin, :visible)
956
+ f"""
957
+ INSERT INTO user_permission_overrides
958
+ (room, "user", moderator, { 'admin,' if admin is not None else '' } visible_mod)
959
+ VALUES (:r, :u, TRUE, { ':admin,' if admin is not None else '' } :visible)
957
960
ON CONFLICT (room, "user") DO UPDATE SET
958
961
moderator = excluded.moderator,
959
- admin = excluded.admin,
962
+ { ' admin = excluded.admin,' if admin is not None else '' }
960
963
visible_mod = excluded.visible_mod
961
964
""" ,
962
965
r = self .id ,
@@ -970,16 +973,22 @@ def set_moderator(self, user: User, *, added_by: User, admin=False, visible=True
970
973
971
974
app .logger .info (f"{ added_by } set { user } as { 'admin' if admin else 'moderator' } of { self } " )
972
975
973
- def remove_moderator (self , user : User , * , removed_by : User ):
974
- """Remove `user` as a moderator/admin of this room. Requires admin permission."""
976
+ def remove_moderator (self , user : User , * , removed_by : User , remove_admin_only : bool = False ):
977
+ """
978
+ Remove `user` as a moderator/admin of this room. Requires admin permission.
979
+
980
+ If `remove_admin_only` is True then user will have admin permissions removed but will remain
981
+ a room moderator if already a room moderator or admin.
982
+ """
975
983
976
984
if not self .check_admin (removed_by ):
977
985
raise BadPermission ()
978
986
979
987
query (
980
- """
988
+ f """
981
989
UPDATE user_permission_overrides
982
- SET moderator = FALSE, admin = FALSE, visible_mod = TRUE
990
+ SET admin = FALSE
991
+ { ', moderator = FALSE, visible_mod = TRUE' if not remove_admin_only else '' }
983
992
WHERE room = :r AND "user" = :u
984
993
""" ,
985
994
r = self .id ,
@@ -1321,6 +1330,63 @@ def get_rooms():
1321
1330
return [Room (row ) for row in query ("SELECT * FROM rooms ORDER BY token" )]
1322
1331
1323
1332
1333
+ def get_rooms_with_permission (
1334
+ user : User ,
1335
+ * ,
1336
+ tokens : Optional [Union [list , tuple ]] = None ,
1337
+ read : Optional [bool ] = None ,
1338
+ write : Optional [bool ] = None ,
1339
+ upload : Optional [bool ] = None ,
1340
+ banned : Optional [bool ] = None ,
1341
+ moderator : Optional [bool ] = None ,
1342
+ admin : Optional [bool ] = None ,
1343
+ ):
1344
+ """
1345
+ Returns a list of rooms that the given user has matching permissions for.
1346
+
1347
+ Parameters:
1348
+ user: the user object to query permissions for. May not be None.
1349
+ tokens: if non-None then this specifies a list or tuple of room tokens to filter by. When
1350
+ omitted, all rooms are returned. Note that rooms are returned sorted by token, *not* in
1351
+ the order specified here; duplicates are not returned; nor are entries for non-existent
1352
+ tokens.
1353
+ read/write/upload/banned/moderator/admin:
1354
+ Any of these that are specified as non-None must match the user's permissions for the room.
1355
+ For example `read=True, write=False` would return all rooms where the user has read-only
1356
+ access but not rooms in which the user has both or neither read and write permissions.
1357
+ At least one of these arguments must be specified as non-None.
1358
+ """
1359
+ if user is None :
1360
+ raise RuntimeError ("user is required for get_rooms_with_permission" )
1361
+ if not any (arg is not None for arg in (read , write , upload , banned , moderator , admin )):
1362
+ raise RuntimeError ("At least one of read/write/upload/banned/moderator/admin must be given" )
1363
+ if tokens and (
1364
+ not (isinstance (tokens , list ) or isinstance (tokens , tuple ))
1365
+ or any (not isinstance (t , str ) for t in tokens )
1366
+ ):
1367
+ raise RuntimeError ("tokens= must be a list or tuple of room token names" )
1368
+
1369
+ return [
1370
+ Room (row )
1371
+ for row in query (
1372
+ f"""
1373
+ SELECT rooms.* FROM user_permissions perm JOIN rooms ON rooms.id = room
1374
+ WHERE "user" = :u { 'AND token IN :tokens' if tokens else '' }
1375
+ { '' if banned is None else ('AND' if banned else 'AND NOT' ) + ' perm.banned' }
1376
+ { '' if read is None else ('AND' if read else 'AND NOT' ) + ' perm.read' }
1377
+ { '' if write is None else ('AND' if write else 'AND NOT' ) + ' perm.write' }
1378
+ { '' if upload is None else ('AND' if upload else 'AND NOT' ) + ' perm.upload' }
1379
+ { '' if moderator is None else ('AND' if moderator else 'AND NOT' ) + ' perm.moderator' }
1380
+ { '' if admin is None else ('AND' if admin else 'AND NOT' ) + ' perm.admin' }
1381
+ ORDER BY token
1382
+ """ ,
1383
+ u = user .id ,
1384
+ tokens = tokens ,
1385
+ bind_expanding = ['tokens' ] if tokens else None ,
1386
+ )
1387
+ ]
1388
+
1389
+
1324
1390
def get_readable_rooms (user : Optional [User ] = None ):
1325
1391
"""
1326
1392
Get a list of rooms that a user can access; if user is None then return all publicly readable
@@ -1329,14 +1395,7 @@ def get_readable_rooms(user: Optional[User] = None):
1329
1395
if user is None :
1330
1396
result = query ("SELECT * FROM rooms WHERE read ORDER BY token" )
1331
1397
else :
1332
- result = query (
1333
- """
1334
- SELECT rooms.* FROM user_permissions perm JOIN rooms ON rooms.id = room
1335
- WHERE "user" = :u AND perm.read AND NOT perm.banned
1336
- ORDER BY token
1337
- """ ,
1338
- u = user .id ,
1339
- )
1398
+ return get_rooms_with_permission (user , read = True , banned = False )
1340
1399
return [Room (row ) for row in result ]
1341
1400
1342
1401
0 commit comments