2017-06-29 13:20:35 +02:00
|
|
|
from itertools import chain
|
2017-06-20 15:39:22 +02:00
|
|
|
from operator import itemgetter
|
2017-06-20 14:02:30 +02:00
|
|
|
|
|
|
|
from django.conf import settings
|
2017-06-25 18:19:01 +02:00
|
|
|
from django.contrib import messages
|
2017-06-29 15:53:26 +02:00
|
|
|
from django.core.exceptions import PermissionDenied
|
2017-06-20 14:02:30 +02:00
|
|
|
from django.shortcuts import get_object_or_404, redirect, render
|
|
|
|
from django.urls import reverse
|
|
|
|
from django.utils.formats import date_format
|
|
|
|
from django.utils.translation import ugettext_lazy as _
|
|
|
|
|
2017-06-29 15:53:26 +02:00
|
|
|
from c3nav.editor.forms import ChangeSetForm
|
2017-06-20 14:02:30 +02:00
|
|
|
from c3nav.editor.models import ChangeSet
|
2017-06-21 14:19:13 +02:00
|
|
|
from c3nav.editor.utils import is_created_pk
|
2017-06-20 14:02:30 +02:00
|
|
|
from c3nav.editor.views.base import sidebar_view
|
2017-06-27 19:52:21 +02:00
|
|
|
from c3nav.mapdata.models.locations import LocationRedirect, LocationSlug
|
2017-06-20 14:02:30 +02:00
|
|
|
|
|
|
|
|
|
|
|
@sidebar_view
|
2017-06-27 03:20:50 +02:00
|
|
|
def changeset_detail(request, pk):
|
2017-06-20 15:39:22 +02:00
|
|
|
changeset = request.changeset
|
2017-06-20 14:02:30 +02:00
|
|
|
if str(pk) != str(request.changeset.pk):
|
|
|
|
changeset = get_object_or_404(ChangeSet.qs_for_request(request), pk=pk)
|
2017-06-29 17:15:11 +02:00
|
|
|
can_edit = changeset.can_edit(request)
|
2017-06-20 15:39:22 +02:00
|
|
|
|
2017-06-29 16:22:41 +02:00
|
|
|
if request.method == 'POST' and can_edit:
|
2017-06-25 18:19:01 +02:00
|
|
|
restore = request.POST.get('restore')
|
2017-06-25 18:29:30 +02:00
|
|
|
if restore and restore.isdigit():
|
2017-06-29 16:22:41 +02:00
|
|
|
try:
|
|
|
|
changed_object = changeset.changed_objects_set.get(pk=restore)
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
if changed_object.deleted:
|
|
|
|
changed_object.deleted = False
|
|
|
|
changed_object.save(standalone=True)
|
|
|
|
messages.success(request, _('Object has been successfully restored!'))
|
|
|
|
|
|
|
|
return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk}))
|
2017-06-25 18:19:01 +02:00
|
|
|
|
2017-06-27 03:20:50 +02:00
|
|
|
elif request.POST.get('delete') == '1':
|
2017-06-20 15:39:22 +02:00
|
|
|
if request.POST.get('delete_confirm') == '1':
|
|
|
|
changeset.delete()
|
|
|
|
return redirect(reverse('editor.index'))
|
|
|
|
|
2017-06-25 18:27:44 +02:00
|
|
|
return render(request, 'editor/delete.html', {
|
2017-06-20 15:39:22 +02:00
|
|
|
'model_title': ChangeSet._meta.verbose_name,
|
|
|
|
'obj_title': changeset.title,
|
|
|
|
})
|
2017-06-25 18:27:44 +02:00
|
|
|
|
2017-06-27 03:20:50 +02:00
|
|
|
changeset.fill_changes_cache(include_deleted_created=True)
|
2017-06-20 15:39:22 +02:00
|
|
|
|
2017-06-21 13:48:13 +02:00
|
|
|
objects = changeset.get_objects()
|
2017-06-20 14:02:30 +02:00
|
|
|
|
2017-06-27 03:20:50 +02:00
|
|
|
changed_objects_data = []
|
|
|
|
|
2017-06-27 19:52:21 +02:00
|
|
|
added_redirects = {}
|
|
|
|
removed_redirects = {}
|
|
|
|
for changed_object in changeset.changed_objects.get(LocationRedirect, {}).values():
|
|
|
|
if changed_object.is_created == changed_object.deleted:
|
|
|
|
continue
|
|
|
|
values = changed_object.updated_fields
|
|
|
|
redirect_list = (removed_redirects if changed_object.deleted else added_redirects)
|
|
|
|
redirect_list.setdefault(values['target'], []).append(values['slug'])
|
|
|
|
|
2017-06-29 13:20:35 +02:00
|
|
|
redirect_changed_objects = []
|
|
|
|
|
|
|
|
for pk in set(added_redirects.keys()) | set(removed_redirects.keys()):
|
|
|
|
obj = objects[LocationSlug][pk]
|
|
|
|
model = obj.__class__
|
|
|
|
try:
|
|
|
|
changeset.changed_objects[model][pk]
|
|
|
|
except KeyError:
|
|
|
|
redirect_changed_objects.append((model, {pk: changeset.get_changed_object(obj)}))
|
|
|
|
|
|
|
|
for model, changed_objects in chain(changeset.changed_objects.items(), redirect_changed_objects):
|
2017-06-27 19:52:21 +02:00
|
|
|
if model == LocationRedirect:
|
|
|
|
continue
|
|
|
|
|
2017-06-27 14:31:50 +02:00
|
|
|
for pk, changed_object in changed_objects.items():
|
2017-06-27 03:20:50 +02:00
|
|
|
obj = objects[model][pk]
|
2017-06-20 14:02:30 +02:00
|
|
|
|
|
|
|
obj_desc = _('%(model)s #%(id)s') % {'model': obj.__class__._meta.verbose_name, 'id': pk}
|
|
|
|
if is_created_pk(pk):
|
2017-06-29 16:22:41 +02:00
|
|
|
obj_still_exists = pk in changeset.created_objects.get(obj.__class__, ())
|
2017-06-20 14:02:30 +02:00
|
|
|
else:
|
2017-06-20 21:21:13 +02:00
|
|
|
obj_still_exists = pk not in changeset.deleted_existing.get(obj.__class__, ())
|
2017-06-20 14:02:30 +02:00
|
|
|
|
|
|
|
edit_url = None
|
2017-06-27 18:56:54 +02:00
|
|
|
if obj_still_exists and can_edit and not isinstance(obj, LocationRedirect):
|
2017-06-20 14:02:30 +02:00
|
|
|
reverse_kwargs = {'pk': obj.pk}
|
2017-06-20 17:40:26 +02:00
|
|
|
if hasattr(obj, 'level_id'):
|
2017-06-20 14:02:30 +02:00
|
|
|
reverse_kwargs['level'] = obj.level_id
|
2017-06-20 17:40:26 +02:00
|
|
|
elif hasattr(obj, 'space_id'):
|
2017-06-20 14:02:30 +02:00
|
|
|
reverse_kwargs['space'] = obj.space_id
|
2017-06-20 15:39:22 +02:00
|
|
|
edit_url = reverse('editor.' + obj.__class__._meta.default_related_name + '.edit',
|
|
|
|
kwargs=reverse_kwargs)
|
2017-06-20 14:02:30 +02:00
|
|
|
|
2017-06-27 03:20:50 +02:00
|
|
|
changes = []
|
|
|
|
changed_object_data = {
|
2017-06-20 14:02:30 +02:00
|
|
|
'model': obj.__class__,
|
|
|
|
'model_title': obj.__class__._meta.verbose_name,
|
2017-06-29 16:22:41 +02:00
|
|
|
'pk': changed_object.pk,
|
2017-06-27 03:25:05 +02:00
|
|
|
'desc': obj_desc,
|
2017-06-27 18:56:54 +02:00
|
|
|
'title': obj.title if getattr(obj, 'titles', None) else None,
|
2017-06-20 14:02:30 +02:00
|
|
|
'changes': changes,
|
|
|
|
'edit_url': edit_url,
|
2017-06-29 16:22:41 +02:00
|
|
|
'deleted': changed_object.deleted,
|
2017-06-29 13:20:35 +02:00
|
|
|
'order': (changed_object.deleted and changed_object.is_created, not changed_object.is_created),
|
2017-06-20 15:39:22 +02:00
|
|
|
}
|
2017-06-27 03:20:50 +02:00
|
|
|
changed_objects_data.append(changed_object_data)
|
2017-06-20 15:39:22 +02:00
|
|
|
|
2017-06-27 14:31:50 +02:00
|
|
|
form_fields = changeset.wrap_model(type(obj)).EditorForm._meta.fields
|
2017-06-20 14:02:30 +02:00
|
|
|
|
2017-06-27 03:20:50 +02:00
|
|
|
if changed_object.is_created:
|
|
|
|
changes.append({
|
|
|
|
'icon': 'plus',
|
|
|
|
'class': 'success',
|
|
|
|
'title': _('created'),
|
|
|
|
})
|
2017-06-21 12:51:44 +02:00
|
|
|
|
2017-06-27 03:20:50 +02:00
|
|
|
update_changes = []
|
2017-06-25 15:36:51 +02:00
|
|
|
|
2017-06-27 14:31:50 +02:00
|
|
|
for name, value in changed_object.updated_fields.items():
|
2017-06-27 03:20:50 +02:00
|
|
|
change_data = {
|
|
|
|
'icon': 'option-vertical',
|
|
|
|
'class': 'muted',
|
|
|
|
}
|
|
|
|
if name == 'geometry':
|
2017-06-20 15:39:22 +02:00
|
|
|
change_data.update({
|
2017-06-27 03:20:50 +02:00
|
|
|
'icon': 'map-marker',
|
|
|
|
'class': 'info',
|
|
|
|
'title': _('edited geometry'),
|
|
|
|
'order': (8,),
|
2017-06-20 15:39:22 +02:00
|
|
|
})
|
2017-06-20 14:02:30 +02:00
|
|
|
else:
|
2017-06-27 03:20:50 +02:00
|
|
|
if name.startswith('title_'):
|
|
|
|
lang = name[6:]
|
|
|
|
field_title = _('Title (%(lang)s)') % {'lang': dict(settings.LANGUAGES).get(lang, lang)}
|
|
|
|
field_value = str(value)
|
|
|
|
if field_value:
|
|
|
|
obj.titles[lang] = field_value
|
|
|
|
else:
|
|
|
|
obj.titles.pop(lang, None)
|
2017-06-22 23:49:45 +02:00
|
|
|
change_data.update({
|
2017-06-27 03:20:50 +02:00
|
|
|
'order': (4, tuple(code for code, title in settings.LANGUAGES).index(lang)),
|
2017-06-22 23:49:45 +02:00
|
|
|
})
|
2017-06-27 03:20:50 +02:00
|
|
|
else:
|
|
|
|
field = model._meta.get_field(name)
|
|
|
|
field_title = field.verbose_name
|
|
|
|
field_value = field.to_python(value)
|
|
|
|
if field.related_model is not None:
|
|
|
|
field_value = objects[field.related_model][field_value].title
|
|
|
|
order = 5
|
|
|
|
if name == 'slug':
|
|
|
|
order = 1
|
|
|
|
if name not in form_fields:
|
|
|
|
order = 0
|
|
|
|
change_data.update({
|
|
|
|
'order': (order, form_fields.index(name) if order else 1),
|
|
|
|
})
|
|
|
|
if not field_value:
|
|
|
|
change_data.update({
|
|
|
|
'title': _('remove %(field_title)s') % {'field_title': field_title},
|
|
|
|
})
|
|
|
|
else:
|
|
|
|
change_data.update({
|
|
|
|
'title': field_title,
|
|
|
|
'value': field_value,
|
|
|
|
})
|
|
|
|
update_changes.append(change_data)
|
2017-06-22 23:49:45 +02:00
|
|
|
|
2017-06-27 03:20:50 +02:00
|
|
|
changes.extend(sorted(update_changes, key=itemgetter('order')))
|
|
|
|
|
|
|
|
for m2m_mode in ('m2m_added', 'm2m_removed'):
|
|
|
|
m2m_list = getattr(changed_object, m2m_mode).items()
|
2017-06-27 16:10:28 +02:00
|
|
|
for name, values in sorted(m2m_list, key=lambda nv: form_fields.index(nv[0])):
|
2017-06-27 03:20:50 +02:00
|
|
|
field = model._meta.get_field(name)
|
|
|
|
for value in values:
|
2017-06-27 16:10:28 +02:00
|
|
|
changes.append({
|
2017-06-27 03:20:50 +02:00
|
|
|
'icon': 'chevron-right' if m2m_mode == 'm2m_added' else 'chevron-left',
|
|
|
|
'class': 'info',
|
|
|
|
'title': field.verbose_name,
|
|
|
|
'value': objects[field.related_model][value].title,
|
|
|
|
})
|
|
|
|
|
2017-06-27 19:52:21 +02:00
|
|
|
if isinstance(obj, LocationSlug):
|
|
|
|
for slug in added_redirects.get(obj.pk, ()):
|
|
|
|
changes.append({
|
|
|
|
'icon': 'chevron-right',
|
|
|
|
'class': 'info',
|
|
|
|
'title': _('Redirect slugs'),
|
|
|
|
'value': slug,
|
|
|
|
})
|
|
|
|
for slug in removed_redirects.get(obj.pk, ()):
|
|
|
|
changes.append({
|
|
|
|
'icon': 'chevron-left',
|
|
|
|
'class': 'info',
|
|
|
|
'title': _('Redirect slugs'),
|
|
|
|
'value': slug,
|
|
|
|
})
|
|
|
|
|
2017-06-27 03:20:50 +02:00
|
|
|
if changed_object.deleted:
|
|
|
|
changes.append({
|
|
|
|
'icon': 'minus',
|
|
|
|
'class': 'danger',
|
|
|
|
'title': _('deleted'),
|
|
|
|
'order': (9,),
|
2017-06-20 14:02:30 +02:00
|
|
|
})
|
2017-06-27 03:20:50 +02:00
|
|
|
|
|
|
|
changed_objects_data = sorted(changed_objects_data, key=itemgetter('order'))
|
|
|
|
|
2017-06-20 14:02:30 +02:00
|
|
|
if changeset.author:
|
2017-06-29 15:53:26 +02:00
|
|
|
created = _('created at %(datetime)s by') % {'datetime': date_format(changeset.created, 'DATETIME_FORMAT')}
|
2017-06-20 14:02:30 +02:00
|
|
|
else:
|
2017-06-29 15:53:26 +02:00
|
|
|
created = _('created at %(datetime)s') % {'datetime': date_format(changeset.created, 'DATETIME_FORMAT')}
|
2017-06-20 14:02:30 +02:00
|
|
|
|
|
|
|
ctx = {
|
|
|
|
'changeset': changeset,
|
2017-06-29 15:53:26 +02:00
|
|
|
'created': created,
|
|
|
|
'can_edit': can_edit,
|
2017-06-27 03:20:50 +02:00
|
|
|
'changed_objects': changed_objects_data,
|
2017-06-20 14:02:30 +02:00
|
|
|
}
|
2017-06-27 03:20:50 +02:00
|
|
|
|
|
|
|
return render(request, 'editor/changeset.html', ctx)
|
2017-06-29 15:53:26 +02:00
|
|
|
|
|
|
|
|
|
|
|
@sidebar_view
|
|
|
|
def changeset_edit(request, pk):
|
|
|
|
changeset = request.changeset
|
|
|
|
if str(pk) != str(request.changeset.pk):
|
|
|
|
changeset = get_object_or_404(ChangeSet.qs_for_request(request), pk=pk)
|
|
|
|
|
2017-06-29 17:15:11 +02:00
|
|
|
if not changeset.can_edit(request):
|
2017-06-29 15:53:26 +02:00
|
|
|
raise PermissionDenied
|
|
|
|
|
|
|
|
if request.method == 'POST':
|
|
|
|
form = ChangeSetForm(instance=changeset, data=request.POST)
|
|
|
|
if form.is_valid():
|
|
|
|
form.save()
|
|
|
|
return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk}))
|
|
|
|
else:
|
|
|
|
form = ChangeSetForm(instance=changeset)
|
|
|
|
|
|
|
|
return render(request, 'editor/changeset_edit.html', {
|
|
|
|
'changeset': changeset,
|
|
|
|
'form': form,
|
|
|
|
})
|