picata 0.0.1__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- LICENSE.md +24 -0
- README.md +59 -0
- components/HelloWorld.tsx +11 -0
- entrypoint.tsx +268 -0
- manage.py +15 -0
- picata/__init__.py +1 -0
- picata/apps.py +33 -0
- picata/blocks.py +175 -0
- picata/helpers/__init__.py +70 -0
- picata/helpers/wagtail.py +61 -0
- picata/log_utils.py +47 -0
- picata/middleware.py +54 -0
- picata/migrations/0001_initial.py +264 -0
- picata/migrations/0002_alter_article_content_alter_basicpage_content.py +112 -0
- picata/migrations/0003_alter_article_content_alter_basicpage_content.py +104 -0
- picata/migrations/0004_alter_article_content_alter_basicpage_content.py +105 -0
- picata/migrations/0005_socialsettings.py +48 -0
- picata/migrations/0006_alter_article_content.py +71 -0
- picata/migrations/0007_splitviewpage.py +69 -0
- picata/migrations/0008_alter_splitviewpage_content.py +96 -0
- picata/migrations/0009_alter_splitviewpage_content.py +111 -0
- picata/migrations/0010_alter_splitviewpage_content.py +105 -0
- picata/migrations/0011_alter_splitviewpage_options_and_more.py +113 -0
- picata/migrations/0012_alter_splitviewpage_content.py +109 -0
- picata/migrations/0013_alter_article_content.py +43 -0
- picata/migrations/0014_alter_article_content_alter_article_summary.py +24 -0
- picata/migrations/0015_alter_article_options_article_tagline_and_more.py +28 -0
- picata/migrations/0016_alter_article_options_alter_articletag_options_and_more.py +33 -0
- picata/migrations/0017_articletagrelation_alter_article_tags_and_more.py +35 -0
- picata/migrations/0018_rename_articletag_pagetag_and_more.py +21 -0
- picata/migrations/0019_rename_name_plural_articletype__name_plural.py +18 -0
- picata/migrations/0020_rename__name_plural_articletype__pluralised_name.py +18 -0
- picata/migrations/0021_rename_article_type_article_page_type.py +18 -0
- picata/migrations/0022_homepage.py +28 -0
- picata/migrations/__init__.py +0 -0
- picata/models.py +486 -0
- picata/settings/__init__.py +1 -0
- picata/settings/base.py +345 -0
- picata/settings/dev.py +94 -0
- picata/settings/mypy.py +7 -0
- picata/settings/prod.py +12 -0
- picata/settings/test.py +6 -0
- picata/static/picata/ada-profile.jpg +0 -0
- picata/static/picata/ada-social-bear.jpg +0 -0
- picata/static/picata/favicon.ico +0 -0
- picata/static/picata/fonts/Bitter-Light.ttf +0 -0
- picata/static/picata/fonts/Bitter-LightItalic.ttf +0 -0
- picata/static/picata/fonts/FiraCode-Light.ttf +0 -0
- picata/static/picata/fonts/FiraCode-SemiBold.ttf +0 -0
- picata/static/picata/fonts/Sacramento-Regular.ttf +0 -0
- picata/static/picata/fonts/ZillaSlab-Bold.ttf +0 -0
- picata/static/picata/fonts/ZillaSlab-BoldItalic.ttf +0 -0
- picata/static/picata/fonts/ZillaSlab-Light.ttf +0 -0
- picata/static/picata/fonts/ZillaSlab-LightItalic.ttf +0 -0
- picata/static/picata/fonts/ZillaSlabHighlight-Bold.ttf +0 -0
- picata/static/picata/icons.svg +56 -0
- picata/templates/picata/3_column.html +28 -0
- picata/templates/picata/404.html +11 -0
- picata/templates/picata/500.html +13 -0
- picata/templates/picata/_post_list.html +24 -0
- picata/templates/picata/article.html +20 -0
- picata/templates/picata/base.html +135 -0
- picata/templates/picata/basic_page.html +10 -0
- picata/templates/picata/blocks/icon_link_item.html +7 -0
- picata/templates/picata/blocks/icon_link_list.html +4 -0
- picata/templates/picata/blocks/icon_link_list_stream.html +3 -0
- picata/templates/picata/dl_view.html +18 -0
- picata/templates/picata/home_page.html +21 -0
- picata/templates/picata/post_listing.html +17 -0
- picata/templates/picata/previews/3col.html +73 -0
- picata/templates/picata/previews/dl.html +10 -0
- picata/templates/picata/previews/split.html +10 -0
- picata/templates/picata/previews/theme_gallery.html +158 -0
- picata/templates/picata/search_results.html +28 -0
- picata/templates/picata/split_view.html +15 -0
- picata/templates/picata/tags/site_menu.html +8 -0
- picata/templatetags/__init__.py +1 -0
- picata/templatetags/absolute_static.py +15 -0
- picata/templatetags/menu_tags.py +42 -0
- picata/templatetags/stringify.py +23 -0
- picata/transformers.py +60 -0
- picata/typing/__init__.py +19 -0
- picata/typing/wagtail.py +31 -0
- picata/urls.py +48 -0
- picata/validators.py +36 -0
- picata/views.py +80 -0
- picata/wagtail_hooks.py +43 -0
- picata/wsgi.py +15 -0
- picata-0.0.1.dist-info/METADATA +87 -0
- picata-0.0.1.dist-info/RECORD +94 -0
- picata-0.0.1.dist-info/WHEEL +4 -0
- picata-0.0.1.dist-info/licenses/LICENSE.md +24 -0
- pygments.sass +382 -0
- styles.sass +300 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
"""Generic helper-functions."""
|
2
|
+
# NB: Django's meta-class shenanigans over-complicate type hinting when QuerySets get involved.
|
3
|
+
# pyright: reportAttributeAccessIssue=false
|
4
|
+
|
5
|
+
from typing import cast
|
6
|
+
|
7
|
+
from django.http import HttpRequest
|
8
|
+
from wagtail.models import Page
|
9
|
+
from wagtail.query import PageQuerySet
|
10
|
+
|
11
|
+
from hpk.models import TaggedPage
|
12
|
+
|
13
|
+
from . import get_models_of_type
|
14
|
+
|
15
|
+
TAGGED_PAGE_TYPES = get_models_of_type(TaggedPage)
|
16
|
+
|
17
|
+
|
18
|
+
def visible_pages_qs(request: HttpRequest) -> PageQuerySet:
|
19
|
+
"""Return a QuerySet of all pages derived from `Page` visible to the user."""
|
20
|
+
pages = cast(PageQuerySet, Page.objects.all())
|
21
|
+
if not request.user.is_authenticated:
|
22
|
+
pages = pages.live()
|
23
|
+
return pages
|
24
|
+
|
25
|
+
|
26
|
+
def filter_pages_by_tags(pages: list[Page], tags: set[str]) -> list[TaggedPage]:
|
27
|
+
"""Filter a list of pages to those containing all of a list of tags."""
|
28
|
+
filtered_pages = []
|
29
|
+
for page in pages:
|
30
|
+
try:
|
31
|
+
if isinstance(page, tuple(TAGGED_PAGE_TYPES)):
|
32
|
+
page_tags = {tag.name for tag in page.tags.all()}
|
33
|
+
if set(tags).issubset(page_tags):
|
34
|
+
filtered_pages.append(page)
|
35
|
+
except AttributeError:
|
36
|
+
continue
|
37
|
+
return filtered_pages
|
38
|
+
|
39
|
+
|
40
|
+
def filter_pages_by_type(pages: list[Page], page_type_slugs: set[str]) -> list[Page]:
|
41
|
+
"""Filter a list of pages to those with a `page_type` matching any of the given slugs."""
|
42
|
+
filtered_pages = []
|
43
|
+
for page in pages:
|
44
|
+
try:
|
45
|
+
if (
|
46
|
+
hasattr(page, "page_type")
|
47
|
+
and page.page_type
|
48
|
+
and page.page_type.slug in page_type_slugs
|
49
|
+
):
|
50
|
+
filtered_pages.append(page)
|
51
|
+
except AttributeError:
|
52
|
+
continue
|
53
|
+
return filtered_pages
|
54
|
+
|
55
|
+
|
56
|
+
def page_preview_data(request: HttpRequest, page: Page) -> dict[str, str]:
|
57
|
+
"""Return a dictionary of available publication and preview data for a page."""
|
58
|
+
page_data = getattr(page, "preview_data", {}).copy()
|
59
|
+
if hasattr(page, "get_publication_data"):
|
60
|
+
page_data.update(page.get_publication_data(request))
|
61
|
+
return page_data
|
picata/log_utils.py
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
"""Customisations to the global logging system and custom logging classses."""
|
2
|
+
|
3
|
+
import logging
|
4
|
+
from logging.handlers import TimedRotatingFileHandler
|
5
|
+
|
6
|
+
# Define custom levels
|
7
|
+
TRACE_LEVEL = 5
|
8
|
+
SUCCESS_LEVEL = 25
|
9
|
+
|
10
|
+
logging.addLevelName(TRACE_LEVEL, "TRACE")
|
11
|
+
logging.addLevelName(SUCCESS_LEVEL, "SUCCESS")
|
12
|
+
|
13
|
+
|
14
|
+
# Handlers
|
15
|
+
|
16
|
+
|
17
|
+
class RotatingDailyFileHandler(TimedRotatingFileHandler):
|
18
|
+
"""Rotates file logs daily at midnight, with a week of backups by default."""
|
19
|
+
|
20
|
+
def __init__(self, filename: str, backup_days: int = 7) -> None:
|
21
|
+
"""Pass our defaults and given args to TimedRotatingFileHandler's __init__ method."""
|
22
|
+
super().__init__(filename, when="midnight", interval=1, backupCount=backup_days)
|
23
|
+
|
24
|
+
|
25
|
+
# Formatters
|
26
|
+
|
27
|
+
|
28
|
+
class FormatterWithEverything(logging.Formatter):
|
29
|
+
"""The *most* verbose logging formatter."""
|
30
|
+
|
31
|
+
def format(self, record: logging.LogRecord) -> str:
|
32
|
+
"""Return a ludicrously verbose log message format."""
|
33
|
+
verbose_message = (
|
34
|
+
f"LEVEL: {record.levelname}\n"
|
35
|
+
f"TIME: {self.formatTime(record)}\n"
|
36
|
+
f"LOGGER: {record.name}\n"
|
37
|
+
f"MODULE: {record.module}\n"
|
38
|
+
f"FUNC: {record.funcName}\n"
|
39
|
+
f"LINE: {record.lineno}\n"
|
40
|
+
f"PATH: {record.pathname}\n"
|
41
|
+
f"THREAD: {record.threadName}\n"
|
42
|
+
f"PROCESS: {record.process}\n"
|
43
|
+
f"MESSAGE: {record.getMessage()}\n"
|
44
|
+
)
|
45
|
+
if record.exc_info:
|
46
|
+
verbose_message += f"EXCEPTION: {self.formatException(record.exc_info)}\n"
|
47
|
+
return verbose_message
|
picata/middleware.py
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
"""HTML-processing middlware; should be placed last in (at the heart of) MIDDLEWARE."""
|
2
|
+
|
3
|
+
import logging
|
4
|
+
import re
|
5
|
+
from collections.abc import Callable
|
6
|
+
from typing import ClassVar
|
7
|
+
|
8
|
+
from django.http import HttpRequest, HttpResponse
|
9
|
+
from lxml import etree
|
10
|
+
|
11
|
+
from hpk.helpers import make_response
|
12
|
+
|
13
|
+
logger = logging.getLogger(__name__)
|
14
|
+
|
15
|
+
|
16
|
+
class HTMLProcessingMiddleware:
|
17
|
+
"""Middleware register for text/html document transformers."""
|
18
|
+
|
19
|
+
transformers: ClassVar[list[Callable[[etree._Element], None]]] = []
|
20
|
+
|
21
|
+
def __init__(self, get_response: Callable) -> None:
|
22
|
+
"""Standard middleware initialisation; get the get_response method."""
|
23
|
+
self.get_response = get_response
|
24
|
+
|
25
|
+
def __call__(self, request: HttpRequest) -> HttpResponse:
|
26
|
+
"""Filter the response through every registered transformer function."""
|
27
|
+
response = self.get_response(request)
|
28
|
+
|
29
|
+
if "text/html" in response.get("Content-Type", ""):
|
30
|
+
doctype = self.extract_doctype(response.content.decode())
|
31
|
+
tree = etree.fromstring(response.content, etree.HTMLParser()) # noqa: S320
|
32
|
+
if tree is not None:
|
33
|
+
for transformer in self.transformers:
|
34
|
+
transformer(tree)
|
35
|
+
processed_html = etree.tostring(
|
36
|
+
tree,
|
37
|
+
pretty_print=True, # type: ignore [reportCallIssue]
|
38
|
+
method="html", # type: ignore [reportCallIssue]
|
39
|
+
encoding=str, # type: ignore [reportCallIssue]
|
40
|
+
)
|
41
|
+
return make_response(response, f"{doctype}\n{processed_html}")
|
42
|
+
|
43
|
+
return response
|
44
|
+
|
45
|
+
@staticmethod
|
46
|
+
def extract_doctype(html: str) -> str:
|
47
|
+
"""Extract the DOCTYPE declaration from the HTML."""
|
48
|
+
match = re.match(r"^(<!DOCTYPE [^>]+>)", html, re.IGNORECASE)
|
49
|
+
return match.group(1) if match else ""
|
50
|
+
|
51
|
+
@classmethod
|
52
|
+
def add_transformer(cls, func: Callable[[etree._Element], None]) -> None:
|
53
|
+
"""Add a transformation function to the global pipeline."""
|
54
|
+
cls.transformers.append(func)
|
@@ -0,0 +1,264 @@
|
|
1
|
+
# Generated by Django 5.1.4 on 2024-12-19 01:11
|
2
|
+
|
3
|
+
import django.db.models.deletion
|
4
|
+
import modelcluster.contrib.taggit
|
5
|
+
import modelcluster.fields
|
6
|
+
import wagtail.fields
|
7
|
+
from django.db import migrations, models
|
8
|
+
|
9
|
+
|
10
|
+
class Migration(migrations.Migration):
|
11
|
+
initial = True
|
12
|
+
|
13
|
+
dependencies = [
|
14
|
+
("taggit", "0006_rename_taggeditem_content_type_object_id_taggit_tagg_content_8fc721_idx"),
|
15
|
+
("wagtailcore", "0094_alter_page_locale"),
|
16
|
+
]
|
17
|
+
|
18
|
+
operations = [
|
19
|
+
migrations.CreateModel(
|
20
|
+
name="Article",
|
21
|
+
fields=[
|
22
|
+
(
|
23
|
+
"page_ptr",
|
24
|
+
models.OneToOneField(
|
25
|
+
auto_created=True,
|
26
|
+
on_delete=django.db.models.deletion.CASCADE,
|
27
|
+
parent_link=True,
|
28
|
+
primary_key=True,
|
29
|
+
serialize=False,
|
30
|
+
to="wagtailcore.page",
|
31
|
+
),
|
32
|
+
),
|
33
|
+
(
|
34
|
+
"summary",
|
35
|
+
wagtail.fields.RichTextField(
|
36
|
+
blank=True, help_text="A short summary, or tagline for the article."
|
37
|
+
),
|
38
|
+
),
|
39
|
+
(
|
40
|
+
"content",
|
41
|
+
wagtail.fields.StreamField(
|
42
|
+
[("section", 5), ("image", 3)],
|
43
|
+
blank=True,
|
44
|
+
block_lookup={
|
45
|
+
0: (
|
46
|
+
"wagtail.blocks.CharBlock",
|
47
|
+
(),
|
48
|
+
{"help_text": "Heading for this section.", "required": True},
|
49
|
+
),
|
50
|
+
1: (
|
51
|
+
"wagtail.blocks.IntegerBlock",
|
52
|
+
(),
|
53
|
+
{
|
54
|
+
"help_text": "Heading level",
|
55
|
+
"max_value": 6,
|
56
|
+
"min_value": 1,
|
57
|
+
"required": True,
|
58
|
+
},
|
59
|
+
),
|
60
|
+
2: (
|
61
|
+
"wagtail.blocks.RichTextBlock",
|
62
|
+
(),
|
63
|
+
{
|
64
|
+
"features": [
|
65
|
+
"bold",
|
66
|
+
"italic",
|
67
|
+
"link",
|
68
|
+
"ul",
|
69
|
+
"ol",
|
70
|
+
"document-link",
|
71
|
+
]
|
72
|
+
},
|
73
|
+
),
|
74
|
+
3: ("wagtail.images.blocks.ImageChooserBlock", (), {}),
|
75
|
+
4: (
|
76
|
+
"wagtail.blocks.StreamBlock",
|
77
|
+
[[("rich_text", 2), ("image", 3)]],
|
78
|
+
{
|
79
|
+
"help_text": "Content blocks for this section.",
|
80
|
+
"required": False,
|
81
|
+
},
|
82
|
+
),
|
83
|
+
5: (
|
84
|
+
"wagtail.blocks.StructBlock",
|
85
|
+
[[("heading", 0), ("level", 1), ("content", 4)]],
|
86
|
+
{},
|
87
|
+
),
|
88
|
+
},
|
89
|
+
help_text="Main content for the article.",
|
90
|
+
),
|
91
|
+
),
|
92
|
+
],
|
93
|
+
options={
|
94
|
+
"verbose_name": "Article",
|
95
|
+
"verbose_name_plural": "Articles",
|
96
|
+
},
|
97
|
+
bases=("wagtailcore.page",),
|
98
|
+
),
|
99
|
+
migrations.CreateModel(
|
100
|
+
name="ArticleTag",
|
101
|
+
fields=[
|
102
|
+
(
|
103
|
+
"id",
|
104
|
+
models.BigAutoField(
|
105
|
+
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
106
|
+
),
|
107
|
+
),
|
108
|
+
("name", models.CharField(max_length=100, unique=True, verbose_name="name")),
|
109
|
+
(
|
110
|
+
"slug",
|
111
|
+
models.SlugField(
|
112
|
+
allow_unicode=True, max_length=100, unique=True, verbose_name="slug"
|
113
|
+
),
|
114
|
+
),
|
115
|
+
],
|
116
|
+
options={
|
117
|
+
"verbose_name": "Article Tag",
|
118
|
+
"verbose_name_plural": "Article Tags",
|
119
|
+
},
|
120
|
+
),
|
121
|
+
migrations.CreateModel(
|
122
|
+
name="ArticleType",
|
123
|
+
fields=[
|
124
|
+
(
|
125
|
+
"id",
|
126
|
+
models.BigAutoField(
|
127
|
+
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
128
|
+
),
|
129
|
+
),
|
130
|
+
(
|
131
|
+
"name",
|
132
|
+
models.CharField(
|
133
|
+
help_text="Name of the article type.", max_length=100, unique=True
|
134
|
+
),
|
135
|
+
),
|
136
|
+
(
|
137
|
+
"name_plural",
|
138
|
+
models.CharField(
|
139
|
+
blank=True,
|
140
|
+
help_text="Plural form of the article type name (optional). Defaults to appending 's'.", # noqa: E501
|
141
|
+
max_length=100,
|
142
|
+
),
|
143
|
+
),
|
144
|
+
("slug", models.SlugField(max_length=100, unique=True)),
|
145
|
+
(
|
146
|
+
"description",
|
147
|
+
models.TextField(blank=True, help_text="Optional description of this type."),
|
148
|
+
),
|
149
|
+
],
|
150
|
+
),
|
151
|
+
migrations.CreateModel(
|
152
|
+
name="BasicPage",
|
153
|
+
fields=[
|
154
|
+
(
|
155
|
+
"page_ptr",
|
156
|
+
models.OneToOneField(
|
157
|
+
auto_created=True,
|
158
|
+
on_delete=django.db.models.deletion.CASCADE,
|
159
|
+
parent_link=True,
|
160
|
+
primary_key=True,
|
161
|
+
serialize=False,
|
162
|
+
to="wagtailcore.page",
|
163
|
+
),
|
164
|
+
),
|
165
|
+
(
|
166
|
+
"content",
|
167
|
+
wagtail.fields.StreamField(
|
168
|
+
[("rich_text", 0), ("image", 1)],
|
169
|
+
blank=True,
|
170
|
+
block_lookup={
|
171
|
+
0: ("wagtail.blocks.RichTextBlock", (), {}),
|
172
|
+
1: ("wagtail.images.blocks.ImageChooserBlock", (), {}),
|
173
|
+
},
|
174
|
+
help_text="Main content for the page.",
|
175
|
+
),
|
176
|
+
),
|
177
|
+
],
|
178
|
+
options={
|
179
|
+
"verbose_name": "Basic Page",
|
180
|
+
"verbose_name_plural": "Basic Pages",
|
181
|
+
},
|
182
|
+
bases=("wagtailcore.page",),
|
183
|
+
),
|
184
|
+
migrations.CreateModel(
|
185
|
+
name="PostGroupPage",
|
186
|
+
fields=[
|
187
|
+
(
|
188
|
+
"page_ptr",
|
189
|
+
models.OneToOneField(
|
190
|
+
auto_created=True,
|
191
|
+
on_delete=django.db.models.deletion.CASCADE,
|
192
|
+
parent_link=True,
|
193
|
+
primary_key=True,
|
194
|
+
serialize=False,
|
195
|
+
to="wagtailcore.page",
|
196
|
+
),
|
197
|
+
),
|
198
|
+
(
|
199
|
+
"intro",
|
200
|
+
wagtail.fields.RichTextField(
|
201
|
+
blank=True, help_text="An optional introduction to this group."
|
202
|
+
),
|
203
|
+
),
|
204
|
+
],
|
205
|
+
options={
|
206
|
+
"verbose_name": "Post Group",
|
207
|
+
"verbose_name_plural": "Post Groups",
|
208
|
+
},
|
209
|
+
bases=("wagtailcore.page",),
|
210
|
+
),
|
211
|
+
migrations.CreateModel(
|
212
|
+
name="ArticleTagItem",
|
213
|
+
fields=[
|
214
|
+
(
|
215
|
+
"id",
|
216
|
+
models.BigAutoField(
|
217
|
+
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
218
|
+
),
|
219
|
+
),
|
220
|
+
(
|
221
|
+
"content_object",
|
222
|
+
modelcluster.fields.ParentalKey(
|
223
|
+
on_delete=django.db.models.deletion.CASCADE,
|
224
|
+
related_name="tagged_items",
|
225
|
+
to="hpk.article",
|
226
|
+
),
|
227
|
+
),
|
228
|
+
(
|
229
|
+
"tag",
|
230
|
+
models.ForeignKey(
|
231
|
+
on_delete=django.db.models.deletion.CASCADE,
|
232
|
+
related_name="%(app_label)s_%(class)s_items",
|
233
|
+
to="taggit.tag",
|
234
|
+
),
|
235
|
+
),
|
236
|
+
],
|
237
|
+
options={
|
238
|
+
"abstract": False,
|
239
|
+
},
|
240
|
+
),
|
241
|
+
migrations.AddField(
|
242
|
+
model_name="article",
|
243
|
+
name="tags",
|
244
|
+
field=modelcluster.contrib.taggit.ClusterTaggableManager(
|
245
|
+
blank=True,
|
246
|
+
help_text="Tags for the article.",
|
247
|
+
through="hpk.ArticleTagItem",
|
248
|
+
to="taggit.Tag",
|
249
|
+
verbose_name="Tags",
|
250
|
+
),
|
251
|
+
),
|
252
|
+
migrations.AddField(
|
253
|
+
model_name="article",
|
254
|
+
name="article_type",
|
255
|
+
field=models.ForeignKey(
|
256
|
+
blank=True,
|
257
|
+
help_text="Select the type of article.",
|
258
|
+
null=True,
|
259
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
260
|
+
related_name="articles",
|
261
|
+
to="hpk.articletype",
|
262
|
+
),
|
263
|
+
),
|
264
|
+
]
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# Generated by Django 5.1.4 on 2024-12-19 22:18
|
2
|
+
|
3
|
+
import wagtail.fields
|
4
|
+
from django.db import migrations
|
5
|
+
|
6
|
+
|
7
|
+
class Migration(migrations.Migration):
|
8
|
+
dependencies = [
|
9
|
+
("hpk", "0001_initial"),
|
10
|
+
]
|
11
|
+
|
12
|
+
operations = [
|
13
|
+
migrations.AlterField(
|
14
|
+
model_name="article",
|
15
|
+
name="content",
|
16
|
+
field=wagtail.fields.StreamField(
|
17
|
+
[("section", 5), ("code", 8), ("image", 3)],
|
18
|
+
blank=True,
|
19
|
+
block_lookup={
|
20
|
+
0: (
|
21
|
+
"wagtail.blocks.CharBlock",
|
22
|
+
(),
|
23
|
+
{"help_text": "Heading for this section.", "required": True},
|
24
|
+
),
|
25
|
+
1: (
|
26
|
+
"wagtail.blocks.IntegerBlock",
|
27
|
+
(),
|
28
|
+
{
|
29
|
+
"help_text": "Heading level",
|
30
|
+
"max_value": 6,
|
31
|
+
"min_value": 1,
|
32
|
+
"required": True,
|
33
|
+
},
|
34
|
+
),
|
35
|
+
2: (
|
36
|
+
"wagtail.blocks.RichTextBlock",
|
37
|
+
(),
|
38
|
+
{"features": ["bold", "italic", "link", "ul", "ol", "document-link"]},
|
39
|
+
),
|
40
|
+
3: ("wagtail.images.blocks.ImageChooserBlock", (), {}),
|
41
|
+
4: (
|
42
|
+
"wagtail.blocks.StreamBlock",
|
43
|
+
[[("rich_text", 2), ("image", 3)]],
|
44
|
+
{"help_text": "Content blocks for this section.", "required": False},
|
45
|
+
),
|
46
|
+
5: (
|
47
|
+
"wagtail.blocks.StructBlock",
|
48
|
+
[[("heading", 0), ("level", 1), ("content", 4)]],
|
49
|
+
{},
|
50
|
+
),
|
51
|
+
6: (
|
52
|
+
"wagtail.blocks.TextBlock",
|
53
|
+
(),
|
54
|
+
{"help_text": "Paste your code here.", "required": True},
|
55
|
+
),
|
56
|
+
7: (
|
57
|
+
"wagtail.blocks.ChoiceBlock",
|
58
|
+
[],
|
59
|
+
{
|
60
|
+
"choices": [
|
61
|
+
("python", "Python"),
|
62
|
+
("javascript", "JavaScript"),
|
63
|
+
("html", "HTML"),
|
64
|
+
("css", "CSS"),
|
65
|
+
("bash", "Bash"),
|
66
|
+
("plaintext", "Plain Text"),
|
67
|
+
],
|
68
|
+
"help_text": "Select the language for syntax highlighting.",
|
69
|
+
"required": False,
|
70
|
+
},
|
71
|
+
),
|
72
|
+
8: ("wagtail.blocks.StructBlock", [[("code", 6), ("language", 7)]], {}),
|
73
|
+
},
|
74
|
+
help_text="Main content for the article.",
|
75
|
+
),
|
76
|
+
),
|
77
|
+
migrations.AlterField(
|
78
|
+
model_name="basicpage",
|
79
|
+
name="content",
|
80
|
+
field=wagtail.fields.StreamField(
|
81
|
+
[("rich_text", 0), ("code", 3), ("image", 4)],
|
82
|
+
blank=True,
|
83
|
+
block_lookup={
|
84
|
+
0: ("wagtail.blocks.RichTextBlock", (), {}),
|
85
|
+
1: (
|
86
|
+
"wagtail.blocks.TextBlock",
|
87
|
+
(),
|
88
|
+
{"help_text": "Paste your code here.", "required": True},
|
89
|
+
),
|
90
|
+
2: (
|
91
|
+
"wagtail.blocks.ChoiceBlock",
|
92
|
+
[],
|
93
|
+
{
|
94
|
+
"choices": [
|
95
|
+
("python", "Python"),
|
96
|
+
("javascript", "JavaScript"),
|
97
|
+
("html", "HTML"),
|
98
|
+
("css", "CSS"),
|
99
|
+
("bash", "Bash"),
|
100
|
+
("plaintext", "Plain Text"),
|
101
|
+
],
|
102
|
+
"help_text": "Select the language for syntax highlighting.",
|
103
|
+
"required": False,
|
104
|
+
},
|
105
|
+
),
|
106
|
+
3: ("wagtail.blocks.StructBlock", [[("code", 1), ("language", 2)]], {}),
|
107
|
+
4: ("wagtail.images.blocks.ImageChooserBlock", (), {}),
|
108
|
+
},
|
109
|
+
help_text="Main content for the page.",
|
110
|
+
),
|
111
|
+
),
|
112
|
+
]
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# Generated by Django 5.1.4 on 2024-12-19 22:21
|
2
|
+
|
3
|
+
import wagtail.fields
|
4
|
+
from django.db import migrations
|
5
|
+
|
6
|
+
|
7
|
+
class Migration(migrations.Migration):
|
8
|
+
dependencies = [
|
9
|
+
("hpk", "0002_alter_article_content_alter_basicpage_content"),
|
10
|
+
]
|
11
|
+
|
12
|
+
operations = [
|
13
|
+
migrations.AlterField(
|
14
|
+
model_name="article",
|
15
|
+
name="content",
|
16
|
+
field=wagtail.fields.StreamField(
|
17
|
+
[("section", 5), ("code", 8), ("image", 3)],
|
18
|
+
blank=True,
|
19
|
+
block_lookup={
|
20
|
+
0: (
|
21
|
+
"wagtail.blocks.CharBlock",
|
22
|
+
(),
|
23
|
+
{"help_text": "Heading for this section.", "required": True},
|
24
|
+
),
|
25
|
+
1: (
|
26
|
+
"wagtail.blocks.IntegerBlock",
|
27
|
+
(),
|
28
|
+
{
|
29
|
+
"help_text": "Heading level",
|
30
|
+
"max_value": 6,
|
31
|
+
"min_value": 1,
|
32
|
+
"required": True,
|
33
|
+
},
|
34
|
+
),
|
35
|
+
2: (
|
36
|
+
"wagtail.blocks.RichTextBlock",
|
37
|
+
(),
|
38
|
+
{"features": ["bold", "italic", "link", "ul", "ol", "document-link"]},
|
39
|
+
),
|
40
|
+
3: ("wagtail.images.blocks.ImageChooserBlock", (), {}),
|
41
|
+
4: (
|
42
|
+
"wagtail.blocks.StreamBlock",
|
43
|
+
[[("rich_text", 2), ("image", 3)]],
|
44
|
+
{"help_text": "Content blocks for this section.", "required": False},
|
45
|
+
),
|
46
|
+
5: (
|
47
|
+
"wagtail.blocks.StructBlock",
|
48
|
+
[[("heading", 0), ("level", 1), ("content", 4)]],
|
49
|
+
{},
|
50
|
+
),
|
51
|
+
6: ("wagtail.blocks.TextBlock", (), {"help_text": None, "required": True}),
|
52
|
+
7: (
|
53
|
+
"wagtail.blocks.ChoiceBlock",
|
54
|
+
[],
|
55
|
+
{
|
56
|
+
"choices": [
|
57
|
+
("python", "Python"),
|
58
|
+
("javascript", "JavaScript"),
|
59
|
+
("html", "HTML"),
|
60
|
+
("css", "CSS"),
|
61
|
+
("bash", "Bash"),
|
62
|
+
("plaintext", "Plain Text"),
|
63
|
+
],
|
64
|
+
"help_text": "Select the language for syntax highlighting.",
|
65
|
+
"required": False,
|
66
|
+
},
|
67
|
+
),
|
68
|
+
8: ("wagtail.blocks.StructBlock", [[("code", 6), ("language", 7)]], {}),
|
69
|
+
},
|
70
|
+
help_text="Main content for the article.",
|
71
|
+
),
|
72
|
+
),
|
73
|
+
migrations.AlterField(
|
74
|
+
model_name="basicpage",
|
75
|
+
name="content",
|
76
|
+
field=wagtail.fields.StreamField(
|
77
|
+
[("rich_text", 0), ("code", 3), ("image", 4)],
|
78
|
+
blank=True,
|
79
|
+
block_lookup={
|
80
|
+
0: ("wagtail.blocks.RichTextBlock", (), {}),
|
81
|
+
1: ("wagtail.blocks.TextBlock", (), {"help_text": None, "required": True}),
|
82
|
+
2: (
|
83
|
+
"wagtail.blocks.ChoiceBlock",
|
84
|
+
[],
|
85
|
+
{
|
86
|
+
"choices": [
|
87
|
+
("python", "Python"),
|
88
|
+
("javascript", "JavaScript"),
|
89
|
+
("html", "HTML"),
|
90
|
+
("css", "CSS"),
|
91
|
+
("bash", "Bash"),
|
92
|
+
("plaintext", "Plain Text"),
|
93
|
+
],
|
94
|
+
"help_text": "Select the language for syntax highlighting.",
|
95
|
+
"required": False,
|
96
|
+
},
|
97
|
+
),
|
98
|
+
3: ("wagtail.blocks.StructBlock", [[("code", 1), ("language", 2)]], {}),
|
99
|
+
4: ("wagtail.images.blocks.ImageChooserBlock", (), {}),
|
100
|
+
},
|
101
|
+
help_text="Main content for the page.",
|
102
|
+
),
|
103
|
+
),
|
104
|
+
]
|