diff --git a/club/migrations/0005_auto_20161120_1149.py b/club/migrations/0005_auto_20161120_1149.py new file mode 100644 index 00000000..df8d8126 --- /dev/null +++ b/club/migrations/0005_auto_20161120_1149.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('club', '0004_auto_20160915_1057'), + ] + + operations = [ + migrations.AlterField( + model_name='club', + name='home', + field=models.OneToOneField(related_name='home_of_club', blank=True, on_delete=django.db.models.deletion.SET_NULL, verbose_name='home', null=True, to='core.SithFile'), + ), + ] diff --git a/club/models.py b/club/models.py index 0ed5ab02..21d9302c 100644 --- a/club/models.py +++ b/club/models.py @@ -36,7 +36,8 @@ class Club(models.Model): default=settings.SITH_GROUPS['root']['id']) edit_groups = models.ManyToManyField(Group, related_name="editable_club", blank=True) view_groups = models.ManyToManyField(Group, related_name="viewable_club", blank=True) - home = models.OneToOneField(SithFile, related_name='home_of_club', verbose_name=_("home"), null=True, blank=True) + home = models.OneToOneField(SithFile, related_name='home_of_club', verbose_name=_("home"), null=True, blank=True, + on_delete=models.SET_NULL) def check_loop(self): """Raise a validation error when a loop is found within the parent list""" diff --git a/core/migrations/0009_auto_20161120_1155.py b/core/migrations/0009_auto_20161120_1155.py new file mode 100644 index 00000000..524e29da --- /dev/null +++ b/core/migrations/0009_auto_20161120_1155.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import core.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0008_sithfile_asked_for_removal'), + ] + + operations = [ + migrations.AddField( + model_name='sithfile', + name='compressed', + field=models.FileField(upload_to=core.models.get_compressed_directory, null=True, verbose_name='compressed file', blank=True), + ), + migrations.AddField( + model_name='sithfile', + name='thumbnail', + field=models.FileField(upload_to=core.models.get_thumbnail_directory, null=True, verbose_name='thumbnail', blank=True), + ), + migrations.AlterField( + model_name='user', + name='home', + field=models.OneToOneField(verbose_name='home', related_name='home_of', on_delete=django.db.models.deletion.SET_NULL, null=True, to='core.SithFile', blank=True), + ), + ] diff --git a/core/models.py b/core/models.py index 901e3e59..791685fd 100644 --- a/core/models.py +++ b/core/models.py @@ -115,7 +115,8 @@ class User(AbstractBaseUser): ), ) groups = models.ManyToManyField(RealGroup, related_name='users', blank=True) - home = models.OneToOneField('SithFile', related_name='home_of', verbose_name=_("home"), null=True, blank=True) + home = models.OneToOneField('SithFile', related_name='home_of', verbose_name=_("home"), null=True, blank=True, + on_delete=models.SET_NULL) profile_pict = models.OneToOneField('SithFile', related_name='profile_of', verbose_name=_("profile"), null=True, blank=True, on_delete=models.SET_NULL) avatar_pict = models.OneToOneField('SithFile', related_name='avatar_of', verbose_name=_("avatar"), null=True, @@ -491,10 +492,18 @@ class Preferences(models.Model): def get_directory(instance, filename): return '.{0}/{1}'.format(instance.get_parent_path(), filename) +def get_compressed_directory(instance, filename): + return '.{0}/compressed/{1}'.format(instance.get_parent_path(), filename) + +def get_thumbnail_directory(instance, filename): + return '.{0}/thumbnail/{1}'.format(instance.get_parent_path(), filename) + class SithFile(models.Model): name = models.CharField(_('file name'), max_length=256, blank=False) parent = models.ForeignKey('self', related_name="children", verbose_name=_("parent"), null=True, blank=True) file = models.FileField(upload_to=get_directory, verbose_name=_("file"), null=True, blank=True) + compressed = models.FileField(upload_to=get_compressed_directory, verbose_name=_("compressed file"), null=True, blank=True) + thumbnail = models.FileField(upload_to=get_thumbnail_directory, verbose_name=_("thumbnail"), null=True, blank=True) owner = models.ForeignKey(User, related_name="owned_files", verbose_name=_("owner")) edit_groups = models.ManyToManyField(Group, related_name="editable_files", verbose_name=_("edit group"), blank=True) view_groups = models.ManyToManyField(Group, related_name="viewable_files", verbose_name=_("view group"), blank=True) @@ -528,6 +537,10 @@ class SithFile(models.Model): for c in self.children.all(): c.delete() self.file.delete() + if self.compressed: + self.compressed.delete() + if self.thumbnail: + self.thumbnail.delete() return super(SithFile, self).delete() def clean(self): @@ -605,7 +618,7 @@ class SithFile(models.Model): return l def get_parent_path(self): - return '/' + '/'.join([p.name for p in self.get_parent_list()]) + return '/' + '/'.join([p.name for p in self.get_parent_list()[::-1]]) def get_display_name(self): return self.name diff --git a/core/utils.py b/core/utils.py index 4b3ec2b2..087cafa2 100644 --- a/core/utils.py +++ b/core/utils.py @@ -13,7 +13,7 @@ def scale_dimension(width, height, long_edge): ratio = long_edge * 1. / height return int(width * ratio), int(height * ratio) -def resize_image(im, edge, format): # TODO move that into a utils file +def resize_image(im, edge, format): (w, h) = im.size (width, height) = scale_dimension(w, h, long_edge=edge) content = BytesIO() diff --git a/core/views/files.py b/core/views/files.py index 69b42325..5f2cbb73 100644 --- a/core/views/files.py +++ b/core/views/files.py @@ -19,7 +19,7 @@ import os from core.models import SithFile from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin, can_view, not_found -def send_file(request, file_id, file_class=SithFile): +def send_file(request, file_id, file_class=SithFile, file_attr="file"): """ Send a file through Django without loading the whole file into memory at once. The FileWrapper will turn the file object into an @@ -35,7 +35,7 @@ def send_file(request, file_id, file_class=SithFile): Counter.objects.filter(token=request.session['counter_token']).exists()) ): raise PermissionDenied - name = f.file.name + name = f.__getattribute__(file_attr).name with open(settings.MEDIA_ROOT + name, 'rb') as filename: wrapper = FileWrapper(filename) response = HttpResponse(wrapper, content_type=f.mime_type) diff --git a/sas/models.py b/sas/models.py index 7a786797..b8a9ee2f 100644 --- a/sas/models.py +++ b/sas/models.py @@ -24,6 +24,12 @@ class Picture(SithFile): def get_download_url(self): return reverse('sas:download', kwargs={'picture_id': self.id}) + def get_download_compressed_url(self): + return reverse('sas:download_compressed', kwargs={'picture_id': self.id}) + + def get_download_thumb_url(self): + return reverse('sas:download_thumb', kwargs={'picture_id': self.id}) + def get_next(self): return self.parent.children.exclude(is_moderated=False, asked_for_removal=True).filter(id__gt=self.id).order_by('id').first() diff --git a/sas/templates/sas/album.jinja b/sas/templates/sas/album.jinja index e9269798..45ceb9ae 100644 --- a/sas/templates/sas/album.jinja +++ b/sas/templates/sas/album.jinja @@ -28,7 +28,7 @@ {% if p.as_picture.can_be_viewed_by(user) %}
- {{ p.get_display_name() }} + {{ p.get_display_name() }}
{% endif %} diff --git a/sas/templates/sas/moderation.jinja b/sas/templates/sas/moderation.jinja index 170652a7..d3f5a8f2 100644 --- a/sas/templates/sas/moderation.jinja +++ b/sas/templates/sas/moderation.jinja @@ -17,7 +17,7 @@ {% endif %}

