attachment.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. from rest_framework import serializers
  2. from django.template.defaultfilters import filesizeformat
  3. from django.urls import reverse
  4. from django.utils.translation import ugettext as _
  5. from misago.threads.models import Attachment, AttachmentType
  6. IMAGE_EXTENSIONS = ('jpg', 'jpeg', 'png', 'gif')
  7. class AttachmentSerializer(serializers.ModelSerializer):
  8. post = serializers.PrimaryKeyRelatedField(read_only=True)
  9. filetype = serializers.SerializerMethodField()
  10. uploader_ip = serializers.SerializerMethodField()
  11. has_thumbnail = serializers.SerializerMethodField()
  12. class Meta:
  13. model = Attachment
  14. fields = [
  15. 'id',
  16. 'secret',
  17. 'filetype',
  18. 'post',
  19. 'uploaded_on',
  20. 'uploader_name',
  21. 'uploader_ip',
  22. 'filename',
  23. 'size',
  24. 'is_image',
  25. 'has_thumbnail',
  26. ]
  27. def get_filetype(self, obj):
  28. return obj.filetype.name
  29. def get_uploader_ip(self, obj):
  30. user = self.context.get('user')
  31. if user and user.acl_cache['can_see_users_ips']:
  32. return obj.uploader_ip
  33. else:
  34. return None
  35. def get_has_thumbnail(self, obj):
  36. return bool(obj.thumbnail)
  37. class NewAttachmentSerializer(serializers.Serializer):
  38. upload = serializers.FileField()
  39. def validate_upload(self, upload):
  40. user = self.context['request'].user
  41. user_roles = set(r.pk for r in user.get_roles())
  42. max_attachment_size = user.acl_cache['max_attachment_size']
  43. self.filetype = self.validate_filetype(upload, user_roles)
  44. self.validate_filesize(upload, self.filetype, max_attachment_size)
  45. return upload
  46. def validate_filetype(self, upload, user_roles):
  47. filename = upload.name.strip().lower()
  48. queryset = AttachmentType.objects.filter(status=AttachmentType.ENABLED)
  49. for filetype in queryset.prefetch_related('limit_uploads_to'):
  50. for extension in filetype.extensions_list:
  51. if filename.endswith('.%s' % extension):
  52. break
  53. else:
  54. continue
  55. if filetype.mimetypes_list and upload.content_type not in filetype.mimetypes_list:
  56. continue
  57. if filetype.limit_uploads_to.exists():
  58. allowed_roles = set(r.pk for r in filetype.limit_uploads_to.all())
  59. if not user_roles & allowed_roles:
  60. continue
  61. return filetype
  62. raise serializers.ValidationError(_("You can't upload files of this type."))
  63. def validate_filesize(self, upload, filetype, hard_limit):
  64. if upload.size > hard_limit * 1024:
  65. message = _("You can't upload files larger than %(limit)s (your file has %(upload)s).")
  66. raise serializers.ValidationError(
  67. message % {
  68. 'upload': filesizeformat(upload.size).rstrip('.0'),
  69. 'limit': filesizeformat(hard_limit * 1024).rstrip('.0'),
  70. }
  71. )
  72. if filetype.size_limit and upload.size > filetype.size_limit * 1024:
  73. message = _(
  74. "You can't upload files of this type larger than %(limit)s (your file has %(upload)s)."
  75. )
  76. raise serializers.ValidationError(
  77. message % {
  78. 'upload': filesizeformat(upload.size).rstrip('.0'),
  79. 'limit': filesizeformat(filetype.size_limit * 1024).rstrip('.0'),
  80. }
  81. )
  82. def is_upload_image(self, upload):
  83. filename = upload.name.strip().lower()
  84. for extension in IMAGE_EXTENSIONS:
  85. if filename.endswith('.%s' % extension):
  86. return True
  87. return False
  88. def save(self):
  89. request = self.context['request']
  90. upload = self.validated_data['upload']
  91. self.instance = Attachment(
  92. secret=Attachment.generate_new_secret(),
  93. filetype=self.filetype,
  94. size=upload.size,
  95. uploader=request.user,
  96. uploader_name=request.user.username,
  97. uploader_slug=request.user.slug,
  98. uploader_ip=request.user_ip,
  99. filename=upload.name,
  100. )
  101. if self.is_upload_image(upload):
  102. try:
  103. self.instance.set_image(upload)
  104. except IOError:
  105. raise serializers.ValidationError({
  106. 'upload': [_("Uploaded image was corrupted or invalid.")],
  107. })
  108. else:
  109. self.instance.set_file(upload)
  110. self.instance.save()
  111. return self.instance