wagtail-write-api 0.2.2__tar.gz → 0.2.3__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.
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/PKG-INFO +1 -1
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/docs/api/pages.md +2 -2
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/docs/guides/rich-text.md +6 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/pyproject.toml +1 -1
- wagtail_write_api-0.2.3/src/wagtail_write_api/__init__.py +1 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/converters/rich_text.py +24 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/tests/test_rich_text.py +48 -0
- wagtail_write_api-0.2.2/src/wagtail_write_api/__init__.py +0 -1
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/.github/workflows/docs.yml +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/.github/workflows/publish.yml +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/.gitignore +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/CLAUDE.md +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/LICENSE +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/Makefile +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/README.md +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/docs/api/authentication.md +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/docs/api/images.md +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/docs/api/schema-discovery.md +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/docs/development/contributing.md +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/docs/development/example-app.md +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/docs/getting-started/configuration.md +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/docs/getting-started/installation.md +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/docs/getting-started/quickstart.md +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/docs/guides/permissions.md +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/docs/guides/streamfield.md +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/docs/guides/workflow.md +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/docs/index.md +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/example/Makefile +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/example/example_project/__init__.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/example/example_project/settings.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/example/example_project/urls.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/example/example_project/wsgi.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/example/manage.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/example/testapp/__init__.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/example/testapp/management/__init__.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/example/testapp/management/commands/__init__.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/example/testapp/management/commands/seed_demo.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/example/testapp/migrations/0001_initial.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/example/testapp/migrations/__init__.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/example/testapp/models.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/example/testapp/wagtail_hooks.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/api.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/apps.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/auth.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/converters/__init__.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/endpoints/__init__.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/endpoints/images.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/endpoints/pages.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/endpoints/schema_discovery.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/management/__init__.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/management/commands/__init__.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/management/commands/create_api_token.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/migrations/0001_initial.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/migrations/__init__.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/models.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/permissions.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/schema/__init__.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/schema/fields.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/schema/generator.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/schema/registry.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/settings.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/urls.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/utils.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/tests/__init__.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/tests/conftest.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/tests/test_auth.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/tests/test_images_api.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/tests/test_pages_read.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/tests/test_pages_workflow.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/tests/test_pages_write.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/tests/test_schema_generation.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/tests/test_smoke.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/tests/test_streamfield.py +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/uv.lock +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/wagtail-write-api-plan.md +0 -0
- {wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/zensical.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wagtail-write-api
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
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
|
|
@@ -34,8 +34,8 @@ GET /pages/
|
|
|
34
34
|
| Parameter | Type | Description |
|
|
35
35
|
|-----------|------|-------------|
|
|
36
36
|
| `type` | string | Filter by page type, e.g. `blog.BlogPage` |
|
|
37
|
-
| `parent` | int | Direct children of this page ID |
|
|
38
|
-
| `descendant_of` | int | All descendants of this page ID |
|
|
37
|
+
| `parent` | int or string | Direct children of this page ID or URL path (e.g. `5` or `/blog/`) |
|
|
38
|
+
| `descendant_of` | int or string | All descendants of this page ID or URL path |
|
|
39
39
|
| `status` | string | `draft`, `live`, or `live+draft` |
|
|
40
40
|
| `slug` | string | Exact slug match (may return multiple if slug exists under different parents) |
|
|
41
41
|
| `path` | string | Exact URL path match, e.g. `/blog/my-post/` (always 0 or 1 result) |
|
|
@@ -92,6 +92,12 @@ WAGTAIL_WRITE_API = {
|
|
|
92
92
|
!!! tip "For CMS editors"
|
|
93
93
|
If your client needs to read content, edit it, and write it back, use `"wagtail"` format. This preserves the internal link references (page IDs) through the round trip. With `"html"` format, internal links are expanded to URL paths, which can't be losslessly converted back.
|
|
94
94
|
|
|
95
|
+
## StreamField blocks sent to a RichTextField
|
|
96
|
+
|
|
97
|
+
If a client accidentally sends StreamField-style blocks (a list of `{"type": ..., "value": ...}` dicts) to a `RichTextField`, the API extracts the HTML content from the blocks rather than storing a stringified list. Paragraph and text block values are concatenated, and heading blocks are converted to HTML heading tags.
|
|
98
|
+
|
|
99
|
+
This is a convenience fallback — for best results, send one of the documented input formats above.
|
|
100
|
+
|
|
95
101
|
## Rich text in StreamField
|
|
96
102
|
|
|
97
103
|
`RichTextBlock` values in StreamField accept the same input format:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.3"
|
{wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/converters/rich_text.py
RENAMED
|
@@ -14,6 +14,9 @@ def convert_rich_text_input(value) -> str:
|
|
|
14
14
|
if isinstance(value, str):
|
|
15
15
|
return value
|
|
16
16
|
|
|
17
|
+
if isinstance(value, list):
|
|
18
|
+
return _blocks_to_html(value)
|
|
19
|
+
|
|
17
20
|
if not isinstance(value, dict):
|
|
18
21
|
return str(value)
|
|
19
22
|
|
|
@@ -54,3 +57,24 @@ def markdown_to_wagtail(md_text: str) -> str:
|
|
|
54
57
|
# The wagtail links are already in the output as <a linktype="..." id="...">
|
|
55
58
|
# because we replaced them before markdown processing
|
|
56
59
|
return html
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _blocks_to_html(blocks: list) -> str:
|
|
63
|
+
"""Extract HTML from a list of StreamField-style blocks.
|
|
64
|
+
|
|
65
|
+
Handles the case where a client sends block data to a RichTextField —
|
|
66
|
+
we pull out the text content rather than storing a stringified list.
|
|
67
|
+
"""
|
|
68
|
+
parts = []
|
|
69
|
+
for block in blocks:
|
|
70
|
+
if not isinstance(block, dict):
|
|
71
|
+
continue
|
|
72
|
+
value = block.get("value", "")
|
|
73
|
+
block_type = block.get("type", "")
|
|
74
|
+
if block_type == "heading" and isinstance(value, dict):
|
|
75
|
+
size = value.get("size", "h2")
|
|
76
|
+
text = value.get("text", "")
|
|
77
|
+
parts.append(f"<{size}>{text}</{size}>")
|
|
78
|
+
elif isinstance(value, str):
|
|
79
|
+
parts.append(value)
|
|
80
|
+
return "".join(parts)
|
|
@@ -87,6 +87,54 @@ class TestRichTextInput:
|
|
|
87
87
|
page = SimplePage.objects.get(title="Plain String")
|
|
88
88
|
assert page.body == "<p>Just plain HTML</p>"
|
|
89
89
|
|
|
90
|
+
def test_streamfield_blocks_coerced_to_html(self, api_client, auth_header, home_page):
|
|
91
|
+
"""StreamField-style blocks sent to a RichTextField are coerced to HTML."""
|
|
92
|
+
response = api_client.post(
|
|
93
|
+
"/api/write/v1/pages/",
|
|
94
|
+
data=json.dumps(
|
|
95
|
+
{
|
|
96
|
+
"type": "testapp.SimplePage",
|
|
97
|
+
"parent": home_page.id,
|
|
98
|
+
"title": "Blocks Coerced",
|
|
99
|
+
"body": [
|
|
100
|
+
{"type": "paragraph", "value": "<p>Hello</p>", "id": "a"},
|
|
101
|
+
{"type": "paragraph", "value": "<p>World</p>", "id": "b"},
|
|
102
|
+
],
|
|
103
|
+
}
|
|
104
|
+
),
|
|
105
|
+
content_type="application/json",
|
|
106
|
+
**auth_header,
|
|
107
|
+
)
|
|
108
|
+
assert response.status_code == 201
|
|
109
|
+
page = SimplePage.objects.get(title="Blocks Coerced")
|
|
110
|
+
assert isinstance(page.body, str)
|
|
111
|
+
assert "<p>Hello</p>" in page.body
|
|
112
|
+
assert "<p>World</p>" in page.body
|
|
113
|
+
assert "[{" not in page.body # not stringified Python
|
|
114
|
+
|
|
115
|
+
def test_streamfield_heading_blocks_coerced(self, api_client, auth_header, home_page):
|
|
116
|
+
"""Heading blocks are converted to HTML heading tags."""
|
|
117
|
+
response = api_client.post(
|
|
118
|
+
"/api/write/v1/pages/",
|
|
119
|
+
data=json.dumps(
|
|
120
|
+
{
|
|
121
|
+
"type": "testapp.SimplePage",
|
|
122
|
+
"parent": home_page.id,
|
|
123
|
+
"title": "Heading Coerced",
|
|
124
|
+
"body": [
|
|
125
|
+
{"type": "heading", "value": {"text": "Title", "size": "h2"}, "id": "a"},
|
|
126
|
+
{"type": "paragraph", "value": "<p>Body text</p>", "id": "b"},
|
|
127
|
+
],
|
|
128
|
+
}
|
|
129
|
+
),
|
|
130
|
+
content_type="application/json",
|
|
131
|
+
**auth_header,
|
|
132
|
+
)
|
|
133
|
+
assert response.status_code == 201
|
|
134
|
+
page = SimplePage.objects.get(title="Heading Coerced")
|
|
135
|
+
assert "<h2>Title</h2>" in page.body
|
|
136
|
+
assert "<p>Body text</p>" in page.body
|
|
137
|
+
|
|
90
138
|
def test_markdown_wagtail_page_link(self, api_client, auth_header, home_page):
|
|
91
139
|
response = api_client.post(
|
|
92
140
|
"/api/write/v1/pages/",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.2.2"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/example/testapp/management/commands/__init__.py
RENAMED
|
File without changes
|
{wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/example/testapp/management/commands/seed_demo.py
RENAMED
|
File without changes
|
{wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/example/testapp/migrations/0001_initial.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/converters/__init__.py
RENAMED
|
File without changes
|
{wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/endpoints/__init__.py
RENAMED
|
File without changes
|
{wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/endpoints/images.py
RENAMED
|
File without changes
|
{wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/endpoints/pages.py
RENAMED
|
File without changes
|
|
File without changes
|
{wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/management/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/migrations/0001_initial.py
RENAMED
|
File without changes
|
{wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/migrations/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/schema/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/schema/generator.py
RENAMED
|
File without changes
|
{wagtail_write_api-0.2.2 → wagtail_write_api-0.2.3}/src/wagtail_write_api/schema/registry.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|