picata 0.0.1__tar.gz → 0.0.3__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. {picata-0.0.1 → picata-0.0.3}/.gitignore +1 -0
  2. picata-0.0.3/PKG-INFO +102 -0
  3. picata-0.0.3/README.md +51 -0
  4. {picata-0.0.1 → picata-0.0.3}/manage.py +1 -1
  5. picata-0.0.3/picata/__init__.py +1 -0
  6. {picata-0.0.1 → picata-0.0.3}/picata/apps.py +6 -6
  7. {picata-0.0.1 → picata-0.0.3}/picata/blocks.py +3 -2
  8. {picata-0.0.1 → picata-0.0.3}/picata/helpers/wagtail.py +1 -1
  9. {picata-0.0.1 → picata-0.0.3}/picata/middleware.py +1 -1
  10. picata-0.0.3/picata/migrations/0001_initial.py +130 -0
  11. {picata-0.0.1 → picata-0.0.3}/picata/models.py +6 -5
  12. {picata-0.0.1 → picata-0.0.3}/picata/settings/base.py +15 -15
  13. {picata-0.0.1 → picata-0.0.3}/picata/settings/dev.py +4 -2
  14. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/base.html +3 -3
  15. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/previews/theme_gallery.html +1 -1
  16. {picata-0.0.1 → picata-0.0.3}/picata/templatetags/absolute_static.py +1 -1
  17. picata-0.0.3/picata/templatetags/menu_tags.py +56 -0
  18. {picata-0.0.1 → picata-0.0.3}/picata/transformers.py +1 -1
  19. {picata-0.0.1 → picata-0.0.3}/picata/typing/__init__.py +1 -1
  20. {picata-0.0.1 → picata-0.0.3}/picata/typing/wagtail.py +1 -1
  21. {picata-0.0.1 → picata-0.0.3}/picata/urls.py +2 -2
  22. {picata-0.0.1 → picata-0.0.3}/picata/views.py +3 -2
  23. {picata-0.0.1 → picata-0.0.3}/picata/wagtail_hooks.py +1 -1
  24. {picata-0.0.1 → picata-0.0.3}/picata/wsgi.py +2 -2
  25. {picata-0.0.1 → picata-0.0.3}/pyproject.toml +4 -10
  26. picata-0.0.1/PKG-INFO +0 -87
  27. picata-0.0.1/README.md +0 -59
  28. picata-0.0.1/picata/__init__.py +0 -1
  29. picata-0.0.1/picata/migrations/0001_initial.py +0 -264
  30. picata-0.0.1/picata/migrations/0002_alter_article_content_alter_basicpage_content.py +0 -112
  31. picata-0.0.1/picata/migrations/0003_alter_article_content_alter_basicpage_content.py +0 -104
  32. picata-0.0.1/picata/migrations/0004_alter_article_content_alter_basicpage_content.py +0 -105
  33. picata-0.0.1/picata/migrations/0005_socialsettings.py +0 -48
  34. picata-0.0.1/picata/migrations/0006_alter_article_content.py +0 -71
  35. picata-0.0.1/picata/migrations/0007_splitviewpage.py +0 -69
  36. picata-0.0.1/picata/migrations/0008_alter_splitviewpage_content.py +0 -96
  37. picata-0.0.1/picata/migrations/0009_alter_splitviewpage_content.py +0 -111
  38. picata-0.0.1/picata/migrations/0010_alter_splitviewpage_content.py +0 -105
  39. picata-0.0.1/picata/migrations/0011_alter_splitviewpage_options_and_more.py +0 -113
  40. picata-0.0.1/picata/migrations/0012_alter_splitviewpage_content.py +0 -109
  41. picata-0.0.1/picata/migrations/0013_alter_article_content.py +0 -43
  42. picata-0.0.1/picata/migrations/0014_alter_article_content_alter_article_summary.py +0 -24
  43. picata-0.0.1/picata/migrations/0015_alter_article_options_article_tagline_and_more.py +0 -28
  44. picata-0.0.1/picata/migrations/0016_alter_article_options_alter_articletag_options_and_more.py +0 -33
  45. picata-0.0.1/picata/migrations/0017_articletagrelation_alter_article_tags_and_more.py +0 -35
  46. picata-0.0.1/picata/migrations/0018_rename_articletag_pagetag_and_more.py +0 -21
  47. picata-0.0.1/picata/migrations/0019_rename_name_plural_articletype__name_plural.py +0 -18
  48. picata-0.0.1/picata/migrations/0020_rename__name_plural_articletype__pluralised_name.py +0 -18
  49. picata-0.0.1/picata/migrations/0021_rename_article_type_article_page_type.py +0 -18
  50. picata-0.0.1/picata/migrations/0022_homepage.py +0 -28
  51. picata-0.0.1/picata/templatetags/menu_tags.py +0 -42
  52. {picata-0.0.1 → picata-0.0.3}/LICENSE.md +0 -0
  53. {picata-0.0.1 → picata-0.0.3}/components/HelloWorld.tsx +0 -0
  54. {picata-0.0.1 → picata-0.0.3}/entrypoint.tsx +0 -0
  55. {picata-0.0.1 → picata-0.0.3}/picata/helpers/__init__.py +0 -0
  56. {picata-0.0.1 → picata-0.0.3}/picata/log_utils.py +0 -0
  57. {picata-0.0.1 → picata-0.0.3}/picata/migrations/__init__.py +0 -0
  58. {picata-0.0.1 → picata-0.0.3}/picata/settings/__init__.py +0 -0
  59. {picata-0.0.1 → picata-0.0.3}/picata/settings/mypy.py +0 -0
  60. {picata-0.0.1 → picata-0.0.3}/picata/settings/prod.py +0 -0
  61. {picata-0.0.1 → picata-0.0.3}/picata/settings/test.py +0 -0
  62. {picata-0.0.1 → picata-0.0.3}/picata/static/picata/ada-profile.jpg +0 -0
  63. {picata-0.0.1 → picata-0.0.3}/picata/static/picata/ada-social-bear.jpg +0 -0
  64. {picata-0.0.1 → picata-0.0.3}/picata/static/picata/favicon.ico +0 -0
  65. {picata-0.0.1 → picata-0.0.3}/picata/static/picata/fonts/Bitter-Light.ttf +0 -0
  66. {picata-0.0.1 → picata-0.0.3}/picata/static/picata/fonts/Bitter-LightItalic.ttf +0 -0
  67. {picata-0.0.1 → picata-0.0.3}/picata/static/picata/fonts/FiraCode-Light.ttf +0 -0
  68. {picata-0.0.1 → picata-0.0.3}/picata/static/picata/fonts/FiraCode-SemiBold.ttf +0 -0
  69. {picata-0.0.1 → picata-0.0.3}/picata/static/picata/fonts/Sacramento-Regular.ttf +0 -0
  70. {picata-0.0.1 → picata-0.0.3}/picata/static/picata/fonts/ZillaSlab-Bold.ttf +0 -0
  71. {picata-0.0.1 → picata-0.0.3}/picata/static/picata/fonts/ZillaSlab-BoldItalic.ttf +0 -0
  72. {picata-0.0.1 → picata-0.0.3}/picata/static/picata/fonts/ZillaSlab-Light.ttf +0 -0
  73. {picata-0.0.1 → picata-0.0.3}/picata/static/picata/fonts/ZillaSlab-LightItalic.ttf +0 -0
  74. {picata-0.0.1 → picata-0.0.3}/picata/static/picata/fonts/ZillaSlabHighlight-Bold.ttf +0 -0
  75. {picata-0.0.1 → picata-0.0.3}/picata/static/picata/icons.svg +0 -0
  76. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/3_column.html +0 -0
  77. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/404.html +0 -0
  78. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/500.html +0 -0
  79. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/_post_list.html +0 -0
  80. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/article.html +0 -0
  81. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/basic_page.html +0 -0
  82. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/blocks/icon_link_item.html +0 -0
  83. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/blocks/icon_link_list.html +0 -0
  84. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/blocks/icon_link_list_stream.html +0 -0
  85. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/dl_view.html +0 -0
  86. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/home_page.html +0 -0
  87. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/post_listing.html +0 -0
  88. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/previews/3col.html +0 -0
  89. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/previews/dl.html +0 -0
  90. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/previews/split.html +0 -0
  91. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/search_results.html +0 -0
  92. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/split_view.html +0 -0
  93. {picata-0.0.1 → picata-0.0.3}/picata/templates/picata/tags/site_menu.html +0 -0
  94. {picata-0.0.1 → picata-0.0.3}/picata/templatetags/__init__.py +0 -0
  95. {picata-0.0.1 → picata-0.0.3}/picata/templatetags/stringify.py +0 -0
  96. {picata-0.0.1 → picata-0.0.3}/picata/validators.py +0 -0
  97. {picata-0.0.1 → picata-0.0.3}/pygments.sass +0 -0
  98. {picata-0.0.1 → picata-0.0.3}/styles.sass +0 -0
