Skip to content

Commit ba4cd1e

Browse files
committed
fix(admin): use permissions instead of role IDs for admin edits
1 parent c6d2191 commit ba4cd1e

2 files changed

Lines changed: 47 additions & 11 deletions

File tree

app/operation/admin.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,6 @@ async def _modify_admin(
123123
if modified_admin.status is not None and modified_admin.status == AdminStatus.disabled:
124124
await self.raise_error(message="You're not allowed to disable your own account.", code=403)
125125

126-
# Non-owner admins cannot modify other admins with equal or higher role level (role_id <= 2)
127-
# Only the owner can modify administrators (role_id=2)
128-
if not current_admin.is_owner and not is_self and db_admin.role_id <= 2:
129-
await self.raise_error(message="You're not allowed to modify an administrator account.", code=403)
130-
131126
if modified_admin.telegram_id:
132127
existing_admins = await find_admins_by_telegram_id(
133128
db, modified_admin.telegram_id, exclude_admin_id=db_admin.id, limit=1

tests/api/test_admin.py

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -522,8 +522,8 @@ def test_administrator_cannot_disable_self(access_token):
522522
delete_admin(access_token, administrator_admin["username"])
523523

524524

525-
def test_administrator_cannot_modify_other_administrator(access_token):
526-
"""An administrator cannot edit another administrator account."""
525+
def test_administrator_can_modify_other_non_owner_admin(access_token):
526+
"""An admin with admins.update can edit another non-owner admin, regardless of role id."""
527527
admin_a = create_admin(access_token)
528528
admin_b = create_admin(access_token)
529529
set_admin_role(admin_a["username"], 2)
@@ -544,15 +544,14 @@ def test_administrator_cannot_modify_other_administrator(access_token):
544544
url=f"/api/admin/{admin_b['username']}",
545545
json={
546546
"status": "active",
547-
"note": "should-fail",
547+
"note": "updated-by-admin",
548548
},
549549
headers={"Authorization": f"Bearer {admin_a_token}"},
550550
)
551551

552-
assert response.status_code == status.HTTP_403_FORBIDDEN
552+
assert response.status_code == status.HTTP_200_OK
553+
assert response.json()["note"] == "updated-by-admin"
553554
finally:
554-
set_admin_role(admin_a["username"], 3)
555-
set_admin_role(admin_b["username"], 3)
556555
delete_admin(access_token, admin_a["username"])
557556
delete_admin(access_token, admin_b["username"])
558557

@@ -1236,6 +1235,48 @@ def test_create_admin_with_custom_role(access_token):
12361235
client.delete(f"/api/admin-role/{role['id']}", headers={"Authorization": f"Bearer {access_token}"})
12371236

12381237

1238+
def test_custom_role_with_admin_update_can_modify_administrator(access_token):
1239+
"""A custom role with admins.update can modify role_id=2 admins."""
1240+
role_response = client.post(
1241+
"/api/admin-role",
1242+
headers=auth_headers(access_token),
1243+
json={
1244+
"name": unique_name("admin_update_role"),
1245+
"permissions": {"admins": {"update": True}},
1246+
"limits": {
1247+
"max_users": None,
1248+
"data_limit_min": None,
1249+
"data_limit_max": None,
1250+
"expire_min": None,
1251+
"expire_max": None,
1252+
"max_hwid_per_user": None,
1253+
},
1254+
"features": {"can_use_reset_strategy": True, "can_use_next_plan": True},
1255+
"access": {"require_template": False, "allowed_template_ids": None, "allowed_group_ids": None},
1256+
},
1257+
)
1258+
assert role_response.status_code == status.HTTP_201_CREATED
1259+
role = role_response.json()
1260+
1261+
actor = create_admin(access_token, role_id=role["id"])
1262+
target = create_admin(access_token, role_id=2)
1263+
try:
1264+
actor_token = _login(actor["username"], actor["password"])
1265+
1266+
response = client.put(
1267+
f"/api/admin/{target['username']}",
1268+
json={"note": "custom-role-update"},
1269+
headers=auth_headers(actor_token),
1270+
)
1271+
1272+
assert response.status_code == status.HTTP_200_OK
1273+
assert response.json()["note"] == "custom-role-update"
1274+
finally:
1275+
delete_admin(access_token, actor["username"])
1276+
delete_admin(access_token, target["username"])
1277+
client.delete(f"/api/admin-role/{role['id']}", headers=auth_headers(access_token))
1278+
1279+
12391280
# ---------------------------------------------------------------------------
12401281
# Admin data_limit, status, and limited-access tests
12411282
# ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)