attachments.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. from django.core.exceptions import PermissionDenied, ValidationError
  2. from django.template.defaultfilters import filesizeformat
  3. from django.utils.translation import gettext as _
  4. from rest_framework import viewsets
  5. from rest_framework.response import Response
  6. from misago.acl import add_acl
  7. from ..models import Attachment, AttachmentType
  8. from ..serializers import AttachmentSerializer
  9. IMAGE_EXTENSIONS = ('jpg', 'jpeg', 'png', 'gif')
  10. class AttachmentViewSet(viewsets.ViewSet):
  11. def create(self, request):
  12. if not request.user.acl['max_attachment_size']:
  13. raise PermissionDenied(_("You don't have permission to upload new files."))
  14. try:
  15. return self.create_attachment(request)
  16. except ValidationError as e:
  17. return Response({
  18. 'detail': e.args[0]
  19. }, status=400)
  20. def create_attachment(self, request):
  21. upload = request.FILES.get('upload')
  22. if not upload:
  23. raise ValidationError(_("No file has been uploaded."))
  24. user_roles = set(r.pk for r in request.user.get_roles())
  25. filetype = validate_filetype(upload, user_roles)
  26. validate_filesize(upload, filetype, request.user.acl['max_attachment_size'])
  27. attachment = Attachment(
  28. secret=Attachment.generate_new_secret(),
  29. filetype=filetype,
  30. size=upload.size,
  31. uploader=request.user,
  32. uploader_name=request.user.username,
  33. uploader_slug=request.user.slug,
  34. uploader_ip=request.user_ip,
  35. filename=upload.name,
  36. )
  37. if is_upload_image(upload):
  38. try:
  39. attachment.set_image(upload)
  40. except IOError:
  41. raise ValidationError(_("Uploaded image was corrupted or invalid."))
  42. else:
  43. attachment.set_file(upload)
  44. attachment.save()
  45. add_acl(request.user, attachment)
  46. return Response(AttachmentSerializer(attachment, context={'user': request.user}).data)
  47. def validate_filetype(upload, user_roles):
  48. filename = upload.name.strip().lower()
  49. queryset = AttachmentType.objects.filter(status=AttachmentType.ENABLED)
  50. for filetype in queryset.prefetch_related('limit_uploads_to'):
  51. for extension in filetype.extensions_list:
  52. if filename.endswith('.%s' % extension):
  53. break
  54. else:
  55. continue
  56. if filetype.mimetypes_list and upload.content_type not in filetype.mimetypes_list:
  57. continue
  58. if filetype.limit_uploads_to.exists():
  59. allowed_roles = set(r.pk for r in filetype.limit_uploads_to.all())
  60. if not user_roles & allowed_roles:
  61. continue
  62. return filetype
  63. raise ValidationError(_("You can't upload files of this type."))
  64. def validate_filesize(upload, filetype, hard_limit):
  65. if upload.size > hard_limit * 1024:
  66. message = _("You can't upload files larger than %(limit)s (your file has %(upload)s).")
  67. raise ValidationError(message % {
  68. 'upload': filesizeformat(upload.size).rstrip('.0'),
  69. 'limit': filesizeformat(hard_limit * 1024).rstrip('.0')
  70. })
  71. if filetype.size_limit and upload.size > filetype.size_limit * 1024:
  72. message = _("You can't upload files of this type larger than %(limit)s (your file has %(upload)s).")
  73. raise ValidationError(message % {
  74. 'upload': filesizeformat(upload.size).rstrip('.0'),
  75. 'limit': filesizeformat(filetype.size_limit * 1024).rstrip('.0')
  76. })
  77. def is_upload_image(upload):
  78. filename = upload.name.strip().lower()
  79. for extension in IMAGE_EXTENSIONS:
  80. if filename.endswith('.%s' % extension):
  81. return True
  82. return False