maps: new MapLayerOptions model (#22639)
This commit is contained in:
parent
3d3805d2cd
commit
34e627b0d8
|
@ -20,7 +20,7 @@ from django.utils.text import slugify
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from combo.data.fields import TemplatableURLField
|
||||
from .models import MapLayer
|
||||
from .models import MapLayer, MapLayerOptions
|
||||
|
||||
|
||||
class IconRadioSelect(forms.RadioSelect):
|
||||
|
@ -37,7 +37,6 @@ class MapNewLayerForm(forms.ModelForm):
|
|||
'icon_colour': forms.TextInput(attrs={'type': 'color'}),
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MapNewLayerForm, self).__init__(*args, **kwargs)
|
||||
self.fields['icon'].choices = list(
|
||||
|
@ -59,3 +58,13 @@ class MapLayerForm(forms.ModelForm):
|
|||
super(MapLayerForm, self).__init__(*args, **kwargs)
|
||||
self.fields['icon'].choices = list(
|
||||
sorted(self.fields['icon'].choices, key=lambda x: slugify(force_text(x[1]))))
|
||||
|
||||
|
||||
class MapLayerOptionsForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = MapLayerOptions
|
||||
fields = ['map_layer']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MapLayerOptionsForm, self).__init__(*args, **kwargs)
|
||||
self.fields['map_layer'].queryset = self.instance.map_cell.get_free_layers()
|
||||
|
|
|
@ -14,13 +14,17 @@
|
|||
# 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_lazy
|
||||
from django.views.generic import (TemplateView, ListView, CreateView,
|
||||
UpdateView, DeleteView)
|
||||
from django.core.urlresolvers import reverse, reverse_lazy
|
||||
from django.http import Http404
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.views.generic import ListView, CreateView, UpdateView, DeleteView
|
||||
|
||||
from combo.data.models import CellBase, PageSnapshot
|
||||
from .models import Map
|
||||
from .models import MapLayer
|
||||
from .forms import MapNewLayerForm, MapLayerForm
|
||||
from .models import MapLayerOptions
|
||||
from .forms import MapNewLayerForm, MapLayerForm, MapLayerOptionsForm
|
||||
|
||||
|
||||
class MapLayerMixin(object):
|
||||
|
@ -49,3 +53,69 @@ class LayerEditView(MapLayerMixin, UpdateView):
|
|||
|
||||
class LayerDeleteView(MapLayerMixin, DeleteView):
|
||||
template_name = 'maps/map_layer_confirm_delete.html'
|
||||
|
||||
|
||||
class MapCellAddLayer(CreateView):
|
||||
form_class = MapLayerOptionsForm
|
||||
template_name = 'maps/layer_options_form.html'
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
try:
|
||||
self.cell = CellBase.get_cell(kwargs['cell_reference'], page=kwargs['page_pk'])
|
||||
except Map.DoesNotExist:
|
||||
raise Http404
|
||||
return super(MapCellAddLayer, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(MapCellAddLayer, self).get_form_kwargs()
|
||||
kwargs['instance'] = MapLayerOptions(map_cell=self.cell)
|
||||
return kwargs
|
||||
|
||||
def form_valid(self, form):
|
||||
PageSnapshot.take(
|
||||
self.cell.page,
|
||||
request=self.request,
|
||||
comment=_('added layer "%s" to cell "%s"') % (form.instance.map_layer, self.cell))
|
||||
return super(MapCellAddLayer, self).form_valid(form)
|
||||
|
||||
def get_success_url(self):
|
||||
return '%s#cell-%s' % (
|
||||
reverse('combo-manager-page-view', kwargs={'pk': self.kwargs.get('page_pk')}),
|
||||
self.kwargs['cell_reference'])
|
||||
|
||||
|
||||
map_cell_add_layer = MapCellAddLayer.as_view()
|
||||
|
||||
|
||||
class MapCellDeleteLayer(DeleteView):
|
||||
template_name = 'combo/generic_confirm_delete.html'
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
try:
|
||||
self.cell = CellBase.get_cell(kwargs['cell_reference'], page=kwargs['page_pk'])
|
||||
except Map.DoesNotExist:
|
||||
raise Http404
|
||||
self.object = get_object_or_404(
|
||||
MapLayerOptions,
|
||||
pk=kwargs['layeroptions_pk'],
|
||||
map_cell=self.cell)
|
||||
return super(MapCellDeleteLayer, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_object(self, *args, **kwargs):
|
||||
return self.object
|
||||
|
||||
def delete(self, request, *args, **kwargs):
|
||||
response = super(MapCellDeleteLayer, self).delete(request, *args, **kwargs)
|
||||
PageSnapshot.take(
|
||||
self.cell.page,
|
||||
request=self.request,
|
||||
comment=_('removed layer "%s" from cell "%s"') % (self.object.map_layer, self.cell))
|
||||
return response
|
||||
|
||||
def get_success_url(self):
|
||||
return '%s#cell-%s' % (
|
||||
reverse('combo-manager-page-view', kwargs={'pk': self.kwargs.get('page_pk')}),
|
||||
self.kwargs['cell_reference'])
|
||||
|
||||
|
||||
map_cell_delete_layer = MapCellDeleteLayer.as_view()
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('maps', '0007_auto_20180706_1345'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.SeparateDatabaseAndState(
|
||||
state_operations=[
|
||||
migrations.CreateModel(
|
||||
name='MapLayerOptions',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'maps_map_layers',
|
||||
},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='map',
|
||||
name='layers',
|
||||
field=models.ManyToManyField(blank=True, through='maps.MapLayerOptions', to='maps.MapLayer', verbose_name='Layers'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='maplayeroptions',
|
||||
name='map_cell',
|
||||
field=models.ForeignKey(db_column='map_id', on_delete=django.db.models.deletion.CASCADE, to='maps.Map'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='maplayeroptions',
|
||||
name='map_layer',
|
||||
field=models.ForeignKey(db_column='maplayer_id', verbose_name='Layer', on_delete=django.db.models.deletion.CASCADE, to='maps.MapLayer'),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='maplayeroptions',
|
||||
unique_together=set([('map_cell', 'map_layer')]),
|
||||
),
|
||||
],
|
||||
database_operations=[]
|
||||
)
|
||||
]
|
|
@ -0,0 +1,35 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.18 on 2020-02-07 09:00
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('maps', '0008_map_layer_options'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='maplayer',
|
||||
name='kind',
|
||||
field=models.CharField(choices=[('tiles', 'Tiles'), ('geojson', 'GeoJSON')], default='geojson', max_length=10),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='maplayer',
|
||||
name='tiles_attribution',
|
||||
field=models.CharField(blank=True, max_length=1024, null=True, verbose_name='Attribution'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='maplayer',
|
||||
name='tiles_default',
|
||||
field=models.BooleanField(default=False, verbose_name='Default tiles layer'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='maplayer',
|
||||
name='tiles_template_url',
|
||||
field=models.CharField(blank=True, max_length=1024, null=True, verbose_name='Tiles URL'),
|
||||
),
|
||||
]
|
|
@ -267,9 +267,15 @@ class Map(CellBase):
|
|||
group_markers = models.BooleanField(_('Group markers in clusters'), default=False)
|
||||
marker_behaviour_onclick = models.CharField(_('Marker behaviour on click'), max_length=32,
|
||||
default='none', choices=MARKER_BEHAVIOUR_ONCLICK)
|
||||
layers = models.ManyToManyField(MapLayer, verbose_name=_('Layers'), blank=True)
|
||||
layers = models.ManyToManyField(
|
||||
MapLayer,
|
||||
through='MapLayerOptions',
|
||||
verbose_name=_('Layers'),
|
||||
blank=True
|
||||
)
|
||||
|
||||
template_name = 'maps/map_cell.html'
|
||||
manager_form_template = 'maps/map_cell_form.html'
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Map')
|
||||
|
@ -287,10 +293,8 @@ class Map(CellBase):
|
|||
|
||||
def get_default_form_class(self):
|
||||
fields = ('title', 'initial_state', 'initial_zoom', 'min_zoom',
|
||||
'max_zoom', 'group_markers', 'marker_behaviour_onclick', 'layers')
|
||||
widgets = {'layers': forms.widgets.CheckboxSelectMultiple}
|
||||
return forms.models.modelform_factory(self.__class__, fields=fields,
|
||||
widgets=widgets)
|
||||
'max_zoom', 'group_markers', 'marker_behaviour_onclick')
|
||||
return forms.models.modelform_factory(self.__class__, fields=fields)
|
||||
|
||||
def get_geojson(self, request):
|
||||
geojson = {'type': 'FeatureCollection', 'features': []}
|
||||
|
@ -302,7 +306,7 @@ class Map(CellBase):
|
|||
|
||||
@classmethod
|
||||
def is_enabled(cls):
|
||||
return MapLayer.objects.count() > 0
|
||||
return MapLayer.objects.exists()
|
||||
|
||||
def get_cell_extra_context(self, context):
|
||||
ctx = super(Map, self).get_cell_extra_context(context)
|
||||
|
@ -322,6 +326,52 @@ class Map(CellBase):
|
|||
ctx['marker_behaviour_onclick'] = self.marker_behaviour_onclick
|
||||
return ctx
|
||||
|
||||
def get_free_layers(self):
|
||||
used_layers = MapLayerOptions.objects.filter(map_cell=self).values('map_layer')
|
||||
return MapLayer.objects.exclude(pk__in=used_layers)
|
||||
|
||||
def export_subobjects(self):
|
||||
return {'layers': [x.get_as_serialized_object() for x in MapLayerOptions.objects.filter(map_cell=self)]}
|
||||
|
||||
@classmethod
|
||||
def prepare_serialized_data(cls, cell_data):
|
||||
# ensure compatibility with old exports
|
||||
if 'layers' in cell_data['fields']:
|
||||
layers = cell_data['fields'].pop('layers')
|
||||
cell_data['layers'] = [
|
||||
{
|
||||
'fields': {'map_layer': layer},
|
||||
'model': 'maps.maplayeroptions'
|
||||
} for layer in layers
|
||||
]
|
||||
return cell_data
|
||||
|
||||
def import_subobjects(self, cell_json):
|
||||
if 'layers' not in cell_json:
|
||||
return
|
||||
for layer in cell_json['layers']:
|
||||
layer['fields']['map_cell'] = self.pk
|
||||
for layer in serializers.deserialize('json', json.dumps(cell_json['layers'])):
|
||||
layer.save()
|
||||
|
||||
def duplicate_m2m(self, new_cell):
|
||||
# set layers
|
||||
new_cell.layers.set(self.layers.all())
|
||||
for layer in self.layers.all():
|
||||
MapLayerOptions.objects.create(map_cell=new_cell, map_layer=layer)
|
||||
|
||||
|
||||
class MapLayerOptions(models.Model):
|
||||
map_cell = models.ForeignKey(Map, on_delete=models.CASCADE, db_column='map_id')
|
||||
map_layer = models.ForeignKey(MapLayer, verbose_name=_('Layer'), on_delete=models.CASCADE, db_column='maplayer_id')
|
||||
|
||||
class Meta:
|
||||
db_table = 'maps_map_layers'
|
||||
unique_together = ('map_cell', 'map_layer')
|
||||
|
||||
def get_as_serialized_object(self):
|
||||
serialized_options = json.loads(
|
||||
serializers.serialize('json', [self], use_natural_foreign_keys=True, use_natural_primary_keys=True)
|
||||
)[0]
|
||||
del serialized_options['fields']['map_cell']
|
||||
del serialized_options['pk']
|
||||
return serialized_options
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
{% extends "combo/manager_base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block appbar %}
|
||||
{% if form.instance.pk %}
|
||||
<h2>{% trans "Edit layer" %}</h2>
|
||||
{% else %}
|
||||
<h2>{% trans "New layer" %}</h2>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<div class="buttons">
|
||||
<button class="submit-button">{% trans "Save" %}</button>
|
||||
<a class="cancel" href="{% url 'combo-manager-page-view' pk=form.instance.map_cell.page_id %}">{% trans 'Cancel' %}</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -0,0 +1,26 @@
|
|||
{% extends "combo/cell_form.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block cell-form %}
|
||||
{{ form.as_p }}
|
||||
{% with cell.maplayeroptions_set.all as options %}
|
||||
{% if options %}
|
||||
<p><label>{% trans "Layers:" %}</label></p>
|
||||
<div>
|
||||
<ul class="objects-list list-of-layers">
|
||||
{% for option in options %}
|
||||
<li>
|
||||
<span>{{ option.map_layer }}</span>
|
||||
<a rel="popup" title="{% trans "Delete" %}" class="link-action-icon delete" href="{% url 'maps-manager-cell-delete-layer' page_pk=page.pk cell_reference=cell.get_reference layeroptions_pk=option.pk %}">{% trans "Delete" %}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% if cell.get_free_layers.exists %}
|
||||
<div class="buttons">
|
||||
<a rel="popup" href="{% url 'maps-manager-cell-add-layer' page_pk=page.pk cell_reference=cell.get_reference %}">{% trans "Add a layer" %}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
|
@ -18,18 +18,23 @@ from django.conf.urls import url, include
|
|||
|
||||
from combo.urls_utils import decorated_includes, manager_required
|
||||
|
||||
from .manager_views import (ManagerHomeView, LayerAddView,
|
||||
LayerEditView, LayerDeleteView)
|
||||
from . import manager_views
|
||||
|
||||
from .views import GeojsonView
|
||||
|
||||
maps_manager_urls = [
|
||||
url('^$', ManagerHomeView.as_view(), name='maps-manager-homepage'),
|
||||
url('^layers/add/$', LayerAddView.as_view(), name='maps-manager-layer-add'),
|
||||
url(r'^layers/(?P<slug>[\w-]+)/edit/$', LayerEditView.as_view(),
|
||||
url('^$', manager_views.ManagerHomeView.as_view(), name='maps-manager-homepage'),
|
||||
url('^layers/add/$', manager_views.LayerAddView.as_view(), name='maps-manager-layer-add'),
|
||||
url(r'^layers/(?P<slug>[\w-]+)/edit/$', manager_views.LayerEditView.as_view(),
|
||||
name='maps-manager-layer-edit'),
|
||||
url(r'^layers/(?P<slug>[\w-]+)/delete/$', LayerDeleteView.as_view(),
|
||||
url(r'^layers/(?P<slug>[\w-]+)/delete/$', manager_views.LayerDeleteView.as_view(),
|
||||
name='maps-manager-layer-delete'),
|
||||
url(r'^pages/(?P<page_pk>\d+)/cell/(?P<cell_reference>[\w_-]+)/add-layer/$',
|
||||
manager_views.map_cell_add_layer,
|
||||
name='maps-manager-cell-add-layer'),
|
||||
url(r'^pages/(?P<page_pk>\d+)/cell/(?P<cell_reference>[\w_-]+)/layer/(?P<layeroptions_pk>\d+)/delete/$',
|
||||
manager_views.map_cell_delete_layer,
|
||||
name='maps-manager-cell-delete-layer'),
|
||||
]
|
||||
|
||||
urlpatterns = [
|
||||
|
|
|
@ -413,13 +413,14 @@ class Page(models.Model):
|
|||
@classmethod
|
||||
def load_serialized_cells(cls, cells):
|
||||
# load new cells
|
||||
deserialized_cells = serializers.deserialize('json', json.dumps(cells),
|
||||
ignorenonexistent=True)
|
||||
for index, cell in enumerate(deserialized_cells):
|
||||
for cell_data in cells:
|
||||
model = apps.get_model(cell_data['model'])
|
||||
cell_data = model.prepare_serialized_data(cell_data)
|
||||
cell = list(serializers.deserialize('json', json.dumps([cell_data]), ignorenonexistent=True))[0]
|
||||
cell.save()
|
||||
# will populate cached_* attributes
|
||||
cell.object.save()
|
||||
cell.object.import_subobjects(cells[index])
|
||||
cell.object.import_subobjects(cell_data)
|
||||
|
||||
@classmethod
|
||||
def load_serialized_pages(cls, json_site):
|
||||
|
@ -774,6 +775,10 @@ class CellBase(six.with_metaclass(CellMeta, models.Model)):
|
|||
def get_external_links_data(self):
|
||||
return []
|
||||
|
||||
@classmethod
|
||||
def prepare_serialized_data(cls, cell_data):
|
||||
return cell_data
|
||||
|
||||
def export_subobjects(self):
|
||||
return {}
|
||||
|
||||
|
|
|
@ -485,7 +485,8 @@ ul.objects-list.list-of-links li {
|
|||
padding-left: 0;
|
||||
}
|
||||
|
||||
ul.objects-list.list-of-links li a.link-action-icon {
|
||||
ul.objects-list.list-of-links li a.link-action-icon,
|
||||
ul.objects-list.list-of-layers li a.link-action-icon {
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
|
@ -499,7 +500,8 @@ ul.objects-list.list-of-links li a.link-action-icon {
|
|||
line-height: 3em;
|
||||
}
|
||||
|
||||
ul.objects-list.list-of-links li a.link-action-icon::before {
|
||||
ul.objects-list.list-of-links li a.link-action-icon::before,
|
||||
ul.objects-list.list-of-layers li a.link-action-icon::before {
|
||||
font-family: FontAwesome;
|
||||
text-indent: 0px;
|
||||
text-align: center;
|
||||
|
@ -507,14 +509,17 @@ ul.objects-list.list-of-links li a.link-action-icon::before {
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
ul.objects-list.list-of-links li a.link-action-icon.delete::before {
|
||||
ul.objects-list.list-of-links li a.link-action-icon.delete::before,
|
||||
ul.objects-list.list-of-layers li a.link-action-icon.delete::before {
|
||||
content: "\f057"; /* remove-sign */
|
||||
}
|
||||
|
||||
ul.objects-list.list-of-links li a.link-action-icon.edit {
|
||||
ul.objects-list.list-of-links li a.link-action-icon.edit,
|
||||
ul.objects-list.list-of-layers li a.link-action-icon.edit {
|
||||
right: 3em;
|
||||
}
|
||||
|
||||
ul.objects-list.list-of-links li a.link-action-icon.edit::before {
|
||||
ul.objects-list.list-of-links li a.link-action-icon.edit::before,
|
||||
ul.objects-list.list-of-layers li a.link-action-icon.edit::before {
|
||||
content: "\f044";
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ 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.maps.models import MapLayer, Map, MapLayerOptions
|
||||
from combo.apps.pwa.models import PwaSettings, PwaNavigationEntry
|
||||
from combo.data.models import Page, TextCell
|
||||
from combo.data.utils import export_site, import_site, MissingGroups
|
||||
|
@ -123,20 +123,36 @@ def test_import_export_map_layers(app, some_map_layers):
|
|||
import_site(data={}, if_empty=True)
|
||||
assert MapLayer.objects.count() == 2
|
||||
|
||||
|
||||
def test_import_export_map_cells(app, some_data, some_map_layers):
|
||||
page = Page.objects.get(slug='one')
|
||||
cell = Map(page=page, order=0, placeholder='content')
|
||||
cell.save()
|
||||
cell.layers.add(MapLayer.objects.get(slug='foo'))
|
||||
cell.save()
|
||||
MapLayerOptions.objects.create(map_cell=cell, map_layer=MapLayer.objects.get(slug='foo'))
|
||||
site_export = get_output_of_command('export_site')
|
||||
import_site(data={}, clean=True)
|
||||
assert Map.objects.count() == 0
|
||||
assert MapLayer.objects.count() == 0
|
||||
|
||||
import_site(data=json.loads(site_export), clean=True)
|
||||
site_data = json.loads(site_export)
|
||||
import_site(data=site_data, clean=True)
|
||||
assert Map.objects.count() == 1
|
||||
assert MapLayer.objects.filter(slug='foo').exists() is True
|
||||
assert Map.objects.all()[0].layers.all()[0].slug == 'foo'
|
||||
|
||||
# test old export format
|
||||
import_site(data={}, clean=True)
|
||||
assert Map.objects.count() == 0
|
||||
assert MapLayer.objects.count() == 0
|
||||
|
||||
del site_data['pages'][0]['cells'][0]['layers']
|
||||
site_data['pages'][0]['cells'][0]['fields']['layers'] = [['foo']]
|
||||
import_site(data=site_data, clean=True)
|
||||
assert Map.objects.count() == 1
|
||||
assert MapLayer.objects.filter(slug='foo').exists() is True
|
||||
assert Map.objects.all()[0].layers.all()[0].slug == 'foo'
|
||||
|
||||
|
||||
def test_group_restrictions_import_export(app, some_data):
|
||||
group = Group(name='A Group')
|
||||
group.save()
|
||||
|
|
|
@ -9,7 +9,7 @@ from django.core.urlresolvers import reverse
|
|||
from django.contrib.auth.models import Group
|
||||
|
||||
from combo.data.models import Page
|
||||
from combo.apps.maps.models import MapLayer, Map
|
||||
from combo.apps.maps.models import MapLayer, Map, MapLayerOptions
|
||||
|
||||
from .test_manager import login
|
||||
|
||||
|
@ -123,7 +123,7 @@ def test_cell_rendering(app, layer):
|
|||
page.save()
|
||||
cell = Map(page=page, placeholder='content', order=0, title='Map with points')
|
||||
cell.save()
|
||||
cell.layers.add(layer)
|
||||
MapLayerOptions.objects.create(map_cell=cell, map_layer=layer)
|
||||
context = {'request': RequestFactory().get('/')}
|
||||
rendered = cell.render(context)
|
||||
assert 'data-init-zoom="13"' in rendered
|
||||
|
@ -152,7 +152,7 @@ def test_get_geojson_on_non_public_page(app, layer):
|
|||
cell = Map(page=page, placeholder='content', order=0,
|
||||
title='Map with points')
|
||||
cell.save()
|
||||
cell.layers.add(layer)
|
||||
MapLayerOptions.objects.create(map_cell=cell, map_layer=layer)
|
||||
app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}), status=403)
|
||||
|
||||
def test_get_geojson_on_non_publik_cell(app, layer):
|
||||
|
@ -161,7 +161,7 @@ def test_get_geojson_on_non_publik_cell(app, layer):
|
|||
cell = Map(page=page, placeholder='content', order=0, public=False,
|
||||
title='Map with points')
|
||||
cell.save()
|
||||
cell.layers.add(layer)
|
||||
MapLayerOptions.objects.create(map_cell=cell, map_layer=layer)
|
||||
app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}), status=403)
|
||||
|
||||
def test_geojson_on_restricted_cell(app, layer, user):
|
||||
|
@ -171,7 +171,7 @@ def test_geojson_on_restricted_cell(app, layer, user):
|
|||
cell = Map(page=page, placeholder='content', order=0, public=False)
|
||||
cell.title = 'Map with points'
|
||||
cell.save()
|
||||
cell.layers.add(layer)
|
||||
MapLayerOptions.objects.create(map_cell=cell, map_layer=layer)
|
||||
cell.groups.add(group)
|
||||
login(app)
|
||||
app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}), status=403)
|
||||
|
@ -193,7 +193,7 @@ def test_get_geojson(app, layer, user):
|
|||
cell.save()
|
||||
layer.geojson_url = 'http://example.org/geojson?t1'
|
||||
layer.save()
|
||||
cell.layers.add(layer)
|
||||
MapLayerOptions.objects.create(map_cell=cell, map_layer=layer)
|
||||
|
||||
# check cache duration
|
||||
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as requests_get:
|
||||
|
@ -307,7 +307,7 @@ def test_get_geojson(app, layer, user):
|
|||
layer2.icon = 'fa-bicycle'
|
||||
layer2.icon_colour = '0000FF'
|
||||
layer2.save()
|
||||
cell.layers.add(layer2)
|
||||
MapLayerOptions.objects.create(map_cell=cell, map_layer=layer2)
|
||||
|
||||
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as requests_get:
|
||||
requests_get.return_value = mock.Mock(
|
||||
|
@ -338,7 +338,7 @@ def test_get_geojson_properties(app, layer, user):
|
|||
cell.title = 'Map'
|
||||
cell.save()
|
||||
layer.save()
|
||||
cell.layers.add(layer)
|
||||
MapLayerOptions.objects.create(map_cell=cell, map_layer=layer)
|
||||
|
||||
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as requests_get:
|
||||
layer.geojson_url = 'http://example.org/geojson?t1'
|
||||
|
@ -397,8 +397,7 @@ def test_get_geojson_properties(app, layer, user):
|
|||
def test_duplicate(layer):
|
||||
page = Page.objects.create(title='xxx', slug='new', template_name='standard')
|
||||
cell = Map.objects.create(page=page, placeholder='content', order=0, public=True, title='Map')
|
||||
layer.save()
|
||||
cell.layers.add(layer)
|
||||
MapLayerOptions.objects.create(map_cell=cell, map_layer=layer)
|
||||
|
||||
new_cell = cell.duplicate()
|
||||
assert list(new_cell.layers.all()) == [layer]
|
||||
|
|
|
@ -3,10 +3,9 @@
|
|||
import pytest
|
||||
import mock
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from combo.apps.maps.models import Map
|
||||
from combo.apps.maps.models import MapLayer
|
||||
from combo.apps.maps.models import MapLayerOptions
|
||||
from combo.data.models import Page
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
@ -124,3 +123,34 @@ def test_download_geojson(mock_request, app, admin_user):
|
|||
assert item['properties']['layer']['label'] == 'Test'
|
||||
assert item['properties']['layer']['colour'] == '#FFFFFF'
|
||||
assert item['properties']['layer']['icon_colour'] == '#FFFFFF'
|
||||
|
||||
|
||||
def test_add_delete_layer(app, admin_user):
|
||||
layer = MapLayer.objects.create(
|
||||
label='bicycles',
|
||||
geojson_url='http://example.org/geojson',
|
||||
)
|
||||
page = Page.objects.create(title='One', slug='one', template_name='standard')
|
||||
cell = Map.objects.create(page=page, placeholder='content', order=0, public=True, title='Map')
|
||||
app = login(app)
|
||||
resp = app.get('/manage/pages/%s/' % page.pk)
|
||||
|
||||
assert list(cell.get_free_layers()) == [layer]
|
||||
resp = resp.click(href='.*/add-layer/$')
|
||||
resp.forms[0]['map_layer'] = layer.pk
|
||||
resp = resp.forms[0].submit()
|
||||
assert resp.status_int == 302
|
||||
assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference()))
|
||||
assert MapLayerOptions.objects.count() == 1
|
||||
options = MapLayerOptions.objects.get()
|
||||
assert options.map_cell == cell
|
||||
assert options.map_layer == layer
|
||||
|
||||
resp = resp.follow()
|
||||
assert list(cell.get_free_layers()) == []
|
||||
assert '/add-layer/$' not in resp.text
|
||||
resp = resp.click(href='.*/layer/%s/delete/$' % options.pk)
|
||||
resp = resp.forms[0].submit()
|
||||
assert resp.status_int == 302
|
||||
assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference()))
|
||||
assert MapLayerOptions.objects.count() == 0
|
||||
|
|
Loading…
Reference in New Issue