fixes to make the last commit work (asside from applying changes)

This commit is contained in:
Laura Klünder 2024-09-26 17:08:41 +02:00
parent 174866c2fd
commit f2f0b9fdae
7 changed files with 32 additions and 18 deletions

View file

@ -4,7 +4,8 @@ from django.apps import apps
from c3nav.api.schema import BaseSchema
from c3nav.editor.operations import DatabaseOperationCollection, CreateObjectOperation, UpdateObjectOperation, \
DeleteObjectOperation, ClearManyToManyOperation, FieldValuesDict, ObjectReference, PreviousObjectCollection
DeleteObjectOperation, ClearManyToManyOperation, FieldValuesDict, ObjectReference, PreviousObjectCollection, \
DatabaseOperation
from c3nav.mapdata.fields import I18nField
@ -33,14 +34,18 @@ class ChangedObjectCollection(BaseSchema):
objects: dict[str, dict[int, ChangedObject]] = {}
def __iter__(self):
yield from chain(*(objects.keys() for model, objects in self.objects.items()))
yield from chain(*(objects.values() for model, objects in self.objects.items()))
def __len__(self):
return sum(len(v) for v in self.objects.values())
def add_operations(self, operations: DatabaseOperationCollection):
"""
Add the given operations, creating/updating changed objects to represent the resulting state.
"""
# todo: merge prev
for operation in operations.operations:
# todo: if something is being changed back, remove it from thingy?
self.prev.add_other(operations.prev)
for operation in operations:
changed_object = self.objects.setdefault(operation.obj.model, {}).get(operation.obj.id, None)
if changed_object is None:
changed_object = ChangedObject(obj=operation.obj,

View file

@ -43,7 +43,8 @@ class ChangeSet(models.Model):
related_name='assigned_changesets', verbose_name=_('assigned to'))
map_update = models.OneToOneField(MapUpdate, null=True, related_name='changeset',
verbose_name=_('map update'), on_delete=models.PROTECT)
changes: ChangedObjectCollection = SchemaField(schema=ChangedObjectCollection, default=ChangedObjectCollection)
changes: ChangedObjectCollection = SchemaField(schema=ChangedObjectCollection,
default=lambda: ChangedObjectCollection)
class Meta:
verbose_name = _('Change Set')
@ -164,7 +165,7 @@ class ChangeSet(models.Model):
return self.can_edit(request) and self.state == 'unproposed'
def can_propose(self, request):
return self.can_edit(request) and not self.proposed and self.changes.operations
return self.can_edit(request) and not self.proposed and self.changes
def can_unpropose(self, request):
return self.author_id == request.user.pk and self.state in ('proposed', 'reproposed')
@ -347,8 +348,7 @@ class ChangeSet(models.Model):
"""
Get the number of changed objects.
"""
return len([changed_object for changed_object in self.changes.changed_objects
if changed_object.obj.model != "locationredirect"])
return len(self.changes)
def get_changed_objects_by_model(self, model):
if isinstance(model, str):

View file

@ -1,7 +1,7 @@
import datetime
import json
from dataclasses import dataclass
from typing import Annotated, Literal, Union, TypeAlias, Any
from typing import Annotated, Literal, Union, TypeAlias, Any, Self
from uuid import UUID, uuid4
from django.apps import apps
@ -70,6 +70,10 @@ class PreviousObjectCollection(BaseSchema):
titles=titles,
)
def add_other(self, other: Self):
for key in set(self.objects.keys()) | set(other.objects.keys()):
self.objects[key] = {**other.objects.get(key, {}), **self.objects.get(key, {})}
class BaseOperation(BaseSchema):
obj: ObjectReference
@ -194,10 +198,16 @@ class DatabaseOperationCollection(BaseSchema):
Iterable as a list of DatabaseOperation instances.
"""
prev: PreviousObjectCollection = PreviousObjectCollection()
operations: list[DatabaseOperation] = []
_operations: list[DatabaseOperation] = []
def __iter__(self):
yield from self.operations
yield from self._operations
def __len__(self):
return len(self._operations)
def append(self, item: DatabaseOperation):
self._operations.append(item)
def prefetch(self) -> "PrefetchedDatabaseOperationCollection":
return PrefetchedDatabaseOperationCollection(operations=self, instances=self.prev.get_instances())
@ -210,7 +220,7 @@ class PrefetchedDatabaseOperationCollection:
def apply(self):
# todo: what if unique constraint error occurs?
for operation in self.operations.operations:
for operation in self.operations:
if isinstance(operation, CreateObjectOperation):
self.instances[operation.obj] = operation.apply_create()
else:

View file

@ -34,8 +34,7 @@ class DatabaseOverlayManager:
"""
This class handles the currently active database overlay and will apply and/or intercept changes.
"""
prev: PreviousObjectCollection = PreviousObjectCollection()
operations: list[DatabaseOperation] = field(default_factory=list)
operations: DatabaseOperationCollection = field(default_factory=DatabaseOperationCollection)
pre_change_values: dict[ObjectReference, FieldValuesDict] = field(default_factory=dict, init=False, repr=False)
@classmethod
@ -54,7 +53,7 @@ class DatabaseOverlayManager:
operations = DatabaseOperationCollection()
try:
with transaction.atomic():
manager = DatabaseOverlayManager(prev=copy.deepcopy(operations.prev))
manager = DatabaseOverlayManager(operations=DatabaseOperationCollection(prev=operations.prev))
operations.prefetch().apply()
overlay_state.manager = manager
yield manager

View file

@ -50,7 +50,7 @@ def accesses_mapdata(func):
changed_geometries.reset()
with DatabaseOverlayManager.enable(operations=None, commit=writable_method) as manager:
result = func(request, *args, **kwargs)
if manager.new_operations:
if manager.operations:
if writable_method:
MapUpdate.objects.create(user=request.user, type='direct_edit')
else:

View file

@ -218,7 +218,7 @@ def changeset_detail(request, pk):
else:
title = next(iter(changed_object.titles.values()))
prev_values = changeset.operations.prev.get(changed_object.obj).values
prev_values = changeset.changes.prev.get(changed_object.obj).values
edit_url = None
if not changed_object.deleted:

View file

@ -128,7 +128,7 @@ def space_detail(request, level, pk):
def get_changeset_exceeded(request):
return request.user_permissions.max_changeset_changes <= len(request.changeset.operations.operations)
return request.user_permissions.max_changeset_changes <= len(request.changeset.changes)
@etag(editor_etag_func)