Skip to content

Commit f2277e1

Browse files
committed
support text direct downloads
1 parent f20a7a5 commit f2277e1

2 files changed

Lines changed: 38 additions & 1 deletion

File tree

apps/base/views.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44
import os
55
import uuid
66
from datetime import timedelta
7-
from urllib.parse import unquote
7+
from urllib.parse import quote, unquote
88

99
from typing import Optional, Tuple, Union
1010

1111
from fastapi import APIRouter, Form, Request, UploadFile, File, Depends, HTTPException
1212
from pydantic import BaseModel, ValidationError
1313
from starlette import status
14+
from starlette.responses import Response
1415
from tortoise.expressions import Case, F, Q, When
1516

1617
from apps.admin.dependencies import share_required_login
@@ -334,6 +335,17 @@ async def get_code_file(code: str, ip: str = Depends(ip_limit["error"])):
334335
assert isinstance(file_code, FileCodes)
335336
if not await consume_file_usage(file_code):
336337
return APIResponse(code=404, detail="文件已过期")
338+
if file_code.text is not None:
339+
filename = f"{file_code.prefix or 'Text'}{file_code.suffix or '.txt'}"
340+
return Response(
341+
content=file_code.text,
342+
media_type="text/plain",
343+
headers={
344+
"Content-Disposition": (
345+
f"attachment; filename*=UTF-8''{quote(filename, safe='')}"
346+
)
347+
},
348+
)
337349
return await file_storage.get_file_response(file_code)
338350

339351

tests/test_issue_482_share_usage.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ async def _run_scenario(self):
7171
await self._assert_count_consumption_is_atomic()
7272
await self._assert_time_expiration_and_usage_are_atomic()
7373
await self._assert_download_url_is_single_use()
74+
await self._assert_text_share_downloads_as_txt()
7475
await self._assert_limited_files_do_not_expose_direct_urls()
7576
await self._assert_metadata_counts_all_attempts()
7677
finally:
@@ -156,6 +157,30 @@ async def _assert_download_url_is_single_use(self):
156157
self.assertEqual(record.expired_count, 0)
157158
self.assertEqual(record.used_count, 1)
158159

160+
async def _assert_text_share_downloads_as_txt(self):
161+
record = await FileCodes.create(
162+
code="text-download",
163+
prefix="TAG",
164+
text="hello, 文本直链",
165+
expired_count=-1,
166+
expired_at=None,
167+
)
168+
169+
with patch.dict(views.storages, {"local": FakeStorage}):
170+
response = await views.get_code_file(
171+
code=record.code, ip="127.0.0.1"
172+
)
173+
174+
self.assertEqual(response.status_code, 200)
175+
self.assertEqual(response.body.decode("utf-8"), record.text)
176+
self.assertEqual(response.media_type, "text/plain")
177+
self.assertEqual(
178+
response.headers["content-disposition"],
179+
"attachment; filename*=UTF-8''TAG.txt",
180+
)
181+
await record.refresh_from_db()
182+
self.assertEqual(record.used_count, 1)
183+
159184
async def _assert_limited_files_do_not_expose_direct_urls(self):
160185
record = await FileCodes.create(
161186
code="proxy-only",

0 commit comments

Comments
 (0)