docs: add block/mute user relations, emoji-sync CLI, and uid indexes

- Add `/block`, `/mute` endpoints with block/unblock and mute/unmute functionality in `routers/relations.py`, hiding blocked users' content everywhere except their own profile while muting only suppresses notifications
- Introduce `devplace emoji-sync` CLI command to regenerate `static/js/emoji-shortcodes.js` from the emoji library, documented in `CLAUDE.md` and wired in `cli.py`
- Create `get_blocked_uids()` database helper and apply it in `content.py` `load_detail()` to filter blocked users' posts from detail views
- Implement `_uid_index()` and `_drop_index()` helpers in `database.py` for unique uid indexes across tables, with `user_relations` added to `SOFT_DELETE_TABLES`
- Document new routes in `AGENTS.md` and `README.md`, including emoji shortcodes rendering behavior distinct from the emoji picker
This commit is contained in:
2026-06-19 08:06:09 +00:00
parent f3a4667fce
commit 741d7aade6
136 changed files with 3025 additions and 564 deletions
+19 -4
View File
@@ -4,7 +4,7 @@ import time
import pytest
import requests
from tests.conftest import BASE_URL
from devplacepy.database import get_table
from devplacepy.database import get_table, invalidate_admins_cache
from devplacepy.utils import clear_user_cache
from devplacepy import project_files
from devplacepy.project_files import ProjectFileError
@@ -33,7 +33,18 @@ def _make_admin_project_visibility():
name, uid, key = _signup_project_visibility()
get_table("users").update({"uid": uid, "role": "Admin"}, ["uid"])
clear_user_cache(uid)
invalidate_admins_cache()
return name, uid, key
def _eventually(predicate, *, attempts=25, delay=0.15):
result = predicate()
for _ in range(attempts):
if result:
return result
time.sleep(delay)
result = predicate()
return result
def _h_project_visibility(key=None):
headers = {"Accept": "application/json"}
if key:
@@ -117,9 +128,13 @@ def test_admin_private_hidden_from_other_admin(app_server):
slug = _create_project_project_visibility(
owner_key, "Admin Hidden", is_private=True
)["slug"]
assert slug not in _list_slugs(key=other_admin_key, user_uid=owner_uid)
assert _detail_status(other_admin_key, slug) == 404
assert _file_raw_status(other_admin_key, slug, "missing.txt") == 404
assert _eventually(
lambda: slug not in _list_slugs(key=other_admin_key, user_uid=owner_uid)
)
assert _eventually(lambda: _detail_status(other_admin_key, slug) == 404)
assert _eventually(
lambda: _file_raw_status(other_admin_key, slug, "missing.txt") == 404
)
assert slug in _list_slugs(key=owner_key, user_uid=owner_uid)
assert _detail_status(owner_key, slug) == 200