django-prose-editor 0.20.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. django_prose_editor-0.20.0/.gitignore +27 -0
  2. django_prose_editor-0.20.0/LICENSE +45 -0
  3. django_prose_editor-0.20.0/PKG-INFO +70 -0
  4. django_prose_editor-0.20.0/README.rst +29 -0
  5. django_prose_editor-0.20.0/django_prose_editor/.gitignore +1 -0
  6. django_prose_editor-0.20.0/django_prose_editor/__init__.py +1 -0
  7. django_prose_editor-0.20.0/django_prose_editor/apps.py +9 -0
  8. django_prose_editor-0.20.0/django_prose_editor/checks.py +239 -0
  9. django_prose_editor-0.20.0/django_prose_editor/config.py +426 -0
  10. django_prose_editor-0.20.0/django_prose_editor/fields.py +178 -0
  11. django_prose_editor-0.20.0/django_prose_editor/locale/de/LC_MESSAGES/django.mo +0 -0
  12. django_prose_editor-0.20.0/django_prose_editor/locale/de/LC_MESSAGES/django.po +34 -0
  13. django_prose_editor-0.20.0/django_prose_editor/locale/de/LC_MESSAGES/djangojs.mo +0 -0
  14. django_prose_editor-0.20.0/django_prose_editor/locale/de/LC_MESSAGES/djangojs.po +141 -0
  15. django_prose_editor-0.20.0/django_prose_editor/sanitized.py +21 -0
  16. django_prose_editor-0.20.0/django_prose_editor/static/django_prose_editor/configurable.js +2 -0
  17. django_prose_editor-0.20.0/django_prose_editor/static/django_prose_editor/configurable.js.map +1 -0
  18. django_prose_editor-0.20.0/django_prose_editor/static/django_prose_editor/default.js +2 -0
  19. django_prose_editor-0.20.0/django_prose_editor/static/django_prose_editor/default.js.map +1 -0
  20. django_prose_editor-0.20.0/django_prose_editor/static/django_prose_editor/editor.css +2 -0
  21. django_prose_editor-0.20.0/django_prose_editor/static/django_prose_editor/editor.css.map +1 -0
  22. django_prose_editor-0.20.0/django_prose_editor/static/django_prose_editor/editor.js +117 -0
  23. django_prose_editor-0.20.0/django_prose_editor/static/django_prose_editor/editor.js.map +1 -0
  24. django_prose_editor-0.20.0/django_prose_editor/static/django_prose_editor/material-icons.css +2 -0
  25. django_prose_editor-0.20.0/django_prose_editor/static/django_prose_editor/material-icons.css.map +1 -0
  26. django_prose_editor-0.20.0/django_prose_editor/static/django_prose_editor/material-icons.woff2 +0 -0
  27. django_prose_editor-0.20.0/django_prose_editor/static/django_prose_editor/overrides.css +2 -0
  28. django_prose_editor-0.20.0/django_prose_editor/static/django_prose_editor/overrides.css.map +1 -0
  29. django_prose_editor-0.20.0/django_prose_editor/widgets.py +120 -0
  30. django_prose_editor-0.20.0/pyproject.toml +142 -0
