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 import forms
from django.conf import settings 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 import ckeditor.fields
@ -48,3 +51,22 @@ class RichTextFormField(ckeditor.fields.RichTextFormField):
value = value.replace(u' !', u'\u202f!') value = value.replace(u' !', u'\u202f!')
value = value.replace(u' ?', u'\u202f?') value = value.replace(u' ?', u'\u202f?')
return value 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.template import Context, engines, TemplateDoesNotExist
from django.test.client import RequestFactory from django.test.client import RequestFactory
from .fields import RichTextField from .fields import RichTextField, TemplatableURLField
from jsonfield import JSONField from jsonfield import JSONField
@ -505,9 +505,11 @@ class CellBase(six.with_metaclass(CellMeta, models.Model)):
last_update_timestamp = models.DateTimeField(auto_now=True) last_update_timestamp = models.DateTimeField(auto_now=True)
default_form_class = None default_form_class = None
manager_form_factory_kwargs = {}
manager_form_template = 'combo/cell_form.html'
visible = True visible = True
user_dependant = False user_dependant = False
manager_form_template = 'combo/cell_form.html'
template_name = None template_name = None
# get_badge(self, context); set to None so cell types can be skipped easily # 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: if not fields:
return None 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): def get_options_form_class(self):
return model_forms.modelform_factory(self.__class__, return model_forms.modelform_factory(self.__class__,
@ -907,10 +909,11 @@ class LinkCell(CellBase):
@register_cell_class @register_cell_class
class FeedCell(CellBase): class FeedCell(CellBase):
title = models.CharField(_('Title'), max_length=150, blank=True) 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'), limit = models.PositiveSmallIntegerField(_('Maximum number of entries'),
null=True, blank=True) null=True, blank=True)
manager_form_factory_kwargs = {'field_classes': {'url': TemplatableURLField}}
template_name = 'combo/feed-cell.html' template_name = 'combo/feed-cell.html'
class Meta: class Meta:
@ -1275,7 +1278,7 @@ class JsonCellBase(CellBase):
@register_cell_class @register_cell_class
class JsonCell(JsonCellBase): class JsonCell(JsonCellBase):
title = models.CharField(_('Title'), max_length=150, blank=True) 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) template_string = models.TextField(_('Display Template'), blank=True, null=True)
cache_duration = models.PositiveIntegerField( cache_duration = models.PositiveIntegerField(
_('Cache duration'), default=60) _('Cache duration'), default=60)
@ -1287,6 +1290,8 @@ class JsonCell(JsonCellBase):
timeout = models.PositiveIntegerField(_('Request timeout'), default=0, timeout = models.PositiveIntegerField(_('Request timeout'), default=0,
help_text=_('In seconds. Use 0 for default system timeout')) help_text=_('In seconds. Use 0 for default system timeout'))
manager_form_factory_kwargs = {'field_classes': {'url': TemplatableURLField}}
class Meta: class Meta:
verbose_name = _('JSON Prototype') 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' 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): def test_edit_config_json_cell(app, admin_user):
Page.objects.all().delete() Page.objects.all().delete()
page = Page(title='One', slug='one', template_name='standard') page = Page(title='One', slug='one', template_name='standard')