general: add page versionning (#21602)
This commit is contained in:
parent
b439f67a7a
commit
43da526e69
|
@ -0,0 +1,38 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.8 on 2018-04-01 13:00
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import jsonfield.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('data', '0032_page_description'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='PageSnapshot',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('timestamp', models.DateTimeField(auto_now_add=True)),
|
||||
('comment', models.TextField(blank=True, null=True)),
|
||||
('serialization', jsonfield.fields.JSONField(blank=True, default=dict)),
|
||||
('page', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='data.Page')),
|
||||
('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'ordering': ('-timestamp',),
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='page',
|
||||
name='snapshot',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='temporary_page', to='data.PageSnapshot'),
|
||||
),
|
||||
]
|
|
@ -38,6 +38,7 @@ from django.db.models import Max
|
|||
from django.forms import models as model_forms
|
||||
from django import forms
|
||||
from django import template
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.html import strip_tags
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.text import slugify
|
||||
|
@ -95,13 +96,27 @@ class Placeholder(object):
|
|||
|
||||
|
||||
class PageManager(models.Manager):
|
||||
snapshots = False
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.snapshots = kwargs.pop('snapshots', False)
|
||||
super(PageManager, self).__init__(*args, **kwargs)
|
||||
|
||||
def get_by_natural_key(self, path):
|
||||
parts = [x for x in path.strip('/').split('/') if x] or ['index']
|
||||
return self.get(slug=parts[-1])
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super(PageManager, self).get_queryset()
|
||||
if self.snapshots:
|
||||
return queryset.filter(snapshot__isnull=False)
|
||||
else:
|
||||
return queryset.filter(snapshot__isnull=True)
|
||||
|
||||
|
||||
class Page(models.Model):
|
||||
objects = PageManager()
|
||||
snapshots = PageManager(snapshots=True)
|
||||
|
||||
title = models.CharField(_('Title'), max_length=150)
|
||||
slug = models.SlugField(_('Slug'))
|
||||
|
@ -118,6 +133,12 @@ class Page(models.Model):
|
|||
|
||||
picture = models.ImageField(_('Picture'), upload_to='page-pictures/', null=True)
|
||||
|
||||
# mark temporarily restored snapshots, it is required to save objects
|
||||
# (pages and cells) for real for viewing past snapshots as many cells are
|
||||
# asynchronously loaded and must refer to a real Page object.
|
||||
snapshot = models.ForeignKey('PageSnapshot', on_delete=models.CASCADE, null=True,
|
||||
related_name='temporary_page')
|
||||
|
||||
_level = None
|
||||
_children = None
|
||||
|
||||
|
@ -271,6 +292,8 @@ class Page(models.Model):
|
|||
serialized_page = json.loads(serializers.serialize('json', [self],
|
||||
use_natural_foreign_keys=True, use_natural_primary_keys=True))[0]
|
||||
del serialized_page['model']
|
||||
if 'snapshot' in serialized_page:
|
||||
del serialized_page['snapshot']
|
||||
serialized_page['cells'] = json.loads(serializers.serialize('json',
|
||||
cells, use_natural_foreign_keys=True, use_natural_primary_keys=True))
|
||||
serialized_page['fields']['groups'] = [x[0] for x in serialized_page['fields']['groups']]
|
||||
|
@ -284,20 +307,25 @@ class Page(models.Model):
|
|||
return serialized_page
|
||||
|
||||
@classmethod
|
||||
def load_serialized_page(cls, json_page):
|
||||
def load_serialized_page(cls, json_page, snapshot=None):
|
||||
json_page['model'] = 'data.page'
|
||||
json_page['fields']['groups'] = [[x] for x in json_page['fields']['groups'] if isinstance(x, basestring)]
|
||||
page, created = Page.objects.get_or_create(slug=json_page['fields']['slug'])
|
||||
page, created = Page.objects.get_or_create(slug=json_page['fields']['slug'], snapshot=snapshot)
|
||||
json_page['pk'] = page.id
|
||||
page = [x for x in serializers.deserialize('json', json.dumps([json_page]))][0]
|
||||
page.object.snapshot = snapshot
|
||||
page.save()
|
||||
for cell in json_page.get('cells'):
|
||||
cell['fields']['groups'] = [[x] for x in cell['fields']['groups'] if isinstance(x, basestring)]
|
||||
cell['fields']['page'] = page.object.natural_key()
|
||||
if snapshot:
|
||||
cell['fields']['page'] = page.object.id
|
||||
else:
|
||||
cell['fields']['page'] = page.object.natural_key()
|
||||
|
||||
# if there were cells, remove them
|
||||
for cell in CellBase.get_cells(page_id=page.object.id):
|
||||
cell.delete()
|
||||
return page.object # get page out of deserialization object
|
||||
|
||||
@classmethod
|
||||
def load_serialized_cells(cls, cells):
|
||||
|
@ -333,6 +361,38 @@ class Page(models.Model):
|
|||
return max([self.last_update_timestamp] + [x.last_update_timestamp for x in cells])
|
||||
|
||||
|
||||
class PageSnapshot(models.Model):
|
||||
page = models.ForeignKey(Page, on_delete=models.SET_NULL, null=True)
|
||||
timestamp = models.DateTimeField(auto_now_add=True)
|
||||
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True)
|
||||
comment = models.TextField(blank=True, null=True)
|
||||
serialization = JSONField(blank=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ('-timestamp',)
|
||||
|
||||
@classmethod
|
||||
def take(cls, page, request=None, comment=None, deletion=False):
|
||||
snapshot = cls(page=page, comment=comment)
|
||||
if request and not request.user.is_anonymous:
|
||||
snapshot.user = request.user
|
||||
if not deletion:
|
||||
snapshot.serialization = page.get_serialized_page()
|
||||
else:
|
||||
snapshot.serialization = {}
|
||||
snapshot.comment = comment or _('deletion')
|
||||
snapshot.save()
|
||||
|
||||
def get_page(self):
|
||||
try:
|
||||
# try reusing existing page
|
||||
return Page.snapshots.get(snapshot=self)
|
||||
except Page.DoesNotExist:
|
||||
page = Page.load_serialized_page(self.serialization, snapshot=self)
|
||||
page.load_serialized_cells(self.serialization['cells'])
|
||||
return page
|
||||
|
||||
|
||||
class CellMeta(MediaDefiningClass, ModelBase):
|
||||
pass
|
||||
|
||||
|
@ -375,7 +435,7 @@ class CellBase(models.Model):
|
|||
label = unicode(self.get_verbose_name())
|
||||
additional_label = self.get_additional_label()
|
||||
if label and additional_label:
|
||||
return '%s (%s)' % (label, re.sub(r'\r?\n', ' ', additional_label))
|
||||
return '%s (%s)' % (label, re.sub(r'\r?\n', ' ', force_text(additional_label)))
|
||||
else:
|
||||
return label
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
{% extends "combo/manager_base.html" %}
|
||||
{% load i18n %}
|
||||
{% load cells %}
|
||||
{% load thumbnail %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans 'Page History' %} - {{ view.page.title }}</h2>
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a href="{% url 'combo-manager-page-view' pk=view.page.id %}">{% trans 'Page' %} - {{view.page.title }}</a>
|
||||
<a href="{% url 'combo-manager-page-history' pk=view.page.id %}">{% trans "History" %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div>
|
||||
<ul class="objects-list">
|
||||
{% for snapshot in object_list %}
|
||||
<li>{{ snapshot.timestamp }}, {{ snapshot.comment }}
|
||||
{% if snapshot.user %} ({{ snapshot.user.get_full_name }}){% endif %}
|
||||
— <a href="{% url 'combo-snapshot-view' pk=snapshot.id %}">{% trans "view" %}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% include "gadjo/pagination.html" %}
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -6,6 +6,7 @@
|
|||
{% block appbar %}
|
||||
<h2>{% trans 'Page' %} - {{ object.title }}</h2>
|
||||
<a href="{{ object.get_online_url }}">{% trans 'see online' %}</a>
|
||||
<a href="{% url 'combo-manager-page-history' pk=object.id %}">{% trans 'history' %}</a>
|
||||
<a href="{% url 'combo-manager-page-export' pk=object.id %}">{% trans 'export' %}</a>
|
||||
<a rel="popup" href="{% url 'combo-manager-page-delete' pk=object.id %}">{% trans 'delete' %}</a>
|
||||
{% endblock %}
|
||||
|
|
|
@ -53,6 +53,8 @@ urlpatterns = [
|
|||
name='combo-manager-page-delete'),
|
||||
url(r'^pages/(?P<pk>\w+)/export$', views.page_export,
|
||||
name='combo-manager-page-export'),
|
||||
url(r'^pages/(?P<pk>\w+)/history$', views.page_history,
|
||||
name='combo-manager-page-history'),
|
||||
url(r'^pages/(?P<page_pk>\w+)/add-cell-to-(?P<ph_key>[\w_-]+)/(?P<cell_type>\w+)/(?P<variant>[\w-]+)/$',
|
||||
views.page_add_cell,
|
||||
name='combo-manager-page-add-cell'),
|
||||
|
|
|
@ -31,7 +31,7 @@ from django.views.decorators.csrf import requires_csrf_token
|
|||
from django.views.generic import (TemplateView, RedirectView, DetailView,
|
||||
CreateView, UpdateView, ListView, DeleteView, FormView)
|
||||
|
||||
from combo.data.models import Page, CellBase, ParentContentCell
|
||||
from combo.data.models import Page, CellBase, ParentContentCell, PageSnapshot
|
||||
from combo.data.library import get_cell_class
|
||||
from combo.data.utils import export_site, import_site, MissingGroups
|
||||
from combo import plugins
|
||||
|
@ -119,6 +119,12 @@ page_add = PageAddView.as_view()
|
|||
class PageEditView(UpdateView):
|
||||
model = Page
|
||||
template_name = 'combo/page_add.html'
|
||||
comment = None
|
||||
|
||||
def form_valid(self, form):
|
||||
result = super(PageEditView, self).form_valid(form)
|
||||
PageSnapshot.take(self.get_object(), request=self.request, comment=self.comment)
|
||||
return result
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('combo-manager-page-view', kwargs={'pk': self.object.id})
|
||||
|
@ -127,6 +133,10 @@ class PageEditView(UpdateView):
|
|||
class PageSelectTemplateView(PageEditView):
|
||||
form_class = PageSelectTemplateForm
|
||||
|
||||
@property
|
||||
def comment(self):
|
||||
return _('switched template to %s') % settings.COMBO_PUBLIC_TEMPLATES[self.object.template_name]['name']
|
||||
|
||||
def form_valid(self, form):
|
||||
old_template_name = self.get_object().template_name
|
||||
new_template_name = self.object.template_name
|
||||
|
@ -150,42 +160,49 @@ page_select_template = PageSelectTemplateView.as_view()
|
|||
|
||||
class PageEditRedirectionView(PageEditView):
|
||||
form_class = PageEditRedirectionForm
|
||||
comment = _('changed redirection')
|
||||
|
||||
page_edit_redirection = PageEditRedirectionView.as_view()
|
||||
|
||||
|
||||
class PageEditExcludeFromNavigationView(PageEditView):
|
||||
form_class = PageEditExcludeFromNavigationForm
|
||||
comment = _('changed navigation exclusion')
|
||||
|
||||
page_edit_exclude_from_navigation = PageEditExcludeFromNavigationView.as_view()
|
||||
|
||||
|
||||
class PageEditSlugView(PageEditView):
|
||||
form_class = PageEditSlugForm
|
||||
comment = _('changed slug')
|
||||
|
||||
page_edit_slug = PageEditSlugView.as_view()
|
||||
|
||||
|
||||
class PageEditDescriptionView(PageEditView):
|
||||
form_class = PageEditDescriptionForm
|
||||
comment = _('changed description')
|
||||
|
||||
page_edit_description = PageEditDescriptionView.as_view()
|
||||
|
||||
|
||||
class PageEditTitleView(PageEditView):
|
||||
form_class = PageEditTitleForm
|
||||
comment = _('changed title')
|
||||
|
||||
page_edit_title = PageEditTitleView.as_view()
|
||||
|
||||
|
||||
class PageVisibilityView(PageEditView):
|
||||
form_class = PageVisibilityForm
|
||||
comment = _('changed visibility')
|
||||
|
||||
page_visibility = PageVisibilityView.as_view()
|
||||
|
||||
|
||||
class PageEditPictureView(PageEditView):
|
||||
form_class = PageEditPictureForm
|
||||
comment = _('changed picture')
|
||||
|
||||
page_edit_picture = PageEditPictureView.as_view()
|
||||
|
||||
|
@ -197,6 +214,7 @@ class PageRemovePictureView(DetailView):
|
|||
page = self.get_object()
|
||||
page.picture = None
|
||||
page.save()
|
||||
PageSnapshot.take(page, request=self.request, comment=_('removed picture'))
|
||||
return HttpResponseRedirect(reverse('combo-manager-page-view', kwargs={'pk': page.id}))
|
||||
|
||||
page_remove_picture = PageRemovePictureView.as_view()
|
||||
|
@ -252,6 +270,7 @@ class PageDeleteView(DeleteView):
|
|||
new_parent = deleted_page.parent_id
|
||||
Page.objects.filter(parent=deleted_page).update(parent=new_parent)
|
||||
|
||||
PageSnapshot.take(deleted_page, request=self.request, deletion=True)
|
||||
return self.delete(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
@ -276,6 +295,19 @@ class PageExportView(DetailView):
|
|||
|
||||
page_export = PageExportView.as_view()
|
||||
|
||||
|
||||
class PageHistoryView(ListView):
|
||||
model = PageSnapshot
|
||||
template_name = 'combo/page_history.html'
|
||||
paginate_by = 20
|
||||
|
||||
def get_queryset(self):
|
||||
self.page = Page.objects.get(id=self.kwargs['pk'])
|
||||
return self.page.pagesnapshot_set.all()
|
||||
|
||||
page_history = PageHistoryView.as_view()
|
||||
|
||||
|
||||
class PageAddCellView(RedirectView):
|
||||
permanent = False
|
||||
|
||||
|
@ -289,6 +321,7 @@ class PageAddCellView(RedirectView):
|
|||
else:
|
||||
cell.order = 1
|
||||
cell.save()
|
||||
PageSnapshot.take(cell.page, request=self.request, comment=_('added cell "%s"') % cell)
|
||||
return reverse('combo-manager-page-view', kwargs={'pk': page_pk})
|
||||
|
||||
page_add_cell = PageAddCellView.as_view()
|
||||
|
@ -317,8 +350,11 @@ class PageEditCellView(UpdateView):
|
|||
def form_valid(self, form):
|
||||
if self.request.is_ajax():
|
||||
self.object = form.save()
|
||||
return self.form_invalid(form)
|
||||
return super(PageEditCellView, self).form_valid(form)
|
||||
response = self.form_invalid(form) # avoid redirection
|
||||
else:
|
||||
response = super(PageEditCellView, self).form_valid(form)
|
||||
PageSnapshot.take(self.object.page, request=self.request, comment=_('changed cell "%s"') % self.object)
|
||||
return response
|
||||
|
||||
page_edit_cell = PageEditCellView.as_view()
|
||||
|
||||
|
@ -334,6 +370,14 @@ class PageDeleteCellView(DeleteView):
|
|||
except ObjectDoesNotExist:
|
||||
raise Http404()
|
||||
|
||||
def delete(self, request, *args, **kwargs):
|
||||
cell = self.get_object()
|
||||
comment = _('removed cell "%s"') % cell
|
||||
page = cell.page
|
||||
response = super(PageDeleteCellView, self).delete(request, *args, **kwargs)
|
||||
PageSnapshot.take(page, request=self.request, comment=comment)
|
||||
return response
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('combo-manager-page-view', kwargs={'pk': self.kwargs.get('page_pk')})
|
||||
|
||||
|
@ -359,6 +403,7 @@ page_cell_options = PageCellOptionsView.as_view()
|
|||
|
||||
|
||||
def cell_order(request, page_pk):
|
||||
has_changes = False
|
||||
for cell in CellBase.get_cells(page_id=page_pk):
|
||||
old_order = cell.order
|
||||
old_placeholder = cell.placeholder
|
||||
|
@ -373,7 +418,11 @@ def cell_order(request, page_pk):
|
|||
if new_order != old_order or new_placeholder != old_placeholder:
|
||||
cell.order = new_order
|
||||
cell.placeholder = new_placeholder
|
||||
has_changes = True
|
||||
cell.save()
|
||||
if has_changes:
|
||||
page = Page.objects.get(id=page_pk)
|
||||
PageSnapshot.take(page, request=request, comment=_('reordered cells'))
|
||||
return HttpResponse(status=204)
|
||||
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
from django.conf.urls import url
|
||||
|
||||
from combo.urls_utils import manager_required
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
|
@ -23,6 +24,7 @@ urlpatterns = [
|
|||
url(r'^api/search/', views.api_search, name='api-search'),
|
||||
url(r'^ajax/cell/(?P<page_pk>\w+)/(?P<cell_reference>[\w_-]+)/$',
|
||||
views.ajax_page_cell, name='combo-public-ajax-page-cell'),
|
||||
url(r'^snapshot/(?P<pk>\w+)/$', manager_required(views.snapshot), name='combo-snapshot-view'),
|
||||
url(r'__style__/$', views.style),
|
||||
url(r'__skeleton__/$', views.skeleton),
|
||||
url(r'', views.page),
|
||||
|
|
|
@ -44,7 +44,7 @@ if 'mellon' in settings.INSTALLED_APPS:
|
|||
else:
|
||||
get_idps = lambda: []
|
||||
|
||||
from combo.data.models import CellBase, PostException, Page, ParentContentCell, TextCell
|
||||
from combo.data.models import CellBase, PostException, Page, ParentContentCell, TextCell, PageSnapshot
|
||||
from combo.profile.models import Profile
|
||||
from combo.apps.search.models import SearchCell
|
||||
from combo import utils
|
||||
|
@ -73,7 +73,15 @@ def ajax_page_cell(request, page_pk, cell_reference):
|
|||
try:
|
||||
page = Page.objects.get(id=page_pk)
|
||||
except Page.DoesNotExist:
|
||||
raise Http404()
|
||||
# check it's not from a snapshots
|
||||
try:
|
||||
page = Page.snapshots.get(id=page_pk)
|
||||
except Page.DoesNotExist:
|
||||
raise Http404()
|
||||
# as it's from a snapshot access is limited to managers
|
||||
if not (request.user and request.user.is_staff):
|
||||
raise PermissionDenied()
|
||||
|
||||
if not page.is_visible(request.user):
|
||||
raise PermissionDenied()
|
||||
try:
|
||||
|
@ -441,3 +449,8 @@ def api_search(request):
|
|||
})
|
||||
|
||||
return HttpResponse(json.dumps({'data': hits}), content_type='application/json')
|
||||
|
||||
|
||||
def snapshot(request, *args, **kwargs):
|
||||
snapshot = PageSnapshot.objects.get(id=kwargs['pk'])
|
||||
return publish_page(request, snapshot.get_page())
|
||||
|
|
|
@ -19,7 +19,7 @@ from webtest import TestApp
|
|||
from webtest import Upload
|
||||
|
||||
from combo.wsgi import application
|
||||
from combo.data.models import Page, CellBase, TextCell, LinkCell, ConfigJsonCell, JsonCell
|
||||
from combo.data.models import Page, CellBase, TextCell, LinkCell, ConfigJsonCell, JsonCell, PageSnapshot
|
||||
from combo.apps.family.models import FamilyInfosCell
|
||||
from combo.apps.search.models import SearchCell
|
||||
|
||||
|
@ -727,3 +727,104 @@ def test_page_discover_placeholder_with_error_cells(app, admin_user):
|
|||
|
||||
resp = app.get('/manage/pages/%s/' % page.id)
|
||||
assert re.findall('data-placeholder-key="(.*)">', resp.body) == ['content', 'footer']
|
||||
|
||||
def test_page_versionning(app, admin_user):
|
||||
Page.objects.all().delete()
|
||||
PageSnapshot.objects.all()
|
||||
|
||||
page = Page(title='One', slug='one')
|
||||
page.save()
|
||||
|
||||
cell1 = TextCell(page=page, placeholder='content', text='Foobar1', order=0)
|
||||
cell1.save()
|
||||
cell2 = TextCell(page=page, placeholder='content', text='Foobar2', order=1)
|
||||
cell2.save()
|
||||
cell3 = TextCell(page=page, placeholder='content', text='Foobar3', order=1)
|
||||
cell3.save()
|
||||
|
||||
anonymous_app = app
|
||||
|
||||
app = login(app)
|
||||
resp = app.get('/manage/pages/%s/' % page.id, status=200)
|
||||
|
||||
# update title
|
||||
resp = resp.click(href='.*/title')
|
||||
resp.form['title'].value = 'One Two'
|
||||
resp = resp.form.submit()
|
||||
resp = resp.follow()
|
||||
assert Page.objects.all()[0].title == 'One Two'
|
||||
assert PageSnapshot.objects.all().count() == 1
|
||||
|
||||
# change cell text
|
||||
resp.forms[0]['c%s-text' % cell1.get_reference()].value = 'Hello world'
|
||||
resp = resp.forms[0].submit().follow()
|
||||
assert PageSnapshot.objects.all().count() == 2
|
||||
|
||||
# reorder cells
|
||||
params = []
|
||||
for i, cell in enumerate([cell3, cell1, cell2]):
|
||||
params.append(('ph_data_textcell-%s' % cell.id, 'content')) # no placeholder change
|
||||
params.append(('pos_data_textcell-%s' % cell.id, str(i)))
|
||||
|
||||
app.get('/manage/pages/%s/order?%s' % (page.id, urllib.urlencode(params)))
|
||||
assert PageSnapshot.objects.all().count() == 3
|
||||
|
||||
resp = resp.click('history')
|
||||
assert resp.body.index('reordered cells') < resp.body.index('changed cell') < resp.body.index('changed title')
|
||||
|
||||
resp2 = resp.click('view', index=1)
|
||||
assert resp2.body.index('Hello world') < resp2.body.index('Foobar3')
|
||||
|
||||
resp2 = resp.click('view', index=0)
|
||||
assert resp2.body.index('Hello world') > resp2.body.index('Foobar3')
|
||||
|
||||
resp2 = resp.click('view', index=2)
|
||||
assert 'Foobar1' in resp2.body
|
||||
assert not 'Hello world' in resp2.body
|
||||
|
||||
assert Page.objects.all().count() == 1
|
||||
|
||||
# check with asynchronous cells
|
||||
resp = app.get('/manage/pages/%s/add-cell-to-content/data_jsoncell/default/' % page.id)
|
||||
resp = resp.follow()
|
||||
resp.forms[3]['cdata_jsoncell-1-template_string'].value = 'A{{json.data.0.text}}B'
|
||||
resp.forms[3]['cdata_jsoncell-1-url'].value = 'http://example.com'
|
||||
resp = resp.forms[3].submit().follow()
|
||||
assert PageSnapshot.objects.all().count() == 5 # add + change
|
||||
|
||||
resp.forms[3]['cdata_jsoncell-1-template_string'].value = 'C{{json.data.0.text}}D'
|
||||
resp = resp.forms[3].submit().follow()
|
||||
assert PageSnapshot.objects.all().count() == 6
|
||||
|
||||
resp.forms[1]['c%s-text' % cell1.get_reference()].value = 'Foo back to 1'
|
||||
resp = resp.forms[0].submit().follow()
|
||||
|
||||
resp = resp.click('history')
|
||||
assert 'added cell' in resp.body
|
||||
|
||||
resp2 = resp.click('view', index=1)
|
||||
json_cell_url = re.findall(r'/ajax/cell/.*/data_jsoncell-.*/', resp2.body)[0]
|
||||
|
||||
with mock.patch('combo.utils.requests.get') as requests_get:
|
||||
data = {'data': [{'url': 'xxx', 'text': 'xxx'}]}
|
||||
requests_get.return_value = mock.Mock(content=json.dumps(data), status_code=200)
|
||||
resp3 = app.get(json_cell_url)
|
||||
assert resp3.body.strip() == 'CxxxD'
|
||||
|
||||
# previous version should return AxxxB
|
||||
resp2 = resp.click('view', index=2)
|
||||
json_cell_url = re.findall(r'/ajax/cell/.*/data_jsoncell-.*/', resp2.body)[0]
|
||||
|
||||
with mock.patch('combo.utils.requests.get') as requests_get:
|
||||
data = {'data': [{'url': 'xxx', 'text': 'xxx'}]}
|
||||
requests_get.return_value = mock.Mock(content=json.dumps(data), status_code=200)
|
||||
resp3 = app.get(json_cell_url)
|
||||
assert resp3.body.strip() == 'AxxxB'
|
||||
|
||||
# check anonymous users can't get to cells from snapshots
|
||||
app.get('/logout/')
|
||||
resp3 = app.get(json_cell_url, status=403)
|
||||
|
||||
# clean it up
|
||||
Page.snapshots.all().delete()
|
||||
assert JsonCell.objects.count() == 1
|
||||
|
|
Loading…
Reference in New Issue