wagtail-write-api 0.2.0__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/PKG-INFO +1 -1
  2. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/pyproject.toml +1 -1
  3. wagtail_write_api-0.2.2/src/wagtail_write_api/__init__.py +1 -0
  4. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/api.py +5 -2
  5. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/endpoints/pages.py +17 -8
  6. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/tests/test_pages_read.py +12 -0
  7. wagtail_write_api-0.2.0/src/wagtail_write_api/__init__.py +0 -1
  8. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/.github/workflows/docs.yml +0 -0
  9. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/.github/workflows/publish.yml +0 -0
  10. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/.gitignore +0 -0
  11. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/CLAUDE.md +0 -0
  12. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/LICENSE +0 -0
  13. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/Makefile +0 -0
  14. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/README.md +0 -0
  15. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/docs/api/authentication.md +0 -0
  16. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/docs/api/images.md +0 -0
  17. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/docs/api/pages.md +0 -0
  18. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/docs/api/schema-discovery.md +0 -0
  19. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/docs/development/contributing.md +0 -0
  20. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/docs/development/example-app.md +0 -0
  21. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/docs/getting-started/configuration.md +0 -0
  22. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/docs/getting-started/installation.md +0 -0
  23. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/docs/getting-started/quickstart.md +0 -0
  24. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/docs/guides/permissions.md +0 -0
  25. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/docs/guides/rich-text.md +0 -0
  26. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/docs/guides/streamfield.md +0 -0
  27. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/docs/guides/workflow.md +0 -0
  28. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/docs/index.md +0 -0
  29. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/example/Makefile +0 -0
  30. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/example/example_project/__init__.py +0 -0
  31. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/example/example_project/settings.py +0 -0
  32. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/example/example_project/urls.py +0 -0
  33. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/example/example_project/wsgi.py +0 -0
  34. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/example/manage.py +0 -0
  35. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/example/testapp/__init__.py +0 -0
  36. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/example/testapp/management/__init__.py +0 -0
  37. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/example/testapp/management/commands/__init__.py +0 -0
  38. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/example/testapp/management/commands/seed_demo.py +0 -0
  39. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/example/testapp/migrations/0001_initial.py +0 -0
  40. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/example/testapp/migrations/__init__.py +0 -0
  41. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/example/testapp/models.py +0 -0
  42. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/example/testapp/wagtail_hooks.py +0 -0
  43. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/apps.py +0 -0
  44. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/auth.py +0 -0
  45. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/converters/__init__.py +0 -0
  46. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/converters/rich_text.py +0 -0
  47. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/endpoints/__init__.py +0 -0
  48. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/endpoints/images.py +0 -0
  49. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/endpoints/schema_discovery.py +0 -0
  50. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/management/__init__.py +0 -0
  51. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/management/commands/__init__.py +0 -0
  52. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/management/commands/create_api_token.py +0 -0
  53. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/migrations/0001_initial.py +0 -0
  54. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/migrations/__init__.py +0 -0
  55. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/models.py +0 -0
  56. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/permissions.py +0 -0
  57. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/schema/__init__.py +0 -0
  58. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/schema/fields.py +0 -0
  59. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/schema/generator.py +0 -0
  60. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/schema/registry.py +0 -0
  61. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/settings.py +0 -0
  62. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/urls.py +0 -0
  63. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/src/wagtail_write_api/utils.py +0 -0
  64. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/tests/__init__.py +0 -0
  65. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/tests/conftest.py +0 -0
  66. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/tests/test_auth.py +0 -0
  67. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/tests/test_images_api.py +0 -0
  68. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/tests/test_pages_workflow.py +0 -0
  69. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/tests/test_pages_write.py +0 -0
  70. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/tests/test_rich_text.py +0 -0
  71. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/tests/test_schema_generation.py +0 -0
  72. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/tests/test_smoke.py +0 -0
  73. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/tests/test_streamfield.py +0 -0
  74. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/uv.lock +0 -0
  75. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/wagtail-write-api-plan.md +0 -0
  76. {wagtail_write_api-0.2.0 → wagtail_write_api-0.2.2}/zensical.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wagtail-write-api
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: A read/write REST API for Wagtail CMS
5
5
  Project-URL: Homepage, https://tomdyson.github.io/wagtail-write-api/
