diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2019-09-11 14:34:25 +0200 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2019-09-11 14:35:02 +0200 |
commit | b103ce9f92012db9d0bc9164b76705633c3c453a (patch) | |
tree | a22f1e8ce124fa48d218d040b7eaafb33915d84b /ishtar_common | |
parent | 81dc5e04cd5c71c1fc0f8cd1d4be73620da8e8f0 (diff) | |
download | Ishtar-b103ce9f92012db9d0bc9164b76705633c3c453a.tar.bz2 Ishtar-b103ce9f92012db9d0bc9164b76705633c3c453a.zip |
Serialization - Import/Export: manage put an release of locks
Diffstat (limited to 'ishtar_common')
-rw-r--r-- | ishtar_common/admin.py | 8 | ||||
-rw-r--r-- | ishtar_common/migrations/0109_auto_20190911_1256.py | 33 | ||||
-rw-r--r-- | ishtar_common/models.py | 11 | ||||
-rw-r--r-- | ishtar_common/serializers.py | 62 | ||||
-rw-r--r-- | ishtar_common/serializers_utils.py | 3 | ||||
-rw-r--r-- | ishtar_common/tasks.py | 7 | ||||
-rw-r--r-- | ishtar_common/tests.py | 6 | ||||
-rw-r--r-- | ishtar_common/views.py | 5 | ||||
-rw-r--r-- | ishtar_common/views_item.py | 3 |
9 files changed, 105 insertions, 33 deletions
diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py index 691e68b26..bd068890e 100644 --- a/ishtar_common/admin.py +++ b/ishtar_common/admin.py @@ -1442,18 +1442,12 @@ class ExportTaskAdmin(admin.ModelAdmin): 'launch_date', 'finished_date'] list_filter = ['state'] actions = [launch_export_action] + form = make_ajax_form(models.ExportTask, {'lock_user': 'user'}) admin_site.register(models.ExportTask, ExportTaskAdmin) -""" - - - -""" - - def launch_import_action(modeladmin, request, queryset): model = modeladmin.model back_url = reverse( diff --git a/ishtar_common/migrations/0109_auto_20190911_1256.py b/ishtar_common/migrations/0109_auto_20190911_1256.py new file mode 100644 index 000000000..09d6d36f7 --- /dev/null +++ b/ishtar_common/migrations/0109_auto_20190911_1256.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.18 on 2019-09-11 12:56 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('ishtar_common', '0108_auto_20190910_1323'), + ] + + operations = [ + migrations.AddField( + model_name='exporttask', + name='lock_user', + field=models.ForeignKey(blank=True, help_text='Owner of the lock if item are locked. Warning: if no user is provided the locks can be remove by any user with the permission to edit.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Lock user'), + ), + migrations.AddField( + model_name='exporttask', + name='put_locks', + field=models.BooleanField(default=False, verbose_name='Put locks on associated items'), + ), + migrations.AddField( + model_name='importtask', + name='releasing_locks', + field=models.BooleanField(default=False, verbose_name='Releasing locks on associated items'), + ), + ] diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 1c17a4421..f2ebb3c29 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -5710,6 +5710,15 @@ class ExportTask(models.Model): "export")) state = models.CharField(_("State"), max_length=2, choices=EXPORT_STATE, default='C') + put_locks = models.BooleanField(_("Put locks on associated items"), + default=False) + lock_user = models.ForeignKey( + User, related_name='+', on_delete=models.SET_NULL, + verbose_name=_("Lock user"), blank=True, null=True, + help_text=_("Owner of the lock if item are locked. Warning: if no " + "user is provided the locks can be remove by any user " + "with the permission to edit.") + ) export_types = models.BooleanField(_("Export types"), default=True) export_conf = models.BooleanField(_("Export configuration"), default=True) export_importers = models.BooleanField(_("Export importers"), default=True) @@ -5769,6 +5778,8 @@ class ImportTask(models.Model): delete_before = models.BooleanField( _("Delete before adding"), default=False, help_text=_("Delete existing items before adding")) + releasing_locks = models.BooleanField( + _("Releasing locks on associated items"), default=False) source = models.FileField(_("Source"), upload_to="imports/%Y/%m/") class Meta: diff --git a/ishtar_common/serializers.py b/ishtar_common/serializers.py index 4b06a9be3..0914a297a 100644 --- a/ishtar_common/serializers.py +++ b/ishtar_common/serializers.py @@ -122,7 +122,8 @@ def directory_serialization(archive=False, return_empty_types=False, def document_serialization(archive=False, return_empty_types=False, archive_name=None, operation_queryset=None, site_queryset=None, cr_queryset=None, - find_queryset=None, warehouse_queryset=None): + find_queryset=None, warehouse_queryset=None, + put_locks=False, lock_user=None): result_queryset = {} get_queryset_attr = None if operation_queryset: @@ -164,6 +165,12 @@ def document_serialization(archive=False, return_empty_types=False, result = generic_get_results([models.Document], "documents", result_queryset=result_queryset) + if put_locks: + q = models.Document.objects + if result_queryset: + q = result_queryset["Document"] + q.update(locked=True, lock_user=lock_user) + media_archive = None if archive: media_archive = generic_archive_files([models.Document], @@ -215,7 +222,8 @@ def full_serialization(operation_queryset=None, site_queryset=None, warehouse_queryset=None, archive=True, no_geo=True, info=None, export_types=True, export_conf=True, export_importers=True, export_geo=True, export_dir=True, - export_docs=True, export_items=True): + export_docs=True, export_items=True, put_locks=False, + lock_user=None): archive_name = None if export_types: # print("type") @@ -242,7 +250,9 @@ def full_serialization(operation_queryset=None, site_queryset=None, archive=archive, archive_name=archive_name, operation_queryset=operation_queryset, site_queryset=site_queryset, cr_queryset=cr_queryset, find_queryset=find_queryset, - warehouse_queryset=warehouse_queryset) + warehouse_queryset=warehouse_queryset, + put_locks=put_locks, lock_user=lock_user + ) if export_items: # print("operation") archive_name = operation_serialization( @@ -250,32 +260,33 @@ def full_serialization(operation_queryset=None, site_queryset=None, archive_name=archive_name, operation_queryset=operation_queryset, site_queryset=site_queryset, cr_queryset=cr_queryset, find_queryset=find_queryset, warehouse_queryset=warehouse_queryset, - no_geo=no_geo) + no_geo=no_geo, put_locks=put_locks, lock_user=lock_user) # print("cr") cr_serialization( archive=archive, archive_name=archive_name, operation_queryset=operation_queryset, site_queryset=site_queryset, cr_queryset=cr_queryset, find_queryset=find_queryset, warehouse_queryset=warehouse_queryset, - no_geo=no_geo) + no_geo=no_geo, put_locks=put_locks, lock_user=lock_user) # print("find") find_serialization( archive=archive, archive_name=archive_name, operation_queryset=operation_queryset, site_queryset=site_queryset, cr_queryset=cr_queryset, find_queryset=find_queryset, warehouse_queryset=warehouse_queryset, - no_geo=no_geo) + no_geo=no_geo, put_locks=put_locks, lock_user=lock_user) # print("warehouse") warehouse_serialization( archive=archive, archive_name=archive_name, operation_queryset=operation_queryset, site_queryset=site_queryset, cr_queryset=cr_queryset, find_queryset=find_queryset, warehouse_queryset=warehouse_queryset, - no_geo=no_geo) + no_geo=no_geo, put_locks=put_locks, lock_user=lock_user) return archive_name -def restore_serialized(archive_name, user=None, delete_existing=False): +def restore_serialized(archive_name, user=None, delete_existing=False, + release_locks=False): with zipfile.ZipFile(archive_name, "r") as zip_file: # check version info = json.loads(zip_file.read("info.json").decode("utf-8")) @@ -323,13 +334,15 @@ def restore_serialized(archive_name, user=None, delete_existing=False): # regenerate labels, add a new version, etc. historized = hasattr(model, "history_modifier") and ( hasattr(model, "history_creator")) + releasing_locks = hasattr(model, "locked") and ( + release_locks) need_resave = hasattr(model, "CACHED_LABELS") or \ hasattr(model, "cached_label") or \ - (user and historized) + releasing_locks or (user and historized) idx = -1 for idx, obj in enumerate(deserialize("json", data)): extra_attrs = {} - if historized: + if historized or hasattr(model, "locked"): keys = obj.object.natural_key() old_obj = None try: @@ -337,14 +350,20 @@ def restore_serialized(archive_name, user=None, delete_existing=False): *keys) except model.DoesNotExist: pass - if old_obj and (old_obj.history_creator or - old_obj.history_modifier): - extra_attrs = { - "history_modifier_id": - old_obj.history_modifier_id, - "history_creator_id": - old_obj.history_creator_id - } + if old_obj: + if historized and (old_obj.history_creator or + old_obj.history_modifier): + extra_attrs = { + "history_modifier_id": + old_obj.history_modifier_id, + "history_creator_id": + old_obj.history_creator_id + } + if hasattr(model, "locked") and old_obj.locked: + extra_attrs.update({ + "locked": old_obj.locked, + "lock_user": old_obj.lock_user, + }) obj.save() if need_resave or extra_attrs: obj = model.objects.get(id=obj.object.id) @@ -356,10 +375,17 @@ def restore_serialized(archive_name, user=None, delete_existing=False): "history_creator_id"] else: obj.history_creator = user + if extra_attrs and \ + "locked" in extra_attrs: + obj.locked = extra_attrs["locked"] + obj.lock_user = extra_attrs["lock_user"] elif extra_attrs: for k in extra_attrs: setattr(obj, k, extra_attrs[k]) obj.skip_history_when_saving = True + if releasing_locks: + obj.locked = False + obj.lock_user = None obj._no_move = True obj.save() if idx >= 0: diff --git a/ishtar_common/serializers_utils.py b/ishtar_common/serializers_utils.py index ef36e2695..2242c349e 100644 --- a/ishtar_common/serializers_utils.py +++ b/ishtar_common/serializers_utils.py @@ -161,7 +161,8 @@ def generic_get_results(model_list, dirname, no_geo=True, new_result += result_to_add result[key] = json.dumps(new_result, indent=2) - excluded_fields = ["history_modifier", "history_creator", "imports"] + excluded_fields = ["history_modifier", "history_creator", "imports", + "locked", "lock_user"] if hasattr(model, "SERIALIZATION_EXCLUDE"): excluded_fields = list(model.SERIALIZATION_EXCLUDE) if no_geo: diff --git a/ishtar_common/tasks.py b/ishtar_common/tasks.py index 1f95df392..07286ad76 100644 --- a/ishtar_common/tasks.py +++ b/ishtar_common/tasks.py @@ -52,7 +52,8 @@ def launch_import(import_task): restore_serialized(import_task.source.path, import_task.import_user, - delete_existing=import_task.delete_before) + delete_existing=import_task.delete_before, + release_locks=import_task.releasing_locks) import_task.finished_date = datetime.datetime.now() import_task.state = 'F' import_task.save() @@ -66,7 +67,9 @@ def launch_export(export_task): export_task.state = 'P' export_task.save() - kwargs = {"info": {}} + kwargs = {"info": {}, + "put_locks": export_task.put_locks, + "lock_user": export_task.lock_user} for fltr_key in ("export_types", "export_conf", "export_importers", "export_geo", "export_dir", "export_docs", "export_items"): diff --git a/ishtar_common/tests.py b/ishtar_common/tests.py index 22876784c..939a29d2b 100644 --- a/ishtar_common/tests.py +++ b/ishtar_common/tests.py @@ -664,8 +664,10 @@ class GenericSerializationTest: zip_filename = serialization(**kwargs) return current_number, zip_filename - def generic_restore_test(self, zip_filename, current_number, model_list): - restore_serialized(zip_filename, delete_existing=True) + def generic_restore_test(self, zip_filename, current_number, model_list, + release_locks=False, delete_existing=True): + restore_serialized(zip_filename, delete_existing=delete_existing, + release_locks=release_locks) for model in model_list: previous_nb = current_number[(model.__module__, model.__name__)] current_nb = model.objects.count() diff --git a/ishtar_common/views.py b/ishtar_common/views.py index db0d3631b..acf7eb70c 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -2114,7 +2114,8 @@ class QANotAvailable(IshtarMixin, LoginRequiredMixin, TemplateView): template_name = 'ishtar/forms/qa_message.html' modal_size = "small" contexts = {"locked-by-others": _("Some items have been locked by other " - "user")} + "users."), + "locked": _("Some items are locked.")} def get_context_data(self, **kwargs): data = super(QANotAvailable, self).get_context_data(**kwargs) @@ -2196,7 +2197,7 @@ class QAItemEditForm(QAItemForm): for item in self.items: if item.locked: redirected = HttpResponseRedirect( - reverse("qa-not-available")) + reverse("qa-not-available", args=["locked"])) return redirected def get_form_class(self): diff --git a/ishtar_common/views_item.py b/ishtar_common/views_item.py index 2c4cc1a55..6c10285db 100644 --- a/ishtar_common/views_item.py +++ b/ishtar_common/views_item.py @@ -282,7 +282,8 @@ def show_item(model, name, extra_dct=None, model_for_perms=None): pandoc_args = ["pandoc", "-f", "html", "-t", "odt", "-o", odt.name, html_source.name] try: - subprocess.check_call(pandoc_args) + subprocess.check_call(pandoc_args, stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL) except subprocess.CalledProcessError: return HttpResponse(content, content_type="application/xhtml") |