add a gallery cell type (#7344)
Signed-off-by: Christophe Siraut <csiraut@entrouvert.com>
This commit is contained in:
parent
1d6ec5f7e0
commit
24af3c8a2f
|
@ -0,0 +1,26 @@
|
|||
# combo - content management system
|
||||
# Copyright (C) 2015 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import django.apps
|
||||
|
||||
class AppConfig(django.apps.AppConfig):
|
||||
name = 'combo.apps.gallery'
|
||||
|
||||
def get_after_manager_urls(self):
|
||||
from . import urls
|
||||
return urls.gallery_manager_urls
|
||||
|
||||
default_app_config = 'combo.apps.gallery.AppConfig'
|
|
@ -0,0 +1,31 @@
|
|||
# combo - content management system
|
||||
# Copyright (C) 2015 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from .models import Image
|
||||
|
||||
class ImageAddForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Image
|
||||
fields = ('image', 'title',)
|
||||
|
||||
|
||||
class ImageEditForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Image
|
||||
fields = ('title',)
|
|
@ -0,0 +1,47 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('auth', '0001_initial'),
|
||||
('data', '0005_auto_20150226_0903'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='GalleryCell',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('placeholder', models.CharField(max_length=20)),
|
||||
('order', models.PositiveIntegerField()),
|
||||
('extra_css_class', models.CharField(max_length=100, verbose_name='Extra classes for CSS styling', blank=True)),
|
||||
('slug', models.SlugField(verbose_name='Slug', blank=True)),
|
||||
('public', models.BooleanField(default=True, verbose_name='Public')),
|
||||
('restricted_to_unlogged', models.BooleanField(default=False, verbose_name='Restrict to unlogged users')),
|
||||
('last_update_timestamp', models.DateTimeField(auto_now=True)),
|
||||
('groups', models.ManyToManyField(to='auth.Group', verbose_name='Groups', blank=True)),
|
||||
('page', models.ForeignKey(to='data.Page')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Gallery',
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Image',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('image', models.ImageField(upload_to=b'uploads/gallery/%Y/%m/', verbose_name='Image')),
|
||||
('order', models.PositiveIntegerField()),
|
||||
('gallery', models.ForeignKey(verbose_name='Gallery', to='gallery.GalleryCell')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['order'],
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('gallery', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='image',
|
||||
name='title',
|
||||
field=models.CharField(max_length=50, verbose_name='Title', blank=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('gallery', '0002_image_title'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='gallerycell',
|
||||
name='title',
|
||||
field=models.CharField(max_length=50, null=True, verbose_name='Title', blank=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
|
@ -0,0 +1,66 @@
|
|||
# combo - content management system
|
||||
# Copyright (C) 2015 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import json
|
||||
|
||||
from django import template
|
||||
from django.db import models
|
||||
from django.core import serializers
|
||||
from django.forms import models as model_forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from combo.data.models import CellBase
|
||||
from combo.data.library import register_cell_class
|
||||
|
||||
@register_cell_class
|
||||
class GalleryCell(CellBase):
|
||||
title = models.CharField(_('Title'), max_length=50, blank=True, null=True)
|
||||
template_name = 'combo/gallerycell.html'
|
||||
manager_form_template = 'combo/gallery_manager.html'
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Gallery')
|
||||
|
||||
def get_additional_label(self):
|
||||
if self.title:
|
||||
return self.title
|
||||
return ''
|
||||
|
||||
def export_subobjects(self):
|
||||
return {'images': [x.get_as_serialized_object() for x in self.image_set.all()]}
|
||||
|
||||
def import_subobjects(self, cell_json):
|
||||
for image in cell_json['images']:
|
||||
image['fields']['gallery_id'] = self.id
|
||||
for image in serializers.deserialize('json', json.dumps(cell_json['images'])):
|
||||
image.save()
|
||||
|
||||
|
||||
class Image(models.Model):
|
||||
gallery = models.ForeignKey(GalleryCell, verbose_name=_('Gallery'))
|
||||
image = models.ImageField(_('Image'),
|
||||
upload_to='uploads/gallery/%Y/%m/')
|
||||
order = models.PositiveIntegerField()
|
||||
title = models.CharField(_('Title'), max_length=50, blank=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['order']
|
||||
|
||||
def get_as_serialized_object(self):
|
||||
serialized_image = json.loads(serializers.serialize('json', [self], use_natural_foreign_keys=True, use_natural_primary_keys=True))[0]
|
||||
del serialized_image['fields']['gallery']
|
||||
del serialized_image['pk']
|
||||
return serialized_image
|
|
@ -0,0 +1,29 @@
|
|||
function gallery(element) {
|
||||
var element_id = '#' + $(element).attr('id');
|
||||
$(element).sortable({
|
||||
items: '> li[data-object-id]',
|
||||
containment: 'parent',
|
||||
placeholder: 'empty-image',
|
||||
update: function(event, ui) {
|
||||
var new_order = $(element).find('> li').map(function() { return $(this).data('object-id'); }).get().join();
|
||||
$.ajax({
|
||||
url: $(element).data('order-url'),
|
||||
data: {'new-order': new_order},
|
||||
success: function(data, status) {
|
||||
$(element).replaceWith($(data).find(element_id));
|
||||
gallery($(element_id));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
$('.image-delete').on('click', function() {
|
||||
$.ajax({
|
||||
url: $(this).attr('href'),
|
||||
success: function(data, status) {
|
||||
$(element).replaceWith($(data).find(element_id));
|
||||
gallery($(element_id));
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
};
|
|
@ -0,0 +1,26 @@
|
|||
{% extends "combo/manager_base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block appbar %}
|
||||
{% if object.id %}
|
||||
<h2>{% trans "Edit Image" %}</h2>
|
||||
{% else %}
|
||||
<h2>{% trans "New Image" %}</h2>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<div class="buttons">
|
||||
<button>{% trans "Save" %}</button>
|
||||
{% if object.id %}
|
||||
<a class="cancel" href="{{ object.get_absolute_url }}">{% trans 'Cancel' %}</a>
|
||||
{% else %}
|
||||
<a class="cancel" href="{% url 'combo-manager-homepage' %}">{% trans 'Cancel' %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -0,0 +1,23 @@
|
|||
{% extends 'combo/cell_form.html' %}
|
||||
{% load static thumbnail i18n %}
|
||||
|
||||
{% block cell-form %}
|
||||
<ul class="gallery" id="gallery-{{cell.id}}" data-order-url="{% url 'combo-gallery-image-order' gallery_pk=cell.id %}">
|
||||
{% for image in cell.image_set.all %}
|
||||
<li data-object-id="{{image.id}}">
|
||||
{% thumbnail image.image "120x120" crop="50% 25%" as im %}
|
||||
<img height="120" src="{{ im.url }}"/>
|
||||
{% endthumbnail %}
|
||||
<span class="image-actions">
|
||||
<a rel="popup" class="image-edit icon-edit" href="{% url 'combo-gallery-image-edit' gallery_pk=cell.id pk=image.id %}"></a>
|
||||
<a class="image-delete icon-remove-sign" href="{% url 'combo-gallery-image-delete' gallery_pk=cell.id pk=image.id %}"></a>
|
||||
</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
<li><a class="button" rel="popup" href="{% url 'combo-gallery-image-add' gallery_pk=cell.id %}">{% trans 'Add an Image' %}</a></li>
|
||||
</ul>
|
||||
|
||||
<script src="{% static "js/combo.gallery.js" %}"></script>
|
||||
<script>gallery($('#gallery-{{cell.id}}'));</script>
|
||||
|
||||
{% endblock %}
|
|
@ -0,0 +1,34 @@
|
|||
{% load thumbnail %}
|
||||
|
||||
{% block cell-content %}
|
||||
<div class="gallery" id="gallery-{{cell.id}}">
|
||||
{% for image in cell.image_set.all %}
|
||||
{% if forloop.first %}
|
||||
{% thumbnail image.image "640x480" crop="50% 25%" as im %}
|
||||
<div class="main-image">
|
||||
<img src="{{ im.url }}" title="{{ image.title }}"/>
|
||||
</div>
|
||||
<div>
|
||||
{% endthumbnail %}
|
||||
{% endif %}
|
||||
{% thumbnail image.image "60x60" crop="50% 25%" as im %}
|
||||
{% thumbnail image.image "640x480" crop="50% 25%" as im_large %}
|
||||
<a data-image-large="{{ im_large.url }}" class="image-switch"><img src="{{ im.url }}"
|
||||
{% if image.title %} title="{{image.title}}" {% endif %}/></a>
|
||||
{% endthumbnail %}
|
||||
{% endthumbnail %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
var $gallery = $('#gallery-{{cell.id}}');
|
||||
$gallery.find('.image-switch').on('click', function() {
|
||||
$gallery.find('div.main-image img').attr('src', $(this).data('image-large'));
|
||||
var $title = $(this).find('img').attr('title') || '';
|
||||
$gallery.find('div.main-image img').attr('title', $title);
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -0,0 +1,30 @@
|
|||
# combo - content management system
|
||||
# Copyright (C) 2015 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from . import views
|
||||
|
||||
gallery_manager_urls = [
|
||||
url('^gallery/(?P<gallery_pk>\w+)/images/add/$', views.image_add,
|
||||
name='combo-gallery-image-add'),
|
||||
url('^gallery/(?P<gallery_pk>\w+)/order$', views.image_order,
|
||||
name='combo-gallery-image-order'),
|
||||
url('^gallery/(?P<gallery_pk>\w+)/images/(?P<pk>\w+)/edit$', views.image_edit,
|
||||
name='combo-gallery-image-edit'),
|
||||
url('^gallery/(?P<gallery_pk>\w+)/images/(?P<pk>\w+)/delete$', views.image_delete,
|
||||
name='combo-gallery-image-delete'),
|
||||
]
|
|
@ -0,0 +1,68 @@
|
|||
# combo - content management system
|
||||
# Copyright (C) 2015 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.core.urlresolvers import reverse, reverse_lazy
|
||||
from django.shortcuts import redirect
|
||||
from django.views.generic import (TemplateView, RedirectView, DetailView,
|
||||
CreateView, UpdateView, ListView, DeleteView, FormView)
|
||||
|
||||
from .models import Image, GalleryCell
|
||||
from .forms import ImageAddForm, ImageEditForm
|
||||
|
||||
class ImageAddView(CreateView):
|
||||
model = Image
|
||||
template_name = 'combo/gallery_image_form.html'
|
||||
form_class = ImageAddForm
|
||||
|
||||
def form_valid(self, form):
|
||||
form.instance.gallery_id = self.kwargs.get('gallery_pk')
|
||||
other_images = form.instance.gallery.image_set.all()
|
||||
if other_images:
|
||||
form.instance.order = max([x.order for x in other_images]) + 1
|
||||
else:
|
||||
form.instance.order = 0
|
||||
return super(ImageAddView, self).form_valid(form)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('combo-manager-page-view', kwargs={'pk': self.object.gallery.page.id})
|
||||
|
||||
image_add = ImageAddView.as_view()
|
||||
|
||||
|
||||
class ImageEditView(UpdateView):
|
||||
model = Image
|
||||
template_name = 'combo/gallery_image_form.html'
|
||||
form_class = ImageEditForm
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('combo-manager-page-view', kwargs={'pk': self.object.gallery.page.id})
|
||||
|
||||
image_edit = ImageEditView.as_view()
|
||||
|
||||
|
||||
def image_delete(request, gallery_pk, pk):
|
||||
gallery = GalleryCell.objects.get(id=gallery_pk)
|
||||
Image.objects.get(id=pk).delete()
|
||||
return redirect(reverse('combo-manager-page-view', kwargs={'pk': gallery.page.id}))
|
||||
|
||||
|
||||
def image_order(request, gallery_pk):
|
||||
gallery = GalleryCell.objects.get(id=gallery_pk)
|
||||
new_order = [int(x) for x in request.GET['new-order'].split(',')]
|
||||
for image in gallery.image_set.all():
|
||||
image.order = new_order.index(image.id)+1
|
||||
image.save()
|
||||
return redirect(reverse('combo-manager-page-view', kwargs={'pk': gallery.page.id}))
|
|
@ -359,6 +359,8 @@ class Page(models.Model):
|
|||
del serialized_page['fields']['related_cells']
|
||||
serialized_page['cells'] = json.loads(serializers.serialize('json',
|
||||
cells, use_natural_foreign_keys=True, use_natural_primary_keys=True))
|
||||
for index, cell in enumerate(cells):
|
||||
serialized_page['cells'][index].update(cell.export_subobjects())
|
||||
serialized_page['fields']['groups'] = [x[0] for x in serialized_page['fields']['groups']]
|
||||
for cell in serialized_page['cells']:
|
||||
del cell['pk']
|
||||
|
@ -385,6 +387,7 @@ class Page(models.Model):
|
|||
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()
|
||||
|
@ -393,10 +396,11 @@ class Page(models.Model):
|
|||
@classmethod
|
||||
def load_serialized_cells(cls, cells):
|
||||
# load new cells
|
||||
for cell in serializers.deserialize('json', json.dumps(cells)):
|
||||
for index, cell in enumerate(serializers.deserialize('json', json.dumps(cells))):
|
||||
cell.save()
|
||||
# will populate cached_* attributes
|
||||
cell.object.save()
|
||||
cell.object.import_subobjects(cells[index])
|
||||
|
||||
@classmethod
|
||||
def load_serialized_pages(cls, json_site):
|
||||
|
@ -718,6 +722,11 @@ class CellBase(six.with_metaclass(CellMeta, models.Model)):
|
|||
def get_external_links_data(self):
|
||||
return []
|
||||
|
||||
def export_subobjects(self):
|
||||
return {}
|
||||
|
||||
def import_subobjects(self, cell_json):
|
||||
pass
|
||||
|
||||
@register_cell_class
|
||||
class TextCell(CellBase):
|
||||
|
|
|
@ -112,6 +112,7 @@ div.cell-list button.save {
|
|||
|
||||
|
||||
div.cell div.buttons {
|
||||
clear: both;
|
||||
margin-top: 2em;
|
||||
margin-bottom: 1ex;
|
||||
}
|
||||
|
@ -188,6 +189,9 @@ p#redirection {
|
|||
float: right;
|
||||
}
|
||||
|
||||
.icon-eye-open:before { content: "\f06e "; }
|
||||
.icon-edit:before { content: "\f044"; }
|
||||
|
||||
#assets-browser {
|
||||
display: flex;
|
||||
}
|
||||
|
@ -380,3 +384,51 @@ span.error {
|
|||
#id_sub_slug + span.helptext {
|
||||
max-width: 35rem;
|
||||
}
|
||||
|
||||
div.gallerycell div.buttons button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
ul.gallery {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul.gallery li {
|
||||
float: left;
|
||||
margin: 0 0.5rem 0.5rem 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
ul.gallery li img {
|
||||
border: 1px solid #aaa;
|
||||
background: white;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
ul.gallery li.empty-image {
|
||||
width: 122px;
|
||||
}
|
||||
|
||||
ul.gallery li span.image-actions {
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
right: 5px;
|
||||
font-size: 150%;
|
||||
}
|
||||
|
||||
ul.gallery li:last-child {
|
||||
height: 124px;
|
||||
width: 124px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ul.gallery li:last-child a {
|
||||
display: block;
|
||||
line-height: 120px;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@ INSTALLED_APPS = (
|
|||
'combo.apps.maps',
|
||||
'combo.apps.calendar',
|
||||
'combo.apps.pwa',
|
||||
'combo.apps.gallery',
|
||||
'haystack',
|
||||
'xstatic.pkg.josefinsans',
|
||||
'xstatic.pkg.leaflet',
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from combo.data.models import Page
|
||||
from combo.apps.gallery.models import GalleryCell, Image
|
||||
|
||||
from .test_manager import login
|
||||
|
||||
TESTS_DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
def test_adding_gallery_images(app, admin_user):
|
||||
page = Page(title='Pictures', slug='test_gallery_cell', template_name='standard')
|
||||
page.save()
|
||||
cell = GalleryCell(page=page, placeholder='content', order=0)
|
||||
cell.save()
|
||||
|
||||
app.post(reverse('combo-gallery-image-add', kwargs={'gallery_pk': cell.id}), params={'image': ['foo'], 'title': 'white'}, status=403)
|
||||
|
||||
app = login(app)
|
||||
mgr = app.get(reverse('combo-manager-page-edit-cell', kwargs={'page_pk': page.id, 'cell_reference': cell.get_reference()}), status=200)
|
||||
assert '<ul class="gallery"' in mgr.content
|
||||
assert 'js/combo.gallery.js' in mgr.content
|
||||
|
||||
assert len(cell.image_set.all()) == 0
|
||||
form = app.get(reverse('combo-gallery-image-add', kwargs={'gallery_pk': cell.id})).form
|
||||
form['image'] = [os.path.join(TESTS_DATA_DIR, 'black.jpeg')]
|
||||
form['title'] = 'black'
|
||||
form.submit()
|
||||
form = app.get(reverse('combo-gallery-image-add', kwargs={'gallery_pk': cell.id})).form
|
||||
form['image'] = [os.path.join(TESTS_DATA_DIR, 'black.jpeg')]
|
||||
form['title'] = 'white'
|
||||
form.submit()
|
||||
assert len(cell.image_set.all()) == 2
|
||||
|
||||
image_2 = cell.image_set.all()[1]
|
||||
form = app.get(reverse('combo-gallery-image-edit', kwargs={'gallery_pk': cell.id, 'pk': image_2.id})).form
|
||||
form['title'] = 'pink'
|
||||
form.submit()
|
||||
assert len(cell.image_set.filter(title='pink')) == 1
|
||||
|
||||
data = app.get('/%s/' % page.slug, status=200)
|
||||
assert 'pink' in data.content
|
||||
|
||||
mgr = app.get(reverse('combo-gallery-image-delete', kwargs={'gallery_pk': cell.id, 'pk': image_2.id}), status=302)
|
||||
assert len(cell.image_set.all()) == 1
|
||||
|
||||
data = app.get('/%s/' % page.slug, status=200)
|
||||
assert 'pink' not in data.content
|
|
@ -14,6 +14,7 @@ from django.utils.encoding import force_bytes, force_text
|
|||
from django.utils.six import BytesIO, StringIO
|
||||
|
||||
from combo.apps.assets.models import Asset
|
||||
from combo.apps.gallery.models import Image, GalleryCell
|
||||
from combo.apps.maps.models import MapLayer, Map
|
||||
from combo.apps.pwa.models import PwaSettings, PwaNavigationEntry
|
||||
from combo.data.models import Page, TextCell
|
||||
|
@ -250,3 +251,20 @@ def test_import_export_pwa_navigation(app, some_data):
|
|||
assert PwaNavigationEntry.objects.all().count() == 2
|
||||
assert os.path.basename(PwaNavigationEntry.objects.get(order=1).icon.file.name) == 'test2.png'
|
||||
assert PwaNavigationEntry.objects.get(order=1).icon.read() == b'TEST2'
|
||||
|
||||
def test_import_export_gallery_images(app, some_data):
|
||||
page = Page.objects.get(slug='one')
|
||||
gallery = GalleryCell(page=page, order=2, placeholder='images')
|
||||
gallery.save()
|
||||
image1 = Image(gallery=gallery, image='path/foo.jpg', title='foo', order=1)
|
||||
image2 = Image(gallery=gallery, image='path/bar.jpg', title='bar', order=2)
|
||||
image1.save()
|
||||
image2.save()
|
||||
output = get_output_of_command('export_site')
|
||||
import_site(data={}, clean=True)
|
||||
assert Image.objects.all().count() == 0
|
||||
|
||||
import_site(data=json.loads(output))
|
||||
assert Image.objects.all().count() == 2
|
||||
assert image1.title == 'foo'
|
||||
assert image1.image == 'path/foo.jpg'
|
||||
|
|
Loading…
Reference in New Issue