| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- """Who sees announcements, and per-user read state.
- Administrators see them; other signed-in users only when
- ``announcements_all_users`` is on. With authentication off, the person running
- Bambuddy sees them. Anyone else gets an empty list, which hides the sidebar entry
- and the banner the same way "nothing published" does.
- """
- import json
- import secrets
- import pytest
- from httpx import AsyncClient
- from backend.app.models.announcement import Announcement
- from backend.app.models.settings import Settings
- URL = "/api/v1/announcements"
- _FIXTURE_PW = "Aa1!" + secrets.token_urlsafe(12) # pragma: allowlist secret
- async def _seed(db, *public_ids: str, level: str = "important") -> None:
- for pid in public_ids:
- db.add(
- Announcement(
- public_id=pid,
- level=level,
- texts=json.dumps({"en": {"title": f"T {pid}", "body": "B"}, "de": {"title": "D", "body": "B"}}),
- )
- )
- await db.commit()
- async def _setting(db, key: str, value: str) -> None:
- db.add(Settings(key=key, value=value))
- await db.commit()
- async def _admin(client: AsyncClient, username: str) -> dict:
- await client.post(
- "/api/v1/auth/setup",
- json={"auth_enabled": True, "admin_username": username, "admin_password": _FIXTURE_PW},
- )
- login = await client.post("/api/v1/auth/login", json={"username": username, "password": _FIXTURE_PW})
- assert login.status_code == 200, login.text
- return {"Authorization": f"Bearer {login.json()['access_token']}"}
- async def _user(client: AsyncClient, admin: dict, username: str) -> dict:
- grp = await client.post(
- "/api/v1/groups/", headers=admin, json={"name": f"ann_{username}", "permissions": ["printers:read"]}
- )
- assert grp.status_code == 201, grp.text
- created = await client.post(
- "/api/v1/users/",
- headers=admin,
- json={"username": username, "password": _FIXTURE_PW, "role": "user", "group_ids": [grp.json()["id"]]},
- )
- assert created.status_code == 201, created.text
- login = await client.post("/api/v1/auth/login", json={"username": username, "password": _FIXTURE_PW})
- return {"Authorization": f"Bearer {login.json()['access_token']}"}
- @pytest.mark.integration
- class TestAuthOff:
- @pytest.mark.asyncio
- async def test_listed_with_every_language_and_unread(self, async_client: AsyncClient, db_session):
- await _seed(db_session, "a1")
- r = await async_client.get(URL)
- assert r.status_code == 200
- [item] = r.json()
- assert item["id"] == "a1" and item["level"] == "important" and item["read"] is False
- assert set(item["texts"]) == {"en", "de"}
- @pytest.mark.asyncio
- async def test_read_sticks(self, async_client: AsyncClient, db_session):
- await _seed(db_session, "a1")
- assert (await async_client.post(f"{URL}/a1/read")).status_code == 204
- assert (await async_client.get(URL)).json()[0]["read"] is True
- @pytest.mark.asyncio
- async def test_unknown_id_is_404(self, async_client: AsyncClient):
- assert (await async_client.post(f"{URL}/nope/read")).status_code == 404
- @pytest.mark.asyncio
- async def test_switched_off_shows_nothing(self, async_client: AsyncClient, db_session):
- await _seed(db_session, "a1")
- await _setting(db_session, "announcements_enabled", "false")
- assert (await async_client.get(URL)).json() == []
- assert (await async_client.post(f"{URL}/a1/read")).status_code == 404
- @pytest.mark.integration
- class TestAuthOn:
- @pytest.mark.asyncio
- async def test_signed_out_is_401(self, async_client: AsyncClient, db_session):
- await _admin(async_client, "annadmin0")
- assert (await async_client.get(URL)).status_code == 401
- @pytest.mark.asyncio
- async def test_admin_sees_them_a_user_does_not(self, async_client: AsyncClient, db_session):
- await _seed(db_session, "a1")
- admin = await _admin(async_client, "annadmin1")
- user = await _user(async_client, admin, "annuser1")
- assert [i["id"] for i in (await async_client.get(URL, headers=admin)).json()] == ["a1"]
- assert (await async_client.get(URL, headers=user)).json() == []
- assert (await async_client.post(f"{URL}/a1/read", headers=user)).status_code == 404
- @pytest.mark.asyncio
- async def test_all_users_setting_shows_them_with_separate_read_state(self, async_client: AsyncClient, db_session):
- await _seed(db_session, "a1")
- admin = await _admin(async_client, "annadmin2")
- user = await _user(async_client, admin, "annuser2")
- await _setting(db_session, "announcements_all_users", "true")
- assert (await async_client.post(f"{URL}/a1/read", headers=user)).status_code == 204
- assert (await async_client.get(URL, headers=user)).json()[0]["read"] is True
- assert (await async_client.get(URL, headers=admin)).json()[0]["read"] is False
- @pytest.mark.integration
- class TestSettings:
- @pytest.mark.asyncio
- async def test_both_switches_round_trip(self, async_client: AsyncClient):
- defaults = (await async_client.get("/api/v1/settings/")).json()
- assert defaults["announcements_enabled"] is True
- assert defaults["announcements_all_users"] is False
- r = await async_client.put(
- "/api/v1/settings/", json={"announcements_enabled": False, "announcements_all_users": True}
- )
- assert r.status_code == 200, r.text
- after = (await async_client.get("/api/v1/settings/")).json()
- assert after["announcements_enabled"] is False
- assert after["announcements_all_users"] is True
|