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
+54 -1
View File
@@ -124,11 +124,64 @@ def test_comment_voted_state_persists(alice):
)
def test_mention_first_match_highlighted(alice):
page, _ = alice
create_post(page, "random", "Mention highlight test post")
textarea = page.locator(".comment-form textarea[name='content']").first
textarea.wait_for(state="visible", timeout=10000)
textarea.fill("@bob")
item = page.locator(".mention-dropdown-item:has-text('bob_test')").first
item.wait_for(state="visible", timeout=5000)
expect(item).to_have_class(re.compile(r"\bactive\b"))
def test_mention_tab_inserts_first_match(alice):
page, _ = alice
create_post(page, "random", "Mention tab insert test post")
textarea = page.locator(".comment-form textarea[name='content']").first
textarea.wait_for(state="visible", timeout=10000)
textarea.fill("@bob")
page.locator(".mention-dropdown-item:has-text('bob_test')").first.wait_for(
state="visible", timeout=5000
)
textarea.press("Tab")
expect(textarea).to_have_value(re.compile(r"^@bob_test\s"))
def test_mention_arrow_then_enter_inserts(alice):
page, _ = alice
create_post(page, "random", "Mention arrow nav test post")
textarea = page.locator(".comment-form textarea[name='content']").first
textarea.wait_for(state="visible", timeout=10000)
textarea.fill("@bob")
page.locator(".mention-dropdown-item:has-text('bob_test')").first.wait_for(
state="visible", timeout=5000
)
textarea.press("ArrowDown")
textarea.press("Enter")
expect(textarea).to_have_value(re.compile(r"@bob_test\s"))
def test_mention_escape_closes_dropdown(alice):
page, _ = alice
create_post(page, "random", "Mention escape test post")
textarea = page.locator(".comment-form textarea[name='content']").first
textarea.wait_for(state="visible", timeout=10000)
textarea.fill("@bob")
item = page.locator(".mention-dropdown-item:has-text('bob_test')").first
item.wait_for(state="visible", timeout=5000)
textarea.press("Escape")
expect(item).to_be_hidden()
def test_profile_stars_reflect_content_votes(alice):
page, user = alice
before = _profile_stars(page, user["username"])
create_post(page, "devlog", "Reputation contribution post")
page.locator(".post-action-btn.vote-up").first.click()
with page.expect_response(
lambda r: "/votes/" in r.url and r.request.method == "POST"
):
page.locator(".post-action-btn.vote-up").first.click()
expect(page.locator(".post-vote-count").first).to_have_text("1")
after = _profile_stars(page, user["username"])
assert after == before + 1, f"expected stars {before + 1}, got {after}"