-
-
Notifications
You must be signed in to change notification settings - Fork 589
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #80 from vastsa/new
新版本,前端改vite+vue3
- Loading branch information
Showing
80 changed files
with
4,208 additions
and
5,247 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# @Time : 2023/8/13 20:43 | ||
# @Author : Lan | ||
# @File : __init__.py.py | ||
# @Software: PyCharm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# @Time : 2023/8/14 14:38 | ||
# @Author : Lan | ||
# @File : __init__.py.py | ||
# @Software: PyCharm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# @Time : 2023/8/14 14:38 | ||
# @Author : Lan | ||
# @File : views.py | ||
# @Software: PyCharm | ||
from fastapi import APIRouter | ||
|
||
admin_api = APIRouter( | ||
prefix='/admin', | ||
tags=['管理'], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# @Time : 2023/8/13 20:43 | ||
# @Author : Lan | ||
# @File : __init__.py.py | ||
# @Software: PyCharm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# @Time : 2023/8/13 20:43 | ||
# @Author : Lan | ||
# @File : models.py | ||
# @Software: PyCharm | ||
from datetime import datetime | ||
from typing import Optional | ||
|
||
from tortoise import fields | ||
from tortoise.models import Model | ||
from tortoise.contrib.pydantic import pydantic_model_creator | ||
|
||
from core.utils import get_now | ||
|
||
|
||
class FileCodes(Model): | ||
id: Optional[int] = fields.IntField(pk=True) | ||
code: Optional[int] = fields.CharField(description='分享码', max_length=255, index=True, unique=True) | ||
prefix: Optional[str] = fields.CharField(max_length=255, description='前缀', default='') | ||
suffix: Optional[str] = fields.CharField(max_length=255, description='后缀', default='') | ||
uuid_file_name: Optional[str] = fields.CharField(max_length=255, description='uuid文件名', null=True) | ||
file_path: Optional[str] = fields.CharField(max_length=255, description='文件路径', null=True) | ||
size: Optional[int] = fields.IntField(description='文件大小', default=0) | ||
text: Optional[str] = fields.TextField(description='文本内容', null=True) | ||
expired_at: Optional[datetime] = fields.DatetimeField(null=True, description='过期时间') | ||
expired_count: Optional[int] = fields.IntField(description='可用次数', default=0) | ||
used_count: Optional[int] = fields.IntField(description='已用次数', default=0) | ||
|
||
created_at: Optional[datetime] = fields.DatetimeField(auto_now_add=True, description='创建时间') | ||
|
||
async def is_expired(self): | ||
if self.expired_at and (self.expired_count == -1 or self.used_count < self.expired_count): | ||
return self.expired_at < await get_now() | ||
else: | ||
return self.expired_count != -1 and self.used_count >= self.expired_count | ||
|
||
async def get_file_path(self): | ||
return f"{self.file_path}/{self.uuid_file_name}" | ||
|
||
|
||
file_codes_pydantic = pydantic_model_creator(FileCodes, name='FileCodes') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from pydantic import BaseModel | ||
|
||
|
||
class SelectFileModel(BaseModel): | ||
code: str |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
# @Time : 2023/8/14 01:10 | ||
# @Author : Lan | ||
# @File : utils.py | ||
# @Software: PyCharm | ||
import datetime | ||
import uuid | ||
import os | ||
from fastapi import UploadFile | ||
|
||
from apps.base.depends import IPRateLimit | ||
from apps.base.models import FileCodes | ||
from core.utils import get_random_num, get_random_string | ||
|
||
|
||
async def get_file_path_name(file: UploadFile): | ||
""" | ||
获取文件路径和文件名 | ||
:param file: | ||
:return: { | ||
'path': 'share/data/2021/08/13', | ||
'suffix': '.jpg', | ||
'prefix': 'test', | ||
'file_uuid': '44a83bbd70e04c8aa7fd93bfd8c88249', | ||
'uuid_file_name': '44a83bbd70e04c8aa7fd93bfd8c88249.jpg', | ||
'save_path': 'share/data/2021/08/13/44a83bbd70e04c8aa7fd93bfd8c88249.jpg' | ||
} | ||
""" | ||
today = datetime.datetime.now() | ||
path = f"share/data/{today.strftime('%Y/%m/%d')}" | ||
prefix, suffix = os.path.splitext(file.filename) | ||
file_uuid = f"{uuid.uuid4().hex}" | ||
uuid_file_name = f"{file_uuid}{suffix}" | ||
save_path = f"{path}/{uuid_file_name}" | ||
return path, suffix, prefix, uuid_file_name, save_path | ||
|
||
|
||
async def get_expire_info(expire_value: int, expire_style: str): | ||
""" | ||
获取过期信息 | ||
:param expire_value: | ||
:param expire_style: | ||
:return: expired_at 过期时间, expired_count 可用次数, used_count 已用次数, code 随机码 | ||
""" | ||
expired_count, used_count, now, code = -1, 0, datetime.datetime.now(), None | ||
if expire_style == 'day': | ||
expired_at = now + datetime.timedelta(days=expire_value) | ||
elif expire_style == 'hour': | ||
expired_at = now + datetime.timedelta(hours=expire_value) | ||
elif expire_style == 'minute': | ||
expired_at = now + datetime.timedelta(minutes=expire_value) | ||
elif expire_style == 'count': | ||
expired_at = now + datetime.timedelta(days=1) | ||
expired_count = expire_value | ||
elif expire_style == 'forever': | ||
expired_at = None | ||
code = await get_random_code(style='string') | ||
else: | ||
expired_at = now + datetime.timedelta(days=1) | ||
if not code: | ||
code = await get_random_code() | ||
return expired_at, expired_count, used_count, code | ||
|
||
|
||
async def get_random_code(style='num'): | ||
""" | ||
获取随机字符串 | ||
:return: | ||
""" | ||
while True: | ||
code = await get_random_num() if style == 'num' else await get_random_string() | ||
if not await FileCodes.filter(code=code).exists(): | ||
return code | ||
|
||
|
||
# 错误IP限制器 | ||
error_ip_limit = IPRateLimit(1, 1) | ||
# 上传文件限制器 | ||
upload_ip_limit = IPRateLimit(10, 1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
# @Time : 2023/8/14 03:59 | ||
# @Author : Lan | ||
# @File : views.py | ||
# @Software: PyCharm | ||
from fastapi import APIRouter, Form, UploadFile, File, Depends | ||
from starlette.responses import FileResponse | ||
|
||
from apps.base.models import FileCodes | ||
from apps.base.pydantics import SelectFileModel | ||
from apps.base.utils import get_expire_info, get_file_path_name, error_ip_limit | ||
from core.response import APIResponse | ||
from core.storage import file_storage | ||
|
||
share_api = APIRouter( | ||
prefix='/share', | ||
tags=['分享'], | ||
) | ||
|
||
|
||
@share_api.post('/text/') | ||
async def share_text(text: str = Form(...), expire_value: int = Form(default=1, gt=0), expire_style: str = Form(default='day')): | ||
expired_at, expired_count, used_count, code = await get_expire_info(expire_value, expire_style) | ||
await FileCodes.create( | ||
code=code, | ||
text=text, | ||
expired_at=expired_at, | ||
expired_count=expired_count, | ||
used_count=used_count, | ||
size=len(text), | ||
prefix='文本分享' | ||
) | ||
return APIResponse(detail={ | ||
'code': code, | ||
}) | ||
|
||
|
||
@share_api.post('/file/') | ||
async def share_file(expire_value: int = Form(default=1, gt=0), expire_style: str = Form(default='day'), file: UploadFile = File(...)): | ||
expired_at, expired_count, used_count, code = await get_expire_info(expire_value, expire_style) | ||
path, suffix, prefix, uuid_file_name, save_path = await get_file_path_name(file) | ||
await file_storage.save_file(file, save_path) | ||
await FileCodes.create( | ||
code=code, | ||
prefix=prefix, | ||
suffix=suffix, | ||
uuid_file_name=uuid_file_name, | ||
file_path=path, | ||
size=file.size, | ||
expired_at=expired_at, | ||
expired_count=expired_count, | ||
used_count=used_count, | ||
) | ||
return APIResponse(detail={ | ||
'code': code, | ||
'name': file.filename, | ||
}) | ||
|
||
|
||
@share_api.post('/select/') | ||
async def select_file(data: SelectFileModel, ip: str = Depends(error_ip_limit)): | ||
file_code = await FileCodes.filter(code=data.code).first() | ||
if not file_code: | ||
error_ip_limit.add_ip(ip) | ||
return APIResponse(code=404, detail='文件不存在') | ||
if await file_code.is_expired(): | ||
return APIResponse(code=403, detail='文件已过期') | ||
file_code.used_count += 1 | ||
await file_code.save() | ||
return APIResponse(detail={ | ||
'code': file_code.code, | ||
'name': file_code.prefix + file_code.suffix, | ||
'size': file_code.size, | ||
'text': file_code.text if file_code.text is not None else await file_storage.get_file_url(file_code), | ||
}) | ||
|
||
|
||
@share_api.get('/download') | ||
async def download_file(key: str, code: str, ip: str = Depends(error_ip_limit)): | ||
is_valid = await file_storage.get_select_token(code) == key | ||
if not is_valid: | ||
error_ip_limit.add_ip(ip) | ||
file_code = await FileCodes.filter(code=code).first() | ||
if not file_code: | ||
return APIResponse(code=404, detail='文件不存在') | ||
if file_code.text: | ||
return APIResponse(detail=file_code.text) | ||
else: | ||
file_path = file_storage.root_path / await file_code.get_file_path() | ||
if not file_path.exists(): | ||
return APIResponse(code=404, detail='文件已过期删除') | ||
return FileResponse(file_path, filename=file_code.prefix + file_code.suffix) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# @Time : 2023/8/11 20:06 | ||
# @Author : Lan | ||
# @File : __init__.py.py | ||
# @Software: PyCharm |
Empty file.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# @Time : 2023/8/14 11:48 | ||
# @Author : Lan | ||
# @File : response.py | ||
# @Software: PyCharm | ||
from typing import Generic, TypeVar | ||
|
||
from pydantic.v1.generics import GenericModel | ||
|
||
T = TypeVar('T') | ||
|
||
|
||
class APIResponse(GenericModel, Generic[T]): | ||
code: int = 200 | ||
message: str = 'ok' | ||
detail: T |
Oops, something went wrong.