test_work_center_api.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. from __future__ import annotations
  2. USER_UID = "01900000-0000-7000-8000-000000007901"
  3. TASK_UID = "01900000-0000-7000-8000-000000007902"
  4. WORKFLOW_UID = "01900000-0000-7000-8000-000000007903"
  5. class FakeWorkCenterService:
  6. def __init__(self):
  7. self.calls = []
  8. def list_tasks(self, **filters):
  9. self.calls.append(("list_tasks", filters))
  10. return [{"uid": TASK_UID, "subject_type": "quality_issue"}]
  11. def create_task(self, payload, actor_uid):
  12. self.calls.append(("create_task", payload, actor_uid))
  13. return {"uid": TASK_UID, "current_version": 1, **payload}
  14. def review_task(self, uid, payload, expected_version, actor_uid):
  15. self.calls.append(("review", uid, payload, expected_version, actor_uid))
  16. return {"uid": uid, "status": "approved", "current_version": 2}
  17. def list_workflows(self):
  18. return []
  19. def create_workflow(self, payload, actor_uid):
  20. self.calls.append(("workflow", payload, actor_uid))
  21. return {"uid": WORKFLOW_UID, "current_version": 1}
  22. def dashboard(self, at=None):
  23. return {"pending_count": 1, "overdue_count": 0, "closure_rate": 0}
  24. def get_notification_preferences(self, user_uid):
  25. return {"user_uid": user_uid, "revision": 0, "enabled_channels": ["in_app"]}
  26. def replace_notification_preferences(self, payload, expected_revision, actor_uid):
  27. self.calls.append(("preferences", payload, expected_revision, actor_uid))
  28. return {"user_uid": actor_uid, "revision": expected_revision + 1, **payload}
  29. def _headers(role, **extra):
  30. return {"Authorization": f"Bearer {role}", **extra}
  31. def _client(monkeypatch):
  32. from app import create_app
  33. from app.api.system import work_center
  34. service = FakeWorkCenterService()
  35. monkeypatch.setattr(work_center, "_service", lambda: service)
  36. monkeypatch.setattr(
  37. "app.core.system.auth.load_identity_from_token",
  38. lambda token, secret: (
  39. {"id": USER_UID, "username": token, "roles": [token]}
  40. if token in {"viewer", "editor", "admin"}
  41. else None
  42. ),
  43. )
  44. app = create_app()
  45. app.config.update(TESTING=True)
  46. return app.test_client(), service
  47. def test_unified_inbox_is_readable_and_filters_non_manager_scope(monkeypatch):
  48. client, service = _client(monkeypatch)
  49. response = client.get(
  50. "/api/system/work-center/tasks?subject_type=quality_issue",
  51. headers=_headers("viewer"),
  52. )
  53. assert response.status_code == 200
  54. filters = service.calls[-1][1]
  55. assert filters["requester_uid"] == USER_UID
  56. assert filters["can_manage"] is False
  57. assert filters["subject_type"] == "quality_issue"
  58. def test_editor_can_create_and_review_versioned_task_but_not_manage_flow(monkeypatch):
  59. client, service = _client(monkeypatch)
  60. created = client.post(
  61. "/api/system/work-center/tasks",
  62. json={"title": "quality remediation"},
  63. headers=_headers("editor"),
  64. )
  65. assert created.status_code == 201
  66. assert created.headers["ETag"] == '"1"'
  67. missing_version = client.post(
  68. f"/api/system/work-center/tasks/{TASK_UID}/review",
  69. json={"decision": "approve", "reason": "ready"},
  70. headers=_headers("editor"),
  71. )
  72. assert missing_version.status_code == 428
  73. reviewed = client.post(
  74. f"/api/system/work-center/tasks/{TASK_UID}/review",
  75. json={"decision": "approve", "reason": "ready"},
  76. headers=_headers("editor", **{"If-Match": '"1"'}),
  77. )
  78. assert reviewed.status_code == 200
  79. assert reviewed.headers["ETag"] == '"2"'
  80. assert service.calls[-1][3] == 1
  81. forbidden = client.post(
  82. "/api/system/work-center/workflows",
  83. json={"code": "FLOW"},
  84. headers=_headers("editor"),
  85. )
  86. assert forbidden.status_code == 403
  87. def test_admin_manages_workflow_and_user_versions_preferences(monkeypatch):
  88. client, service = _client(monkeypatch)
  89. workflow = client.post(
  90. "/api/system/work-center/workflows",
  91. json={"code": "FLOW"},
  92. headers=_headers("admin"),
  93. )
  94. assert workflow.status_code == 201
  95. preference = client.put(
  96. "/api/system/work-center/preferences",
  97. json={"enabled_channels": ["in_app"]},
  98. headers=_headers("editor", **{"If-Match": '"0"'}),
  99. )
  100. assert preference.status_code == 200
  101. assert preference.headers["ETag"] == '"1"'
  102. assert service.calls[-1][2] == 0