Merge pull request #470 from taigaio/astagi-feature/attachments-sha1
Astagi feature/attachments sha1remotes/origin/logger
commit
503f320942
|
@ -19,6 +19,7 @@
|
||||||
- Add externall apps: now Taiga can integrate with hundreds of applications and service.
|
- Add externall apps: now Taiga can integrate with hundreds of applications and service.
|
||||||
- Improve searching system, now full text searchs are supported
|
- Improve searching system, now full text searchs are supported
|
||||||
- Improve export system, now is more efficient and prevents possible crashes with heavy projects.
|
- Improve export system, now is more efficient and prevents possible crashes with heavy projects.
|
||||||
|
- Add sha1 hash to attachments to verify the integrity of files (thanks to [@astagi](https://github.com/astagi)).
|
||||||
- i18n.
|
- i18n.
|
||||||
- Add italian (it) translation.
|
- Add italian (it) translation.
|
||||||
- Add polish (pl) translation.
|
- Add polish (pl) translation.
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
|
from taiga.projects.attachments.models import Attachment
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
for attachment in Attachment.objects.all():
|
||||||
|
attachment.save()
|
|
@ -0,0 +1,20 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('attachments', '0004_auto_20150508_1141'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='attachment',
|
||||||
|
name='sha1',
|
||||||
|
field=models.CharField(default='', verbose_name='sha1', max_length=40, blank=True),
|
||||||
|
preserve_default=True,
|
||||||
|
),
|
||||||
|
]
|
|
@ -68,6 +68,7 @@ class Attachment(models.Model):
|
||||||
upload_to=get_attachment_file_path,
|
upload_to=get_attachment_file_path,
|
||||||
verbose_name=_("attached file"))
|
verbose_name=_("attached file"))
|
||||||
|
|
||||||
|
sha1 = models.CharField(default="", max_length=40, verbose_name=_("sha1"), blank=True)
|
||||||
|
|
||||||
is_deprecated = models.BooleanField(default=False, verbose_name=_("is deprecated"))
|
is_deprecated = models.BooleanField(default=False, verbose_name=_("is deprecated"))
|
||||||
description = models.TextField(null=False, blank=True, verbose_name=_("description"))
|
description = models.TextField(null=False, blank=True, verbose_name=_("description"))
|
||||||
|
@ -83,11 +84,30 @@ class Attachment(models.Model):
|
||||||
("view_attachment", "Can view attachment"),
|
("view_attachment", "Can view attachment"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(Attachment, self).__init__(*args, **kwargs)
|
||||||
|
self._orig_attached_file = self.attached_file
|
||||||
|
|
||||||
|
def _generate_sha1(self, blocksize=65536):
|
||||||
|
hasher = hashlib.sha1()
|
||||||
|
while True:
|
||||||
|
buff = self.attached_file.file.read(blocksize)
|
||||||
|
if not buff:
|
||||||
|
break
|
||||||
|
hasher.update(buff)
|
||||||
|
self.sha1 = hasher.hexdigest()
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if not self._importing or not self.modified_date:
|
if not self._importing or not self.modified_date:
|
||||||
self.modified_date = timezone.now()
|
self.modified_date = timezone.now()
|
||||||
|
if self.attached_file:
|
||||||
return super().save(*args, **kwargs)
|
if not self.sha1 or self.attached_file != self._orig_attached_file:
|
||||||
|
self._generate_sha1()
|
||||||
|
save = super().save(*args, **kwargs)
|
||||||
|
self._orig_attached_file = self.attached_file
|
||||||
|
if self.attached_file:
|
||||||
|
self.attached_file.file.close()
|
||||||
|
return save
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Attachment: {}".format(self.id)
|
return "Attachment: {}".format(self.id)
|
||||||
|
|
|
@ -34,8 +34,8 @@ class AttachmentSerializer(serializers.ModelSerializer):
|
||||||
model = models.Attachment
|
model = models.Attachment
|
||||||
fields = ("id", "project", "owner", "name", "attached_file", "size", "url",
|
fields = ("id", "project", "owner", "name", "attached_file", "size", "url",
|
||||||
"description", "is_deprecated", "created_date", "modified_date",
|
"description", "is_deprecated", "created_date", "modified_date",
|
||||||
"object_id", "order")
|
"object_id", "order", "sha1")
|
||||||
read_only_fields = ("owner", "created_date", "modified_date")
|
read_only_fields = ("owner", "created_date", "modified_date", "sha1")
|
||||||
|
|
||||||
def get_url(self, obj):
|
def get_url(self, obj):
|
||||||
return obj.attached_file.url
|
return obj.attached_file.url
|
Loading…
Reference in New Issue