From 8520375eb784c82b716dfce170c1f381118a9c13 Mon Sep 17 00:00:00 2001 From: Daniel Carr Date: Wed, 15 Jul 2020 16:41:27 +1000 Subject: [PATCH 1/5] added requires_watermark field --- attachments/migrations/TODO-makemigrations | 0 attachments/models.py | 1 + 2 files changed, 1 insertion(+) create mode 100644 attachments/migrations/TODO-makemigrations diff --git a/attachments/migrations/TODO-makemigrations b/attachments/migrations/TODO-makemigrations new file mode 100644 index 0000000..e69de29 diff --git a/attachments/models.py b/attachments/models.py index 0e38c56..8d87724 100644 --- a/attachments/models.py +++ b/attachments/models.py @@ -54,6 +54,7 @@ class Attachment(models.Model): show_in_standard_package = models.BooleanField( _("Show in standard package"), default=True ) + requires_watermark = models.BooleanField(_("Requires Watermark"), default=False) class Meta: verbose_name = _("attachment") From 0e542d3d490e8da897067b5393231f233b63bbf4 Mon Sep 17 00:00:00 2001 From: Daniel Carr Date: Thu, 16 Jul 2020 15:06:31 +1000 Subject: [PATCH 2/5] put attachments requiring watermarks in a different location --- README.rst | 3 +++ attachments/models.py | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 1589666..9e7eefd 100644 --- a/README.rst +++ b/README.rst @@ -56,6 +56,9 @@ Installation: bytes before raising form validation errors. If not set there is no restriction on file size. +7. TODO: Set ``ATTACHMENT_STORAGE`` to a ``Storage`` class string to use for persisting stuff + + Mind that you serve files! ========================== diff --git a/attachments/models.py b/attachments/models.py index 8d87724..2e83832 100644 --- a/attachments/models.py +++ b/attachments/models.py @@ -12,7 +12,11 @@ def attachment_upload(instance, filename): """Stores the attachment in a "per module/appname/primary key" folder""" - return "attachments/{app}_{model}/{pk}/{filename}".format( + tmpl = "attachments/{app}_{model}/{pk}/{filename}" + if instance.requires_watermark: + tmpl = "watermarkable_attachments/{app}_{model}/{pk}/{filename}" + + return tmpl.format( app=instance.content_object._meta.app_label, model=instance.content_object._meta.object_name.lower(), pk=instance.content_object.pk, From bdb912947d1cb007fb5ff87bb5e601b0f65ede3f Mon Sep 17 00:00:00 2001 From: Daniel Carr Date: Tue, 21 Jul 2020 14:36:23 +1000 Subject: [PATCH 3/5] added tests, updated views to pass requires_watermark through --- README.rst | 6 ++++-- attachments/forms.py | 2 +- attachments/models.py | 16 +++++++++++----- attachments/tests/base.py | 5 +++-- attachments/tests/test_views.py | 14 ++++++++++++++ 5 files changed, 33 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index 9e7eefd..8f8700b 100644 --- a/README.rst +++ b/README.rst @@ -55,8 +55,6 @@ Installation: 6. Configure ``FILE_UPLOAD_MAX_SIZE`` (optional). This is the maximum size in bytes before raising form validation errors. If not set there is no restriction on file size. - -7. TODO: Set ``ATTACHMENT_STORAGE`` to a ``Storage`` class string to use for persisting stuff Mind that you serve files! @@ -71,6 +69,10 @@ configuration this would look like:: AddType text/plain .html .htm .shtml .php .php5 .php4 .pl .cgi +Private attachments (e.g. attachments marked as +``requires_watermark``) are kept in the ``private_attachments`` +folder. Make sure this is not public + Tests ===== diff --git a/attachments/forms.py b/attachments/forms.py index 8418391..981221c 100644 --- a/attachments/forms.py +++ b/attachments/forms.py @@ -28,7 +28,7 @@ class AttachmentForm(forms.ModelForm): class Meta: model = Attachment - fields = ("attachment_file", "title", "description") + fields = ("attachment_file", "title", "description", "requires_watermark") def save(self, request, obj, *args, **kwargs): self.instance.creator = request.user diff --git a/attachments/models.py b/attachments/models.py index 2e83832..c20c6ac 100644 --- a/attachments/models.py +++ b/attachments/models.py @@ -11,16 +11,22 @@ def attachment_upload(instance, filename): - """Stores the attachment in a "per module/appname/primary key" folder""" - tmpl = "attachments/{app}_{model}/{pk}/{filename}" - if instance.requires_watermark: - tmpl = "watermarkable_attachments/{app}_{model}/{pk}/{filename}" + """ + Stores the attachment in a "per module/appname/primary key" folder + Attachments that need to be private (i.e. requires_watermark + attachments), go in the private_attachments folder - return tmpl.format( + """ + attachments_prefix = "attachments" + if instance.requires_watermark: + attachments_prefix = "private_attachments" + + return "{attachments_prefix}/{app}_{model}/{pk}/{filename}".format( app=instance.content_object._meta.app_label, model=instance.content_object._meta.object_name.lower(), pk=instance.content_object.pk, filename=filename, + attachments_prefix=attachments_prefix, ) diff --git a/attachments/tests/base.py b/attachments/tests/base.py index 051d296..0de9ba7 100644 --- a/attachments/tests/base.py +++ b/attachments/tests/base.py @@ -41,10 +41,11 @@ def setUp(self): self.obj = TestModel.objects.create(title="My first test item") - def _upload_testfile(self, file_obj=None): + def _upload_testfile(self, file_obj=None, opts=None): """ Uploads a sample file for the given user. """ + opts = {} if opts == None else opts add_url = reverse( "attachments:add", kwargs={ @@ -61,5 +62,5 @@ def _upload_testfile(self, file_obj=None): content_type="image/jpeg", ) return self.client.post( - add_url, {"attachment_file": file_obj}, follow=True + add_url, {"attachment_file": file_obj, **opts}, follow=True ) diff --git a/attachments/tests/test_views.py b/attachments/tests/test_views.py index 2cb521d..983253d 100644 --- a/attachments/tests/test_views.py +++ b/attachments/tests/test_views.py @@ -223,3 +223,17 @@ def test_delete_does_not_raise_if_os_remove_raises(self): self.assertEqual(Attachment.objects.count(), 0) # NOTE: we don't assert the file path here because # the mock which raises will not actually delete it + + def test_requires_watermark_uploads_to_private_location(self): + self.client.login(**self.cred_jon) + self._upload_testfile(file_obj=None, opts={'requires_watermark': True}) + self.assertEqual(Attachment.objects.count(), 1) + att = Attachment.objects.attachments_for_object(self.obj) + self.assertTrue(att[0].attachment_file.name.startswith('private_attachments')) + + def test_without_requires_watermark_uploads_to_standard_location(self): + self.client.login(**self.cred_jon) + self._upload_testfile(file_obj=None, opts={'requires_watermark': False}) + self.assertEqual(Attachment.objects.count(), 1) + att = Attachment.objects.attachments_for_object(self.obj) + self.assertTrue(att[0].attachment_file.name.startswith('attachments')) From fb951f5275c8da92491519d71d0e0ac1f5751b38 Mon Sep 17 00:00:00 2001 From: Daniel Carr Date: Tue, 21 Jul 2020 14:45:31 +1000 Subject: [PATCH 4/5] add migration --- .../0005_attachment_requires_watermark.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 attachments/migrations/0005_attachment_requires_watermark.py diff --git a/attachments/migrations/0005_attachment_requires_watermark.py b/attachments/migrations/0005_attachment_requires_watermark.py new file mode 100644 index 0000000..a9c5a4c --- /dev/null +++ b/attachments/migrations/0005_attachment_requires_watermark.py @@ -0,0 +1,18 @@ +# Generated by Django 3.0.8 on 2020-07-15 06:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('attachments', '0004_change_model_options'), + ] + + operations = [ + migrations.AddField( + model_name='attachment', + name='requires_watermark', + field=models.BooleanField(default=False, verbose_name='Requires Watermark'), + ), + ] From 5a7634a70b9f5b3cf0c8cde86e528fbcb8352928 Mon Sep 17 00:00:00 2001 From: Daniel Carr Date: Tue, 28 Jul 2020 09:44:19 +1000 Subject: [PATCH 5/5] split migration up to avoid blocking --- ...atermark.py => 0005_requires_watermark.py} | 3 ++- .../0006_requires_watermark_assign_default.py | 23 +++++++++++++++++++ .../0007_requires_watermark_make_not_null.py | 19 +++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) rename attachments/migrations/{0005_attachment_requires_watermark.py => 0005_requires_watermark.py} (76%) create mode 100644 attachments/migrations/0006_requires_watermark_assign_default.py create mode 100644 attachments/migrations/0007_requires_watermark_make_not_null.py diff --git a/attachments/migrations/0005_attachment_requires_watermark.py b/attachments/migrations/0005_requires_watermark.py similarity index 76% rename from attachments/migrations/0005_attachment_requires_watermark.py rename to attachments/migrations/0005_requires_watermark.py index a9c5a4c..afc32aa 100644 --- a/attachments/migrations/0005_attachment_requires_watermark.py +++ b/attachments/migrations/0005_requires_watermark.py @@ -1,6 +1,7 @@ # Generated by Django 3.0.8 on 2020-07-15 06:39 from django.db import migrations, models +import attachments.models class Migration(migrations.Migration): @@ -13,6 +14,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name='attachment', name='requires_watermark', - field=models.BooleanField(default=False, verbose_name='Requires Watermark'), + field=models.BooleanField(null=True, verbose_name='Requires Watermark'), ), ] diff --git a/attachments/migrations/0006_requires_watermark_assign_default.py b/attachments/migrations/0006_requires_watermark_assign_default.py new file mode 100644 index 0000000..c219db9 --- /dev/null +++ b/attachments/migrations/0006_requires_watermark_assign_default.py @@ -0,0 +1,23 @@ +# Generated by Django 3.0.8 on 2020-07-15 06:39 + +from django.db import migrations, models +import attachments.models + + +def assign_requires_watermark(apps, schema_editor): + Attachment = apps.get_model('attachments', 'Attachment') + Attachment.objects.all().update(requires_watermark=False) + + +class Migration(migrations.Migration): + + dependencies = [ + ('attachments', '0005_requires_watermark'), + ] + + operations = [ + migrations.RunPython( + code=assign_requires_watermark, + reverse_code=migrations.RunPython.noop, + ), + ] diff --git a/attachments/migrations/0007_requires_watermark_make_not_null.py b/attachments/migrations/0007_requires_watermark_make_not_null.py new file mode 100644 index 0000000..8d5912d --- /dev/null +++ b/attachments/migrations/0007_requires_watermark_make_not_null.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0.8 on 2020-07-15 06:39 + +from django.db import migrations, models +import attachments.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('attachments', '0006_requires_watermark_assign_default'), + ] + + operations = [ + migrations.AlterField( + model_name='attachment', + name='requires_watermark', + field=models.BooleanField(null=False, default=False, verbose_name='Requires Watermark'), + ), + ]