| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- """Editing an archive cannot move it to a printer or project the caller may not use.
- The archive edit checked only the printer the archive was on. A member of a
- group limited to printer A could move an archive of A to printer B, into the
- history of a team they have no access to, and any caller could link an
- archive to a printer or project that does not exist (stored dangling on
- SQLite, a server error on PostgreSQL). Upload already checked the printer.
- """
- from __future__ import annotations
- import pytest
- from httpx import AsyncClient
- from backend.tests.integration.test_printer_scope_1727 import TEAM_PERMISSIONS, _admin_token, _auth, _group, _user
- pytestmark = [pytest.mark.asyncio, pytest.mark.integration]
- async def _member(client: AsyncClient, admin: str, name: str, printer_ids: list[int]) -> dict[str, str]:
- perms = await _group(client, admin, f"perms_{name}", permissions=[*TEAM_PERMISSIONS, "archives:update_all"])
- team = await _group(client, admin, f"team_{name}", printer_ids=printer_ids)
- return _auth((await _user(client, admin, name, [perms, team]))[0])
- async def _printer_of(client: AsyncClient, headers: dict[str, str], archive_id: int) -> int | None:
- response = await client.get(f"/api/v1/archives/{archive_id}", headers=headers)
- assert response.status_code == 200, response.text
- return response.json()["printer_id"]
- async def test_a_member_cannot_move_an_archive_to_a_printer_outside_the_team(
- async_client: AsyncClient, printer_factory, archive_factory
- ):
- a, b = await printer_factory(name="A"), await printer_factory(name="B")
- admin = await _admin_token(async_client)
- member = await _member(async_client, admin, "member", [a.id])
- other_team = await _member(async_client, admin, "other", [b.id])
- archive = await archive_factory(a.id, print_name="on-a")
- response = await async_client.patch(f"/api/v1/archives/{archive.id}", headers=member, json={"printer_id": b.id})
- assert response.status_code == 404, response.text
- assert response.json()["detail"] == "Printer not found"
- assert await _printer_of(async_client, _auth(admin), archive.id) == a.id
- listed = await async_client.get("/api/v1/archives/", headers=other_team)
- assert [x["print_name"] for x in listed.json()] == []
- async def test_a_member_can_move_an_archive_between_team_printers(
- async_client: AsyncClient, printer_factory, archive_factory
- ):
- a, a2 = await printer_factory(name="A"), await printer_factory(name="A2")
- admin = await _admin_token(async_client)
- member = await _member(async_client, admin, "member", [a.id, a2.id])
- archive = await archive_factory(a.id)
- response = await async_client.patch(f"/api/v1/archives/{archive.id}", headers=member, json={"printer_id": a2.id})
- assert response.status_code == 200, response.text
- assert await _printer_of(async_client, member, archive.id) == a2.id
- async def test_a_member_can_still_clear_the_printer(async_client: AsyncClient, printer_factory, archive_factory):
- # As an upload without a printer: a printer-less archive is in every scope.
- a = await printer_factory(name="A")
- admin = await _admin_token(async_client)
- member = await _member(async_client, admin, "member", [a.id])
- archive = await archive_factory(a.id)
- response = await async_client.patch(f"/api/v1/archives/{archive.id}", headers=member, json={"printer_id": None})
- assert response.status_code == 200, response.text
- assert await _printer_of(async_client, member, archive.id) is None
- async def test_an_admin_can_move_an_archive_to_any_printer(async_client: AsyncClient, printer_factory, archive_factory):
- a, b = await printer_factory(name="A"), await printer_factory(name="B")
- archive = await archive_factory(a.id)
- response = await async_client.patch(f"/api/v1/archives/{archive.id}", json={"printer_id": b.id})
- assert response.status_code == 200, response.text
- assert response.json()["printer_id"] == b.id
- @pytest.mark.parametrize("printer_id", [0, 9999])
- async def test_an_unknown_printer_is_refused(async_client: AsyncClient, printer_factory, archive_factory, printer_id):
- a = await printer_factory(name="A")
- archive = await archive_factory(a.id)
- response = await async_client.patch(f"/api/v1/archives/{archive.id}", json={"printer_id": printer_id})
- assert response.status_code == 400, response.text
- assert response.json()["detail"] == "Printer not found"
- assert (await async_client.get(f"/api/v1/archives/{archive.id}")).json()["printer_id"] == a.id
- @pytest.mark.parametrize("project_id", [0, 9999])
- async def test_an_unknown_project_is_refused(async_client: AsyncClient, printer_factory, archive_factory, project_id):
- a = await printer_factory(name="A")
- archive = await archive_factory(a.id)
- response = await async_client.patch(f"/api/v1/archives/{archive.id}", json={"project_id": project_id})
- assert response.status_code == 400, response.text
- assert response.json()["detail"] == "Project not found"
- assert (await async_client.get(f"/api/v1/archives/{archive.id}")).json()["project_id"] is None
- async def test_a_known_project_can_be_set_and_cleared(async_client: AsyncClient, printer_factory, archive_factory):
- a = await printer_factory(name="A")
- archive = await archive_factory(a.id)
- project = (await async_client.post("/api/v1/projects/", json={"name": "P"})).json()
- linked = await async_client.patch(f"/api/v1/archives/{archive.id}", json={"project_id": project["id"]})
- cleared = await async_client.patch(f"/api/v1/archives/{archive.id}", json={"project_id": None})
- assert linked.status_code == 200, linked.text
- assert linked.json()["project_id"] == project["id"]
- assert cleared.status_code == 200, cleared.text
- assert cleared.json()["project_id"] is None
|