diff options
| -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                          ) | 
