From 2baaa0459d7b676f65b124b5dbf72f4eac267387 Mon Sep 17 00:00:00 2001 From: lan Date: Mon, 14 Aug 2023 05:03:07 +0800 Subject: [PATCH] add:fronted --- apps/base/models.py | 10 ++- apps/base/utils.py | 2 +- apps/base/views.py | 91 ++++++++++++++++++++++ core/storage.py | 4 +- core/utils.py | 11 +++ fcb-fronted/components.d.ts | 5 ++ fcb-fronted/src/components/FileBox.vue | 32 ++++++-- fcb-fronted/src/components/UploadFile.vue | 3 - fcb-fronted/src/components/UploadText.vue | 2 - fcb-fronted/src/utils/request.ts | 2 +- fcb-fronted/src/views/HomeView.vue | 58 +++++++++++++- filecodebox.db-shm | Bin 0 -> 32768 bytes filecodebox.db-wal | 0 main.py | 52 ++----------- 14 files changed, 203 insertions(+), 69 deletions(-) create mode 100644 apps/base/views.py create mode 100644 filecodebox.db-shm create mode 100644 filecodebox.db-wal diff --git a/apps/base/models.py b/apps/base/models.py index b34f6c7..58d88bb 100644 --- a/apps/base/models.py +++ b/apps/base/models.py @@ -9,16 +9,18 @@ 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文件名') - file_path: Optional[str] = fields.CharField(max_length=255, description='文件路径') + 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) @@ -27,7 +29,7 @@ class FileCodes(Model): async def is_expired(self): if self.expired_at: - return self.expired_at < datetime.now() + return self.expired_at < await get_now() else: return self.expired_count != -1 and self.used_count >= self.expired_count diff --git a/apps/base/utils.py b/apps/base/utils.py index ccd6d1d..5c5ed06 100644 --- a/apps/base/utils.py +++ b/apps/base/utils.py @@ -30,7 +30,7 @@ async def get_file_path_name(file: UploadFile): 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, file_uuid, save_path + return path, suffix, prefix, uuid_file_name, save_path async def get_expire_info(expire_value: int, expire_style: str): diff --git a/apps/base/views.py b/apps/base/views.py new file mode 100644 index 0000000..b1f27fa --- /dev/null +++ b/apps/base/views.py @@ -0,0 +1,91 @@ +# @Time : 2023/8/14 03:59 +# @Author : Lan +# @File : views.py +# @Software: PyCharm +from fastapi import APIRouter, Form, UploadFile, File +from pydantic import BaseModel + +from apps.base.models import FileCodes +from apps.base.utils import get_expire_info, get_file_path_name +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 { + 'code': 200, + 'msg': 'success', + 'data': { + '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 { + 'code': 200, + 'msg': 'success', + 'data': { + 'code': code, + 'name': file.filename, + } + } + + +class SelectFileModel(BaseModel): + code: str + + +@share_api.post('/select/') +async def select_file(data: SelectFileModel): + file_code = await FileCodes.filter(code=data.code).first() + if not file_code: + return { + 'code': 404, + 'msg': '文件不存在', + } + if await file_code.is_expired(): + return { + 'code': 403, + 'msg': '文件已过期', + } + return { + 'code': 200, + 'msg': 'success', + 'data': { + 'code': file_code.code, + 'name': file_code.prefix + file_code.suffix, + 'size': file_code.size, + 'text': await file_storage.get_file_url(file_code), + } + } diff --git a/core/storage.py b/core/storage.py index 158f81a..4c66e36 100644 --- a/core/storage.py +++ b/core/storage.py @@ -56,9 +56,11 @@ class S3FileStorage: await s3.delete_object(Bucket=self.bucket_name, Key=await file_code.get_file_path()) async def get_file_url(self, file_code: FileCodes): + if file_code.prefix == '文本分享': + return file_code.text async with self.session.client("s3", endpoint_url=self.endpoint_url) as s3: result = await s3.generate_presigned_url('get_object', Params={'Bucket': self.bucket_name, 'Key': await file_code.get_file_path()}, ExpiresIn=3600) return result -file_storage = SystemFileStorage() +file_storage = S3FileStorage() diff --git a/core/utils.py b/core/utils.py index 47eab36..f6a96cd 100644 --- a/core/utils.py +++ b/core/utils.py @@ -2,6 +2,7 @@ # @Author : Lan # @File : utils.py # @Software: PyCharm +import datetime import random import string @@ -23,3 +24,13 @@ async def get_random_string(): :return: """ return ''.join(random.choice(r_s) for _ in range(5)) + + +async def get_now(): + """ + 获取当前时间 + :return: + """ + return datetime.datetime.now( + datetime.timezone(datetime.timedelta(hours=8)) + ) diff --git a/fcb-fronted/components.d.ts b/fcb-fronted/components.d.ts index 6335a29..a736e4a 100644 --- a/fcb-fronted/components.d.ts +++ b/fcb-fronted/components.d.ts @@ -11,9 +11,11 @@ declare module 'vue' { ElButton: typeof import('element-plus/es')['ElButton'] ElCard: typeof import('element-plus/es')['ElCard'] ElCol: typeof import('element-plus/es')['ElCol'] + ElDialog: typeof import('element-plus/es')['ElDialog'] ElDrawer: typeof import('element-plus/es')['ElDrawer'] ElIcon: typeof import('element-plus/es')['ElIcon'] ElInput: typeof import('element-plus/es')['ElInput'] + ElModal: typeof import('element-plus/es')['ElModal'] ElOption: typeof import('element-plus/es')['ElOption'] ElProgress: typeof import('element-plus/es')['ElProgress'] ElRadio: typeof import('element-plus/es')['ElRadio'] @@ -28,4 +30,7 @@ declare module 'vue' { UploadFile: typeof import('./src/components/UploadFile.vue')['default'] UploadText: typeof import('./src/components/UploadText.vue')['default'] } + export interface ComponentCustomProperties { + vLoading: typeof import('element-plus/es')['ElLoadingDirective'] + } } diff --git a/fcb-fronted/src/components/FileBox.vue b/fcb-fronted/src/components/FileBox.vue index d3b66f5..566cfcf 100644 --- a/fcb-fronted/src/components/FileBox.vue +++ b/fcb-fronted/src/components/FileBox.vue @@ -6,6 +6,14 @@ const fileStore = useFileDataStore(); const fileBoxStore = useFileBoxStore(); import QrcodeVue from "qrcode.vue"; import { useRoute } from "vue-router"; +import { ref } from "vue"; +const openUrl = (url: string) => { + if (url.startsWith('/')) { + url = window.location.origin + url; + } + window.open(url); +}; +const route = useRoute(); const copyText = (text: any, style = 0) => { if (style === 1) { @@ -20,22 +28,34 @@ const copyText = (text: any, style = 0) => { } document.body.removeChild(temp); }; -const route = useRoute();