diff options
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 |
commit | 3d12b0ac2e97ab43a555106f404ed7cf442caf17 (patch) | |
tree | 76b335690d709db53f269849b93f6b99e7e1fd7c /ishtar_common | |
parent | 43c017bc8dd00372f26728130b00b1cd9196fb10 (diff) | |
download | Ishtar-3d12b0ac2e97ab43a555106f404ed7cf442caf17.tar.bz2 Ishtar-3d12b0ac2e97ab43a555106f404ed7cf442caf17.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.py | 20 | ||||
-rw-r--r-- | ishtar_common/models.py | 135 | ||||
-rw-r--r-- | ishtar_common/wizards.py | 4 |
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 ) |