split up editor views.py

This commit is contained in:
Laura Klünder 2017-06-20 14:02:30 +02:00
parent 53d0d1d44d
commit e1ec198e06
6 changed files with 264 additions and 248 deletions

View file

@ -1,8 +1,9 @@
from django.apps import apps
from django.conf.urls import url
from c3nav.editor.views import (changeset_detail, edit, level_detail, list_objects, login_view, logout_view, main_index,
space_detail)
from c3nav.editor.views.changes import changeset_detail
from c3nav.editor.views.edit import edit, level_detail, list_objects, main_index, space_detail
from c3nav.editor.views.login import login_view, logout_view
def add_editor_urls(model_name, parent_model_name=None, with_list=True, explicit_edit=False):

View file

View file

@ -0,0 +1,24 @@
from functools import wraps
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.views.decorators.cache import never_cache
from c3nav.editor.models import ChangeSet
def sidebar_view(func):
@wraps(func)
def with_ajax_check(request, *args, **kwargs):
request.changeset = ChangeSet.get_for_request(request)
response = func(request, *args, **kwargs)
if request.is_ajax() or 'ajax' in request.GET:
if isinstance(response, HttpResponseRedirect):
return render(request, 'editor/redirect.html', {'target': response['location']})
response.write(render(request, 'editor/fragment_nav.html', {}).content)
return response
if isinstance(response, HttpResponseRedirect):
return response
return render(request, 'editor/map.html', {'content': response.content})
return never_cache(with_ajax_check)

View file

