in-between state, we now need to fix geometry field serialization

This commit is contained in:
Laura Klünder 2024-08-26 14:27:25 +02:00
parent 6db9e28a74
commit f729efb9d4
6 changed files with 205 additions and 103 deletions

View file

@ -1,5 +1,6 @@
from abc import ABC, abstractmethod
from collections import OrderedDict
from contextlib import contextmanager
from functools import wraps
from typing import Optional
@ -17,19 +18,52 @@ from django.utils.translation import gettext_lazy as _
from c3nav.editor.models import ChangeSet
from c3nav.editor.overlay import DatabaseOverlayManager
from c3nav.mapdata.models import MapUpdate
from c3nav.mapdata.models.access import AccessPermission
from c3nav.mapdata.models.base import SerializableMixin
from c3nav.mapdata.utils.cache.changes import changed_geometries
from c3nav.mapdata.utils.user import can_access_editor
@contextmanager
def maybe_lock_changeset_to_edit(request):
if request.changeset.pk:
with request.changeset.lock_to_edit(request=request) as changeset:
request.changeset = changeset
yield
else:
yield
def accesses_mapdata(func):
@wraps(func)
def wrapped(request, *args, **kwargs):
changes = None if request.changeset.direct_editing is None else request.changeset.changes
with DatabaseOverlayManager.enable(changes, commit=request.changeset.direct_editing) as manager:
result = func(request, *args, **kwargs)
print("operations", manager.new_operations)
return result
writable_method = request.method in ("POST", "PUT")
if request.changeset.direct_editing:
with MapUpdate.lock():
changed_geometries.reset()
with DatabaseOverlayManager.enable(changes=None, commit=writable_method) as manager:
result = func(request, *args, **kwargs)
if manager.new_operations:
if writable_method:
MapUpdate.objects.create(user=request.user, type='direct_edit')
else:
raise ValueError # todo: good error message, but this shouldn't happen
else:
with maybe_lock_changeset_to_edit(request=request):
with DatabaseOverlayManager.enable(changes=request.changeset.changes, commit=False) as manager:
result = func(request, *args, **kwargs)
if manager.new_operations:
manager.save_new_operations()
print(request.changeset.changes)
print('saving to changeset!!')
request.changeset.save()
update = request.changeset.updates.create(user=request.user, objects_changed=True)
request.changeset.last_update = update
request.changeset.last_change = update
request.changeset.save()
return result
return wrapped
@ -48,7 +82,8 @@ def sidebar_view(func=None, select_related=None, api_hybrid=False):
if not can_access_editor(request):
raise PermissionDenied
request.changeset = ChangeSet.get_for_request(request, select_related)
if getattr(request, "changeset", None) is None:
request.changeset = ChangeSet.get_for_request(request, select_related)
if api:
request.is_delete = request.method == 'DELETE'

View file

@ -38,24 +38,24 @@ def changeset_detail(request, pk):
if request.method == 'POST':
restore = request.POST.get('restore')
if restore and restore.isdigit():
with changeset.lock_to_edit(request) as changeset:
if changeset.can_edit(request):
try:
changed_object = changeset.changed_objects_set.get(pk=restore)
except Exception:
pass
else:
try:
changed_object.restore()
messages.success(request, _('Object has been successfully restored.'))
except PermissionError:
messages.error(request, _('You cannot restore this object, because it depends on '
'a deleted object or it would violate a unique contraint.'))
else:
messages.error(request, _('You can not edit changes on this change set.'))
return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk}))
raise NotImplementedError # todo: restore (no pun intended) this feature
# if request.changeset.can_edit(request):
# try:
# changed_object = changeset.changed_objects_set.get(pk=restore)
# except Exception:
# pass
# else:
# try:
# changed_object.restore()
# messages.success(request, _('Object has been successfully restored.'))
# except PermissionError:
# messages.error(request, _('You cannot restore this object, because it depends on '
# 'a deleted object or it would violate a unique contraint.'))
#
# else:
# messages.error(request, _('You can not edit changes on this change set.'))
#
# return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk}))
elif request.POST.get('activate') == '1':
with changeset.lock_to_edit(request) as changeset:

View file