6
6
  Project-URL: Repository, https://github.com/tomdyson/wagtail-write-api
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "wagtail-write-api"
7
- version = "0.2.0"
7
+ version = "0.2.2"
8
8
  description = "A read/write REST API for Wagtail CMS"
9
9
  readme = "README.md"
10
10
  license = "BSD-3-Clause"
@@ -0,0 +1 @@
1
+ __version__ = "0.2.2"
@@ -24,11 +24,14 @@ def on_permission_denied(request, exc):
24
24
  def on_validation_error(request, exc):
25
25
  if hasattr(exc, "message_dict"):
26
26
  details = [
27
- {"field": field, "message": msgs[0] if msgs else ""}
27
+ {"field": field, "message": msgs[0] if len(msgs) == 1 else msgs}
28
28
  for field, msgs in exc.message_dict.items()
29
29
  ]
30
30
  else:
31
- details = [{"message": str(exc)}]
31
+ details = [
32
+ {"message": m.message % m.params if m.params else m.message}
33
+ for m in exc.error_list
34
+ ]
32
35
  return api.create_response(
33
36
  request,
34
37
  {"error": "validation_error", "message": "Validation failed", "details": details},
@@ -19,8 +19,8 @@ router = Router(tags=["pages"], auth=WagtailTokenAuth())
19
19
  def list_pages(
20
20
  request,
21
21
  type: Optional[str] = None,
22
- parent: Optional[int] = None,
23
- descendant_of: Optional[int] = None,
22
+ parent: Optional[str] = None,
23
+ descendant_of: Optional[str] = None,
24
24
  status: Optional[str] = None,
25
25
  search: Optional[str] = None,
26
26
  order: Optional[str] = None,
@@ -44,17 +44,23 @@ def list_pages(
44
44
 
45
45
  if parent:
46
46
  try:
47
- parent_page = Page.objects.get(id=parent)
47
+ parent_page = Page.objects.get(id=int(parent))
48
+ except (ValueError, Page.DoesNotExist):
49
+ parent_page = _resolve_page_by_path(parent)
50
+ if parent_page:
48
51
  qs = qs.child_of(parent_page)
49
- except Page.DoesNotExist:
50
- pass
52
+ else:
53
+ qs = qs.none()
51
54
 
52
55
  if descendant_of:
53
56
  try:
54
- ancestor = Page.objects.get(id=descendant_of)
57
+ ancestor = Page.objects.get(id=int(descendant_of))
58
+ except (ValueError, Page.DoesNotExist):
59
+ ancestor = _resolve_page_by_path(descendant_of)
60
+ if ancestor:
55
61
  qs = qs.descendant_of(ancestor)
56
- except Page.DoesNotExist:
57
- pass
62
+ else:
63
+ qs = qs.none()
58
64
 
59
65
  if status == "live":
60
66
  qs = qs.filter(live=True, has_unpublished_changes=False)
@@ -202,6 +208,9 @@ def create_page(request):
202
208
  except (TypeError, ValueError, AttributeError) as exc:
203
209
  return 422, {"error": "validation_error", "message": f"Invalid field data: {exc}"}
204
210
 
211
+ # Validate before saving — full_clean() produces field-level errors
212
+ page.full_clean(exclude=["path", "depth"])
213
+
205
214
  # Add to tree and save revision
206
215
  try:
207
216
  parent_page.add_child(instance=page)
@@ -66,6 +66,18 @@ class TestListPages:
66
66
  data = response.json()
67
67
  assert len(data["items"]) == 2 # blog1 and blog2
68
68
 
69
+ def test_filter_by_parent_path(self, api_client, auth_header, page_tree):
70
+ response = api_client.get("/api/write/v1/pages/?parent=/blog/", **auth_header)
71
+ assert response.status_code == 200
72
+ data = response.json()
73
+ assert len(data["items"]) == 2 # blog1 and blog2
74
+
75
+ def test_filter_by_parent_invalid_returns_empty(self, api_client, auth_header, page_tree):
76
+ response = api_client.get("/api/write/v1/pages/?parent=/nonexistent/", **auth_header)
77
+ assert response.status_code == 200
78
+ data = response.json()
79
+ assert len(data["items"]) == 0
80
+
69
81
  def test_filter_by_status_live(self, api_client, auth_header, page_tree):
70
82
  response = api_client.get("/api/write/v1/pages/?status=live", **auth_header)
71
83
  assert response.status_code == 200
@@ -1 +0,0 @@
1
- __version__ = "0.2.0"