attachments.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. from django.contrib import messages
  2. from django.core.urlresolvers import reverse
  3. from django.db.models import Count
  4. from django.shortcuts import redirect
  5. from django.utils.translation import ugettext_lazy as _
  6. from misago.admin.views import generic
  7. from ...forms import SearchAttachmentsForm
  8. from ...models import Attachment, Post
  9. class AttachmentAdmin(generic.AdminBaseMixin):
  10. root_link = 'misago:admin:system:attachments:index'
  11. Model = Attachment
  12. templates_dir = 'misago/admin/attachments'
  13. message_404 = _("Requested attachment could not be found.")
  14. def get_queryset(self):
  15. qs = super(AttachmentAdmin, self).get_queryset()
  16. return qs.select_related('filetype', 'uploader', 'post', 'post__thread', 'post__category')
  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. }
  36. ]
  37. def get_search_form(self, request):
  38. return SearchAttachmentsForm
  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. attachment.delete()
  47. if desynced_posts:
  48. for post in Post.objects.select_for_update().filter(id__in=desynced_posts):
  49. self.delete_from_cache(post, deleted_attachments)
  50. message = _("Selected attachments have been deleted.")
  51. messages.success(request, message)
  52. def delete_from_cache(self, post, attachments):
  53. if not post.attachments_cache:
  54. return # admin action may be taken due to desynced state
  55. clean_cache = []
  56. for a in post.attachments_cache:
  57. if a['id'] not in attachments:
  58. clean_cache.append(a)
  59. post.attachments_cache = clean_cache or None
  60. post.save(update_fields=['attachments_cache'])
  61. class DeleteAttachment(AttachmentAdmin, generic.ButtonView):
  62. def button_action(self, request, target):
  63. if target.post:
  64. self.delete_from_cache(target)
  65. target.delete()
  66. message = _('Attachment "%(filename)s" has been deleted.')
  67. messages.success(request, message % {'filename': target.filename})
  68. def delete_from_cache(self, attachment):
  69. if not attachment.post.attachments_cache:
  70. return # admin action may be taken due to desynced state
  71. clean_cache = []
  72. for a in attachment.post.attachments_cache:
  73. if a['id'] != attachment.id:
  74. clean_cache.append(a)
  75. attachment.post.attachments_cache = clean_cache or None
  76. attachment.post.save(update_fields=['attachments_cache'])