@ -128,7 +128,7 @@ def space_detail(request, level, pk):
def get_changeset_exceeded(request):
return request.user_permissions.max_changeset_changes <= request.changeset.changed_objects_count
return request.user_permissions.max_changeset_changes <= len(request.changeset.changes.operations)
@etag(editor_etag_func)
@ -315,15 +315,14 @@ def edit(request, pk=None, model=None, level=None, space=None, on_top_of=None, e
)
if request.POST.get('delete_confirm') == '1' or delete:
with request.changeset.lock_to_edit(request) as changeset:
if changeset.can_edit(request):
obj.delete()
else:
return APIHybridMessageRedirectResponse(
level='error',
message=_('You can not edit changes on this changeset.'),
redirect_to=request.path, status_code=403,
)
if request.changeset.can_edit(request): # todo: move this somewhere else
obj.delete()
else:
return APIHybridMessageRedirectResponse(
level='error',
message=_('You can not edit changes on this changeset.'),
redirect_to=request.path, status_code=403,
)
if model == Level:
if obj.on_top_of_id is not None:
@ -360,28 +359,27 @@ def edit(request, pk=None, model=None, level=None, space=None, on_top_of=None, e
if on_top_of is not None:
obj.on_top_of = on_top_of
with request.changeset.lock_to_edit(request) as changeset:
if changeset.can_edit(request):
try:
obj.save()
except IntegrityError:
error = APIHybridError(status_code=400, message=_('Duplicate entry.'))
else:
if form.redirect_slugs is not None:
for slug in form.add_redirect_slugs:
obj.redirects.create(slug=slug)
for slug in form.remove_redirect_slugs:
obj.redirects.filter(slug=slug).delete()
form.save_m2m()
return APIHybridMessageRedirectResponse(
level='success',
message=_('Object was successfully saved.'),
redirect_to=ctx['back_url']
)
if request.changeset.can_edit(request): # todo: move this somewhere else
try:
obj.save()
except IntegrityError:
error = APIHybridError(status_code=400, message=_('Duplicate entry.'))
else:
error = APIHybridError(status_code=403, message=_('You can not edit changes on this changeset.'))
if form.redirect_slugs is not None:
for slug in form.add_redirect_slugs:
obj.redirects.create(slug=slug)
for slug in form.remove_redirect_slugs:
obj.redirects.filter(slug=slug).delete()
form.save_m2m()
return APIHybridMessageRedirectResponse(
level='success',
message=_('Object was successfully saved.'),
redirect_to=ctx['back_url']
)
else:
error = APIHybridError(status_code=403, message=_('You can not edit changes on this changeset.'))
else:
form = get_editor_form(model)(instance=obj, request=request, space_id=space_id,
@ -640,14 +638,13 @@ def graph_edit(request, level=None, space=None):
return redirect(request.path)
if request.POST.get('delete_confirm') == '1':
with request.changeset.lock_to_edit(request) as changeset:
if changeset.can_edit(request):
node.edges_from_here.all().delete()
node.edges_to_here.all().delete()
node.delete()
else:
messages.error(request, _('You can not edit changes on this changeset.'))
return redirect(request.path)
if request.changeset.can_edit(request): # todo: move this somewhere else
node.edges_from_here.all().delete()
node.edges_to_here.all().delete()
node.delete()
else:
messages.error(request, _('You can not edit changes on this changeset.'))
return redirect(request.path)
messages.success(request, _('Graph Node was successfully deleted.'))
return redirect(request.path)
return render(request, 'editor/delete.html', {
@ -677,13 +674,12 @@ def graph_edit(request, level=None, space=None):
active_node = None
set_active_node = True
else:
with request.changeset.lock_to_edit(request) as changeset:
if changeset.can_edit(request):
connect_nodes(request, active_node, clicked_node, edge_settings_form)
active_node = clicked_node if edge_settings_form.cleaned_data['activate_next'] else None
set_active_node = True
else:
messages.error(request, _('You can not edit changes on this changeset.'))
if request.changeset.can_edit(request): # todo: move this somewhere else
connect_nodes(request, active_node, clicked_node, edge_settings_form)
active_node = clicked_node if edge_settings_form.cleaned_data['activate_next'] else None
set_active_node = True
else:
messages.error(request, _('You can not edit changes on this changeset.'))
elif (clicked_node is None and clicked_position is not None and
active_node is None and space.geometry.contains(clicked_position)):
@ -692,16 +688,15 @@ def graph_edit(request, level=None, space=None):
messages.error(request, _('You can not add graph nodes because your changeset is full.'))
return redirect(request.path)
with request.changeset.lock_to_edit(request) as changeset:
if changeset.can_edit(request):
node = GraphNode(space=space, geometry=clicked_position)
node.save()
messages.success(request, _('New graph node created.'))
if request.changeset.can_edit(request): # todo: move this somewhere else
node = GraphNode(space=space, geometry=clicked_position)
node.save()
messages.success(request, _('New graph node created.'))
active_node = None
set_active_node = True
else:
messages.error(request, _('You can not edit changes on this changeset.'))
active_node = None
set_active_node = True
else:
messages.error(request, _('You can not edit changes on this changeset.'))
if set_active_node:
connections = {}