api: Deprecate uri and add url parameter in "/user_uploads" endpoint.

This commit is contained in:
Vector73 2024-07-15 10:36:38 +05:30 committed by Tim Abbott
parent a07ebba860
commit d21ee6fa23
15 changed files with 78 additions and 38 deletions

View File

@ -20,6 +20,12 @@ format used by the Zulip server that they are interacting with.
## Changes in Zulip 9.0 ## Changes in Zulip 9.0
**Feature level 272**
* [`POST /user_uploads`](/api/upload-file): `uri` was renamed
to `url`, but remains available as a deprecated alias for
backwards-compatibility.
**Feature level 271** **Feature level 271**
* [`GET /messages`](/api/get-messages), * [`GET /messages`](/api/get-messages),

View File

@ -34,7 +34,7 @@ DESKTOP_WARNING_VERSION = "5.9.3"
# new level means in api_docs/changelog.md, as well as "**Changes**" # new level means in api_docs/changelog.md, as well as "**Changes**"
# entries in the endpoint's documentation in `zulip.yaml`. # entries in the endpoint's documentation in `zulip.yaml`.
API_FEATURE_LEVEL = 271 # Last bumped for `with` operator. API_FEATURE_LEVEL = 272 # Last bumped for "POST /user_uploads"
# Bump the minor PROVISION_VERSION to indicate that folks should provision # Bump the minor PROVISION_VERSION to indicate that folks should provision

View File

