52 lines
1.7 KiB
Python
52 lines
1.7 KiB
Python
|
|
# -*- coding: utf-8 -*-
|
|||
|
|
"""默认头像池:新用户未提供头像时,从头像池随机分配一个默认头像。
|
|||
|
|
|
|||
|
|
头像池 = 对象存储桶 avatar/images/images/ 目录下的 1321 张头像
|
|||
|
|
(对象 key 清单见 ``serverdata/avatar_pool.json``,由 code/images/images_data/images
|
|||
|
|
本地目录与桶内对象一一对应生成)。
|
|||
|
|
|
|||
|
|
数据库只存对象相对路径 ``/oss/avatar/images/images/<file>``,
|
|||
|
|
读取时经 ``resolve_url`` 补全为 CDN 直链(见 app/infrastructure/oss.py)。
|
|||
|
|
|
|||
|
|
语义约定:
|
|||
|
|
- 新用户创建时若未显式提供头像(avatar 为空)→ 随机分配一个默认头像;
|
|||
|
|
- 用户一旦自行更换头像(上传真实头像)→ 走 update 流程,不再回退/重随机。
|
|||
|
|
"""
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
import json
|
|||
|
|
import random
|
|||
|
|
from pathlib import Path
|
|||
|
|
from typing import List
|
|||
|
|
|
|||
|
|
from .. import config
|
|||
|
|
|
|||
|
|
_POOL_CACHE: List[str] | None = None
|
|||
|
|
_POOL_PATH: Path = config.SERVERDATA_DIR / "avatar_pool.json"
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _load_pool() -> List[str]:
|
|||
|
|
"""读取头像池对象 key 清单(内存缓存)。文件缺失/损坏时返回空池。"""
|
|||
|
|
global _POOL_CACHE
|
|||
|
|
if _POOL_CACHE is not None:
|
|||
|
|
return _POOL_CACHE
|
|||
|
|
try:
|
|||
|
|
raw = json.loads(_POOL_PATH.read_text(encoding="utf-8"))
|
|||
|
|
keys = [
|
|||
|
|
str(k).strip()
|
|||
|
|
for k in raw
|
|||
|
|
if isinstance(k, str) and k.strip()
|
|||
|
|
]
|
|||
|
|
except Exception: # noqa: BLE001
|
|||
|
|
keys = []
|
|||
|
|
_POOL_CACHE = keys
|
|||
|
|
return keys
|
|||
|
|
|
|||
|
|
|
|||
|
|
def random_default_avatar() -> str:
|
|||
|
|
"""从默认头像池随机返回一个对象路径(``/oss/...``);池为空时返回空串。"""
|
|||
|
|
pool = _load_pool()
|
|||
|
|
if not pool:
|
|||
|
|
return ""
|
|||
|
|
return "/oss/" + random.choice(pool)
|