diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 130d00d0..cf707141 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,9 +3,10 @@ Changelog ========= -2.4.1 (unreleased) +2.5.0 (unreleased) ================== +* Added file link support * Allow link requirement to be changed when another CMS plugin inherits from AbstractLink diff --git a/README.rst b/README.rst index 82013f89..3334afa1 100644 --- a/README.rst +++ b/README.rst @@ -41,6 +41,11 @@ file for additional dependencies: |python| |django| |djangocms| +* Django Filer 1.3.0 or higher + +Make sure `django Filer `_ +is installed and configured appropriately. + Installation ------------ diff --git a/djangocms_link/cms_plugins.py b/djangocms_link/cms_plugins.py index 39693f23..55e91aed 100644 --- a/djangocms_link/cms_plugins.py +++ b/djangocms_link/cms_plugins.py @@ -28,7 +28,8 @@ class LinkPlugin(CMSPluginBase): 'fields': ( ('mailto', 'phone'), ('anchor', 'target'), - ) + ('file_link'), + ), }), (_('Advanced settings'), { 'classes': ('collapse',), diff --git a/djangocms_link/migrations/0014_link_file_link.py b/djangocms_link/migrations/0014_link_file_link.py new file mode 100644 index 00000000..7dc73e28 --- /dev/null +++ b/djangocms_link/migrations/0014_link_file_link.py @@ -0,0 +1,22 @@ +# Generated by Django 2.2.2 on 2019-06-20 04:49 + +import django.db.models.deletion +from django.db import migrations + +import filer.fields.file + + +class Migration(migrations.Migration): + + dependencies = [ + ('filer', '0011_auto_20190418_0137'), + ('djangocms_link', '0013_fix_hostname'), + ] + + operations = [ + migrations.AddField( + model_name='link', + name='file_link', + field=filer.fields.file.FilerFileField(blank=True, help_text='If provided links a file from the filer app.', null=True, on_delete=django.db.models.deletion.SET_NULL, to='filer.File', verbose_name='File link'), + ), + ] diff --git a/djangocms_link/models.py b/djangocms_link/models.py index 3d5a157d..9863e1a6 100644 --- a/djangocms_link/models.py +++ b/djangocms_link/models.py @@ -16,6 +16,7 @@ from cms.models import CMSPlugin, Page from djangocms_attributes_field.fields import AttributesField +from filer.fields.file import FilerFileField from .validators import IntranetURLValidator @@ -87,6 +88,15 @@ class AbstractLink(CMSPlugin): on_delete=models.SET_NULL, help_text=_('If provided, overrides the external link.'), ) + + file_link = FilerFileField( + verbose_name=_('File link'), + blank=True, + null=True, + on_delete=models.SET_NULL, + help_text=_('If provided links a file from the filer app.'), + ) + # other link types anchor = models.CharField( verbose_name=_('Anchor'), @@ -162,6 +172,8 @@ def get_link(self): if ref_page_site_id != cms_page_site_id: ref_site = Site.objects._get_site_by_id(ref_page_site_id).domain link = '//{}{}'.format(ref_site, link) + elif self.file_link: + link = self.file_link.url elif self.external_link: link = self.external_link elif self.phone: @@ -182,6 +194,7 @@ def clean(self): 'internal_link', 'mailto', 'phone', + 'file_link', ) anchor_field_name = 'anchor' field_names_allowed_with_anchor = ( diff --git a/setup.py b/setup.py index 8ded711c..3d63f7aa 100644 --- a/setup.py +++ b/setup.py @@ -7,6 +7,7 @@ REQUIREMENTS = [ 'django-cms>=3.4.5', + 'django-filer>=1.3.0', 'djangocms-attributes-field>=0.4.0', ] diff --git a/tests/requirements.txt b/tests/requirements.txt index 5049ff23..0c426b32 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,5 +1,6 @@ # requirements from setup.py django-select2>=5.11,<7 # 7 works in Django 2+ +django-filer>=1.3.0 djangocms-text-ckeditor html5lib<0.99999999 # other requirements diff --git a/tests/settings.py b/tests/settings.py index ab23981f..77946fd9 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -1,7 +1,11 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +from tempfile import mkdtemp + + HELPER_SETTINGS = { 'INSTALLED_APPS': [ + 'filer', 'django_select2', 'djangocms_text_ckeditor', ], @@ -12,8 +16,15 @@ }] }, 'LANGUAGE_CODE': 'en', + 'THUMBNAIL_PROCESSORS': ( + 'easy_thumbnails.processors.colorspace', + 'easy_thumbnails.processors.autocrop', + 'filer.thumbnail_processors.scale_and_crop_with_subject_location', + 'easy_thumbnails.processors.filters', + ), 'ALLOWED_HOSTS': ['localhost'], - 'DJANGOCMS_LINK_USE_SELECT2': True + 'DJANGOCMS_LINK_USE_SELECT2': True, + 'FILE_UPLOAD_TEMP_DIR': mkdtemp(), } diff --git a/tests/test_file_plugin.py b/tests/test_file_plugin.py new file mode 100644 index 00000000..b5845ce1 --- /dev/null +++ b/tests/test_file_plugin.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +import os + +from django.conf import settings +from django.core.files import File as DjangoFile + +from cms.api import add_plugin, create_page + +from djangocms_helper.base_test import BaseTestCase +from filer.models.filemodels import File as FilerFile +from filer.utils.compatibility import PILImage, PILImageDraw + + +# from https://github.com/divio/django-filer/blob/develop/tests/helpers.py#L46-L52 +def create_image(mode="RGB", size=(800, 600)): + image = PILImage.new(mode, size) + draw = PILImageDraw.Draw(image) + x_bit, y_bit = size[0] // 10, size[1] // 10 + draw.rectangle((x_bit, y_bit * 2, x_bit * 7, y_bit * 3), "red") + draw.rectangle((x_bit * 2, y_bit, x_bit * 3, y_bit * 8), "red") + return image + + +class LinkTestCase(BaseTestCase): + + def setUp(self): + self.page = create_page( + title="help", + template="page.html", + language="en", + ) + + self.img = create_image() + self.image_name = "test_file.jpg" + self.filename = os.path.join(settings.FILE_UPLOAD_TEMP_DIR, self.image_name) + self.img.save(self.filename, "JPEG") + + def tearDown(self): + os.remove(self.filename) + self.page.delete() + self.filer_object.delete() + pass + + def create_filer_file(self): + filer_file = DjangoFile(open(self.filename, "rb"), name=self.image_name) + self.filer_object = FilerFile.objects.create( + original_filename=self.image_name, + file=filer_file, + ) + return self.filer_object + + def test_file(self): + sample_file = self.create_filer_file() + + plugin = add_plugin( + self.page.placeholders.get(slot="content"), + "LinkPlugin", + "en", + file_link=sample_file + ) + self.assertIn("test_file.jpg", plugin.get_link()) + self.assertIn("/media/filer_public/", plugin.get_link()) diff --git a/tests/test_model.py b/tests/test_model.py index a17b3539..4c59ba07 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -2,13 +2,14 @@ from distutils.version import LooseVersion from unittest import skipIf, skipUnless -from django.utils.encoding import force_text from django.core.exceptions import ValidationError +from django.utils.encoding import force_text import cms from cms.api import add_plugin, create_page from djangocms_helper.base_test import BaseTestCase + from djangocms_link.models import AbstractLink