picata 0.0.1__py3-none-any.whl

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 (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
+ ]