From c9d73e9daff8d776e71ea38c3fc9b069737ab65c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Kl=C3=BCnder?= Date: Mon, 26 Aug 2024 16:31:19 +0200 Subject: [PATCH] lets try to display the changeset contents nicely --- src/c3nav/editor/models/changeset.py | 39 +--- src/c3nav/editor/views/changes.py | 279 ++++++++++----------------- 2 files changed, 106 insertions(+), 212 deletions(-) diff --git a/src/c3nav/editor/models/changeset.py b/src/c3nav/editor/models/changeset.py index 3e2bebd2..76f9d9ea 100644 --- a/src/c3nav/editor/models/changeset.py +++ b/src/c3nav/editor/models/changeset.py @@ -124,44 +124,7 @@ class ChangeSet(models.Model): Wrap Objects """ def fill_changes_cache(self): - return - """ - Get all changed objects and fill this ChangeSet's changes cache. - Only executable once, if something is changed later the cache will be automatically updated. - This method gets called automatically when the cache is needed. - Only call it if you need to set include_deleted_created to True. - :rtype: True if the method was executed, else False - """ - if self.changed_objects is not None: - return False - - if self.pk is None: - self.changed_objects = {} - return False - - cache_key = self.cache_key_by_changes + ':cache' - - cached_cache = cache.get(cache_key) - if cached_cache is not None: - (self.changed_objects, self.created_objects, self.updated_existing, - self.deleted_existing, self.m2m_added, self.m2m_removed) = cached_cache - return True - - self.changed_objects = {} - for change in self.changed_objects_set.all(): - change.update_changeset_cache() - - if self.state != 'applied' and not self._cleaning_changes: - self._cleaning_changes = True - try: - self._clean_changes() - finally: - self._cleaning_changes = False - - cache.set(cache_key, (self.changed_objects, self.created_objects, self.updated_existing, - self.deleted_existing, self.m2m_added, self.m2m_removed), 300) - - return True + return # todo: remove """ Analyse Changes diff --git a/src/c3nav/editor/views/changes.py b/src/c3nav/editor/views/changes.py index c46935ed..4ccb37d0 100644 --- a/src/c3nav/editor/views/changes.py +++ b/src/c3nav/editor/views/changes.py @@ -1,6 +1,7 @@ from itertools import chain from operator import itemgetter +from django.apps import apps from django.conf import settings from django.contrib import messages from django.contrib.auth.models import User @@ -16,6 +17,7 @@ from c3nav.editor.forms import ChangeSetForm, RejectForm, get_editor_form 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.fields import I18nField from c3nav.mapdata.models.locations import LocationRedirect, LocationSlug @@ -193,156 +195,90 @@ def changeset_detail(request, pk): changed_objects_data = [] - added_redirects = {} - removed_redirects = {} - for changed_object in changeset.changed_objects.get(LocationRedirect, {}).values(): - if changed_object.is_created == changed_object.deleted: - continue - obj = objects[LocationRedirect][changed_object.obj_pk] - redirect_list = (removed_redirects if changed_object.deleted else added_redirects) - redirect_list.setdefault(obj.target_id, []).append(obj.slug) + # added_redirects = {} + # removed_redirects = {} + # for changed_object in changeset.changed_objects.get(LocationRedirect, {}).values(): + # if changed_object.is_created == changed_object.deleted: + # continue + # obj = objects[LocationRedirect][changed_object.obj_pk] + # redirect_list = (removed_redirects if changed_object.deleted else added_redirects) + # redirect_list.setdefault(obj.target_id, []).append(obj.slug) + # + # redirect_changed_objects = [] + # todo: display redirects nicely - redirect_changed_objects = [] + for changed_object in changeset.changes.changed_objects: + model = apps.get_model("mapdata", changed_object.obj.model) + changes = [] + changed_object_data = { + 'model': model, + 'model_title': model._meta.verbose_name, + 'pk': changed_object.obj.id, + 'desc': changed_object.repr, + 'title': 'TITLE', + 'changes': changes, + 'edit_url': None, + 'deleted': changed_object.deleted, + } - for pk in set(added_redirects.keys()) | set(removed_redirects.keys()): - obj = objects[LocationSlug][pk] - model = obj.__class__ - try: - changeset.changed_objects[model][pk] - except KeyError: - redirect_changed_objects.append((model, {pk: changeset.get_changed_object(obj)})) + form_fields = get_editor_form(model)._meta.fields - for model, changed_objects in chain(changeset.changed_objects.items(), redirect_changed_objects): - if model == LocationRedirect: - continue + if changed_object.created: + changes.append({ + 'icon': 'plus', + 'class': 'success', + 'empty': True, + 'title': _('created'), + }) - for pk, changed_object in changed_objects.items(): - if pk in objects[model]: - obj = objects[model][pk] - obj_desc = format_lazy(_('{model} #{id}'), model=obj.__class__._meta.verbose_name, id=pk) - if is_created_pk(pk): - obj_still_exists = pk in changeset.created_objects.get(obj.__class__, ()) - else: - obj_still_exists = pk not in changeset.deleted_existing.get(obj.__class__, ()) - else: - obj = changed_object.obj._obj - obj_still_exists = False - if changed_object.deleted: - obj_desc = format_lazy(_('{model} #{id}'), model=obj.__class__._meta.verbose_name, id=pk) - - else: - obj_desc = format_lazy(_('{model} #{id} (deleted outside this changeset)'), - model=obj.__class__._meta.verbose_name, id=pk) - - edit_url = None - if obj_still_exists and can_edit and not isinstance(obj, LocationRedirect): - reverse_kwargs = {'pk': obj.pk} - if hasattr(obj, 'space_id'): - reverse_kwargs['space'] = obj.space_id - elif hasattr(obj, 'level_id'): - reverse_kwargs['level'] = obj.level_id - try: - edit_url = reverse('editor.' + obj.__class__._meta.default_related_name + '.edit', - kwargs=reverse_kwargs) - except NoReverseMatch: - pass - - changes = [] - missing_dependencies = changed_object.get_missing_dependencies() - unique_collisions = changed_object.get_unique_collisions() - changed_object_data = { - 'model': obj.__class__, - 'model_title': obj.__class__._meta.verbose_name, - 'pk': changed_object.pk, - 'desc': obj_desc, - 'title': obj.title if getattr(obj, 'titles', None) else None, - 'changes': changes, - 'edit_url': edit_url, - 'deleted': changed_object.deleted, - 'missing_dependencies': missing_dependencies, - 'unique_collisions': unique_collisions, - 'order': (changed_object.deleted and changed_object.is_created, not changed_object.is_created), + update_changes = [] + for name, value in changed_object.fields.items(): + change_data = { + 'icon': 'option-vertical', + 'class': 'muted', } - changed_objects_data.append(changed_object_data) - - form_fields = get_editor_form(model)._meta.fields - - if changed_object.is_created: - changes.append({ - 'icon': 'plus', - 'class': 'success', + if name == 'geometry': + change_data.update({ + 'icon': 'map-marker', + 'class': 'info', 'empty': True, - 'title': _('created'), + 'title': _('created geometry') if changed_object.created else _('edited geometry'), + 'order': (8,), }) - - update_changes = [] - - for name, value in changed_object.updated_fields.items(): - change_data = { - 'icon': 'option-vertical', - 'class': 'muted', - } - if name == 'geometry': - change_data.update({ - 'icon': 'map-marker', - 'class': 'info', - 'empty': True, - 'title': _('created geometry') if changed_object.is_created else _('edited geometry'), - 'order': (8,), - }) - elif name == 'data': - change_data.update({ - 'icon': 'signal', - 'class': 'info', - 'empty': True, - 'title': _('created scan data') if changed_object.is_created else _('edited scan data'), - 'order': (9,), - }) - else: - if '__i18n__' in name: - orig_name, i18n, lang = name.split('__') + elif name == 'data': + change_data.update({ + 'icon': 'signal', + 'class': 'info', + 'empty': True, + 'title': _('created scan data') if changed_object.created else _('edited scan data'), + 'order': (9,), + }) + else: + field = model._meta.get_field(name) + field_title = field.verbose_name + if isinstance(field, I18nField): + for lang, subvalue in value.items(): + sub_change_data = change_data.copy() lang_info = get_language_info(lang) - field = model._meta.get_field(orig_name) field_title = format_lazy(_('{field_name} ({lang})'), field_name=field.verbose_name, lang=lang_info['name_translated']) - field_value = str(value) - if field_value: - getattr(obj, field.attname)[lang] = field_value + if subvalue == '' or subvalue is None: + sub_change_data.update({ + 'empty': True, + 'title': format_lazy(_('remove {field_title}'), field_title=field_title), + }) else: - getattr(obj, field.attname).pop(lang, None) - change_data.update({ + sub_change_data.update({ + 'title': field_title, + 'value': subvalue, + }) + sub_change_data.update({ 'order': (4, tuple(code for code, title in settings.LANGUAGES).index(lang)), }) - else: - field = model._meta.get_field(name) - field_title = field.verbose_name - if field.related_model is not None: - if value is None: - field_value = None - else: - if issubclass(field.related_model, User): - field_value = objects[field.related_model][value].username - else: - field_value = objects[field.related_model][value].title - change_data.update({ - 'missing_dependency': field.name in missing_dependencies, - }) - else: - field_value = field.to_python(value) - if name in unique_collisions: - change_data.update({ - 'unique_collision': field.name in unique_collisions, - }) - order = 5 - if name == 'slug': - order = 1 - if name not in form_fields: - order = 0 - change_data.update({ - 'order': (order, form_fields.index(name) if order else 1), - }) - if field_value == '' or field_value is None: + update_changes.append(sub_change_data) + else: + if value == '' or value is None: change_data.update({ 'empty': True, 'title': format_lazy(_('remove {field_title}'), field_title=field_title), @@ -350,50 +286,45 @@ def changeset_detail(request, pk): else: change_data.update({ 'title': field_title, - 'value': field_value, + 'value': value, }) - update_changes.append(change_data) - - changes.extend(sorted(update_changes, key=itemgetter('order'))) - - for m2m_mode in ('m2m_added', 'm2m_removed'): - m2m_list = getattr(changed_object, m2m_mode).items() - for name, values in sorted(m2m_list, key=lambda nv: form_fields.index(nv[0])): - field = model._meta.get_field(name) - for value in values: - changes.append({ - 'icon': 'chevron-right' if m2m_mode == 'm2m_added' else 'chevron-left', - 'class': 'info', - 'title': field.verbose_name, - 'value': objects[field.related_model][value].title, - }) - - if isinstance(obj, LocationSlug): - for slug in added_redirects.get(obj.pk, ()): - changes.append({ - 'icon': 'chevron-right', - 'class': 'info', - 'title': _('Redirect slugs'), - 'value': slug, - }) - for slug in removed_redirects.get(obj.pk, ()): - changes.append({ - 'icon': 'chevron-left', - 'class': 'info', - 'title': _('Redirect slugs'), - 'value': slug, + order = 5 + if name == 'slug': + order = 1 + if name not in form_fields: + order = 0 + change_data.update({ + 'order': (order, form_fields.index(name) if order else 1), }) + update_changes.append(change_data) + changes.extend(sorted(update_changes, key=itemgetter('order'))) - if changed_object.deleted: + for name, m2m_changes in changed_object.m2m_changes.items(): + field = model._meta.get_field(name) + for item in m2m_changes.added: changes.append({ - 'icon': 'minus', - 'class': 'danger', - 'empty': True, - 'title': _('deleted'), - 'order': (9,), + 'icon': 'chevron-right', + 'class': 'info', + 'title': field.verbose_name, + 'value': item, + }) + for item in m2m_changes.removed: + changes.append({ + 'icon': 'chevron-left', + 'class': 'info', + 'title': field.verbose_name, + 'value': item, }) - changed_objects_data = sorted(changed_objects_data, key=itemgetter('order')) + if changed_object.deleted: + changes.append({ + 'icon': 'minus', + 'class': 'danger', + 'empty': True, + 'title': _('deleted'), + }) + + changed_objects_data.append(changed_object_data) cache.set(cache_key, changed_objects_data, 300) ctx['changed_objects'] = changed_objects_data