attachments.py 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. from django.contrib import messages
  2. from django.db import transaction
  3. from django.utils.translation import gettext_lazy as _
  4. from ....admin.views import generic
  5. from ...forms import FilterAttachmentsForm
  6. from ...models import Attachment, Post
  7. class AttachmentAdmin(generic.AdminBaseMixin):
  8. root_link = "misago:admin:attachments:index"
  9. model = Attachment
  10. templates_dir = "misago/admin/attachments"
  11. message_404 = _("Requested attachment could not be found.")
  12. def get_queryset(self):
  13. qs = super().get_queryset()
  14. return qs.select_related(
  15. "filetype", "uploader", "post", "post__thread", "post__category"
  16. )
  17. class AttachmentsList(AttachmentAdmin, generic.ListView):
  18. items_per_page = 20
  19. ordering = [
  20. ("-id", _("From newest")),
  21. ("id", _("From oldest")),
  22. ("filename", _("A to z")),
  23. ("-filename", _("Z to a")),
  24. ("size", _("Smallest files")),
  25. ("-size", _("Largest files")),
  26. ]
  27. selection_label = _("With attachments: 0")
  28. empty_selection_label = _("Select attachments")
  29. mass_actions = [
  30. {
  31. "action": "delete",
  32. "name": _("Delete attachments"),
  33. "icon": "fa fa-times-circle",
  34. "confirmation": _("Are you sure you want to delete selected attachments?"),
  35. "is_atomic": False,
  36. }
  37. ]
  38. filter_form = FilterAttachmentsForm
  39. def action_delete(self, request, attachments):
  40. deleted_attachments = []
  41. desynced_posts = []
  42. for attachment in attachments:
  43. if attachment.post:
  44. deleted_attachments.append(attachment.pk)
  45. desynced_posts.append(attachment.post_id)
  46. if desynced_posts:
  47. with transaction.atomic():
  48. for post in Post.objects.filter(id__in=desynced_posts):
  49. self.delete_from_cache(post, deleted_attachments)
  50. for attachment in attachments:
  51. attachment.delete()
  52. message = _("Selected attachments have been deleted.")
  53. messages.success(request, message)
  54. def delete_from_cache(self, post, attachments):
  55. if not post.attachments_cache:
  56. return # admin action may be taken due to desynced state
  57. clean_cache = []
  58. for a in post.attachments_cache:
  59. if a["id"] not in attachments:
  60. clean_cache.append(a)
  61. post.attachments_cache = clean_cache or None
  62. post.save(update_fields=["attachments_cache"])
  63. class DeleteAttachment(AttachmentAdmin, generic.ButtonView):
  64. def button_action(self, request, target):
  65. if target.post:
  66. self.delete_from_cache(target)
  67. target.delete()
  68. message = _('Attachment "%(filename)s" has been deleted.')
  69. messages.success(request, message % {"filename": target.filename})
  70. def delete_from_cache(self, attachment):
  71. if not attachment.post.attachments_cache:
  72. return # admin action may be taken due to desynced state
  73. clean_cache = []
  74. for a in attachment.post.attachments_cache:
  75. if a["id"] != attachment.id:
  76. clean_cache.append(a)
  77. attachment.post.attachments_cache = clean_cache or None
  78. attachment.post.save(update_fields=["attachments_cache"])