- {{ p.name }} + {{ p.name }}
{% trans %}Full name: {% endtrans %}{{ p.get_parent_path()+'/'+p.name }}
{% trans %}Owner: {% endtrans %}{{ p.owner.get_display_name() }}
diff --git a/sas/templates/sas/picture.jinja b/sas/templates/sas/picture.jinja index 3b261d68..b46b61bd 100644 --- a/sas/templates/sas/picture.jinja +++ b/sas/templates/sas/picture.jinja @@ -35,21 +35,21 @@ {{ print_path(picture.parent) }} {{ picture.get_display_name() }}

{{ picture.get_display_name() }}

- {{ picture.get_display_name() }} + {{ picture.get_display_name() }}
@@ -73,6 +73,9 @@

+

+ {% trans %}HD version{% endtrans %} +

{% trans %}Ask for removal{% endtrans %}

diff --git a/sas/urls.py b/sas/urls.py index 6731d82b..23464227 100644 --- a/sas/urls.py +++ b/sas/urls.py @@ -8,6 +8,8 @@ urlpatterns = [ url(r'^album/(?P[0-9]+)$', AlbumView.as_view(), name='album'), url(r'^picture/(?P[0-9]+)$', PictureView.as_view(), name='picture'), url(r'^picture/(?P[0-9]+)/download$', send_pict, name='download'), + url(r'^picture/(?P[0-9]+)/download/compressed$', send_compressed, name='download_compressed'), + url(r'^picture/(?P[0-9]+)/download/thumb$', send_thumb, name='download_thumb'), # url(r'^album/new$', AlbumCreateView.as_view(), name='album_new'), # url(r'^(?P[0-9]+)/$', ClubView.as_view(), name='club_view'), ] diff --git a/sas/views.py b/sas/views.py index 321e8259..8f77b348 100644 --- a/sas/views.py +++ b/sas/views.py @@ -23,6 +23,9 @@ class SASForm(forms.Form): required=False) def process(self, parent, owner, files, automodere=False): + from core.utils import resize_image + from io import BytesIO + from PIL import Image try: if self.cleaned_data['album_name'] != "": album = Album(parent=parent, name=self.cleaned_data['album_name'], owner=owner, is_moderated=automodere) @@ -36,8 +39,15 @@ class SASForm(forms.Form): is_folder=False, is_moderated=automodere) try: new_file.clean() - # TODO: generate thumbnail + im = Image.open(BytesIO(f.read())) + thumb = resize_image(im, 200, f.content_type.split('/')[-1]) + compressed = resize_image(im, 600, f.content_type.split('/')[-1]) + new_file.thumbnail = thumb + new_file.thumbnail.name = new_file.name + new_file.compressed = compressed + new_file.compressed.name = new_file.name new_file.save() + print(new_file.compressed) except Exception as e: self.add_error(None, _("Error uploading file %(file_name)s: %(msg)s") % {'file_name': f, 'msg': repr(e)}) @@ -120,6 +130,12 @@ class PictureView(CanViewMixin, DetailView, FormMixin): def send_pict(request, picture_id): return send_file(request, picture_id, Picture) +def send_compressed(request, picture_id): + return send_file(request, picture_id, Picture, "compressed") + +def send_thumb(request, picture_id): + return send_file(request, picture_id, Picture, "thumbnail") + class AlbumView(CanViewMixin, DetailView, FormMixin): model = Album form_class = SASForm