attachments.py 3.3 KB

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