@ -0,0 +1,199 @@
import json
from django.conf import settings
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 _
from c3nav.editor.models import ChangeSet
from c3nav.editor.views.base import sidebar_view
from c3nav.editor.wrappers import is_created_pk
from c3nav.mapdata.models.locations import LocationRedirect, LocationSlug
@sidebar_view
def changeset_detail(request, pk):
if str(pk) != str(request.changeset.pk):
changeset = get_object_or_404(ChangeSet.qs_for_request(request), pk=pk)
else:
changeset = request.changeset
# collect pks of relevant objects
object_pks = {}
for change in changeset.changes.all():
object_pks.setdefault(change.model_class, set()).add(change.obj_pk)
model = None
if change.action == 'update':
if change.model_class == LocationRedirect:
if change.field_name == 'target':
object_pks.setdefault(LocationSlug, set()).add(json.loads(change.field_value))
continue
elif not change.field_name.startswith('title_'):
field = change.model_class._meta.get_field(change.field_name)
model = getattr(field, 'related_model', None)
if change.action in ('m2m_add', 'm2m_remove'):
model = change.model_class._meta.get_field(change.field_name).related_model
if model is not None:
object_pks.setdefault(model, set()).add(json.loads(change.field_value))
# retrieve relevant objects
objects = {}
for model, pks in object_pks.items():
created_pks = set(pk for pk in pks if is_created_pk(pk))
existing_pks = pks-created_pks
model_objects = {}
if existing_pks:
for obj in model.objects.filter(pk__in=existing_pks):
if model == LocationSlug:
obj = obj.get_child()
model_objects[obj.pk] = obj
if created_pks:
for pk in created_pks:
model_objects[pk] = changeset.get_created_object(model, pk, allow_deleted=True)._obj
model_objects[pk].titles = {}
objects[model] = model_objects
grouped_changes = []
changes = []
last_obj = None
for change in changeset.changes.all():
pk = change.obj_pk
obj = objects[change.model_class][pk]
if change.model_class == LocationRedirect:
if change.action not in ('create', 'delete'):
continue
change.action = 'm2m_add' if change.action == 'create' else 'm2m_remove'
change.field_name = 'redirects'
change.field_value = obj.slug
pk = obj.target_id
obj = objects[LocationSlug][pk]
if obj != last_obj:
changes = []
obj_desc = _('%(model)s #%(id)s') % {'model': obj.__class__._meta.verbose_name, 'id': pk}
if is_created_pk(pk):
obj_desc = _('%s (created)') % obj_desc
obj_still_exists = int(pk[1:]) in changeset.created_objects[obj.__class__]
else:
obj_still_exists = pk not in changeset.deleted_existing[obj.__class__]
edit_url = None
if obj_still_exists and changeset == request.changeset:
reverse_kwargs = {'pk': obj.pk}
if hasattr(obj, 'level'):
reverse_kwargs['level'] = obj.level_id
elif hasattr(obj, 'space'):
reverse_kwargs['space'] = obj.space_id
edit_url = reverse('editor.'+obj.__class__._meta.default_related_name+'.edit', kwargs=reverse_kwargs)
grouped_changes.append({
'model': obj.__class__,
'model_title': obj.__class__._meta.verbose_name,
'obj': obj_desc,
'obj_title': obj.title if obj.titles else None,
'changes': changes,
'edit_url': edit_url,
})
last_obj = obj
change_data = {
'pk': change.pk,
'author': change.author,
'created': _('created at %(datetime)s') % {'datetime': date_format(change.created, 'DATETIME_FORMAT')},
}
changes.append(change_data)
if change.action == 'create':
change_data.update({
'icon': 'plus',
'class': 'success',
'title': _('created'),
})
elif change.action == 'delete':
change_data.update({
'icon': 'minus',
'class': 'danger',
'title': _('deleted')
})
elif change.action == 'update':
change_data.update({
'icon': 'option-vertical',
'class': 'muted',
})
if change.field_name == 'geometry':
change_data.update({
'icon': 'map-marker',
'class': 'info',
'title': _('edited geometry'),
})
else:
if change.field_name.startswith('title_'):
lang = change.field_name[6:]
field_title = _('Title (%(lang)s)') % {'lang': dict(settings.LANGUAGES).get(lang, lang)}
field_value = str(json.loads(change.field_value))
if field_value:
obj.titles[lang] = field_value
else:
obj.titles.pop(lang, None)
else:
field = obj.__class__._meta.get_field(change.field_name)
field_title = field.verbose_name
field_value = field.to_python(json.loads(change.field_value))
model = getattr(field, 'related_model', None)
if model is not None:
field_value = objects[model][field_value].title
if not field_value:
change_data.update({
'title': _('unset %(field_title)s') % {'field_title': field_title},
})
else:
change_data.update({
'title': field_title,
'value': field_value,
})
elif change.action in ('m2m_add', 'm2m_remove'):
change_data.update({
'icon': 'chevron-right' if change.action == 'm2m_add' else 'chevron-left',
'class': 'info',
})
if change.field_name == 'redirects':
change_data.update({
'title': _('Redirecting slugs'),
'value': change.field_value,
})
else:
field = obj.__class__._meta.get_field(change.field_name)
change_data.update({
'title': field.verbose_name,
'value': objects[field.related_model][json.loads(change.field_value)].title,
})
else:
change_data.update({
'title': '???',
})
if changeset.author:
desc = _('created at %(datetime)s by') % {'datetime': date_format(changeset.created, 'DATETIME_FORMAT')}
else:
desc = _('created at %(datetime)s') % {'datetime': date_format(changeset.created, 'DATETIME_FORMAT')}
ctx = {
'pk': pk,
'changeset': changeset,
'desc': desc,
'grouped_changes': grouped_changes,
}
if request.method == 'POST':
if request.POST.get('delete') == '1':
if request.POST.get('delete_confirm') == '1':
changeset.delete()
return redirect(reverse('editor.index'))
ctx.update({
'model_title': ChangeSet._meta.verbose_name,
'obj_title': changeset.title,
})
return render(request, 'editor/delete.html', ctx)
return render(request, 'editor/changeset.html', ctx)

View file

