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.
Files changed (94) hide show
  1. LICENSE.md +24 -0
  2. README.md +59 -0
  3. components/HelloWorld.tsx +11 -0
  4. entrypoint.tsx +268 -0
  5. manage.py +15 -0
  6. picata/__init__.py +1 -0
  7. picata/apps.py +33 -0
  8. picata/blocks.py +175 -0
  9. picata/helpers/__init__.py +70 -0
  10. picata/helpers/wagtail.py +61 -0
  11. picata/log_utils.py +47 -0
  12. picata/middleware.py +54 -0
  13. picata/migrations/0001_initial.py +264 -0
  14. picata/migrations/0002_alter_article_content_alter_basicpage_content.py +112 -0
  15. picata/migrations/0003_alter_article_content_alter_basicpage_content.py +104 -0
  16. picata/migrations/0004_alter_article_content_alter_basicpage_content.py +105 -0
  17. picata/migrations/0005_socialsettings.py +48 -0
  18. picata/migrations/0006_alter_article_content.py +71 -0
  19. picata/migrations/0007_splitviewpage.py +69 -0
  20. picata/migrations/0008_alter_splitviewpage_content.py +96 -0
  21. picata/migrations/0009_alter_splitviewpage_content.py +111 -0
  22. picata/migrations/0010_alter_splitviewpage_content.py +105 -0
  23. picata/migrations/0011_alter_splitviewpage_options_and_more.py +113 -0
  24. picata/migrations/0012_alter_splitviewpage_content.py +109 -0
  25. picata/migrations/0013_alter_article_content.py +43 -0
  26. picata/migrations/0014_alter_article_content_alter_article_summary.py +24 -0
  27. picata/migrations/0015_alter_article_options_article_tagline_and_more.py +28 -0
  28. picata/migrations/0016_alter_article_options_alter_articletag_options_and_more.py +33 -0
  29. picata/migrations/0017_articletagrelation_alter_article_tags_and_more.py +35 -0
  30. picata/migrations/0018_rename_articletag_pagetag_and_more.py +21 -0
  31. picata/migrations/0019_rename_name_plural_articletype__name_plural.py +18 -0
  32. picata/migrations/0020_rename__name_plural_articletype__pluralised_name.py +18 -0
  33. picata/migrations/0021_rename_article_type_article_page_type.py +18 -0
  34. picata/migrations/0022_homepage.py +28 -0
  35. picata/migrations/__init__.py +0 -0
  36. picata/models.py +486 -0
  37. picata/settings/__init__.py +1 -0
  38. picata/settings/base.py +345 -0
  39. picata/settings/dev.py +94 -0
  40. picata/settings/mypy.py +7 -0
  41. picata/settings/prod.py +12 -0
  42. picata/settings/test.py +6 -0
  43. picata/static/picata/ada-profile.jpg +0 -0
  44. picata/static/picata/ada-social-bear.jpg +0 -0
  45. picata/static/picata/favicon.ico +0 -0
  46. picata/static/picata/fonts/Bitter-Light.ttf +0 -0
  47. picata/static/picata/fonts/Bitter-LightItalic.ttf +0 -0
  48. picata/static/picata/fonts/FiraCode-Light.ttf +0 -0
  49. picata/static/picata/fonts/FiraCode-SemiBold.ttf +0 -0
  50. picata/static/picata/fonts/Sacramento-Regular.ttf +0 -0
  51. picata/static/picata/fonts/ZillaSlab-Bold.ttf +0 -0
  52. picata/static/picata/fonts/ZillaSlab-BoldItalic.ttf +0 -0
  53. picata/static/picata/fonts/ZillaSlab-Light.ttf +0 -0
  54. picata/static/picata/fonts/ZillaSlab-LightItalic.ttf +0 -0
  55. picata/static/picata/fonts/ZillaSlabHighlight-Bold.ttf +0 -0
  56. picata/static/picata/icons.svg +56 -0
  57. picata/templates/picata/3_column.html +28 -0
  58. picata/templates/picata/404.html +11 -0
  59. picata/templates/picata/500.html +13 -0
  60. picata/templates/picata/_post_list.html +24 -0
  61. picata/templates/picata/article.html +20 -0
  62. picata/templates/picata/base.html +135 -0
  63. picata/templates/picata/basic_page.html +10 -0
  64. picata/templates/picata/blocks/icon_link_item.html +7 -0
  65. picata/templates/picata/blocks/icon_link_list.html +4 -0
  66. picata/templates/picata/blocks/icon_link_list_stream.html +3 -0
  67. picata/templates/picata/dl_view.html +18 -0
  68. picata/templates/picata/home_page.html +21 -0
  69. picata/templates/picata/post_listing.html +17 -0
  70. picata/templates/picata/previews/3col.html +73 -0
  71. picata/templates/picata/previews/dl.html +10 -0
  72. picata/templates/picata/previews/split.html +10 -0
  73. picata/templates/picata/previews/theme_gallery.html +158 -0
  74. picata/templates/picata/search_results.html +28 -0
  75. picata/templates/picata/split_view.html +15 -0
  76. picata/templates/picata/tags/site_menu.html +8 -0
  77. picata/templatetags/__init__.py +1 -0
  78. picata/templatetags/absolute_static.py +15 -0
  79. picata/templatetags/menu_tags.py +42 -0
  80. picata/templatetags/stringify.py +23 -0
  81. picata/transformers.py +60 -0
  82. picata/typing/__init__.py +19 -0
  83. picata/typing/wagtail.py +31 -0
  84. picata/urls.py +48 -0
  85. picata/validators.py +36 -0
  86. picata/views.py +80 -0
  87. picata/wagtail_hooks.py +43 -0
  88. picata/wsgi.py +15 -0
  89. picata-0.0.1.dist-info/METADATA +87 -0
  90. picata-0.0.1.dist-info/RECORD +94 -0
  91. picata-0.0.1.dist-info/WHEEL +4 -0
  92. picata-0.0.1.dist-info/licenses/LICENSE.md +24 -0
  93. pygments.sass +382 -0
  94. 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
+ ]