Skip to content

Commit a3104b1

Browse files
committed
LinkTool
1 parent aacd2b2 commit a3104b1

File tree

4 files changed

+133
-5
lines changed

4 files changed

+133
-5
lines changed

django_editorjs_fields/config.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,13 @@
6565
'Embed': {'class': 'Embed'},
6666
'Delimiter': {'class': 'Delimiter'},
6767
'Warning': {'class': 'Warning', 'inlineToolbar': True},
68-
'LinkTool': {'class': 'LinkTool'},
68+
'LinkTool': {
69+
'class': 'LinkTool',
70+
'config': {
71+
# Backend endpoint for url data fetching
72+
'endpoint': reverse_lazy('editorjs_linktool'),
73+
}
74+
},
6975
'Marker': {'class': 'Marker', 'inlineToolbar': True},
7076
'Table': {'class': 'Table', 'inlineToolbar': True},
7177
}

django_editorjs_fields/templatetags/editorjs.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,34 @@ def generate_embed(data):
9999
return f'<div class="embed {service}">{iframe}{caption}</div>'
100100

101101

102+
def generate_link(data):
103+
104+
link, meta = data.get('link'), data.get('meta')
105+
106+
if not link or not meta:
107+
return ''
108+
109+
title = meta.get('title')
110+
description = meta.get('description')
111+
image = meta.get('image')
112+
113+
wrapper = f'<div class="link-block"><a href="{ link }" target="_blank" rel="nofollow noopener noreferrer">'
114+
115+
if image.get('url'):
116+
image_url = image.get('url')
117+
wrapper += f'<div class="link-block__image" style="background-image: url(\'{image_url}\');"></div>'
118+
119+
if title:
120+
wrapper += f'<p class="link-block__title">{title}</p>'
121+
122+
if description:
123+
wrapper += f'<p class="link-block__description">{description}</p>'
124+
125+
wrapper += f'<p class="link-block__link">{link}</p>'
126+
wrapper += '</a></div>'
127+
return wrapper
128+
129+
102130
@register.filter(is_safe=True)
103131
def editorjs(value):
104132
if not value or value == 'null':
@@ -139,5 +167,7 @@ def editorjs(value):
139167
html_list.append(generate_embed(data))
140168
elif type == 'Quote':
141169
html_list.append(generate_quote(data))
170+
elif type == 'LinkTool':
171+
html_list.append(generate_link(data))
142172

143173
return mark_safe(''.join(html_list))

django_editorjs_fields/urls.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
from django.contrib.admin.views.decorators import staff_member_required
22
from django.urls import path
33

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

66
urlpatterns = [
77
path(
88
'image_upload/',
99
staff_member_required(ImageUploadView.as_view()),
1010
name='editorjs_image_upload',
1111
),
12+
path(
13+
'linktool/',
14+
staff_member_required(LinkToolView.as_view()),
15+
name='editorjs_linktool',
16+
),
1217
]

django_editorjs_fields/views.py

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1+
import json
2+
import logging
13
import os
24
from datetime import datetime
5+
from urllib.error import HTTPError, URLError
6+
from urllib.parse import urlencode
7+
from urllib.request import Request, urlopen
38

9+
# from django.conf import settings
10+
from django.core.exceptions import ValidationError
11+
from django.core.validators import URLValidator
412
from django.http import JsonResponse
513
from django.utils.decorators import method_decorator
614
from django.views import View
@@ -10,9 +18,12 @@
1018
IMAGE_UPLOAD_PATH_DATE)
1119
from .utils import storage
1220

21+
LOGGER = logging.getLogger('django_editorjs_fields')
22+
1323

1424
class ImageUploadView(View):
1525
http_method_names = ["post"]
26+
# http_method_names = ["post", "delete"]
1627

1728
@method_decorator(csrf_exempt)
1829
def dispatch(self, request, *args, **kwargs):
@@ -35,9 +46,6 @@ def post(self, request):
3546
{'success': 0, 'message': 'You can only upload images.'}
3647
)
3748

38-
# filesize = len(the_file['content'])
39-
# filetype = the_file['content-type']
40-
4149
filename, extension = os.path.splitext(the_file.name)
4250

4351
if IMAGE_NAME_ORIGINAL is False:
@@ -57,3 +65,82 @@ def post(self, request):
5765

5866
return JsonResponse({'success': 1, 'file': {"url": link}})
5967
return JsonResponse({'success': 0})
68+
69+
# def delete(self, request):
70+
# path_file = request.GET.get('pathFile')
71+
72+
# if not path_file:
73+
# return JsonResponse({'success': 0, 'message': 'Parameter "pathFile" Not Found'})
74+
75+
# base_dir = getattr(settings, "BASE_DIR", '')
76+
# path_file = f'{base_dir}{path_file}'
77+
78+
# if not os.path.isfile(path_file):
79+
# return JsonResponse({'success': 0, 'message': 'File Not Found'})
80+
81+
# os.remove(path_file)
82+
83+
# return JsonResponse({'success': 1})
84+
85+
86+
class LinkToolView(View):
87+
http_method_names = ["get"]
88+
89+
@method_decorator(csrf_exempt)
90+
def dispatch(self, request, *args, **kwargs):
91+
return super().dispatch(request, *args, **kwargs)
92+
93+
def get(self, request):
94+
95+
url = request.GET.get('url', '')
96+
97+
LOGGER.debug('Starting to get meta for: %s', url)
98+
99+
if not any([url.startswith(s) for s in ('http://', 'https://')]):
100+
LOGGER.debug('Adding the http protocol to the link: %s', url)
101+
url = 'http://' + url
102+
103+
validate = URLValidator(schemes=['http', 'https'])
104+
105+
try:
106+
validate(url)
107+
except ValidationError as e:
108+
LOGGER.error(e)
109+
else:
110+
try:
111+
LOGGER.debug('Let\'s try to get meta from: %s', url)
112+
113+
full_url = 'https://api.microlink.io/?' + \
114+
urlencode({'url': url})
115+
116+
req = Request(full_url, headers={
117+
'User-Agent': request.META.get('HTTP_USER_AGENT', 'Mozilla/5.0 (Windows NT 6.1; Win64; x64)')
118+
})
119+
res = urlopen(req)
120+
except HTTPError as e:
121+
LOGGER.error('The server couldn\'t fulfill the request.')
122+
LOGGER.error('Error code: %s %s', e.code, e.msg)
123+
except URLError as e:
124+
LOGGER.error('We failed to reach a server. url: %s', url)
125+
LOGGER.error('Reason: %s', e.reason)
126+
else:
127+
res_body = res.read()
128+
res_json = json.loads(res_body.decode("utf-8"))
129+
130+
if 'success' in res_json.get('status'):
131+
data = res_json.get('data')
132+
133+
if data:
134+
LOGGER.debug('Response meta: %s', data)
135+
meta = {}
136+
meta['title'] = data.get('title')
137+
meta['description'] = data.get('description')
138+
meta['image'] = data.get('image')
139+
140+
return JsonResponse({
141+
'success': 1,
142+
'link': data.get('url', url),
143+
'meta': meta
144+
})
145+
146+
return JsonResponse({'success': 0})

0 commit comments

Comments
 (0)