@@ -27,10 +28,10 @@
diff --git a/core/templates/core/item_editor.html b/core/templates/core/item_editor.html
index e150b1d..a9f1174 100644
--- a/core/templates/core/item_editor.html
+++ b/core/templates/core/item_editor.html
@@ -28,6 +28,12 @@
{% if item.kind == 'link' %}
{% endif %}
+ {% if item.attachments.all %}
+
+
{% trans "Existing attachments" %}
+ {% for a in item.attachments.all %}
{% endfor %}
+
+ {% endif %}
{% trans "Image preview:" %}![]()
diff --git a/core/tests.py b/core/tests.py
index 40910d6..54a4594 100644
--- a/core/tests.py
+++ b/core/tests.py
@@ -7,7 +7,7 @@ from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase, override_settings
from django.urls import reverse
-from .models import ApiKey, Collection, CollectionSection, Item, Tag, Team, TeamMembership, UserPreference
+from .models import ApiKey, Attachment, Collection, CollectionSection, Item, Tag, Team, TeamMembership, UserPreference
from .templatetags.markdown_extras import markdown, markdown_title
from .views import parse_due_command, parse_quick_content
@@ -214,6 +214,28 @@ class AttachmentEditTests(TestCase):
self.assertEqual(item.attachments.count(), 1)
self.assertContains(response, 'hello.txt')
+ def test_existing_attachments_are_shown_and_can_be_deleted_in_editor(self):
+ item = Item.objects.create(owner=self.user, content='Original')
+ attachment = Attachment.objects.create(item=item, file=SimpleUploadedFile('duplicate.txt', b'duplicate', content_type='text/plain'))
+
+ response = self.client.get(reverse('item_editor', args=[item.id]))
+ self.assertContains(response, 'duplicate.txt')
+ self.assertContains(response, 'name="delete_attachments"')
+
+ response = self.client.post(reverse('item_editor', args=[item.id]), {
+ 'content': 'Original', 'comment': '', 'visibility': Item.Visibility.PRIVATE, 'url': '', 'delete_attachments': [str(attachment.id)],
+ })
+
+ self.assertRedirects(response, item.get_absolute_url())
+ self.assertFalse(item.attachments.exists())
+
+ def test_detail_editor_uses_original_return_url_not_partial_endpoint(self):
+ item = Item.objects.create(owner=self.user, content='Original')
+ response = self.client.get(f'{item.get_absolute_url()}?next=/')
+
+ self.assertContains(response, f'{reverse("item_editor", args=[item.id])}?next=/')
+ self.assertNotContains(response, reverse('item_card', args=[item.id]))
+
class TeamItemEditTests(TestCase):
def setUp(self):
diff --git a/core/views.py b/core/views.py
index 1e1586a..81fa8ac 100644
--- a/core/views.py
+++ b/core/views.py
@@ -157,6 +157,14 @@ def parse_due_at_from_post(post):
return None
+def delete_selected_attachments(item, attachment_ids):
+ for attachment in item.attachments.filter(pk__in=attachment_ids):
+ attachment.file.delete(save=False)
+ attachment.delete()
+ if hasattr(item, '_prefetched_objects_cache'):
+ item._prefetched_objects_cache.pop('attachments', None)
+
+
def attach_files_and_replace_tokens(item, files):
replacements = {}
attached = False
@@ -1013,6 +1021,7 @@ def edit_item(request, pk):
item.visibility, item.team = target_visibility, target_team
item.save()
form.save_m2m()
+ delete_selected_attachments(item, request.POST.getlist('delete_attachments'))
attach_files_and_replace_tokens(item, request.FILES.getlist('files'))
item.sync_metadata()
apply_team_from_tags(item, request.user, force_private=item.visibility == Item.Visibility.PRIVATE)
@@ -1042,6 +1051,7 @@ def item_editor(request, pk):
item.visibility, item.team = target_visibility, target_team
item.save()
form.save_m2m()
+ delete_selected_attachments(item, request.POST.getlist('delete_attachments'))
attach_files_and_replace_tokens(item, request.FILES.getlist('files'))
item.sync_metadata()
apply_team_from_tags(item, request.user, force_private=item.visibility == Item.Visibility.PRIVATE)