@@ -11,6 +11,7 @@ terraform.tfstate.d/
11
11
  infra/dot_env.tfvars
12
12
 
13
13
  build/
14
+ dist/
14
15
  lib/
15
16
  media/
16
17
  static/
picata-0.0.3/PKG-INFO ADDED
@@ -0,0 +1,102 @@
1
+ Metadata-Version: 2.4
2
+ Name: picata
3
+ Version: 0.0.3
4
+ Summary: Ada's Wagtail-based CMS & blog
5
+ Project-URL: Documentation, https://github.com/hipikat/picata#readme
6
+ Project-URL: Issues, https://github.com/hipikat/picata/issues
7
+ Project-URL: Source, https://github.com/hipikat/picata
8
+ Author-email: Ada Wright <ada@hpk.io>
9
+ License: # The MIT License (MIT)
10
+
11
+ Copyright © `2024` `Ada Wright <ada@hpk.io>`
12
+
13
+ Permission is hereby granted, free of charge, to any person
14
+ obtaining a copy of this software and associated documentation
15
+ files (the “Software”), to deal in the Software without
16
+ restriction, including without limitation the rights to use,
17
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the
19
+ Software is furnished to do so, subject to the following
20
+ conditions:
21
+
22
+ The above copyright notice and this permission notice shall be
23
+ included in all copies or substantial portions of the Software.
24
+
25
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
26
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
27
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
29
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
30
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
32
+ OTHER DEALINGS IN THE SOFTWARE.
33
+ License-File: LICENSE.md
34
+ Keywords: blog,cms,django,wagtail
35
+ Classifier: Development Status :: 2 - Pre-Alpha
36
+ Classifier: Framework :: Django CMS
37
+ Classifier: Framework :: Wagtail :: 6
38
+ Classifier: Programming Language :: Python
39
+ Classifier: Programming Language :: Python :: 3.13
40
+ Classifier: Programming Language :: Python :: Implementation :: CPython
41
+ Requires-Python: >=3.13
42
+ Requires-Dist: gunicorn~=23.0.0
43
+ Requires-Dist: lxml~=5.3.0
44
+ Requires-Dist: psutil~=6.1.0
45
+ Requires-Dist: psycopg~=3.2.3
46
+ Requires-Dist: pygments~=2.18.0
47
+ Requires-Dist: python-slugify~=8.0.4
48
+ Requires-Dist: wagtail-modeladmin~=2.1.0
49
+ Requires-Dist: wagtail~=6.2
50
+ Description-Content-Type: text/markdown
51
+
52
+ # Picata
53
+
54
+ **_This project is very much pre-alpha_**
55
+
56
+ Picata is a CMS & blog application I forked off from my personal website. At the
57
+ moment it's effectively a ton of pre-made [Wagtail](https://wagtail.org) "stuff"
58
+ (models, views, templatetags, middleware, hooks, etc.), made generic enough that
59
+ you can `pip install` the package, add it to your `INSTALLED_APPS`, and have a
60
+ CMS/blog up-and-running without having to spend weeks or months tailoring Wagtail
61
+ to your needs.
62
+
63
+ It's still under heavy development, with most documentation and a project
64
+ template pending but - if you're already working with Wagtail - the source
65
+ provides many working solutions to common problems. The repo for the aforementioned
66
+ personal website [lives on GitHub](https://github.com/hipikat/hpk.io), and
67
+ demonstrates a working implementation of this package (requiring, in fact, only
68
+ this package as a dependency).
69
+
70
+ ## What's in the box?
71
+
72
+ - [Wagtail](https://wagtail.org) (on [Django](https://www.djangoproject.com)) as the CMS & web frameworks
73
+ - Runs on [PostgreSQL](https://www.postgresql.org); loaded with scripts for managing the
74
+ database lifecycle and snapshots
75
+ - [Tailwind CSS](https://tailwindcss.com) in [Sass](https://sass-lang.com) for front-end styling
76
+ - [lxml](https://lxml.de) is used for fast HTML processing in a middleware layer
77
+
78
+ ### Development features & workflows
79
+
80
+ Everything's written in very modern Python (circa 2025), with agressive linting and type-checking
81
+ thanks to [mypy](https://mypy-lang.org),
82
+ [Pydantic](https://docs.pydantic.dev/latest/)/[Pyright](https://github.com/microsoft/pyright),
83
+ and [Ruff](https://docs.astral.sh/ruff/). Picata uses [Django Debug Toolbar](https://django-debug-toolbar.readthedocs.io),
84
+ [runserver_plus](https://django-extensions.readthedocs.io/en/latest/runserver_plus.html), and
85
+ [iPython](https://www.google.com/search?client=safari&rls=en&q=ipython&ie=UTF-8&oe=UTF-8) for
86
+ development workflows. The project itself uses [pre-commit](https://pre-commit.com) extensively,
87
+ with 16 hooks to keep everything neat and tidy.
88
+
89
+ All front-end code is written in [TypeScript](https://typescript-eslint.io), with
90
+ [React](https://react.dev) set up and ready-to-go in the [Webpack](https://webpack.js.org) pipeline,
91
+ if you're into that kind of thing.
92
+
93
+ ### Holding things together
94
+
95
+ - Uses [UV](https://github.com/astral-sh/uv) and
96
+ [pyproject.toml](https://packaging.python.org/en/latest/specifications/pyproject-toml/)
97
+ exclusively for Python project management
98
+ - [Just](https://just.systems) as a task runner, with over 60 recipes (at last count)
99
+ - [OpenTofu](https://opentofu.org) (a fork of [Terraform](https://www.terraform.io)) and
100
+ [cloud-init](https://cloud-init.io) for all DevOps & rapid deployment
101
+ - [Docker](https://www.docker.com) and [Docker Compose](https://docs.docker.com/compose/) for local
102
+ development
picata-0.0.3/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # Picata
2
+
3
+ **_This project is very much pre-alpha_**
4
+
5
+ Picata is a CMS & blog application I forked off from my personal website. At the
6
+ moment it's effectively a ton of pre-made [Wagtail](https://wagtail.org) "stuff"
7
+ (models, views, templatetags, middleware, hooks, etc.), made generic enough that
8
+ you can `pip install` the package, add it to your `INSTALLED_APPS`, and have a
9
+ CMS/blog up-and-running without having to spend weeks or months tailoring Wagtail
10
+ to your needs.
11
+
12
+ It's still under heavy development, with most documentation and a project
13
+ template pending but - if you're already working with Wagtail - the source
14
+ provides many working solutions to common problems. The repo for the aforementioned
15
+ personal website [lives on GitHub](https://github.com/hipikat/hpk.io), and
16
+ demonstrates a working implementation of this package (requiring, in fact, only
17
+ this package as a dependency).
18
+
19
+ ## What's in the box?
20
+
21
+ - [Wagtail](https://wagtail.org) (on [Django](https://www.djangoproject.com)) as the CMS & web frameworks
22
+ - Runs on [PostgreSQL](https://www.postgresql.org); loaded with scripts for managing the
23
+ database lifecycle and snapshots
24
+ - [Tailwind CSS](https://tailwindcss.com) in [Sass](https://sass-lang.com) for front-end styling
25
+ - [lxml](https://lxml.de) is used for fast HTML processing in a middleware layer
26
+
27
+ ### Development features & workflows
28
+
29
+ Everything's written in very modern Python (circa 2025), with agressive linting and type-checking
30
+ thanks to [mypy](https://mypy-lang.org),
31
+ [Pydantic](https://docs.pydantic.dev/latest/)/[Pyright](https://github.com/microsoft/pyright),
32
+ and [Ruff](https://docs.astral.sh/ruff/). Picata uses [Django Debug Toolbar](https://django-debug-toolbar.readthedocs.io),
33
+ [runserver_plus](https://django-extensions.readthedocs.io/en/latest/runserver_plus.html), and
34
+ [iPython](https://www.google.com/search?client=safari&rls=en&q=ipython&ie=UTF-8&oe=UTF-8) for
35
+ development workflows. The project itself uses [pre-commit](https://pre-commit.com) extensively,
36
+ with 16 hooks to keep everything neat and tidy.
37
+
38
+ All front-end code is written in [TypeScript](https://typescript-eslint.io), with
39
+ [React](https://react.dev) set up and ready-to-go in the [Webpack](https://webpack.js.org) pipeline,
40
+ if you're into that kind of thing.
41
+
42
+ ### Holding things together
43
+
44
+ - Uses [UV](https://github.com/astral-sh/uv) and
45
+ [pyproject.toml](https://packaging.python.org/en/latest/specifications/pyproject-toml/)
46
+ exclusively for Python project management
47
+ - [Just](https://just.systems) as a task runner, with over 60 recipes (at last count)
48
+ - [OpenTofu](https://opentofu.org) (a fork of [Terraform](https://www.terraform.io)) and
49
+ [cloud-init](https://cloud-init.io) for all DevOps & rapid deployment
50
+ - [Docker](https://www.docker.com) and [Docker Compose](https://docs.docker.com/compose/) for local
51
+ development
@@ -5,7 +5,7 @@ from os import environ
5
5
  from sys import argv
6
6
 
7
7
  if __name__ == "__main__":
8
- environ.setdefault("DJANGO_SETTINGS_MODULE", "hpk.settings.dev")
8
+ environ.setdefault("DJANGO_SETTINGS_MODULE", "picata.settings.dev")
9
9
 
10
10
  if len(argv) >= 2: # noqa: PLR2004
11
11
  environ.setdefault("DJANGO_MANAGEMENT_COMMAND", argv[1])
@@ -0,0 +1 @@
1
+ """Top-level package for the Picata project."""
@@ -1,13 +1,13 @@
1
- """Application configuration for the hpk Django app."""
1
+ """Application configuration for the Picata Django app."""
2
2
 
3
3
  from django.apps import AppConfig
4
4
 
5
5
 
6
6
  class Config(AppConfig):
7
- """Configuration class for the hpk Django application."""
7
+ """Configuration class for the Picata Django application."""
8
8
 
9
9
  default_auto_field = "django.db.models.BigAutoField"
10
- name = "hpk"
10
+ name = "picata"
11
11
 
12
12
  def ready(self) -> None:
13
13
  """Configure Wagtail admin with custom models, and register document transformers."""
@@ -15,13 +15,13 @@ class Config(AppConfig):
15
15
  # Register the 'custom article type' model with the Wagtail admin
16
16
  from wagtail_modeladmin.options import modeladmin_register
17
17
 
18
- from hpk.models import ArticleTypeAdmin
18
+ from picata.models import ArticleTypeAdmin
19
19
 
20
20
  modeladmin_register(ArticleTypeAdmin)
21
21
 
22
22
  # Add document transformers to the HTMLProcessingMiddleware
23
- from hpk.middleware import HTMLProcessingMiddleware
24
- from hpk.transformers import AnchorInserter, add_heading_ids
23
+ from picata.middleware import HTMLProcessingMiddleware
24
+ from picata.transformers import AnchorInserter, add_heading_ids
25
25
 
26
26
  ## Add ids to all headings missing them within html > body > main
27
27
  HTMLProcessingMiddleware.add_transformer(add_heading_ids)
@@ -3,8 +3,6 @@
3
3
  import pygments
4
4
  from django.forms import CharField
5
5
  from django.utils.html import format_html
6
- from hpk.typing.wagtail import BlockRenderContext, BlockRenderValue
7
- from hpk.validators import HREFValidator
8
6
  from pygments import formatters, lexers
9
7
  from pygments.util import ClassNotFound
10
8
  from wagtail.blocks import (
@@ -20,6 +18,9 @@ from wagtail.blocks import (
20
18
  )
21
19
  from wagtail.images.blocks import ImageChooserBlock
22
20
 
21
+ from picata.typing.wagtail import BlockRenderContext, BlockRenderValue
22
+ from picata.validators import HREFValidator
23
+
23
24
 
24
25
  class HREFField(CharField):
25
26
  """Custom field for href attributes (i.e. URLs but also schemes like 'mailto:')."""
@@ -8,7 +8,7 @@ from django.http import HttpRequest
8
8
  from wagtail.models import Page
9
9
  from wagtail.query import PageQuerySet
10
10
 
11
- from hpk.models import TaggedPage
11
+ from picata.models import TaggedPage
12
12
 
13
13
  from . import get_models_of_type
14
14
 
@@ -8,7 +8,7 @@ from typing import ClassVar
8
8
  from django.http import HttpRequest, HttpResponse
9
9
  from lxml import etree
10
10
 
11
- from hpk.helpers import make_response
11
+ from picata.helpers import make_response
12
12
 
13
13
  logger = logging.getLogger(__name__)
14
14
 
@@ -0,0 +1,130 @@
1
+ # Generated by Django 5.1.5 on 2025-01-24 00:18
2
+
3
+ import django.db.models.deletion
4
+ import modelcluster.contrib.taggit
5
+ import modelcluster.fields
6
+ import wagtail.contrib.routable_page.models
7
+ import wagtail.fields
8
+ from django.db import migrations, models
9
+
10
+
11
+ class Migration(migrations.Migration):
12
+
13
+ initial = True
14
+
15
+ dependencies = [
16
+ ('wagtailcore', '0094_alter_page_locale'),
17
+ ('wagtailimages', '0027_image_description'),
18
+ ]
19
+
20
+ operations = [
21
+ migrations.CreateModel(
22
+ name='ArticleType',
23
+ fields=[
24
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
25
+ ('name', models.CharField(help_text='Name of the article type.', max_length=100, unique=True)),
26
+ ('_Pluralised_name', models.CharField(blank=True, help_text="Plural form of the article type name (optional). Defaults to appending 's'.", max_length=100)),
27
+ ('slug', models.SlugField(max_length=100, unique=True)),
28
+ ('description', models.TextField(blank=True, help_text='Optional description of this type.')),
29
+ ],
30
+ ),
31
+ migrations.CreateModel(
32
+ name='BasicPage',
33
+ fields=[
34
+ ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
35
+ ('content', wagtail.fields.StreamField([('rich_text', 0), ('code', 3), ('image', 4)], blank=True, block_lookup={0: ('wagtail.blocks.RichTextBlock', (), {}), 1: ('wagtail.blocks.TextBlock', (), {'help_text': None, 'required': True}), 2: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('python', 'Python'), ('javascript', 'JavaScript'), ('html', 'HTML'), ('css', 'CSS'), ('bash', 'Bash'), ('plaintext', 'Plain Text')], 'required': False}), 3: ('wagtail.blocks.StructBlock', [[('code', 1), ('language', 2)]], {}), 4: ('wagtail.images.blocks.ImageChooserBlock', (), {})}, help_text='Main content for the page.')),
36
+ ],
37
+ options={
38
+ 'abstract': False,
39
+ },
40
+ bases=('wagtailcore.page',),
41
+ ),
42
+ migrations.CreateModel(
43
+ name='HomePage',
44
+ fields=[
45
+ ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
46
+ ('top_content', wagtail.fields.StreamField([('rich_text', 0), ('image', 1), ('icon_link_lists', 11)], blank=True, block_lookup={0: ('wagtail.blocks.RichTextBlock', (), {}), 1: ('picata.blocks.WrappedImageChooserBlock', (), {}), 2: ('wagtail.blocks.CharBlock', (), {'help_text': 'Optional heading for this list (e.g., Social Links).', 'required': False}), 3: ('wagtail.blocks.IntegerBlock', (), {'default': 2, 'help_text': 'Heading level for the list (1-6).', 'max_value': 6, 'min_value': 1, 'required': False}), 4: ('picata.blocks.HREFBlock', (), {'help_text': 'An optional link field', 'max_length': 255, 'required': False}), 5: ('wagtail.blocks.CharBlock', (), {'help_text': 'The title for the list item.', 'max_length': 50, 'required': True}), 6: ('wagtail.blocks.CharBlock', (), {'help_text': 'Id of the icon in the static/icons.svg file.', 'max_length': 255, 'required': False}), 7: ('wagtail.blocks.StructBlock', [[('href', 4), ('label', 5), ('icon', 6)]], {}), 8: ('wagtail.blocks.ListBlock', (7,), {'help_text': 'The list of items.'}), 9: ('wagtail.blocks.StructBlock', [[('heading', 2), ('heading_level', 3), ('items', 8)]], {}), 10: ('wagtail.blocks.StreamBlock', [[('link_list', 9)]], {'help_text': 'Add one or more heading-and-link-list blocks.', 'required': False}), 11: ('wagtail.blocks.StructBlock', [[('lists', 10)]], {})}, help_text="Content stream above 'Recent posts'")),
47
+ ('bottom_content', wagtail.fields.StreamField([('rich_text', 0), ('image', 1), ('icon_link_lists', 11)], blank=True, block_lookup={0: ('wagtail.blocks.RichTextBlock', (), {}), 1: ('picata.blocks.WrappedImageChooserBlock', (), {}), 2: ('wagtail.blocks.CharBlock', (), {'help_text': 'Optional heading for this list (e.g., Social Links).', 'required': False}), 3: ('wagtail.blocks.IntegerBlock', (), {'default': 2, 'help_text': 'Heading level for the list (1-6).', 'max_value': 6, 'min_value': 1, 'required': False}), 4: ('picata.blocks.HREFBlock', (), {'help_text': 'An optional link field', 'max_length': 255, 'required': False}), 5: ('wagtail.blocks.CharBlock', (), {'help_text': 'The title for the list item.', 'max_length': 50, 'required': True}), 6: ('wagtail.blocks.CharBlock', (), {'help_text': 'Id of the icon in the static/icons.svg file.', 'max_length': 255, 'required': False}), 7: ('wagtail.blocks.StructBlock', [[('href', 4), ('label', 5), ('icon', 6)]], {}), 8: ('wagtail.blocks.ListBlock', (7,), {'help_text': 'The list of items.'}), 9: ('wagtail.blocks.StructBlock', [[('heading', 2), ('heading_level', 3), ('items', 8)]], {}), 10: ('wagtail.blocks.StreamBlock', [[('link_list', 9)]], {'help_text': 'Add one or more heading-and-link-list blocks.', 'required': False}), 11: ('wagtail.blocks.StructBlock', [[('lists', 10)]], {})}, help_text="Content stream rendered under 'Recent posts'")),
48
+ ],
49
+ options={
50
+ 'verbose_name': 'home page',
51
+ },
52
+ bases=('wagtailcore.page',),
53
+ ),
54
+ migrations.CreateModel(
55
+ name='PageTag',
56
+ fields=[
57
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
58
+ ('name', models.CharField(max_length=100, unique=True, verbose_name='name')),
59
+ ('slug', models.SlugField(allow_unicode=True, max_length=100, unique=True, verbose_name='slug')),
60
+ ],
61
+ options={
62
+ 'abstract': False,
63
+ },
64
+ ),
65
+ migrations.CreateModel(
66
+ name='PostGroupPage',
67
+ fields=[
68
+ ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
69
+ ('intro', wagtail.fields.RichTextField(blank=True, help_text='An optional introduction to this group.')),
70
+ ],
71
+ options={
72
+ 'verbose_name': 'post listing',
73
+ 'verbose_name_plural': 'post listings',
74
+ },
75
+ bases=(wagtail.contrib.routable_page.models.RoutablePageMixin, 'wagtailcore.page'),
76
+ ),
77
+ migrations.CreateModel(
78
+ name='SplitViewPage',
79
+ fields=[
80
+ ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
81
+ ('content', wagtail.fields.StreamField([('rich_text', 0), ('code', 3), ('image', 4), ('icon_link_lists', 14)], blank=True, block_lookup={0: ('wagtail.blocks.RichTextBlock', (), {}), 1: ('wagtail.blocks.TextBlock', (), {'help_text': None, 'required': True}), 2: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('python', 'Python'), ('javascript', 'JavaScript'), ('html', 'HTML'), ('css', 'CSS'), ('bash', 'Bash'), ('plaintext', 'Plain Text')], 'required': False}), 3: ('wagtail.blocks.StructBlock', [[('code', 1), ('language', 2)]], {}), 4: ('picata.blocks.WrappedImageChooserBlock', (), {}), 5: ('wagtail.blocks.CharBlock', (), {'help_text': 'Optional heading for this list (e.g., Social Links).', 'required': False}), 6: ('wagtail.blocks.IntegerBlock', (), {'default': 2, 'help_text': 'Heading level for the list (1-6).', 'max_value': 6, 'min_value': 1, 'required': False}), 7: ('picata.blocks.HREFBlock', (), {'help_text': 'An optional link field', 'max_length': 255, 'required': False}), 8: ('wagtail.blocks.CharBlock', (), {'help_text': 'The title for the list item.', 'max_length': 50, 'required': True}), 9: ('wagtail.blocks.CharBlock', (), {'help_text': 'Id of the icon in the static/icons.svg file.', 'max_length': 255, 'required': False}), 10: ('wagtail.blocks.StructBlock', [[('href', 7), ('label', 8), ('icon', 9)]], {}), 11: ('wagtail.blocks.ListBlock', (10,), {'help_text': 'The list of items.'}), 12: ('wagtail.blocks.StructBlock', [[('heading', 5), ('heading_level', 6), ('items', 11)]], {}), 13: ('wagtail.blocks.StreamBlock', [[('link_list', 12)]], {'help_text': 'Add one or more heading-and-link-list blocks.', 'required': False}), 14: ('wagtail.blocks.StructBlock', [[('lists', 13)]], {})}, help_text='Main content for the split-view page.')),
82
+ ],
83
+ options={
84
+ 'verbose_name': 'split-view page',
85
+ 'verbose_name_plural': 'split-view pages',
86
+ },
87
+ bases=('wagtailcore.page',),
88
+ ),
89
+ migrations.CreateModel(
90
+ name='Article',
91
+ fields=[
92
+ ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
93
+ ('tagline', models.CharField(blank=True, help_text='A short tagline for the article.')),
94
+ ('summary', wagtail.fields.RichTextField(blank=True, help_text='A summary to be displayed in previews.')),
95
+ ('content', wagtail.fields.StreamField([('rich_text', 0), ('code', 3), ('image', 4)], blank=True, block_lookup={0: ('wagtail.blocks.RichTextBlock', (), {}), 1: ('wagtail.blocks.TextBlock', (), {'help_text': None, 'required': True}), 2: ('wagtail.blocks.ChoiceBlock', [], {'choices': [('python', 'Python'), ('javascript', 'JavaScript'), ('html', 'HTML'), ('css', 'CSS'), ('bash', 'Bash'), ('plaintext', 'Plain Text')], 'required': False}), 3: ('wagtail.blocks.StructBlock', [[('code', 1), ('language', 2)]], {}), 4: ('wagtail.images.blocks.ImageChooserBlock', (), {})}, help_text='Main content for the article.')),
96
+ ('page_type', models.ForeignKey(blank=True, help_text='Select the type of article.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='articles', to='picata.articletype')),
97
+ ],
98
+ options={
99
+ 'abstract': False,
100
+ },
101
+ bases=('wagtailcore.page',),
102
+ ),
103
+ migrations.CreateModel(
104
+ name='PageTagRelation',
105
+ fields=[
106
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
107
+ ('content_object', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='tagged_items', to='picata.article')),
108
+ ('tag', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tagged_items', to='picata.pagetag')),
109
+ ],
110
+ options={
111
+ 'abstract': False,
112
+ },
113
+ ),
114
+ migrations.AddField(
115
+ model_name='article',
116
+ name='tags',
117
+ field=modelcluster.contrib.taggit.ClusterTaggableManager(blank=True, help_text='Tags for the article.', through='picata.PageTagRelation', to='picata.PageTag', verbose_name='Tags'),
118
+ ),
119
+ migrations.CreateModel(
120
+ name='SocialSettings',
121
+ fields=[
122
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
123
+ ('default_social_image', models.ForeignKey(blank=True, help_text='Default image for social media previews.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image')),
124
+ ('site', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, to='wagtailcore.site')),
125
+ ],
126
+ options={
127
+ 'abstract': False,
128
+ },
129
+ ),
130
+ ]
@@ -20,8 +20,6 @@ from django.db.models import (
20
20
  from django.db.models.functions import Coalesce, ExtractYear
21
21
  from django.http import HttpRequest
22
22
  from django.urls import reverse
23
- from hpk.typing import Args, Kwargs
24
- from hpk.typing.wagtail import PageContext
25
23
  from modelcluster.contrib.taggit import ClusterTaggableManager
26
24
  from modelcluster.fields import ParentalKey
27
25
  from taggit.models import TagBase, TaggedItemBase
@@ -37,6 +35,9 @@ from wagtail.query import PageQuerySet
37
35
  from wagtail.search import index
38
36
  from wagtail_modeladmin.options import ModelAdmin
39
37
 
38
+ from picata.typing import Args, Kwargs
39
+ from picata.typing.wagtail import PageContext
40
+
40
41
  from .blocks import (
41
42
  CodeBlock,
42
43
  StaticIconLinkListsBlock,
@@ -103,7 +104,7 @@ class BasePage(Page):
103
104
 
104
105
  def get_context(self, request: HttpRequest, *args: Args, **kwargs: Kwargs) -> BasePageContext:
105
106
  """Gather any publication and preview data available for the page into the context."""
106
- from hpk.helpers.wagtail import page_preview_data
107
+ from picata.helpers.wagtail import page_preview_data
107
108
 
108
109
  context = super().get_context(request, *args, **kwargs)
109
110
  context.update(page_preview_data(request, self))
@@ -356,7 +357,7 @@ class PostGroupPage(RoutablePageMixin, Page):
356
357
  """A top-level page for grouping various types of posts or articles."""
357
358
 
358
359
  template = "picata/post_listing.html"
359
- subpage_types: ClassVar[list[str]] = ["hpk.Article"]
360
+ subpage_types: ClassVar[list[str]] = ["picata.Article"]
360
361
 
361
362
  intro = RichTextField(blank=True, help_text="An optional introduction to this group.")
362
363
 
@@ -465,7 +466,7 @@ class HomePage(BasePage):
465
466
 
466
467
  def get_context(self, request: HttpRequest, *args: Args, **kwargs: Kwargs) -> HomePageContext:
467
468
  """Add content streams and a recent posts list to the context."""
468
- from hpk.helpers.wagtail import page_preview_data
469
+ from picata.helpers.wagtail import page_preview_data
469
470
 
470
471
  recent_posts = Article.objects.live_for_user(request.user).by_date()
471
472
  recent_posts = [page_preview_data(request, post) for post in recent_posts]
@@ -13,8 +13,8 @@ import contextlib
13
13
  from os import getenv
14
14
  from pathlib import Path
15
15
 
16
- from hpk.helpers import get_public_ip
17
- from hpk.log_utils import FormatterWithEverything
16
+ from picata.helpers import get_public_ip
17
+ from picata.log_utils import FormatterWithEverything
18
18
 
19
19
  SRC_DIR = Path(__file__).resolve().parent.parent.parent
20
20
  BASE_DIR = Path(SRC_DIR).parent
@@ -35,7 +35,7 @@ SECRET_KEY = getenv("SECRET_KEY")
35
35
 
36
36
  INSTALLED_APPS = [
37
37
  # Local apps
38
- "hpk.apps.Config",
38
+ "picata.apps.Config",
39
39
  # Wagtail
40
40
  "wagtail.contrib.forms",
41
41
  "wagtail.contrib.redirects",
@@ -72,10 +72,10 @@ MIDDLEWARE = [
72
72
  "django.middleware.clickjacking.XFrameOptionsMiddleware",
73
73
  "django.middleware.security.SecurityMiddleware",
74
74
  "wagtail.contrib.redirects.middleware.RedirectMiddleware",
75
- "hpk.middleware.HTMLProcessingMiddleware",
75
+ "picata.middleware.HTMLProcessingMiddleware",
76
76
  ]
77
77
 
78
- ROOT_URLCONF = "hpk.urls"
78
+ ROOT_URLCONF = "picata.urls"
79
79
 
80
80
  TEMPLATES = [
81
81
  {
@@ -94,7 +94,7 @@ TEMPLATES = [
94
94
  },
95
95
  ]
96
96
 
97
- WSGI_APPLICATION = "hpk.wsgi.application"
97
+ WSGI_APPLICATION = "picata.wsgi.application"
98
98
 
99
99
 
100
100
  # Database
@@ -103,7 +103,7 @@ WSGI_APPLICATION = "hpk.wsgi.application"
103
103
  DATABASES = {
104
104
  "default": {
105
105
  "ENGINE": "django.db.backends.postgresql",
106
- "NAME": getenv("DB_NAME"),
106
+ "NAME": getenv("PICATA_DB"),
107
107
  "USER": getenv("DB_USER"),
108
108
  "PASSWORD": getenv("DB_PASSWORD"),
109
109
  "HOST": getenv("DB_HOST", "localhost"),
@@ -158,14 +158,14 @@ LOGGING = {
158
158
  },
159
159
  "django_log": {
160
160
  "level": "INFO",
161
- "class": "hpk.log_utils.RotatingDailyFileHandler",
161
+ "class": "picata.log_utils.RotatingDailyFileHandler",
162
162
  "filename": LOG_DIR / "django.log",
163
163
  "formatter": "verbose",
164
164
  },
165
- "hpk_log": {
165
+ "picata_log": {
166
166
  "level": "INFO",
167
- "class": "hpk.log_utils.RotatingDailyFileHandler",
168
- "filename": LOG_DIR / "hpk.log",
167
+ "class": "picata.log_utils.RotatingDailyFileHandler",
168
+ "filename": LOG_DIR / "picata.log",
169
169
  "formatter": "verbose",
170
170
  },
171
171
  "warnings_log": {
@@ -178,8 +178,8 @@ LOGGING = {
178
178
  },
179
179
  },
180
180
  "loggers": {
181
- "hpk": {
182
- "handlers": ["hpk_log"],
181
+ "picata": {
182
+ "handlers": ["picata_log"],
183
183
  "level": "INFO",
184
184
  "propagate": True,
185
185
  },
@@ -279,7 +279,7 @@ DEFAULT_FROM_EMAIL = getenv("ADMIN_EMAIL")
279
279
  # Wagtail
280
280
  # See https://docs.wagtail.org/en/stable/
281
281
 
282
- WAGTAIL_SITE_NAME = "Hpk.io"
282
+ WAGTAIL_SITE_NAME = "[Example Site Name]"
283
283
 
284
284
  # Image serving
285
285
  WAGTAILIMAGES_IMAGE_MODEL = "wagtailimages.Image"
@@ -294,7 +294,7 @@ WAGTAILSEARCH_BACKENDS = {
294
294
 
295
295
  # Base URL to use when referring to full URLs within the Wagtail admin backend -
296
296
  # e.g. in notification emails. Don't include '/admin' or a trailing slash
297
- WAGTAILADMIN_BASE_URL = "https://" + getenv("FQDN", "hpk.io")
297
+ WAGTAILADMIN_BASE_URL = "https://" + getenv("FQDN", "example.com")
298
298
 
299
299
  # https://docs.wagtail.org/en/stable/reference/settings.html#general-editing
300
300
  WAGTAILADMIN_RICH_TEXT_EDITORS = {
@@ -31,7 +31,9 @@ ALLOWED_HOSTS += CLASS_C_NETWORK_ADDR
31
31
 
32
32
  if getenv("DJANGO_MANAGEMENT_COMMAND", "").startswith("runserver"):
33
33
  logger.warning(
34
- f"Loading hpk.settings.dev…\nINTERNAL_IPS = {INTERNAL_IPS}\nALLOWED_HOSTS = {ALLOWED_HOSTS}"
34
+ "Loading picata.settings.dev…\n"
35
+ f"INTERNAL_IPS = {INTERNAL_IPS}\n"
36
+ f"ALLOWED_HOSTS = {ALLOWED_HOSTS}"
35
37
  )
36
38
 
37
39
  RUNSERVERPLUS_POLLER_RELOADER_TYPE = "watchdog"
@@ -80,7 +82,7 @@ LOGGING["loggers"]["gunicorn"] = {
80
82
  "propagate": False,
81
83
  }
82
84
 
83
- LOGGING["loggers"]["hpk"]["level"] = "DEBUG"
85
+ LOGGING["loggers"]["picata"]["level"] = "DEBUG"
84
86
 
85
87
  LOGGING["loggers"]["django"]["level"] = "DEBUG"
86
88
  LOGGING["loggers"]["django.db.backends"] = {"level": "INFO"}
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover" />
6
- <title>{% block document_title %}{% if title %}{{ title }} · {% endif %}hpk.io{% endblock %}</title>
6
+ <title>{% block document_title %}{% if title %}{{ title }} · {% endif %}[Example Site]{% endblock %}</title>
7
7
 
8
8
  <style>
9
9
  @font-face { font-family: 'Sacramento'; src: url("{% static 'fonts/Sacramento-Regular.ttf' %}") format("truetype"); font-weight: 400; font-style: normal; }
@@ -25,7 +25,7 @@
25
25
 
26
26
  <meta property="og:title" content="{% block og_title %}Hpk.io{% endblock %}">
27
27
  <meta property="og:description" content="{% block og_description %}Ada Wrights's website - Hpk.io{% endblock %}">
28
- <meta property="og:image" content="{% block og_image %}{% if settings.hpk.SocialSettings.default_social_image %}{{ request.scheme }}://{{ request.get_host }}/{% image_url settings.hpk.SocialSettings.default_social_image 'fill-1200x630' %}{% else %}{% absolute_static 'ada-social-bear.jpg' %}{% endif %}{% endblock %}">
28
+ <meta property="og:image" content="{% block og_image %}{% if settings.picata.SocialSettings.default_social_image %}{{ request.scheme }}://{{ request.get_host }}/{% image_url settings.hpk.SocialSettings.default_social_image 'fill-1200x630' %}{% else %}{% absolute_static 'ada-social-bear.jpg' %}{% endif %}{% endblock %}">
29
29
  <meta property="og:url" content="{{ request.build_absolute_uri }}">
30
30
  <meta property="og:type" content="{% block og_type %}website{% endblock %}">
31
31
 
@@ -35,7 +35,7 @@
35
35
  "@type": "{% block ld_type %}WebPage{% endblock %}",
36
36
  "name": "{{ page.get_social_title }}",
37
37
  "description": "{{ page.get_social_description }}",
38
- "image": "{% block ld_image %}{% if settings.hpk.SocialSettings.default_social_image %}{{ request.scheme }}://{{ request.get_host }}/{% image_url settings.hpk.SocialSettings.default_social_image 'fill-1200x630' %}{% else %}{% absolute_static 'ada-social-bear.jpg' %}{% endif %}{% endblock %}",
38
+ "image": "{% block ld_image %}{% if settings.picata.SocialSettings.default_social_image %}{{ request.scheme }}://{{ request.get_host }}/{% image_url settings.picata.SocialSettings.default_social_image 'fill-1200x630' %}{% else %}{% absolute_static 'ada-social-bear.jpg' %}{% endif %}{% endblock %}",
39
39
  "url": "{{ request.build_absolute_uri }}"
40
40
  }
41
41
  </script>
@@ -5,7 +5,7 @@
5
5
  {% block title %}Theme gallery{% endblock %}
6
6
 
7
7
  {% block article %}
8
- <img src="{% if settings.hpk.SocialSettings.default_social_image %}{% image_url settings.hpk.SocialSettings.default_social_image 'fill-1200x630' %}{% endif %}" width="1200" height="630" />
8
+ <img src="{% if settings.picata.SocialSettings.default_social_image %}{% image_url settings.picata.SocialSettings.default_social_image 'fill-1200x630' %}{% endif %}" width="1200" height="630" />
9
9
  <div class="mx-8 my-8">
10
10
  <div class="grid grid-cols-2 gap-2 md:grid-cols-4">
11
11
  <button class="btn">Default</button>
@@ -3,7 +3,7 @@
3
3
  from django import template
4
4
  from django.templatetags.static import static
5
5
 
6
- from hpk.typing import Context
6
+ from picata.typing import Context
7
7
 
8
8
  register = template.Library()
9
9