add some more comments

This commit is contained in:
Laura Klünder 2024-10-28 17:17:45 +01:00
parent a231b62885
commit b300e23233
2 changed files with 23 additions and 1 deletions

View file

@ -41,7 +41,7 @@ class DatabaseOverlayManager:
@contextmanager @contextmanager
def enable(cls, operations: DatabaseOperationCollection | None = None, commit: bool = False): def enable(cls, operations: DatabaseOperationCollection | None = None, commit: bool = False):
""" """
Context manager to enable the database overlay, optionally pre-applying the given changes. Context manager to enable the database overlay, optionally <pre-applying the given changes.
Only one overlay can be active at the same type, or else you get a TypeError. Only one overlay can be active at the same type, or else you get a TypeError.
:param operations: what operations to pre-apply :param operations: what operations to pre-apply

View file

@ -27,6 +27,7 @@ from c3nav.mapdata.utils.user import can_access_editor
@contextmanager @contextmanager
def maybe_lock_changeset_to_edit(request): def maybe_lock_changeset_to_edit(request):
""" Lock the changeset of the given request, if it can be locked (= has ever been saved to the database)"""
if request.changeset.pk: if request.changeset.pk:
with request.changeset.lock_to_edit(request=request) as changeset: with request.changeset.lock_to_edit(request=request) as changeset:
request.changeset = changeset request.changeset = changeset
@ -41,28 +42,49 @@ def noctx():
def accesses_mapdata(func): def accesses_mapdata(func):
"""
Decorator for editor views that access map data, will honor changesets etc
"""
@wraps(func) @wraps(func)
def wrapped(request, *args, **kwargs): def wrapped(request, *args, **kwargs):
# Omly POST and PUT methods may actually commit changes to the database
writable_method = request.method in ("POST", "PUT") writable_method = request.method in ("POST", "PUT")
if request.changeset.direct_editing: if request.changeset.direct_editing:
# For direct editing, a mapupdate is created if any changes are made
# So, if this request may commit changes, lock the MapUpdate system, which also starts a transaction.
with (MapUpdate.lock() if writable_method else noctx()): with (MapUpdate.lock() if writable_method else noctx()):
# Reset the changed geometries tracker, this will be read when a MapUpdate is created.
changed_geometries.reset() changed_geometries.reset()
# Enable the overlay manager to monitor changes, so we know if any changes even happened
# If this request may commit changes, commit is set to True, so everything will be commited.
with DatabaseOverlayManager.enable(operations=None, commit=writable_method) as manager: with DatabaseOverlayManager.enable(operations=None, commit=writable_method) as manager:
result = func(request, *args, **kwargs) result = func(request, *args, **kwargs)
# If any operations took place, we create a MapUpdate
if manager.operations: if manager.operations:
if writable_method: if writable_method:
MapUpdate.objects.create(user=request.user, type='direct_edit') MapUpdate.objects.create(user=request.user, type='direct_edit')
else: else:
# todo: time for a good error message, even though this case should not be possible
raise ValueError # todo: good error message, but this shouldn't happen raise ValueError # todo: good error message, but this shouldn't happen
else: else:
# For non-direct editing, we will interact with the changeset
with maybe_lock_changeset_to_edit(request=request): with maybe_lock_changeset_to_edit(request=request):
# Turn the changes from the changeset into a list of operations
operations = request.changeset.changes.as_operations # todo: cache this operations = request.changeset.changes.as_operations # todo: cache this
# Enable the overlay manager, temporarily applying the changeset changes
# commit is set to false, meaning all changes will be reset once we leave the manager
with DatabaseOverlayManager.enable(operations=operations, commit=False) as manager: with DatabaseOverlayManager.enable(operations=operations, commit=False) as manager:
result = func(request, *args, **kwargs) result = func(request, *args, **kwargs)
if manager.operations: if manager.operations:
# Add new operations to changeset
request.changeset.changes.add_operations(manager.operations) request.changeset.changes.add_operations(manager.operations)
request.changeset.save() request.changeset.save()
# Add new changeset update
update = request.changeset.updates.create(user=request.user, objects_changed=True) update = request.changeset.updates.create(user=request.user, objects_changed=True)
request.changeset.last_update = update request.changeset.last_update = update
request.changeset.last_change = update request.changeset.last_change = update