test_archive_cost_fields_by_owner.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. """Which archive figures a user who may only edit their own archives can set.
  2. The archive's cost and filament weight are what later runs of it are charged
  3. from. Callers who may edit every archive set both; callers limited to their
  4. own archives may fill in a weight only for an archive without its 3MF, which
  5. has none and cannot be printed again.
  6. """
  7. import pytest
  8. from httpx import AsyncClient
  9. from backend.tests.integration.test_printer_scope_1727 import _admin_token, _auth, _group, _user
  10. OWN = ["archives:read_own", "archives:update_own"]
  11. async def _owner_and_archive(async_client, archive_factory, printer_factory, *, grams, cost, file_path=None):
  12. admin = await _admin_token(async_client)
  13. group = await _group(async_client, admin, "own_archives", permissions=OWN)
  14. jwt, user_id = await _user(async_client, admin, "owner", [group])
  15. printer = await printer_factory()
  16. extra = {} if file_path is None else {"file_path": file_path}
  17. archive = await archive_factory(
  18. printer.id, created_by_id=user_id, filament_used_grams=grams, cost=cost, filament_type="PLA", **extra
  19. )
  20. return admin, jwt, archive.id
  21. @pytest.mark.asyncio
  22. @pytest.mark.integration
  23. async def test_owner_cannot_set_the_cost(async_client: AsyncClient, archive_factory, printer_factory):
  24. _, jwt, archive_id = await _owner_and_archive(async_client, archive_factory, printer_factory, grams=100.0, cost=2.5)
  25. response = await async_client.patch(f"/api/v1/archives/{archive_id}", headers=_auth(jwt), json={"cost": 0.01})
  26. assert response.status_code == 403
  27. after = await async_client.get(f"/api/v1/archives/{archive_id}", headers=_auth(jwt))
  28. assert after.json()["cost"] == 2.5
  29. @pytest.mark.asyncio
  30. @pytest.mark.integration
  31. async def test_owner_cannot_change_an_existing_weight(async_client: AsyncClient, archive_factory, printer_factory):
  32. _, jwt, archive_id = await _owner_and_archive(async_client, archive_factory, printer_factory, grams=100.0, cost=2.5)
  33. response = await async_client.patch(
  34. f"/api/v1/archives/{archive_id}", headers=_auth(jwt), json={"filament_used_grams": 90000}
  35. )
  36. assert response.status_code == 403
  37. after = await async_client.get(f"/api/v1/archives/{archive_id}", headers=_auth(jwt))
  38. assert (after.json()["filament_used_grams"], after.json()["cost"]) == (100.0, 2.5)
  39. @pytest.mark.asyncio
  40. @pytest.mark.integration
  41. async def test_owner_fills_a_missing_weight(async_client: AsyncClient, archive_factory, printer_factory):
  42. _, jwt, archive_id = await _owner_and_archive(
  43. async_client, archive_factory, printer_factory, grams=None, cost=None, file_path=""
  44. )
  45. response = await async_client.patch(
  46. f"/api/v1/archives/{archive_id}", headers=_auth(jwt), json={"filament_used_grams": 120}
  47. )
  48. assert response.status_code == 200
  49. assert (response.json()["filament_used_grams"], response.json()["cost"]) == (120, 3.0)
  50. @pytest.mark.asyncio
  51. @pytest.mark.integration
  52. async def test_filling_the_weight_keeps_an_existing_cost(async_client: AsyncClient, archive_factory, printer_factory):
  53. _, jwt, archive_id = await _owner_and_archive(
  54. async_client, archive_factory, printer_factory, grams=None, cost=7.0, file_path=""
  55. )
  56. response = await async_client.patch(
  57. f"/api/v1/archives/{archive_id}", headers=_auth(jwt), json={"filament_used_grams": 120}
  58. )
  59. assert response.status_code == 200
  60. assert response.json()["cost"] == 7.0
  61. @pytest.mark.asyncio
  62. @pytest.mark.integration
  63. async def test_owner_still_edits_everything_else(async_client: AsyncClient, archive_factory, printer_factory):
  64. _, jwt, archive_id = await _owner_and_archive(async_client, archive_factory, printer_factory, grams=100.0, cost=2.5)
  65. response = await async_client.patch(
  66. f"/api/v1/archives/{archive_id}",
  67. headers=_auth(jwt),
  68. json={"notes": "fine", "filament_used_grams": 100.0},
  69. )
  70. assert response.status_code == 200
  71. assert response.json()["notes"] == "fine"
  72. @pytest.mark.asyncio
  73. @pytest.mark.integration
  74. async def test_editing_every_archive_sets_both(async_client: AsyncClient, archive_factory, printer_factory):
  75. admin, _, archive_id = await _owner_and_archive(
  76. async_client, archive_factory, printer_factory, grams=100.0, cost=2.5
  77. )
  78. weight = await async_client.patch(
  79. f"/api/v1/archives/{archive_id}", headers=_auth(admin), json={"filament_used_grams": 200}
  80. )
  81. cost = await async_client.patch(f"/api/v1/archives/{archive_id}", headers=_auth(admin), json={"cost": 9.99})
  82. assert (weight.status_code, weight.json()["cost"]) == (200, 5.0)
  83. assert (cost.status_code, cost.json()["cost"]) == (200, 9.99)
  84. @pytest.mark.asyncio
  85. @pytest.mark.integration
  86. async def test_owner_cannot_fill_the_weight_of_an_archive_with_its_3mf(
  87. async_client: AsyncClient, archive_factory, printer_factory
  88. ):
  89. """It can be printed again, and those runs are charged from the weight."""
  90. _, jwt, archive_id = await _owner_and_archive(async_client, archive_factory, printer_factory, grams=None, cost=None)
  91. response = await async_client.patch(
  92. f"/api/v1/archives/{archive_id}", headers=_auth(jwt), json={"filament_used_grams": 0.01}
  93. )
  94. assert response.status_code == 403
  95. @pytest.mark.asyncio
  96. @pytest.mark.integration
  97. @pytest.mark.parametrize("body", [{"filament_used_grams": None}, {"cost": None}])
  98. async def test_owner_cannot_clear_either_figure(async_client: AsyncClient, archive_factory, printer_factory, body):
  99. _, jwt, archive_id = await _owner_and_archive(async_client, archive_factory, printer_factory, grams=100.0, cost=2.5)
  100. response = await async_client.patch(f"/api/v1/archives/{archive_id}", headers=_auth(jwt), json=body)
  101. assert response.status_code == 403