fixes to make the last commit work (asside from applying changes)
This commit is contained in:
parent
174866c2fd
commit
f2f0b9fdae
7 changed files with 32 additions and 18 deletions
|
@ -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,
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue