2016-09-19 13:31:40 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
2016-06-07 01:09:05 +02:00
|
|
|
from __future__ import absolute_import
|
|
|
|
|
2016-06-09 12:19:56 +02:00
|
|
|
from django.http import HttpRequest, HttpResponse, HttpResponseForbidden, FileResponse, \
|
|
|
|
HttpResponseNotFound
|
2016-06-07 01:09:05 +02:00
|
|
|
from django.shortcuts import redirect
|
|
|
|
from django.utils.translation import ugettext as _
|
|
|
|
|
2017-02-20 20:55:18 +01:00
|
|
|
from zerver.decorator import authenticated_json_post_view
|
2016-06-07 01:09:05 +02:00
|
|
|
from zerver.lib.request import has_request_variables, REQ
|
|
|
|
from zerver.lib.response import json_success, json_error
|
2016-06-09 12:19:56 +02:00
|
|
|
from zerver.lib.upload import upload_message_image_from_request, get_local_file_path, \
|
2017-03-02 11:17:10 +01:00
|
|
|
get_signed_upload_url, get_realm_for_filename, within_upload_quota
|
2016-06-07 01:09:05 +02:00
|
|
|
from zerver.lib.validator import check_bool
|
2016-06-27 21:09:56 +02:00
|
|
|
from zerver.models import UserProfile
|
2016-06-07 01:09:05 +02:00
|
|
|
from django.conf import settings
|
|
|
|
|
2016-09-16 17:55:38 +02:00
|
|
|
def serve_s3(request, user_profile, realm_id_str, filename):
|
|
|
|
# type: (HttpRequest, UserProfile, str, str) -> HttpResponse
|
2016-06-07 01:09:05 +02:00
|
|
|
url_path = "%s/%s" % (realm_id_str, filename)
|
|
|
|
|
|
|
|
if realm_id_str == "unk":
|
|
|
|
realm_id = get_realm_for_filename(url_path)
|
|
|
|
if realm_id is None:
|
|
|
|
# File does not exist
|
2016-06-09 12:19:56 +02:00
|
|
|
return HttpResponseNotFound('<p>File not found</p>')
|
2016-06-09 07:10:28 +02:00
|
|
|
else:
|
|
|
|
realm_id = int(realm_id_str)
|
2016-06-07 01:09:05 +02:00
|
|
|
|
|
|
|
# Internal users can access all uploads so we can receive attachments in cross-realm messages
|
2017-03-13 19:06:33 +01:00
|
|
|
if user_profile.realm_id == realm_id or user_profile.realm.string_id == 'zulip':
|
2016-06-07 01:09:05 +02:00
|
|
|
uri = get_signed_upload_url(url_path)
|
2016-09-16 17:55:38 +02:00
|
|
|
return redirect(uri)
|
2016-06-07 01:09:05 +02:00
|
|
|
else:
|
|
|
|
return HttpResponseForbidden()
|
2016-06-08 11:22:06 +02:00
|
|
|
|
2016-06-09 12:19:56 +02:00
|
|
|
# TODO: Rewrite this once we have django-sendfile
|
|
|
|
def serve_local(request, path_id):
|
|
|
|
# type: (HttpRequest, str) -> HttpResponse
|
|
|
|
import os
|
|
|
|
import mimetypes
|
|
|
|
local_path = get_local_file_path(path_id)
|
|
|
|
if local_path is None:
|
|
|
|
return HttpResponseNotFound('<p>File not found</p>')
|
|
|
|
filename = os.path.basename(local_path)
|
2016-09-20 06:40:08 +02:00
|
|
|
response = FileResponse(open(local_path, 'rb'),
|
2017-02-19 02:01:01 +01:00
|
|
|
content_type = mimetypes.guess_type(filename))
|
2016-06-09 12:19:56 +02:00
|
|
|
return response
|
|
|
|
|
2016-06-27 16:41:58 +02:00
|
|
|
@has_request_variables
|
2016-09-16 17:55:38 +02:00
|
|
|
def serve_file_backend(request, user_profile, realm_id_str, filename):
|
|
|
|
# type: (HttpRequest, UserProfile, str, str) -> HttpResponse
|
2016-06-09 12:19:56 +02:00
|
|
|
path_id = "%s/%s" % (realm_id_str, filename)
|
2016-06-08 11:22:06 +02:00
|
|
|
if settings.LOCAL_UPLOADS_DIR is not None:
|
2016-06-09 12:19:56 +02:00
|
|
|
return serve_local(request, path_id)
|
2016-06-08 11:22:06 +02:00
|
|
|
|
2016-09-16 17:55:38 +02:00
|
|
|
return serve_s3(request, user_profile, realm_id_str, filename)
|
2016-06-08 11:22:06 +02:00
|
|
|
|
2016-06-27 19:28:09 +02:00
|
|
|
@authenticated_json_post_view
|
|
|
|
def json_upload_file(request, user_profile):
|
|
|
|
# type: (HttpRequest, UserProfile) -> HttpResponse
|
|
|
|
return upload_file_backend(request, user_profile)
|
|
|
|
|
|
|
|
def upload_file_backend(request, user_profile):
|
|
|
|
# type: (HttpRequest, UserProfile) -> HttpResponse
|
|
|
|
if len(request.FILES) == 0:
|
|
|
|
return json_error(_("You must specify a file to upload"))
|
|
|
|
if len(request.FILES) != 1:
|
|
|
|
return json_error(_("You may only upload one file at a time"))
|
|
|
|
|
|
|
|
user_file = list(request.FILES.values())[0]
|
2017-03-02 11:17:10 +01:00
|
|
|
file_size = user_file._get_size()
|
|
|
|
if settings.MAX_FILE_UPLOAD_SIZE * 1024 * 1024 < file_size:
|
2017-01-29 00:08:08 +01:00
|
|
|
return json_error(_("Uploaded file is larger than the allowed limit of %s MB") % (
|
|
|
|
settings.MAX_FILE_UPLOAD_SIZE))
|
2017-03-02 11:17:10 +01:00
|
|
|
if not within_upload_quota(user_profile, file_size):
|
|
|
|
return json_error(_("Upload would exceed your maximum quota."))
|
2016-06-27 19:28:09 +02:00
|
|
|
|
2016-09-19 13:31:40 +02:00
|
|
|
if not isinstance(user_file.name, str):
|
|
|
|
# It seems that in Python 2 unicode strings containing bytes are
|
|
|
|
# rendered differently than ascii strings containing same bytes.
|
|
|
|
#
|
|
|
|
# Example:
|
|
|
|
# >>> print('\xd3\x92')
|
|
|
|
# Ӓ
|
|
|
|
# >>> print(u'\xd3\x92')
|
|
|
|
# Ó
|
|
|
|
#
|
|
|
|
# This is the cause of the problem as user_file.name variable
|
|
|
|
# is received as a unicode which is converted into unicode
|
|
|
|
# strings containing bytes and is rendered incorrectly.
|
|
|
|
#
|
|
|
|
# Example:
|
|
|
|
# >>> from six.moves import urllib
|
|
|
|
# >>> name = u'%D0%97%D0%B4%D1%80%D0%B0%D0%B2%D0%B5%D0%B8%CC%86%D1%82%D0%B5.txt'
|
|
|
|
# >>> print(urllib.parse.unquote(name))
|
|
|
|
# ÐдÑавеиÌÑе # This is wrong
|
|
|
|
#
|
|
|
|
# >>> name = '%D0%97%D0%B4%D1%80%D0%B0%D0%B2%D0%B5%D0%B8%CC%86%D1%82%D0%B5.txt'
|
|
|
|
# >>> print(urllib.parse.unquote(name))
|
|
|
|
# Здравейте.txt # This is correct
|
|
|
|
user_file.name = user_file.name.encode('ascii')
|
|
|
|
|
2016-06-27 19:28:09 +02:00
|
|
|
uri = upload_message_image_from_request(request, user_file, user_profile)
|
|
|
|
return json_success({'uri': uri})
|