@ -1,39 +1,12 @@
import json
from contextlib import suppress
from functools import wraps
from django.conf import settings
from django.contrib.auth import login, logout
from django.contrib.auth.forms import AuthenticationForm
from django.core.exceptions import FieldDoesNotExist, PermissionDenied
from django.http import HttpResponseRedirect
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 _
from django.views.decorators.cache import never_cache
from c3nav.editor.models import ChangeSet
from c3nav.editor.wrappers import is_created_pk
from c3nav.editor.views.base import sidebar_view
from c3nav.mapdata.models.base import EDITOR_FORM_MODELS
from c3nav.mapdata.models.locations import LocationRedirect, LocationSlug
def sidebar_view(func):
@wraps(func)
def with_ajax_check(request, *args, **kwargs):
request.changeset = ChangeSet.get_for_request(request)
response = func(request, *args, **kwargs)
if request.is_ajax() or 'ajax' in request.GET:
if isinstance(response, HttpResponseRedirect):
return render(request, 'editor/redirect.html', {'target': response['location']})
response.write(render(request, 'editor/fragment_nav.html', {}).content)
return response
if isinstance(response, HttpResponseRedirect):
return response
return render(request, 'editor/map.html', {'content': response.content})
return never_cache(with_ajax_check)
def child_model(model, kwargs=None, parent=None):
@ -313,221 +286,3 @@ def list_objects(request, model=None, level=None, space=None, explicit_edit=Fals
})
return render(request, 'editor/list.html', ctx)
@sidebar_view
def changeset_detail(request, pk):
if str(pk) != str(request.changeset.pk):
changeset = get_object_or_404(ChangeSet.qs_for_request(request), pk=pk)
else:
changeset = request.changeset
# collect pks of relevant objects
object_pks = {}
for change in changeset.changes.all():
object_pks.setdefault(change.model_class, set()).add(change.obj_pk)
model = None
if change.action == 'update':
if change.model_class == LocationRedirect:
if change.field_name == 'target':
object_pks.setdefault(LocationSlug, set()).add(json.loads(change.field_value))
continue
elif not change.field_name.startswith('title_'):
field = change.model_class._meta.get_field(change.field_name)
model = getattr(field, 'related_model', None)
if change.action in ('m2m_add', 'm2m_remove'):
model = change.model_class._meta.get_field(change.field_name).related_model
if model is not None:
object_pks.setdefault(model, set()).add(json.loads(change.field_value))
# retrieve relevant objects
objects = {}
for model, pks in object_pks.items():
created_pks = set(pk for pk in pks if is_created_pk(pk))
existing_pks = pks-created_pks
model_objects = {}
if existing_pks:
for obj in model.objects.filter(pk__in=existing_pks):
if model == LocationSlug:
obj = obj.get_child()
model_objects[obj.pk] = obj
if created_pks:
for pk in created_pks:
model_objects[pk] = changeset.get_created_object(model, pk, allow_deleted=True)._obj
model_objects[pk].titles = {}
objects[model] = model_objects
grouped_changes = []
changes = []
last_obj = None
for change in changeset.changes.all():
pk = change.obj_pk
obj = objects[change.model_class][pk]
if change.model_class == LocationRedirect:
if change.action not in ('create', 'delete'):
continue
change.action = 'm2m_add' if change.action == 'create' else 'm2m_remove'
change.field_name = 'redirects'
change.field_value = obj.slug
pk = obj.target_id
obj = objects[LocationSlug][pk]
if obj != last_obj:
changes = []
obj_desc = _('%(model)s #%(id)s') % {'model': obj.__class__._meta.verbose_name, 'id': pk}
if is_created_pk(pk):
obj_desc = _('%s (created)') % obj_desc
obj_still_exists = int(pk[1:]) in changeset.created_objects[obj.__class__]
else:
obj_still_exists = pk not in changeset.deleted_existing[obj.__class__]
edit_url = None
if obj_still_exists and changeset == request.changeset:
reverse_kwargs = {'pk': obj.pk}
if hasattr(obj, 'level'):
reverse_kwargs['level'] = obj.level_id
elif hasattr(obj, 'space'):
reverse_kwargs['space'] = obj.space_id
edit_url = reverse('editor.'+obj.__class__._meta.default_related_name+'.edit', kwargs=reverse_kwargs)
grouped_changes.append({
'model': obj.__class__,
'model_title': obj.__class__._meta.verbose_name,
'obj': obj_desc,
'obj_title': obj.title if obj.titles else None,
'changes': changes,
'edit_url': edit_url,
})
last_obj = obj
change_data = {
'pk': change.pk,
'author': change.author,
'created': _('created at %(datetime)s') % {'datetime': date_format(change.created, 'DATETIME_FORMAT')},
}
changes.append(change_data)
if change.action == 'create':
change_data.update({
'icon': 'plus',
'class': 'success',
'title': _('created'),
})
elif change.action == 'delete':
change_data.update({
'icon': 'minus',
'class': 'danger',
'title': _('deleted')
})
elif change.action == 'update':
change_data.update({
'icon': 'option-vertical',
'class': 'muted',
})
if change.field_name == 'geometry':
change_data.update({
'icon': 'map-marker',
'class': 'info',
'title': _('edited geometry'),
})
else:
if change.field_name.startswith('title_'):
lang = change.field_name[6:]
field_title = _('Title (%(lang)s)') % {'lang': dict(settings.LANGUAGES).get(lang, lang)}
field_value = str(json.loads(change.field_value))
if field_value:
obj.titles[lang] = field_value
else:
obj.titles.pop(lang, None)
else:
field = obj.__class__._meta.get_field(change.field_name)
field_title = field.verbose_name
field_value = field.to_python(json.loads(change.field_value))
model = getattr(field, 'related_model', None)
if model is not None:
field_value = objects[model][field_value].title
if not field_value:
change_data.update({
'title': _('unset %(field_title)s') % {'field_title': field_title},
})
else:
change_data.update({
'title': field_title,
'value': field_value,
})
elif change.action in ('m2m_add', 'm2m_remove'):
change_data.update({
'icon': 'chevron-right' if change.action == 'm2m_add' else 'chevron-left',
'class': 'info',
})
if change.field_name == 'redirects':
change_data.update({
'title': _('Redirecting slugs'),
'value': change.field_value,
})
else:
field = obj.__class__._meta.get_field(change.field_name)
change_data.update({
'title': field.verbose_name,
'value': objects[field.related_model][json.loads(change.field_value)].title,
})
else:
change_data.update({
'title': '???',
})
if changeset.author:
desc = _('created at %(datetime)s by') % {'datetime': date_format(changeset.created, 'DATETIME_FORMAT')}
else:
desc = _('created at %(datetime)s') % {'datetime': date_format(changeset.created, 'DATETIME_FORMAT')}
ctx = {
'pk': pk,
'changeset': changeset,
'desc': desc,
'grouped_changes': grouped_changes,
}
if request.method == 'POST':
if request.POST.get('delete') == '1':
if request.POST.get('delete_confirm') == '1':
changeset.delete()
return redirect(reverse('editor.index'))
ctx.update({
'model_title': ChangeSet._meta.verbose_name,
'obj_title': changeset.title,
})
return render(request, 'editor/delete.html', ctx)
return render(request, 'editor/changeset.html', ctx)
@sidebar_view
def login_view(request):
redirect_path = request.GET['r'] if request.GET.get('r', '').startswith('/editor/') else reverse('editor.index')
if request.user.is_authenticated:
return redirect(redirect_path)
if request.method == 'POST':
form = AuthenticationForm(request, data=request.POST)
if form.is_valid():
login(request, form.user_cache)
if request.changeset.pk is not None:
if request.session.session_key is None:
request.session.save()
request.changeset.author = form.user_cache
request.changeset.session_key = request.session.session_key
request.changeset.save()
return redirect(redirect_path)
else:
form = AuthenticationForm(request)
return render(request, 'editor/login.html', {'form': form})
@sidebar_view
def logout_view(request):
redirect_path = request.GET['r'] if request.GET.get('r', '').startswith('/editor/') else reverse('editor.login')
logout(request)
return redirect(redirect_path)

View file

@ -0,0 +1,37 @@
from django.contrib.auth import login, logout
from django.contrib.auth.forms import AuthenticationForm
from django.shortcuts import redirect, render
from django.urls import reverse
from c3nav.editor.views.base import sidebar_view
@sidebar_view
def login_view(request):
redirect_path = request.GET['r'] if request.GET.get('r', '').startswith('/editor/') else reverse('editor.index')
if request.user.is_authenticated:
return redirect(redirect_path)
if request.method == 'POST':
form = AuthenticationForm(request, data=request.POST)
if form.is_valid():
login(request, form.user_cache)
if request.changeset.pk is not None:
if request.session.session_key is None:
request.session.save()
request.changeset.author = form.user_cache
request.changeset.session_key = request.session.session_key
request.changeset.save()
return redirect(redirect_path)
else:
form = AuthenticationForm(request)
return render(request, 'editor/login.html', {'form': form})
@sidebar_view
def logout_view(request):
redirect_path = request.GET['r'] if request.GET.get('r', '').startswith('/editor/') else reverse('editor.login')
logout(request)
return redirect(redirect_path)