rainycode 1.4.4__tar.gz → 1.4.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. {rainycode-1.4.4 → rainycode-1.4.6}/PKG-INFO +1 -1
  2. {rainycode-1.4.4 → rainycode-1.4.6}/common_models/__init__.py +2 -1
  3. rainycode-1.4.6/common_models/file_model.py +30 -0
  4. rainycode-1.4.6/common_servers/service/file_svc.py +62 -0
  5. {rainycode-1.4.4 → rainycode-1.4.6}/core/base_config.py +5 -0
  6. {rainycode-1.4.4 → rainycode-1.4.6}/pyproject.toml +1 -1
  7. {rainycode-1.4.4 → rainycode-1.4.6}/rainycode.egg-info/PKG-INFO +1 -1
  8. {rainycode-1.4.4 → rainycode-1.4.6}/rainycode.egg-info/SOURCES.txt +2 -0
  9. {rainycode-1.4.4 → rainycode-1.4.6}/common_base/aiorequests.py +0 -0
  10. {rainycode-1.4.4 → rainycode-1.4.6}/common_base/consts.py +0 -0
  11. {rainycode-1.4.4 → rainycode-1.4.6}/common_base/exception.py +0 -0
  12. {rainycode-1.4.4 → rainycode-1.4.6}/common_base/logging.py +0 -0
  13. {rainycode-1.4.4 → rainycode-1.4.6}/common_base/response.py +0 -0
  14. {rainycode-1.4.4 → rainycode-1.4.6}/common_depends/auth_depend.py +0 -0
  15. {rainycode-1.4.4 → rainycode-1.4.6}/common_models/base_model.py +0 -0
  16. {rainycode-1.4.4 → rainycode-1.4.6}/common_models/user_model.py +0 -0
  17. {rainycode-1.4.4 → rainycode-1.4.6}/common_models/wechat_model.py +0 -0
  18. {rainycode-1.4.4 → rainycode-1.4.6}/common_servers/api/auth_api.py +0 -0
  19. {rainycode-1.4.4 → rainycode-1.4.6}/common_servers/api/wechat_api.py +0 -0
  20. {rainycode-1.4.4 → rainycode-1.4.6}/common_servers/router.py +0 -0
  21. {rainycode-1.4.4 → rainycode-1.4.6}/common_servers/schemas/auth_schema.py +0 -0
  22. {rainycode-1.4.4 → rainycode-1.4.6}/common_servers/service/auth_svc.py +0 -0
  23. {rainycode-1.4.4 → rainycode-1.4.6}/common_servers/service/wechat_svc.py +0 -0
  24. {rainycode-1.4.4 → rainycode-1.4.6}/common_utils/bcrypt_util.py +0 -0
  25. {rainycode-1.4.4 → rainycode-1.4.6}/common_utils/captcha_util.py +0 -0
  26. {rainycode-1.4.4 → rainycode-1.4.6}/common_utils/datetime_util.py +0 -0
  27. {rainycode-1.4.4 → rainycode-1.4.6}/common_utils/ip_util.py +0 -0
  28. {rainycode-1.4.4 → rainycode-1.4.6}/common_utils/jwt_util.py +0 -0
  29. {rainycode-1.4.4 → rainycode-1.4.6}/common_utils/snowflake_util.py +0 -0
  30. {rainycode-1.4.4 → rainycode-1.4.6}/common_utils/wechat_util.py +0 -0
  31. {rainycode-1.4.4 → rainycode-1.4.6}/core/databases/aiodb.py +0 -0
  32. {rainycode-1.4.4 → rainycode-1.4.6}/core/databases/aioredis.py +0 -0
  33. {rainycode-1.4.4 → rainycode-1.4.6}/core/middleware/http_middleware.py +0 -0
  34. {rainycode-1.4.4 → rainycode-1.4.6}/core/start.py +0 -0
  35. {rainycode-1.4.4 → rainycode-1.4.6}/rainycode.egg-info/dependency_links.txt +0 -0
  36. {rainycode-1.4.4 → rainycode-1.4.6}/rainycode.egg-info/requires.txt +0 -0
  37. {rainycode-1.4.4 → rainycode-1.4.6}/rainycode.egg-info/top_level.txt +0 -0
  38. {rainycode-1.4.4 → rainycode-1.4.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rainycode
3
- Version: 1.4.4
3
+ Version: 1.4.6
4
4
  Summary: FastAPI base modules
5
5
  Requires-Python: >=3.10
6
6
  Requires-Dist: aerich==0.9.2
@@ -1,4 +1,5 @@
1
+ from common_models.file_model import File
1
2
  from common_models.user_model import User
2
3
  from common_models.wechat_model import WechatApp, WechatUser
3
4
 
4
- __all__ = ["User", "WechatApp", "WechatUser"]
5
+ __all__ = ["File", "User", "WechatApp", "WechatUser"]
@@ -0,0 +1,30 @@
1
+ from core.base_config import base_config
2
+ from tortoise import fields
3
+
4
+ from common_models.base_model import CreateModel
5
+
6
+
7
+ class File(CreateModel):
8
+ """
9
+ 上传文件注册表:所有上传文件落一条元数据,磁盘文件本身放 upload_root 下。
10
+
11
+ url 存最小相对路径(如 dishes/xxx.jpg,不含前缀),经 fix_data 序列化钩子
12
+ (库 model2dict/get_data 会自动调用)加上可配置前缀(/uploads 或完整 CDN URL)
13
+ 得到前端可直接访问的完整路径。业务表经外键引用 File.id(如 UserDish.image),
14
+ 不冗余存 url 字符串。md5 用于识别相同文件(上传去重)。
15
+ """
16
+ id = fields.IntField(primary_key=True, description="主键")
17
+ name = fields.CharField(max_length=255, description="原始文件名")
18
+ url = fields.CharField(max_length=255, description="相对路径(不含前缀, 如 dishes/xxx.jpg)")
19
+ size = fields.IntField(default=0, description="文件字节数")
20
+ ext = fields.CharField(max_length=10, description="扩展名")
21
+ md5 = fields.CharField(max_length=32, null=True, description="文件内容 MD5(用于识别相同文件)")
22
+
23
+ class Meta:
24
+ table = "file"
25
+ table_description = "上传文件表"
26
+
27
+ def fix_data(self, result: dict) -> None:
28
+ """序列化后钩子(库 model2dict 调用):若含 url 则拼接可配置前缀。"""
29
+ if 'url' in result:
30
+ result['url'] = f"{base_config.upload_url_prefix}/{result['url']}"
@@ -0,0 +1,62 @@
1
+ import hashlib
2
+ import uuid
3
+ from pathlib import Path
4
+
5
+ from common_base.exception import CustomException
6
+ from common_models.file_model import File
7
+ from common_models.user_model import User
8
+ from core.base_config import base_config
9
+
10
+ # 默认上传约束
11
+ DEFAULT_MAX_BYTES = 5 * 1024 * 1024 # 5MB
12
+ ALLOWED_IMAGE_EXTS = {'jpg', 'jpeg', 'png', 'webp'}
13
+
14
+
15
+ class FileService:
16
+ """通用文件上传服务:校验格式/大小、写盘、落 File 注册表、按 md5 去重。"""
17
+
18
+ @classmethod
19
+ async def upload(
20
+ cls,
21
+ user: User,
22
+ file,
23
+ *,
24
+ subdir: str,
25
+ allowed_exts: set[str] = ALLOWED_IMAGE_EXTS,
26
+ max_bytes: int = DEFAULT_MAX_BYTES,
27
+ ) -> dict:
28
+ """
29
+ 上传文件到 upload_root/<subdir>/ 并落 File 记录,返回序列化结果(url 经 fix_data 加前缀)。
30
+
31
+ 相同内容(md5 命中)复用已有 File 记录与磁盘文件,不重复写盘。
32
+ file 为 FastAPI UploadFile(含 .filename/.content_type/.read())。
33
+ """
34
+ ext = file.filename.rsplit('.', 1)[-1].lower() if '.' in file.filename else ''
35
+ if ext not in allowed_exts:
36
+ raise CustomException(msg="不支持的文件格式")
37
+
38
+ content = await file.read()
39
+ if len(content) > max_bytes:
40
+ raise CustomException(msg="文件大小超限")
41
+
42
+ md5 = hashlib.md5(content).hexdigest()
43
+ existing = await File.get_or_none(md5=md5)
44
+ if existing:
45
+ # 相同文件已存在,直接复用(不重复写盘),仅返回其注册信息
46
+ return await File.model2dict(existing)
47
+
48
+ filename = f"{uuid.uuid4().hex}.{ext}"
49
+ relative = f"{subdir}/{filename}" # 磁盘相对路径 & File.url(不含前缀)
50
+ path = Path(base_config.upload_root) / relative
51
+ path.parent.mkdir(parents=True, exist_ok=True)
52
+ path.write_bytes(content)
53
+
54
+ row = await File.create(
55
+ name=file.filename or filename,
56
+ url=relative,
57
+ size=len(content),
58
+ ext=ext,
59
+ md5=md5,
60
+ creator_id=user.id,
61
+ )
62
+ return await File.model2dict(row)
@@ -13,6 +13,11 @@ class BaseConfig(BaseSettings):
13
13
  # 基础 URL
14
14
  base_url: str = ""
15
15
 
16
+ # 文件上传:本地存储根目录 + 访问 URL 前缀。
17
+ # upload_url_prefix 可为相对路径(/uploads)或完整 CDN URL(https://cdn.xxx.com/uploads),
18
+ upload_root: str = 'uploads'
19
+ upload_url_prefix: str = '/uploads'
20
+
16
21
  # 跨域
17
22
  cors_origins: list[str] = ['*']
18
23
  cors_allow_credentials: bool = True
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rainycode"
7
- version = "1.4.4"
7
+ version = "1.4.6"
8
8
  description = "FastAPI base modules"
9
9
  requires-python = ">=3.10"
10
10
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rainycode
3
- Version: 1.4.4
3
+ Version: 1.4.6
4
4
  Summary: FastAPI base modules
5
5
  Requires-Python: >=3.10
6
6
  Requires-Dist: aerich==0.9.2
@@ -7,6 +7,7 @@ common_base/response.py
7
7
  common_depends/auth_depend.py
8
8
  common_models/__init__.py
9
9
  common_models/base_model.py
10
+ common_models/file_model.py
10
11
  common_models/user_model.py
11
12
  common_models/wechat_model.py
12
13
  common_servers/router.py
@@ -14,6 +15,7 @@ common_servers/api/auth_api.py
14
15
  common_servers/api/wechat_api.py
15
16
  common_servers/schemas/auth_schema.py
16
17
  common_servers/service/auth_svc.py
18
+ common_servers/service/file_svc.py
17
19
  common_servers/service/wechat_svc.py
18
20
  common_utils/bcrypt_util.py
19
21
  common_utils/captcha_util.py
File without changes
File without changes