@ -369,7 +369,7 @@ export function setup_upload(config: Config): Uppy {
uppy.on("upload-success", (file, response) => { uppy.on("upload-success", (file, response) => {
assert(file !== undefined); assert(file !== undefined);
const {uri: url} = z.object({uri: z.string().optional()}).parse(response.body); const {url} = z.object({url: z.string().optional()}).parse(response.body);
if (url === undefined) { if (url === undefined) {
return; return;
} }

View File

@ -500,7 +500,7 @@ test("uppy_events", ({override_rewire, mock_template}) => {
}; };
let response = { let response = {
body: { body: {
uri: "/user_uploads/4/cb/rue1c-MlMUjDAUdkRrEM4BTJ/copenhagen.png", url: "/user_uploads/4/cb/rue1c-MlMUjDAUdkRrEM4BTJ/copenhagen.png",
}, },
}; };
@ -525,7 +525,7 @@ test("uppy_events", ({override_rewire, mock_template}) => {
response = { response = {
body: { body: {
uri: undefined, url: undefined,
}, },
}; };
compose_ui_replace_syntax_called = false; compose_ui_replace_syntax_called = false;

View File

@ -1416,7 +1416,7 @@ def upload_file(client: Client) -> None:
"type": "stream", "type": "stream",
"to": "Denmark", "to": "Denmark",
"topic": "Castle", "topic": "Castle",
"content": "Check out [this picture]({}) of my castle!".format(result["uri"]), "content": "Check out [this picture]({}) of my castle!".format(result["url"]),
} }
) )
# {code_example|end} # {code_example|end}

View File

@ -8093,7 +8093,7 @@ paths:
summary: Upload a file summary: Upload a file
tags: ["messages"] tags: ["messages"]
description: | description: |
Upload a single file and get the corresponding URI. Upload a single file and get the corresponding URL.
Initially, only you will be able to access the link. To share the Initially, only you will be able to access the link. To share the
uploaded file, you'll need to [send a message][send-message] uploaded file, you'll need to [send a message][send-message]
@ -8140,13 +8140,25 @@ paths:
ignored_parameters_unsupported: {} ignored_parameters_unsupported: {}
uri: uri:
type: string type: string
deprecated: true
description: | description: |
The URI of the uploaded file. The URL of the uploaded file. Alias of `url`.
**Changes**: Deprecated in Zulip 9.0 (feature level 272). The term
"URI" is deprecated in [web standards](https://url.spec.whatwg.org/#goals).
url:
type: string
description: |
The URL of the uploaded file.
**Changes**: New in Zulip 9.0 (feature level 272). Previously,
this property was only available under the legacy `uri` name.
example: example:
{ {
"msg": "", "msg": "",
"result": "success", "result": "success",
"uri": "/user_uploads/1/4e/m2A3MSqFnWRLUf9SaPzQ0Up_/zulip.txt", "uri": "/user_uploads/1/4e/m2A3MSqFnWRLUf9SaPzQ0Up_/zulip.txt",
"url": "/user_uploads/1/4e/m2A3MSqFnWRLUf9SaPzQ0Up_/zulip.txt",
} }
/user_uploads/{realm_id_str}/{filename}: /user_uploads/{realm_id_str}/{filename}:
get: get:

View File

@ -32,7 +32,7 @@ class UnclaimedAttachmentTest(UploadSerializeMixin, ZulipTestCase):
response = self.assert_json_success( response = self.assert_json_success(
self.client_post("/json/user_uploads", {"file": file_obj}) self.client_post("/json/user_uploads", {"file": file_obj})
) )
path_id = re.sub(r"/user_uploads/", "", response["uri"]) path_id = re.sub(r"/user_uploads/", "", response["url"])
return Attachment.objects.get(path_id=path_id) return Attachment.objects.get(path_id=path_id)
def assert_exists( def assert_exists(

View File

@ -3231,7 +3231,9 @@ class NormalActionsTest(BaseAction):
response_dict = self.assert_json_success(result) response_dict = self.assert_json_success(result)
self.assertIn("uri", response_dict) self.assertIn("uri", response_dict)
url = response_dict["uri"] self.assertIn("url", response_dict)
url = response_dict["url"]
self.assertEqual(response_dict["uri"], url)
base = "/user_uploads/" base = "/user_uploads/"
self.assertEqual(base, url[: len(base)]) self.assertEqual(base, url[: len(base)])

View File

@ -656,13 +656,13 @@ class ScheduledMessageTest(ZulipTestCase):
attachment_file1 = StringIO("zulip!") attachment_file1 = StringIO("zulip!")
attachment_file1.name = "dummy_1.txt" attachment_file1.name = "dummy_1.txt"
result = self.client_post("/json/user_uploads", {"file": attachment_file1}) result = self.client_post("/json/user_uploads", {"file": attachment_file1})
path_id1 = re.sub(r"/user_uploads/", "", result.json()["uri"]) path_id1 = re.sub(r"/user_uploads/", "", result.json()["url"])
attachment_object1 = Attachment.objects.get(path_id=path_id1) attachment_object1 = Attachment.objects.get(path_id=path_id1)
attachment_file2 = StringIO("zulip!") attachment_file2 = StringIO("zulip!")
attachment_file2.name = "dummy_1.txt" attachment_file2.name = "dummy_1.txt"
result = self.client_post("/json/user_uploads", {"file": attachment_file2}) result = self.client_post("/json/user_uploads", {"file": attachment_file2})
path_id2 = re.sub(r"/user_uploads/", "", result.json()["uri"]) path_id2 = re.sub(r"/user_uploads/", "", result.json()["url"])
attachment_object2 = Attachment.objects.get(path_id=path_id2) attachment_object2 = Attachment.objects.get(path_id=path_id2)
content = f"Test [zulip.txt](http://{hamlet.realm.host}/user_uploads/{path_id1})" content = f"Test [zulip.txt](http://{hamlet.realm.host}/user_uploads/{path_id1})"

View File

@ -1195,7 +1195,7 @@ class StreamAdminTest(ZulipTestCase):
fp.name = "zulip.txt" fp.name = "zulip.txt"
result = self.client_post("/json/user_uploads", {"file": fp}) result = self.client_post("/json/user_uploads", {"file": fp})
url = self.assert_json_success(result)["uri"] url = self.assert_json_success(result)["url"]
owner = self.example_user("desdemona") owner = self.example_user("desdemona")
realm = owner.realm realm = owner.realm

View File

@ -20,7 +20,9 @@ class ThumbnailTest(ZulipTestCase):
self.assert_json_success(result) self.assert_json_success(result)
json = orjson.loads(result.content) json = orjson.loads(result.content)
self.assertIn("uri", json) self.assertIn("uri", json)
url = json["uri"] self.assertIn("url", json)
url = json["url"]
self.assertEqual(json["uri"], url)
base = "/user_uploads/" base = "/user_uploads/"
self.assertEqual(base, url[: len(base)]) self.assertEqual(base, url[: len(base)])
@ -60,7 +62,8 @@ class ThumbnailTest(ZulipTestCase):
result = self.client_post("/json/user_uploads", {"file": fp}) result = self.client_post("/json/user_uploads", {"file": fp})
self.assert_json_success(result) self.assert_json_success(result)
json = orjson.loads(result.content) json = orjson.loads(result.content)
url = json["uri"] url = json["url"]
self.assertEqual(json["uri"], url)
with ratelimit_rule(86400, 1000, domain="spectator_attachment_access_by_file"): with ratelimit_rule(86400, 1000, domain="spectator_attachment_access_by_file"):
# Deny file access for non-web-public stream # Deny file access for non-web-public stream

View File

@ -56,7 +56,9 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
result = self.api_post(self.example_user("hamlet"), "/api/v1/user_uploads", {"file": fp}) result = self.api_post(self.example_user("hamlet"), "/api/v1/user_uploads", {"file": fp})
response_dict = self.assert_json_success(result) response_dict = self.assert_json_success(result)
self.assertIn("uri", response_dict) self.assertIn("uri", response_dict)
url = response_dict["uri"] self.assertIn("url", response_dict)
url = response_dict["url"]
self.assertEqual(response_dict["uri"], url)
base = "/user_uploads/" base = "/user_uploads/"
self.assertEqual(base, url[: len(base)]) self.assertEqual(base, url[: len(base)])
@ -83,7 +85,9 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
result = self.api_post(self.example_user("hamlet"), "/api/v1/user_uploads", {"file": fp}) result = self.api_post(self.example_user("hamlet"), "/api/v1/user_uploads", {"file": fp})
response_dict = self.assert_json_success(result) response_dict = self.assert_json_success(result)
self.assertIn("uri", response_dict) self.assertIn("uri", response_dict)
url = response_dict["uri"] self.assertIn("url", response_dict)
url = response_dict["url"]
self.assertEqual(response_dict["uri"], url)
base = "/user_uploads/" base = "/user_uploads/"
self.assertEqual(base, url[: len(base)]) self.assertEqual(base, url[: len(base)])
@ -171,7 +175,9 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
result = self.client_post("/json/user_uploads", {"file": fp}) result = self.client_post("/json/user_uploads", {"file": fp})
response_dict = self.assert_json_success(result) response_dict = self.assert_json_success(result)
self.assertIn("uri", response_dict) self.assertIn("uri", response_dict)
url = response_dict["uri"] self.assertIn("url", response_dict)
url = response_dict["url"]
self.assertEqual(response_dict["uri"], url)
base = "/user_uploads/" base = "/user_uploads/"
self.assertEqual(base, url[: len(base)]) self.assertEqual(base, url[: len(base)])
@ -218,7 +224,7 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
fp.name = "zulip_web_public.txt" fp.name = "zulip_web_public.txt"
result = self.client_post("/json/user_uploads", {"file": fp}) result = self.client_post("/json/user_uploads", {"file": fp})
url = self.assert_json_success(result)["uri"] url = self.assert_json_success(result)["url"]
with ratelimit_rule(86400, 1000, domain="spectator_attachment_access_by_file"): with ratelimit_rule(86400, 1000, domain="spectator_attachment_access_by_file"):
# Deny file access for non-web-public stream # Deny file access for non-web-public stream
@ -275,7 +281,7 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
fp.name = "zulip.txt" fp.name = "zulip.txt"
result = self.client_post("/json/user_uploads", {"file": fp}) result = self.client_post("/json/user_uploads", {"file": fp})
response_dict = self.assert_json_success(result) response_dict = self.assert_json_success(result)
url = "/json" + response_dict["uri"] url = "/json" + response_dict["url"]
result = self.client_get(url) result = self.client_get(url)
data = self.assert_json_success(result) data = self.assert_json_success(result)
@ -292,7 +298,7 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
fp.name = "zulip.txt" fp.name = "zulip.txt"
result = self.client_post("/json/user_uploads", {"file": fp}) result = self.client_post("/json/user_uploads", {"file": fp})
response_dict = self.assert_json_success(result) response_dict = self.assert_json_success(result)
url = "/json" + response_dict["uri"] url = "/json" + response_dict["url"]
start_time = time.time() start_time = time.time()
with mock.patch("django.core.signing.time.time", return_value=start_time): with mock.patch("django.core.signing.time.time", return_value=start_time):
@ -314,7 +320,7 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
fp.name = "zulip.txt" fp.name = "zulip.txt"
result = self.client_post("/json/user_uploads", {"file": fp}) result = self.client_post("/json/user_uploads", {"file": fp})
response_dict = self.assert_json_success(result) response_dict = self.assert_json_success(result)
url = response_dict["uri"] url = response_dict["url"]
self.logout() self.logout()
response = self.client_get(url) response = self.client_get(url)
@ -330,7 +336,7 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
fp.name = "zulip.txt" fp.name = "zulip.txt"
result = self.client_post("/json/user_uploads", {"file": fp}) result = self.client_post("/json/user_uploads", {"file": fp})
response_dict = self.assert_json_success(result) response_dict = self.assert_json_success(result)
url = response_dict["uri"] url = response_dict["url"]
self.logout() self.logout()
response = self.client_get( response = self.client_get(
@ -356,6 +362,8 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
response = self.client_get(response_dict["uri"]) response = self.client_get(response_dict["uri"])
self.assertEqual(response.status_code, 404) self.assertEqual(response.status_code, 404)
response = self.client_get(response_dict["url"])
self.assertEqual(response.status_code, 404)
def test_non_existing_file_download(self) -> None: def test_non_existing_file_download(self) -> None:
""" """
@ -421,7 +429,7 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
d1.name = "dummy_1.txt" d1.name = "dummy_1.txt"
result = self.client_post("/json/user_uploads", {"file": d1}) result = self.client_post("/json/user_uploads", {"file": d1})
response_dict = self.assert_json_success(result) response_dict = self.assert_json_success(result)
d1_path_id = re.sub(r"/user_uploads/", "", response_dict["uri"]) d1_path_id = re.sub(r"/user_uploads/", "", response_dict["url"])
self.subscribe(self.example_user("hamlet"), "Denmark") self.subscribe(self.example_user("hamlet"), "Denmark")
host = self.example_user("hamlet").realm.host host = self.example_user("hamlet").realm.host
@ -440,7 +448,7 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
d1.name = "dummy_1.txt" d1.name = "dummy_1.txt"
result = self.client_post("/json/user_uploads", {"file": d1}) result = self.client_post("/json/user_uploads", {"file": d1})
response_dict = self.assert_json_success(result) response_dict = self.assert_json_success(result)
d1_path_id = re.sub(r"/user_uploads/", "", response_dict["uri"]) d1_path_id = re.sub(r"/user_uploads/", "", response_dict["url"])
host = self.example_user("hamlet").realm.host host = self.example_user("hamlet").realm.host
self.make_stream("private_stream", invite_only=True) self.make_stream("private_stream", invite_only=True)
@ -500,11 +508,11 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
self.login_user(hamlet) self.login_user(hamlet)
result = self.client_post("/json/user_uploads", {"file": f1}) result = self.client_post("/json/user_uploads", {"file": f1})
response_dict = self.assert_json_success(result) response_dict = self.assert_json_success(result)
f1_path_id = re.sub(r"/user_uploads/", "", response_dict["uri"]) f1_path_id = re.sub(r"/user_uploads/", "", response_dict["url"])
result = self.client_post("/json/user_uploads", {"file": f2}) result = self.client_post("/json/user_uploads", {"file": f2})
response_dict = self.assert_json_success(result) response_dict = self.assert_json_success(result)
f2_path_id = re.sub(r"/user_uploads/", "", response_dict["uri"]) f2_path_id = re.sub(r"/user_uploads/", "", response_dict["url"])
self.subscribe(hamlet, "test") self.subscribe(hamlet, "test")
body = ( body = (
@ -515,7 +523,7 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
result = self.client_post("/json/user_uploads", {"file": f3}) result = self.client_post("/json/user_uploads", {"file": f3})
response_dict = self.assert_json_success(result) response_dict = self.assert_json_success(result)
f3_path_id = re.sub(r"/user_uploads/", "", response_dict["uri"]) f3_path_id = re.sub(r"/user_uploads/", "", response_dict["url"])
new_body = ( new_body = (
f"[f3.txt](http://{host}/user_uploads/" + f3_path_id + ") " f"[f3.txt](http://{host}/user_uploads/" + f3_path_id + ") "
@ -568,6 +576,7 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
result = self.client_post("/json/user_uploads", {"f1": fp}) result = self.client_post("/json/user_uploads", {"f1": fp})
response_dict = self.assert_json_success(result) response_dict = self.assert_json_success(result)
assert sanitize_name(expected) in response_dict["uri"] assert sanitize_name(expected) in response_dict["uri"]
assert sanitize_name(expected) in response_dict["url"]
def test_sanitize_file_name(self) -> None: def test_sanitize_file_name(self) -> None:
self.login("hamlet") self.login("hamlet")
@ -587,6 +596,8 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
response_dict = self.assert_json_success(result) response_dict = self.assert_json_success(result)
self.assertNotIn(response_dict["uri"], uploaded_filename) self.assertNotIn(response_dict["uri"], uploaded_filename)
self.assertTrue(response_dict["uri"].endswith("/" + expected)) self.assertTrue(response_dict["uri"].endswith("/" + expected))
self.assertNotIn(response_dict["url"], uploaded_filename)
self.assertTrue(response_dict["url"].endswith("/" + expected))
def test_realm_quota(self) -> None: def test_realm_quota(self) -> None:
""" """
@ -598,7 +609,7 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
d1.name = "dummy_1.txt" d1.name = "dummy_1.txt"
result = self.client_post("/json/user_uploads", {"file": d1}) result = self.client_post("/json/user_uploads", {"file": d1})
response_dict = self.assert_json_success(result) response_dict = self.assert_json_success(result)
d1_path_id = re.sub(r"/user_uploads/", "", response_dict["uri"]) d1_path_id = re.sub(r"/user_uploads/", "", response_dict["url"])
d1_attachment = Attachment.objects.get(path_id=d1_path_id) d1_attachment = Attachment.objects.get(path_id=d1_path_id)
realm = get_realm("zulip") realm = get_realm("zulip")
@ -657,7 +668,7 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
fp = StringIO("zulip!") fp = StringIO("zulip!")
fp.name = "zulip.txt" fp.name = "zulip.txt"
result = self.client_post("/json/user_uploads", {"file": fp}) result = self.client_post("/json/user_uploads", {"file": fp})
url = self.assert_json_success(result)["uri"] url = self.assert_json_success(result)["url"]
fp_path_id = re.sub(r"/user_uploads/", "", url) fp_path_id = re.sub(r"/user_uploads/", "", url)
body = f"First message ...[zulip.txt](http://{host}/user_uploads/" + fp_path_id + ")" body = f"First message ...[zulip.txt](http://{host}/user_uploads/" + fp_path_id + ")"
with self.settings(CROSS_REALM_BOT_EMAILS={user_2.email, user_3.email}): with self.settings(CROSS_REALM_BOT_EMAILS={user_2.email, user_3.email}):
@ -703,7 +714,7 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
fp = StringIO("zulip!") fp = StringIO("zulip!")
fp.name = "zulip.txt" fp.name = "zulip.txt"
result = self.client_post("/json/user_uploads", {"file": fp}) result = self.client_post("/json/user_uploads", {"file": fp})
url = self.assert_json_success(result)["uri"] url = self.assert_json_success(result)["url"]
fp_path_id = re.sub(r"/user_uploads/", "", url) fp_path_id = re.sub(r"/user_uploads/", "", url)
body = f"First message ...[zulip.txt](http://{realm.host}/user_uploads/" + fp_path_id + ")" body = f"First message ...[zulip.txt](http://{realm.host}/user_uploads/" + fp_path_id + ")"
self.send_stream_message(hamlet, stream_name, body, "test") self.send_stream_message(hamlet, stream_name, body, "test")
@ -755,7 +766,7 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
fp = StringIO("zulip!") fp = StringIO("zulip!")
fp.name = "zulip.txt" fp.name = "zulip.txt"
result = self.client_post("/json/user_uploads", {"file": fp}) result = self.client_post("/json/user_uploads", {"file": fp})
url = self.assert_json_success(result)["uri"] url = self.assert_json_success(result)["url"]
fp_path_id = re.sub(r"/user_uploads/", "", url) fp_path_id = re.sub(r"/user_uploads/", "", url)
body = ( body = (
f"First message ...[zulip.txt](http://{user.realm.host}/user_uploads/" f"First message ...[zulip.txt](http://{user.realm.host}/user_uploads/"
@ -824,7 +835,7 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
fp = StringIO("zulip!") fp = StringIO("zulip!")
fp.name = "zulip.txt" fp.name = "zulip.txt"
result = self.client_post("/json/user_uploads", {"file": fp}) result = self.client_post("/json/user_uploads", {"file": fp})
url = self.assert_json_success(result)["uri"] url = self.assert_json_success(result)["url"]
fp_path_id = re.sub(r"/user_uploads/", "", url) fp_path_id = re.sub(r"/user_uploads/", "", url)
for i in range(20): for i in range(20):
body = ( body = (
@ -869,7 +880,7 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
fp = StringIO("zulip!") fp = StringIO("zulip!")
fp.name = "zulip.txt" fp.name = "zulip.txt"
result = self.client_post("/json/user_uploads", {"file": fp}) result = self.client_post("/json/user_uploads", {"file": fp})
url = self.assert_json_success(result)["uri"] url = self.assert_json_success(result)["url"]
fp_path_id = re.sub(r"/user_uploads/", "", url) fp_path_id = re.sub(r"/user_uploads/", "", url)
body = f"First message ...[zulip.txt](http://{realm.host}/user_uploads/" + fp_path_id + ")" body = f"First message ...[zulip.txt](http://{realm.host}/user_uploads/" + fp_path_id + ")"
self.send_stream_message(self.example_user("hamlet"), "test-subscribe", body, "test") self.send_stream_message(self.example_user("hamlet"), "test-subscribe", body, "test")
@ -893,7 +904,7 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase):
fp = StringIO("zulip!") fp = StringIO("zulip!")
fp.name = name fp.name = name
result = self.client_post("/json/user_uploads", {"file": fp}) result = self.client_post("/json/user_uploads", {"file": fp})
url = self.assert_json_success(result)["uri"] url = self.assert_json_success(result)["url"]
fp_path_id = re.sub(r"/user_uploads/", "", url) fp_path_id = re.sub(r"/user_uploads/", "", url)
fp_path = os.path.split(fp_path_id)[0] fp_path = os.path.split(fp_path_id)[0]
if download: if download:

View File

@ -76,7 +76,8 @@ class LocalStorageTest(UploadSerializeMixin, ZulipTestCase):
result = self.client_post("/json/user_uploads", {"file": fp}) result = self.client_post("/json/user_uploads", {"file": fp})
response_dict = self.assert_json_success(result) response_dict = self.assert_json_success(result)
path_id = re.sub(r"/user_uploads/", "", response_dict["uri"]) self.assertEqual(response_dict["uri"], response_dict["url"])
path_id = re.sub(r"/user_uploads/", "", response_dict["url"])
assert settings.LOCAL_FILES_DIR is not None assert settings.LOCAL_FILES_DIR is not None
file_path = os.path.join(settings.LOCAL_FILES_DIR, path_id) file_path = os.path.join(settings.LOCAL_FILES_DIR, path_id)

View File

@ -164,8 +164,10 @@ class S3Test(ZulipTestCase):
result = self.client_post("/json/user_uploads", {"file": fp}) result = self.client_post("/json/user_uploads", {"file": fp})
response_dict = self.assert_json_success(result) response_dict = self.assert_json_success(result)
self.assertIn("uri", response_dict) self.assertIn("uri", response_dict)
self.assertIn("url", response_dict)
base = "/user_uploads/" base = "/user_uploads/"
url = response_dict["uri"] url = response_dict["url"]
self.assertEqual(response_dict["uri"], url)
self.assertEqual(base, url[: len(base)]) self.assertEqual(base, url[: len(base)])
# In development, this is just a redirect # In development, this is just a redirect

View File

@ -319,5 +319,8 @@ def upload_file_backend(request: HttpRequest, user_profile: UserProfile) -> Http
) )
check_upload_within_quota(user_profile.realm, file_size) check_upload_within_quota(user_profile.realm, file_size)
uri = upload_message_attachment_from_request(user_file, user_profile) url = upload_message_attachment_from_request(user_file, user_profile)
return json_success(request, data={"uri": uri})
# TODO/compatibility: uri is a deprecated alias for url that can
# be removed once there are no longer clients relying on it.
return json_success(request, data={"uri": url, "url": url})