summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2018-05-10 16:53:30 +0200
committerÉtienne Loks <etienne.loks@iggdrasil.net>2018-06-12 08:44:18 +0200
commit29df409889edeecc11b39021df6f4e6fb39535cc (patch)
tree76b335690d709db53f269849b93f6b99e7e1fd7c /ishtar_common
parent3f14d0f6481f1781d598d29b79a96fb7ee727320 (diff)
downloadIshtar-29df409889edeecc11b39021df6f4e6fb39535cc.tar.bz2
Ishtar-29df409889edeecc11b39021df6f4e6fb39535cc.zip
Move image to logical directory and generate symlinks (refs #4076)
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/migrations/0051_ishtarimage_associated_links.py20
-rw-r--r--ishtar_common/models.py135
-rw-r--r--ishtar_common/wizards.py4
3 files changed, 152 insertions, 7 deletions
diff --git a/ishtar_common/migrations/0051_ishtarimage_associated_links.py b/ishtar_common/migrations/0051_ishtarimage_associated_links.py
new file mode 100644
index 000000000..10ac5ef8f
--- /dev/null
+++ b/ishtar_common/migrations/0051_ishtarimage_associated_links.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.10 on 2018-05-10 16:45
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('ishtar_common', '0050_licensetype_url'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='ishtarimage',
+ name='associated_links',
+ field=models.TextField(blank=True, null=True, verbose_name='Symbolic links'),
+ ),
+ ]
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index d4d6d2c79..0e8d96ddb 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -27,7 +27,6 @@ import inspect
from PIL import Image
import logging
import os
-from os.path import isfile, join
import re
from secretary import Renderer as SecretaryRenderer
import shutil
@@ -939,10 +938,7 @@ class ImageModel(models.Model):
pass
# save the thumbnail
- splited = filename.split('.')
- thumb_filename = u"{}-thumb.{}".format(
- u".".join(splited[:-1]), splited[-1]
- )
+ thumb_filename = self._get_thumb_name(filename)
self.thumbnail.save(
thumb_filename,
self.create_thumb(image, self.THUMB_MAX_SIZE),
@@ -951,6 +947,12 @@ class ImageModel(models.Model):
pass
return super(ImageModel, self).save(*args, **kwargs)
+ def _get_thumb_name(self, filename):
+ splited = filename.split('.')
+ return u"{}-thumb.{}".format(
+ u".".join(splited[:-1]), splited[-1]
+ )
+
class HistoryError(Exception):
def __init__(self, value):
@@ -3041,8 +3043,18 @@ class ImageType(GeneralType):
class IshtarImage(ImageModel):
+ # order is important: put the image in the first match found
+ # other will be symbolic links
+ RELATED_MODELS = [
+ 'treatmentimage_set', 'findimage_set', 'contextrecordimage_set',
+ 'operationimage_set', 'siteimage_set', 'warehouseimage_set',
+ ]
+ LINK_SPLIT = u"<||>"
+
name = models.CharField(_(u"Name"), max_length=250, blank=True, null=True)
description = models.TextField(_(u"Description"), blank=True, null=True)
+ associated_links = models.TextField(_(u"Symbolic links"), blank=True,
+ null=True)
licenses = models.ManyToManyField(LicenseType, verbose_name=_(u"License"),
blank=True)
authors = models.ManyToManyField(Author, verbose_name=_(u"Authors"),
@@ -3064,6 +3076,115 @@ class IshtarImage(ImageModel):
verbose_name_plural = _(u"Images")
ordering = ('name',)
+ def _get_base_image_paths(self):
+ for related_model in self.RELATED_MODELS:
+ q = getattr(self, related_model).all()
+ if q.count():
+ item = q.all()[0].item
+ yield item._get_base_image_path()
+
+ def _get_base_image_path(self):
+ for path in self._get_base_image_paths():
+ return path
+ return u"upload"
+
+ def _get_available_filename(self, path, test_link=None):
+ """
+ Get a filename not used
+ If name already used - generate a name with schema:
+ [base]-[current_number + 1].[suffix]
+
+ :param path: base path
+ :param test_link: test if an existing path match with this link
+ :return: if test_link is not None, (new_path, link_match) otherwise
+ the new_path
+ """
+
+ file_split = path.split('.')
+ suffix, base = "", ""
+ if len(file_split) > 1:
+ base = u".".join(file_split[0:-1])
+ suffix = file_split[-1]
+ else:
+ base = path
+ base_split = base.split('-')
+ current_nb = 0
+ if len(base_split) > 1:
+ try:
+ current_nb = int(base_split[-1])
+ base = u"-".join(base_split[0:-1]) + u"-"
+ except ValueError:
+ pass
+
+ while os.path.exists(path):
+ if test_link and os.path.islink(path) \
+ and os.readlink(path) == test_link:
+ return path, True
+ current_nb += 1
+ path = u"{}-{}.{}".format(base, current_nb, suffix)
+ if test_link:
+ return path, False
+ return path
+
+ def _move_image(self):
+ """
+ Move to the relevant path and create appropriate symbolic links
+
+ :return: list of associated links
+ """
+ reference_path = None
+ initial_path = self.image.path
+ filename = os.path.basename(initial_path)
+ links = []
+
+ for related_model in self.RELATED_MODELS:
+ q = getattr(self, related_model).all()
+ if q.count():
+ item = q.all()[0].item
+ base_path = item._get_base_image_path()
+ new_path = base_path + u"/" + filename
+ if not reference_path:
+ reference_path = settings.MEDIA_ROOT + new_path
+ # correct path
+ if initial_path == reference_path:
+ continue
+ if not os.path.exists(os.path.dirname(reference_path)):
+ os.makedirs(os.path.dirname(reference_path))
+
+ reference_path = self._get_available_filename(
+ reference_path)
+
+ os.rename(initial_path, reference_path)
+ os.rename(self.thumbnail.path,
+ self._get_thumb_name(reference_path))
+ self.image.name = reference_path[len(settings.MEDIA_ROOT):]
+ self.save(no_path_change=True)
+ continue
+ # create a link
+ new_path = settings.MEDIA_ROOT + new_path
+ if not os.path.exists(os.path.dirname(new_path)):
+ os.makedirs(os.path.dirname(new_path))
+ new_path, match = self._get_available_filename(
+ new_path, test_link=reference_path)
+ links.append(new_path)
+ if match: # the current link is correct
+ continue
+ os.symlink(reference_path, new_path)
+ return links
+
+ def save(self, *args, **kwargs):
+ no_path_change = 'no_path_change' in kwargs \
+ and kwargs.pop('no_path_change')
+
+ super(IshtarImage, self).save(*args, **kwargs)
+
+ if not no_path_change and not getattr(self, '_no_path_change', False):
+ links = self._move_image()
+ links = self.LINK_SPLIT.join(links)
+ if links != self.associated_links:
+ self.associated_links = links
+ self.save(no_path_change=True)
+
class ThroughImage(models.Model):
image = models.ForeignKey(
@@ -3414,8 +3535,8 @@ class AdministrationTask(models.Model):
# only script inside the script directory can be executed
for name in os.listdir(script_dir):
if name == self.script.path:
- if isfile(join(script_dir, name)):
- script_name = join(script_dir, name)
+ if os.path.isfile(os.path.join(script_dir, name)):
+ script_name = os.path.join(script_dir, name)
break
if not script_name:
self.result = unicode(
diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py
index f200447e4..7556f5194 100644
--- a/ishtar_common/wizards.py
+++ b/ishtar_common/wizards.py
@@ -875,6 +875,10 @@ class Wizard(NamedUrlWizardView):
elif isinstance(obj,
field.related_model):
related_data[field.name] = obj
+ # let default value if is none
+ for k in related_data.keys():
+ if related_data[k] is None:
+ related_data.pop(k)
related_model.through.objects.create(
**related_data
)