@@ -0,0 +1,27 @@
1
+ *~
2
+ \#*#
3
+ /build
4
+ /.bundle
5
+ .coverage
6
+ /data.db
7
+ /dist
8
+ .DS_Store
9
+ /dump.rdb
10
+ *.egg-info
11
+ /.env
12
+ /htdocs/e
13
+ /.idea
14
+ /log
15
+ /media
16
+ /node_modules
17
+ *.pyc
18
+ /static
19
+ .*.sw*
20
+ /tmp
21
+ .tox
22
+ /vendor
23
+ /venv
24
+ /.vscode
25
+ yarn-error.log
26
+ build
27
+ test-results
@@ -0,0 +1,45 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2024, Feinheit AG
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+
31
+ --------------------------------------------------------------------------------
32
+
33
+ This software includes or depends on the following third-party libraries:
34
+
35
+ ProseMirror (MIT License)
36
+ Copyright (c) 2015-2017 by Marijn Haverbeke and others
37
+ https://prosemirror.net/
38
+
39
+ Tiptap (MIT License)
40
+ Copyright (c) 2024 Tiptap GmbH
41
+ https://tiptap.dev/
42
+
43
+ Material Design Icons (Apache License 2.0)
44
+ Copyright Google Inc.
45
+ https://fonts.google.com/icons
@@ -0,0 +1,70 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-prose-editor
3
+ Version: 0.20.0
4
+ Summary: Prose editor for the Django admin based on ProseMirror
5
+ Project-URL: Documentation, https://django-prose-editor.readthedocs.io/
6
+ Project-URL: Homepage, https://github.com/matthiask/django-prose-editor/
7
+ Author-email: Matthias Kestenholz <mk@feinheit.ch>
8
+ License: BSD-3-Clause
9
+ License-File: LICENSE
10
+ Classifier: Environment :: Web Environment
11
+ Classifier: Framework :: Django
12
+ Classifier: Framework :: Django :: 4.2
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: BSD License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
23
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
24
+ Classifier: Topic :: Software Development
25
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
26
+ Requires-Python: >=3.10
27
+ Requires-Dist: django-js-asset>=3.1.2
28
+ Requires-Dist: django>=4.2
29
+ Provides-Extra: sanitize
30
+ Requires-Dist: nh3>=0.3; extra == 'sanitize'
31
+ Provides-Extra: tests
32
+ Requires-Dist: asgiref; extra == 'tests'
33
+ Requires-Dist: coverage; extra == 'tests'
34
+ Requires-Dist: nh3>=0.3; extra == 'tests'
35
+ Requires-Dist: pytest; extra == 'tests'
36
+ Requires-Dist: pytest-asyncio; extra == 'tests'
37
+ Requires-Dist: pytest-cov; extra == 'tests'
38
+ Requires-Dist: pytest-django; extra == 'tests'
39
+ Requires-Dist: pytest-playwright; extra == 'tests'
40
+ Description-Content-Type: text/x-rst
41
+
42
+ ===================
43
+ django-prose-editor
44
+ ===================
45
+
46
+ Prose editor for the Django admin based on ProseMirror and Tiptap. `Announcement blog post <https://406.ch/writing/django-prose-editor-prose-editing-component-for-the-django-admin/>`__.
47
+
48
+
49
+ Intro
50
+ =====
51
+
52
+ After installing the package (using ``pip install
53
+ django-prose-editor[sanitize]``) the following should get you started:
54
+
55
+ .. code-block:: python
56
+
57
+ from django_prose_editor.fields import ProseEditorField
58
+
59
+ content = ProseEditorField(
60
+ extensions={
61
+ "Bold": True,
62
+ "Italic": True,
63
+ "BulletList": True,
64
+ "ListItem": True,
65
+ "Link": True,
66
+ },
67
+ sanitize=True, # Server side sanitization is strongly recommended.
68
+ )
69
+
70
+ Check the `documentation <https://django-prose-editor.readthedocs.io>`__.
@@ -0,0 +1,29 @@
1
+ ===================
2
+ django-prose-editor
3
+ ===================
4
+
5
+ Prose editor for the Django admin based on ProseMirror and Tiptap. `Announcement blog post <https://406.ch/writing/django-prose-editor-prose-editing-component-for-the-django-admin/>`__.
6
+
7
+
8
+ Intro
9
+ =====
10
+
11
+ After installing the package (using ``pip install
12
+ django-prose-editor[sanitize]``) the following should get you started:
13
+
14
+ .. code-block:: python
15
+
16
+ from django_prose_editor.fields import ProseEditorField
17
+
18
+ content = ProseEditorField(
19
+ extensions={
20
+ "Bold": True,
21
+ "Italic": True,
22
+ "BulletList": True,
23
+ "ListItem": True,
24
+ "Link": True,
25
+ },
26
+ sanitize=True, # Server side sanitization is strongly recommended.
27
+ )
28
+
29
+ Check the `documentation <https://django-prose-editor.readthedocs.io>`__.
@@ -0,0 +1 @@
1
+ version = "0.20.0"
@@ -0,0 +1,9 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class DjangoProseEditorConfig(AppConfig):
5
+ name = "django_prose_editor"
6
+
7
+ def ready(self):
8
+ # Import system checks
9
+ from . import checks # noqa: F401, PLC0415
@@ -0,0 +1,239 @@
1
+ from django.apps import apps
2
+ from django.conf import settings
3
+ from django.core.checks import Error, Warning, register
4
+
5
+ from django_prose_editor.fields import ProseEditorField, _actually_empty
6
+
7
+
8
+ @register()
9
+ def check_js_preset_configuration(app_configs, **kwargs):
10
+ """
11
+ Check that the 'default' JavaScript preset is not being overridden in settings.
12
+ """
13
+ errors = []
14
+
15
+ # Main setting
16
+ if hasattr(settings, "DJANGO_PROSE_EDITOR_PRESETS"):
17
+ presets = settings.DJANGO_PROSE_EDITOR_PRESETS
18
+ if "default" in presets:
19
+ errors.append(
20
+ Error(
21
+ 'Overriding the "default" preset in DJANGO_PROSE_EDITOR_PRESETS is not allowed.',
22
+ hint="Remove the 'default' key from your DJANGO_PROSE_EDITOR_PRESETS setting.",
23
+ obj=settings,
24
+ id="django_prose_editor.E001",
25
+ )
26
+ )
27
+
28
+ if "configurable" in presets:
29
+ errors.append(
30
+ Error(
31
+ 'Overriding the "configurable" preset in DJANGO_PROSE_EDITOR_PRESETS is not allowed.',
32
+ hint="Remove the 'configurable' key from your DJANGO_PROSE_EDITOR_PRESETS setting.",
33
+ obj=settings,
34
+ id="django_prose_editor.E002",
35
+ )
36
+ )
37
+
38
+ return errors
39
+
40
+
41
+ @register()
42
+ def check_extensions_parameter(app_configs, **kwargs):
43
+ """
44
+ Check for usage of 'extensions' (because we want that!)
45
+ """
46
+ warnings = []
47
+
48
+ # Get models to check based on provided app_configs or all models
49
+ models_to_check = []
50
+ if app_configs:
51
+ for app_config in app_configs:
52
+ models_to_check.extend(app_config.get_models())
53
+ else:
54
+ models_to_check = apps.get_models()
55
+
56
+ # Check models for fields using deprecated config
57
+ for model in models_to_check:
58
+ for field in model._meta.fields:
59
+ if isinstance(field, ProseEditorField):
60
+ # Check if this field is using legacy config (no 'extensions' key)
61
+ if (
62
+ not isinstance(field.config, dict)
63
+ or "extensions" not in field.config
64
+ ):
65
+ warnings.append(
66
+ Warning(
67
+ "This ProseEditorField is using the legacy configuration format which is "
68
+ "deprecated and will be removed in a future version. Add the 'extensions' "
69
+ "configuration explicitly to use the new configuration format.",
70
+ obj=f"{model._meta.label}.{field.name}",
71
+ id="django_prose_editor.W001",
72
+ )
73
+ )
74
+
75
+ return warnings
76
+
77
+
78
+ @register()
79
+ def check_custom_extensions_configuration(app_configs, **kwargs):
80
+ """
81
+ Check that custom extensions are properly configured.
82
+ """
83
+ errors = []
84
+
85
+ # Check if custom extensions are defined
86
+ if hasattr(settings, "DJANGO_PROSE_EDITOR_EXTENSIONS"):
87
+ extensions = settings.DJANGO_PROSE_EDITOR_EXTENSIONS
88
+
89
+ # Check that extensions is a list
90
+ if not isinstance(extensions, list):
91
+ errors.append(
92
+ Error(
93
+ "DJANGO_PROSE_EDITOR_EXTENSIONS must be a list of dictionaries.",
94
+ hint="Configure DJANGO_PROSE_EDITOR_EXTENSIONS as a list of dictionaries, each with 'js' and 'extensions' keys.",
95
+ obj=settings,
96
+ id="django_prose_editor.E003",
97
+ )
98
+ )
99
+ return errors
100
+
101
+ # Check each extension group
102
+ for i, extension_group in enumerate(extensions):
103
+ if not isinstance(extension_group, dict):
104
+ errors.append(
105
+ Error(
106
+ f"Extension group at index {i} must be a dictionary.",
107
+ hint="Each extension group must be a dictionary with 'js' and 'extensions' keys.",
108
+ obj=settings,
109
+ id="django_prose_editor.E004",
110
+ )
111
+ )
112
+ continue
113
+
114
+ # Check that required keys are present
115
+ if "extensions" not in extension_group:
116
+ errors.append(
117
+ Error(
118
+ f"Extension group at index {i} is missing the required 'extensions' key.",
119
+ hint="Each extension group must have an 'extensions' key mapping extension names to processors.",
120
+ obj=settings,
121
+ id="django_prose_editor.E005",
122
+ )
123
+ )
124
+ continue
125
+
126
+ if "js" not in extension_group:
127
+ errors.append(
128
+ Warning(
129
+ f"Extension group at index {i} is missing the 'js' key.",
130
+ hint="Each extension group should have a 'js' key listing JavaScript assets for the extensions.",
131
+ obj=settings,
132
+ id="django_prose_editor.W002",
133
+ )
134
+ )
135
+
136
+ # Check the extensions dictionary
137
+ extensions_dict = extension_group["extensions"]
138
+ if not isinstance(extensions_dict, dict):
139
+ errors.append(
140
+ Error(
141
+ f"The 'extensions' key in extension group at index {i} must be a dictionary.",
142
+ hint="The 'extensions' key should map extension names to processor callables or dotted paths.",
143
+ obj=settings,
144
+ id="django_prose_editor.E006",
145
+ )
146
+ )
147
+ continue
148
+
149
+ # Check each processor
150
+ for extension_name, processor in extensions_dict.items():
151
+ # Check if the processor is a string (dotted path) or callable
152
+ if not (callable(processor) or isinstance(processor, str)):
153
+ errors.append(
154
+ Error(
155
+ f'Processor for extension "{extension_name}" in group {i} must be a callable or a dotted path string.',
156
+ hint="Each processor must be either a callable or a dotted import path.",
157
+ obj=settings,
158
+ id="django_prose_editor.E007",
159
+ )
160
+ )
161
+
162
+ # If it's a string, verify it looks like a dotted path
163
+ if isinstance(processor, str) and "." not in processor:
164
+ errors.append(
165
+ Warning(
166
+ f'Processor path "{processor}" for extension "{extension_name}" in group {i} may not be a valid dotted import path.',
167
+ hint="The processor should be a dotted import path like 'myapp.processors.my_processor'.",
168
+ obj=settings,
169
+ id="django_prose_editor.W003",
170
+ )
171
+ )
172
+
173
+ # Check the js assets list
174
+ js_assets = extension_group.get("js", [])
175
+ if not isinstance(js_assets, (list, tuple)):
176
+ errors.append(
177
+ Error(
178
+ f"The 'js' key in extension group at index {i} must be a list.",
179
+ hint="The 'js' key should be a list of JavaScript asset URLs.",
180
+ obj=settings,
181
+ id="django_prose_editor.E008",
182
+ )
183
+ )
184
+
185
+ return errors
186
+
187
+
188
+ @register()
189
+ def check_sanitization_enabled(app_configs, **kwargs):
190
+ """
191
+ Check that all ProseEditorField instances have sanitization enabled.
192
+ """
193
+ warnings = []
194
+
195
+ # Get models to check based on provided app_configs or all models
196
+ models_to_check = []
197
+ if app_configs:
198
+ for app_config in app_configs:
199
+ models_to_check.extend(app_config.get_models())
200
+ else:
201
+ models_to_check = apps.get_models()
202
+
203
+ # Check all models for ProseEditorField without sanitization
204
+ for model in models_to_check:
205
+ for field in model._meta.fields:
206
+ if isinstance(field, ProseEditorField):
207
+ # Check if sanitization is disabled or set to the identity function
208
+ if field.sanitize == _actually_empty:
209
+ # Different messages based on whether using extensions or legacy config
210
+ if isinstance(field.config, dict) and "extensions" in field.config:
211
+ message = (
212
+ "This ProseEditorField is using extensions without sanitization. "
213
+ "For security, it's recommended to enable sanitization with "
214
+ "sanitize=True when using extensions."
215
+ )
216
+ hint = (
217
+ "Add sanitize=True to this field definition for proper HTML sanitization "
218
+ "that matches your configured extensions."
219
+ )
220
+ else:
221
+ message = (
222
+ "This ProseEditorField doesn't have sanitization enabled. "
223
+ "For security, it's recommended to enable sanitization."
224
+ )
225
+ hint = (
226
+ "Consider using the newer extensions mechanism with sanitize=True "
227
+ "for proper HTML sanitization that matches your editor capabilities."
228
+ )
229
+
230
+ warnings.append(
231
+ Warning(
232
+ message,
233
+ hint=hint,
234
+ obj=f"{model._meta.label}.{field.name}",
235
+ id="django_prose_editor.W004",
236
+ )
237
+ )
238
+
239
+ return warnings