summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
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
commite87be285da2557f3a684418c9f91c9dc22139fda (patch)
treea22f1e8ce124fa48d218d040b7eaafb33915d84b /ishtar_common
parent0a18b35422fd85f9cbb39796275bc90065c80689 (diff)
downloadIshtar-e87be285da2557f3a684418c9f91c9dc22139fda.tar.bz2
Ishtar-e87be285da2557f3a684418c9f91c9dc22139fda.zip
Serialization - Import/Export: manage put an release of locks
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/admin.py8
-rw-r--r--ishtar_common/migrations/0109_auto_20190911_1256.py33
-rw-r--r--ishtar_common/models.py11
-rw-r--r--ishtar_common/serializers.py62
-rw-r--r--ishtar_common/serializers_utils.py3
-rw-r--r--ishtar_common/tasks.py7
-rw-r--r--ishtar_common/tests.py6
-rw-r--r--ishtar_common/views.py5
-rw-r--r--ishtar_common/views_item.py3
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")