Skip to content

Commit 75a07d8

Browse files
authored
Merge pull request #28 from 2ik/dev
0.2.6
2 parents 0c33950 + d1f4890 commit 75a07d8

File tree

9 files changed

+120
-38
lines changed

9 files changed

+120
-38
lines changed

README.md

+14-11
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,12 @@ EDITORJS_DEFAULT_CONFIG_TOOLS = {
165165
'Image': {
166166
'class': 'ImageTool',
167167
'inlineToolbar': True,
168-
"config": {"endpoints": {
168+
"config": {
169+
"endpoints": {
169170
"byFile": reverse_lazy('editorjs_image_upload'),
170171
"byUrl": reverse_lazy('editorjs_image_by_url')
171-
}},
172+
}
173+
},
172174
},
173175
'Header': {
174176
'class': 'Header',
@@ -291,15 +293,16 @@ plugin use css property [prefers-color-scheme](https://developer.mozilla.org/en-
291293
The application can be configured by editing the project's `settings.py`
292294
file.
293295

294-
| Key | Description | Default | Type |
295-
| --------------------------------- | ---------------------------------------------------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------ |
296-
| `EDITORJS_DEFAULT_PLUGINS` | List of plugins names Editor.js from npm | [See above](#plugins) | `list[str]`, `tuple[str]` |
297-
| `EDITORJS_DEFAULT_CONFIG_TOOLS` | Map of Tools to use | [See above](#plugins) | `dict[str, dict]` |
298-
| `EDITORJS_IMAGE_UPLOAD_PATH` | Path uploads images | `uploads/images/` | `str` |
299-
| `EDITORJS_IMAGE_UPLOAD_PATH_DATE` | Subdirectories | `%Y/%m/` | `str` |
300-
| `EDITORJS_IMAGE_NAME_ORIGINAL` | To use the original name of the image file? | `False` | `bool` |
301-
| `EDITORJS_IMAGE_NAME` | Image file name. Ignored when `EDITORJS_IMAGE_NAME_ORIGINAL` is `True` | `token_urlsafe(8)` | `callable(filename: str, file: InMemoryUploadedFile)` ([docs](https://docs.djangoproject.com/en/3.0/ref/files/uploads/)) |
302-
| `EDITORJS_VERSION` | Version Editor.js | `2.22.3` | `str` |
296+
| Key | Description | Default | Type |
297+
| --------------------------------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
298+
| `EDITORJS_DEFAULT_PLUGINS` | List of plugins names Editor.js from npm | [See above](#plugins) | `list[str]`, `tuple[str]` |
299+
| `EDITORJS_DEFAULT_CONFIG_TOOLS` | Map of Tools to use | [See above](#plugins) | `dict[str, dict]` |
300+
| `EDITORJS_IMAGE_UPLOAD_PATH` | Path uploads images | `uploads/images/` | `str` |
301+
| `EDITORJS_IMAGE_UPLOAD_PATH_DATE` | Subdirectories | `%Y/%m/` | `str` |
302+
| `EDITORJS_IMAGE_NAME_ORIGINAL` | To use the original name of the image file? | `False` | `bool` |
303+
| `EDITORJS_IMAGE_NAME` | Image file name. Ignored when `EDITORJS_IMAGE_NAME_ORIGINAL` is `True` | `token_urlsafe(8)` | `callable(filename: str, file: InMemoryUploadedFile)` ([docs](https://docs.djangoproject.com/en/3.0/ref/files/uploads/)) |
304+
| `EDITORJS_EMBED_HOSTNAME_ALLOWED` | List of allowed hostname for embed | `('player.vimeo.com','www.youtube.com','coub.com','vine.co','imgur.com','gfycat.com','player.twitch.tv','player.twitch.tv','music.yandex.ru','codepen.io','www.instagram.com','twitframe.com','assets.pinterest.com','www.facebook.com','www.aparat.com'),` | `list[str]`, `tuple[str]` |
305+
| `EDITORJS_VERSION` | Version Editor.js | `2.22.3` | `str` |
303306

304307
For `EDITORJS_IMAGE_NAME` was used `from secrets import token_urlsafe`
305308

django_editorjs_fields/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "0.2.5"
1+
__version__ = "0.2.6"
22

33
from .fields import EditorJsJSONField, EditorJsTextField
44
from .widgets import EditorJsWidget

django_editorjs_fields/config.py

+30-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,30 @@
77

88
VERSION = getattr(settings, "EDITORJS_VERSION", '2.22.2')
99

10+
# ATTACHMENT_REQUIRE_AUTHENTICATION = str(
11+
# getattr(settings, "EDITORJS_ATTACHMENT_REQUIRE_AUTHENTICATION", True)
12+
# )
13+
14+
EMBED_HOSTNAME_ALLOWED = str(
15+
getattr(settings, "EDITORJS_EMBED_HOSTNAME_ALLOWED", (
16+
'player.vimeo.com',
17+
'www.youtube.com',
18+
'coub.com',
19+
'vine.co',
20+
'imgur.com',
21+
'gfycat.com',
22+
'player.twitch.tv',
23+
'player.twitch.tv',
24+
'music.yandex.ru',
25+
'codepen.io',
26+
'www.instagram.com',
27+
'twitframe.com',
28+
'assets.pinterest.com',
29+
'www.facebook.com',
30+
'www.aparat.com',
31+
))
32+
)
33+
1034
IMAGE_UPLOAD_PATH = str(
1135
getattr(settings, "EDITORJS_IMAGE_UPLOAD_PATH", 'uploads/images/')
1236
)
@@ -45,10 +69,12 @@
4569
'Image': {
4670
'class': 'ImageTool',
4771
'inlineToolbar': True,
48-
"config": {"endpoints": {
49-
"byFile": reverse_lazy('editorjs_image_upload'),
50-
"byUrl": reverse_lazy('editorjs_image_by_url')
51-
}},
72+
"config": {
73+
"endpoints": {
74+
"byFile": reverse_lazy('editorjs_image_upload'),
75+
"byUrl": reverse_lazy('editorjs_image_by_url')
76+
}
77+
},
5278
},
5379
'Header': {
5480
'class': 'Header',

django_editorjs_fields/fields.py

+33-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
import json
2+
13
from django.core import checks
4+
from django.core.exceptions import ValidationError
25
from django.db.models import Field
36
from django.forms import Textarea
47

5-
from .config import DEBUG
8+
from .config import DEBUG, EMBED_HOSTNAME_ALLOWED
9+
from .utils import get_hostname_from_url
610
from .widgets import EditorJsWidget
711

812
try:
@@ -51,6 +55,34 @@ def __init__(self, plugins, tools, **kwargs):
5155

5256
super().__init__(**kwargs)
5357

58+
def validate_embed(self, value):
59+
for item in value.get('blocks', []):
60+
type = item.get('type', '').lower()
61+
if type == 'embed':
62+
embed = item['data']['embed']
63+
hostname = get_hostname_from_url(embed)
64+
65+
if hostname not in EMBED_HOSTNAME_ALLOWED:
66+
raise ValidationError(
67+
hostname + ' is not allowed in EDITORJS_EMBED_HOSTNAME_ALLOWED')
68+
69+
def clean(self, value, model_instance):
70+
if value and value != 'null':
71+
if not isinstance(value, dict):
72+
try:
73+
value = json.loads(value)
74+
except ValueError:
75+
pass
76+
except TypeError:
77+
pass
78+
else:
79+
self.validate_embed(value)
80+
value = json.dumps(value)
81+
else:
82+
self.validate_embed(value)
83+
84+
return super().clean(value, model_instance)
85+
5486
def formfield(self, **kwargs):
5587
if self.use_editorjs:
5688
kwargs['widget'] = EditorJsWidget(

django_editorjs_fields/urls.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from django.contrib.admin.views.decorators import staff_member_required
22
from django.urls import path
33

4-
from .views import ImageUploadView, LinkToolView, ImageByUrl
4+
from .views import ImageByUrl, ImageUploadView, LinkToolView
55

66
urlpatterns = [
77
path(

django_editorjs_fields/utils.py

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import urllib.parse
2+
13
from django.conf import settings
24
from django.utils.module_loading import import_string
35

@@ -12,4 +14,9 @@ def get_storage_class():
1214
)()
1315

1416

17+
def get_hostname_from_url(url):
18+
obj_url = urllib.parse.urlsplit(url)
19+
return obj_url.hostname
20+
21+
1522
storage = get_storage_class()

django_editorjs_fields/widgets.py

+32-18
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def default(self, obj):
2323

2424
class EditorJsWidget(widgets.Textarea):
2525
def __init__(self, plugins=None, tools=None, config=None, **kwargs):
26-
self.plugins = PLUGINS if plugins is None else plugins
26+
self.plugins = plugins
2727
self.tools = tools
2828
self.config = config
2929

@@ -39,28 +39,37 @@ def __init__(self, plugins=None, tools=None, config=None, **kwargs):
3939
def configuration(self):
4040
tools = {}
4141
config = self.config or {}
42-
custom_tools = self.tools or {}
43-
# get name packages without version
44-
plugins = ['@'.join(p.split('@')[:2]) for p in self.plugins]
4542

46-
for plugin in plugins:
47-
plugin_key = PLUGINS_KEYS.get(plugin)
48-
plugin_tools = custom_tools.get(
49-
plugin_key) or CONFIG_TOOLS.get(plugin_key) or {}
50-
plugin_class = plugin_tools.get('class')
43+
if self.plugins or self.tools:
44+
custom_tools = self.tools or {}
45+
# get name packages without version
46+
plugins = ['@'.join(p.split('@')[:2])
47+
for p in self.plugins or PLUGINS]
5148

52-
if plugin_class:
49+
for plugin in plugins:
50+
plugin_key = PLUGINS_KEYS.get(plugin)
5351

54-
tools[plugin_key] = custom_tools.get(
55-
plugin_key, CONFIG_TOOLS.get(plugin_key)
56-
)
52+
if not plugin_key:
53+
continue
5754

58-
tools[plugin_key]['class'] = plugin_class
55+
plugin_tools = custom_tools.get(
56+
plugin_key) or CONFIG_TOOLS.get(plugin_key) or {}
57+
plugin_class = plugin_tools.get('class')
5958

60-
custom_tools.pop(plugin_key, None)
59+
if plugin_class:
6160

62-
if custom_tools:
63-
tools.update(custom_tools)
61+
tools[plugin_key] = custom_tools.get(
62+
plugin_key, CONFIG_TOOLS.get(plugin_key)
63+
)
64+
65+
tools[plugin_key]['class'] = plugin_class
66+
67+
custom_tools.pop(plugin_key, None)
68+
69+
if custom_tools:
70+
tools.update(custom_tools)
71+
else: # default
72+
tools.update(CONFIG_TOOLS)
6473

6574
config.update(tools=tools)
6675
return config
@@ -70,7 +79,12 @@ def media(self):
7079
js_list = [
7180
'//cdn.jsdelivr.net/npm/@editorjs/editorjs@' + VERSION # lib
7281
]
73-
js_list += ['//cdn.jsdelivr.net/npm/' + p for p in self.plugins or []]
82+
83+
plugins = self.plugins or PLUGINS
84+
85+
if plugins:
86+
js_list += ['//cdn.jsdelivr.net/npm/' + p for p in plugins]
87+
7488
js_list.append('django-editorjs-fields/js/django-editorjs-fields.js')
7589

7690
return Media(

example/blog/models.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class Post(models.Model):
4646
blank=True,
4747
)
4848
body_textfield = EditorJsTextField( # only images and paragraph (default)
49-
plugins=["@editorjs/image"], null=True, blank=True,
49+
plugins=["@editorjs/image", "@editorjs/embed"], null=True, blank=True,
5050
i18n={
5151
'messages': {
5252
'blockTunes': {

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "django-editorjs-fields"
3-
version = "0.2.5"
3+
version = "0.2.6"
44
description = "Django plugin for using Editor.js"
55
authors = ["Ilya Kotlyakov <[email protected]>"]
66
license = "MIT"

0 commit comments

Comments
 (0)