forked from retoor/devplacepy
feat: restrict backup archive download to primary admin and hide admin-hidden projects from other admins
- Add `get_admin_uids()` and `get_primary_admin_uid()` to database.py for resolving the earliest-created admin - Modify `can_view_project()` in content.py so a project hidden by an admin is invisible to other admins (both web UI and REST API) - Update `_download_url()` and `_backup_payload()` in admin/backups.py to accept a `can_download` flag, gating the download endpoint with `is_primary_admin()` - Remove `role` from `_user_facts()` in docs_live.py to avoid leaking admin status in live docs - Update doc summaries in docs_api.py to reflect the new admin-visibility and backup-download semantics
This commit is contained in:
+78
-1
@@ -1,6 +1,6 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
from devplacepy.database import get_table
|
||||
from devplacepy.database import get_table, get_primary_admin_uid
|
||||
from devplacepy.utils import (
|
||||
award_badge,
|
||||
award_xp,
|
||||
@@ -10,6 +10,7 @@ from devplacepy.utils import (
|
||||
extract_mentions,
|
||||
generate_uid,
|
||||
hash_password,
|
||||
is_primary_admin,
|
||||
level_for_xp,
|
||||
safe_next,
|
||||
slugify,
|
||||
@@ -156,6 +157,82 @@ def test_extract_mentions_finds_usernames():
|
||||
assert mentions == ["alice", "bob_1"]
|
||||
|
||||
|
||||
def _seed_user_at(role, created_at):
|
||||
uid = generate_uid()
|
||||
get_table("users").insert(
|
||||
{
|
||||
"uid": uid,
|
||||
"username": f"pa_{uid[:8]}",
|
||||
"email": f"pa_{uid[:8]}@t.dev",
|
||||
"role": role,
|
||||
"created_at": created_at.isoformat(),
|
||||
}
|
||||
)
|
||||
return get_table("users").find_one(uid=uid)
|
||||
|
||||
|
||||
def _demote_existing_admins():
|
||||
existing = [r["uid"] for r in get_table("users").find(role="Admin")]
|
||||
for uid in existing:
|
||||
get_table("users").update({"uid": uid, "role": "Member"}, ["uid"])
|
||||
return existing
|
||||
|
||||
|
||||
def _restore_admins(uids):
|
||||
for uid in uids:
|
||||
get_table("users").update({"uid": uid, "role": "Admin"}, ["uid"])
|
||||
|
||||
|
||||
def _purge(*rows):
|
||||
for row in rows:
|
||||
get_table("users").delete(uid=row["uid"])
|
||||
|
||||
|
||||
def test_primary_admin_is_earliest_admin(local_db):
|
||||
restore = _demote_existing_admins()
|
||||
member = admin_first = admin_second = None
|
||||
try:
|
||||
base = datetime.now(timezone.utc)
|
||||
member = _seed_user_at("Member", base)
|
||||
admin_first = _seed_user_at("Admin", base + timedelta(seconds=1))
|
||||
admin_second = _seed_user_at("Admin", base + timedelta(seconds=2))
|
||||
|
||||
assert get_primary_admin_uid() == admin_first["uid"]
|
||||
assert is_primary_admin(admin_first) is True
|
||||
assert is_primary_admin(admin_second) is False
|
||||
assert is_primary_admin(member) is False
|
||||
assert is_primary_admin(None) is False
|
||||
finally:
|
||||
_purge(*[r for r in (member, admin_first, admin_second) if r])
|
||||
_restore_admins(restore)
|
||||
|
||||
|
||||
def test_primary_admin_reassigns_when_founder_demoted(local_db):
|
||||
restore = _demote_existing_admins()
|
||||
admin_first = admin_second = None
|
||||
try:
|
||||
base = datetime.now(timezone.utc)
|
||||
admin_first = _seed_user_at("Admin", base + timedelta(seconds=1))
|
||||
admin_second = _seed_user_at("Admin", base + timedelta(seconds=2))
|
||||
assert get_primary_admin_uid() == admin_first["uid"]
|
||||
|
||||
get_table("users").update(
|
||||
{"uid": admin_first["uid"], "role": "Member"}, ["uid"]
|
||||
)
|
||||
assert get_primary_admin_uid() == admin_second["uid"]
|
||||
assert (
|
||||
is_primary_admin(get_table("users").find_one(uid=admin_second["uid"]))
|
||||
is True
|
||||
)
|
||||
assert (
|
||||
is_primary_admin(get_table("users").find_one(uid=admin_first["uid"]))
|
||||
is False
|
||||
)
|
||||
finally:
|
||||
_purge(*[r for r in (admin_first, admin_second) if r])
|
||||
_restore_admins(restore)
|
||||
|
||||
|
||||
def test_award_badge_is_idempotent(local_db):
|
||||
uid, _ = _seed_user()
|
||||
assert award_badge(uid, "First Post") is True
|
||||
|
||||
Reference in New Issue
Block a user