misc: allow template URLs in feed and json cells (#15423)

This commit is contained in:
Frédéric Péters 2019-07-01 21:19:18 +02:00
parent c6b4b5b6bd
commit a72c25dd59
4 changed files with 89 additions and 5 deletions

View File

@ -18,6 +18,9 @@
from django import forms
from django.conf import settings
from django.core import validators
from django.forms.widgets import TextInput
from django.utils.encoding import force_text
import ckeditor.fields
@ -48,3 +51,22 @@ class RichTextFormField(ckeditor.fields.RichTextFormField):
value = value.replace(u' !', u'\u202f!')
value = value.replace(u' ?', u'\u202f?')
return value
def templatable_url_validator(value):
value = force_text(value)
if '{{' in value or '{%' in value:
# leave templates alone
return
validators.URLValidator()(value)
class TemplatableURLField(forms.URLField):
widget = TextInput
default_validators = [templatable_url_validator]
def to_python(self, value):
value = super(forms.URLField, self).to_python(value)
if '{{' in value or '{%' in value:
return value
return super(TemplatableURLField, self).to_python(value)

View File

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.12 on 2019-07-01 19:18
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('data', '0036_page_sub_slug'),
]
operations = [
migrations.AlterField(
model_name='feedcell',
name='url',
field=models.CharField(blank=True, max_length=200, verbose_name='URL'),
),
migrations.AlterField(
model_name='jsoncell',
name='url',
field=models.CharField(blank=True, max_length=200, verbose_name='URL'),
),
]

View File

@ -50,7 +50,7 @@ from django.forms.widgets import MediaDefiningClass
from django.template import Context, engines, TemplateDoesNotExist
from django.test.client import RequestFactory
from .fields import RichTextField
from .fields import RichTextField, TemplatableURLField
from jsonfield import JSONField
@ -505,9 +505,11 @@ class CellBase(six.with_metaclass(CellMeta, models.Model)):
last_update_timestamp = models.DateTimeField(auto_now=True)
default_form_class = None
manager_form_factory_kwargs = {}
manager_form_template = 'combo/cell_form.html'
visible = True
user_dependant = False
manager_form_template = 'combo/cell_form.html'
template_name = None
# get_badge(self, context); set to None so cell types can be skipped easily
@ -658,7 +660,7 @@ class CellBase(six.with_metaclass(CellMeta, models.Model)):
if not fields:
return None
return model_forms.modelform_factory(self.__class__, fields=fields)
return model_forms.modelform_factory(self.__class__, fields=fields, **self.manager_form_factory_kwargs)
def get_options_form_class(self):
return model_forms.modelform_factory(self.__class__,
@ -907,10 +909,11 @@ class LinkCell(CellBase):
@register_cell_class
class FeedCell(CellBase):
title = models.CharField(_('Title'), max_length=150, blank=True)
url = models.URLField(_('URL'), blank=True)
url = models.CharField(_('URL'), blank=True, max_length=200)
limit = models.PositiveSmallIntegerField(_('Maximum number of entries'),
null=True, blank=True)
manager_form_factory_kwargs = {'field_classes': {'url': TemplatableURLField}}
template_name = 'combo/feed-cell.html'
class Meta:
@ -1275,7 +1278,7 @@ class JsonCellBase(CellBase):
@register_cell_class
class JsonCell(JsonCellBase):
title = models.CharField(_('Title'), max_length=150, blank=True)
url = models.URLField(_('URL'), blank=True)
url = models.CharField(_('URL'), blank=True, max_length=200)
template_string = models.TextField(_('Display Template'), blank=True, null=True)
cache_duration = models.PositiveIntegerField(
_('Cache duration'), default=60)
@ -1287,6 +1290,8 @@ class JsonCell(JsonCellBase):
timeout = models.PositiveIntegerField(_('Request timeout'), default=0,
help_text=_('In seconds. Use 0 for default system timeout'))
manager_form_factory_kwargs = {'field_classes': {'url': TemplatableURLField}}
class Meta:
verbose_name = _('JSON Prototype')

View File

@ -586,6 +586,38 @@ def test_edit_text_cell(app, admin_user):
assert TextCell.objects.get(id=cells[0].id).text == u'Hello\u00a0: World'
def test_edit_json_cell(app, admin_user):
Page.objects.all().delete()
page = Page(title='One', slug='one', template_name='standard')
page.save()
app = login(app)
resp = app.get('/manage/pages/%s/' % page.id)
data_add_url = [x for x in resp.html.find_all('option') if x.text == 'JSON Prototype'][0].get('data-add-url')
resp = app.get(data_add_url)
cells = CellBase.get_cells(page_id=page.id)
assert len(cells) == 1
assert isinstance(cells[0], JsonCell)
assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.id, cells[0].get_reference()))
resp = app.get('/manage/pages/%s/' % page.id)
resp.form['cdata_jsoncell-%s-url' % cells[0].id].value = 'xxx'
resp = resp.form.submit()
assert 'Enter a valid URL.' in resp.text
assert JsonCell.objects.get(id=cells[0].id).url == ''
resp = app.get('/manage/pages/%s/' % page.id)
resp.form['cdata_jsoncell-%s-url' % cells[0].id].value = 'https://www.example.net/'
resp = resp.form.submit()
assert JsonCell.objects.get(id=cells[0].id).url == 'https://www.example.net/'
resp = app.get('/manage/pages/%s/' % page.id)
resp.form['cdata_jsoncell-%s-url' % cells[0].id].value = '{{url}}'
resp = resp.form.submit()
assert JsonCell.objects.get(id=cells[0].id).url == '{{url}}'
def test_edit_config_json_cell(app, admin_user):
Page.objects.all().delete()
page = Page(title='One', slug='one', template_name='standard')