- models: 删除 Profile 模型,字段合并到 User;User 新增云朵/公开/收藏计数器;Cloud 新增 favorite_count - schemas/serializers: 展平 UserOut/AuthOut/MeOut/AdminUserOut,移除嵌套 profile - deps: user.profile.role→user.role,移除 selectinload profile - auth/register: 注册时直接设置 user 字段,不再创建 Profile - clouds: 创建/删除云朵时同步 user.cloud_count 计数器,状态变化时同步 public_cloud_count - favorites: 点赞/取消时同步 cloud.favorite_count 计数器 - admin: 审批/隐藏/批量删时同步 public_cloud_count 计数器 - profiles/stats: 用计数器替代实时 COUNT 查询 - alembic: 新增 migration 合并 profiles 到 users,初始化 counters
91 lines
2.9 KiB
Python
91 lines
2.9 KiB
Python
from app.config import settings
|
|
from app.models import Cloud, CloudType, User
|
|
from app.schemas import (
|
|
CloudOut,
|
|
CloudOwnerOut,
|
|
CloudTypeOut,
|
|
CloudTypeSummary,
|
|
UserOut,
|
|
)
|
|
|
|
|
|
def media_url(path: str | None) -> str | None:
|
|
if not path:
|
|
return None
|
|
return f"{settings.media_base_url}/{path.lstrip('/')}"
|
|
|
|
|
|
def user_out(user: User) -> UserOut:
|
|
return UserOut(
|
|
id=user.id,
|
|
email=user.email,
|
|
email_verified=user.email_verified_at is not None,
|
|
username=user.username,
|
|
avatar_url=media_url(user.avatar_path),
|
|
role=user.role,
|
|
is_disabled=user.is_disabled,
|
|
cloud_count=user.cloud_count,
|
|
public_cloud_count=user.public_cloud_count,
|
|
collection_count=user.collection_count,
|
|
created_at=user.created_at,
|
|
)
|
|
|
|
|
|
def cloud_type_summary(cloud_type: CloudType) -> CloudTypeSummary:
|
|
return CloudTypeSummary(
|
|
id=cloud_type.id,
|
|
name=cloud_type.name,
|
|
name_en=cloud_type.name_en,
|
|
rarity=cloud_type.rarity,
|
|
)
|
|
|
|
|
|
def cloud_type_out(cloud_type: CloudType) -> CloudTypeOut:
|
|
return CloudTypeOut(
|
|
id=cloud_type.id,
|
|
name=cloud_type.name,
|
|
name_en=cloud_type.name_en,
|
|
genus=cloud_type.genus,
|
|
rarity=cloud_type.rarity,
|
|
description=cloud_type.description,
|
|
icon_url=cloud_type.icon_url,
|
|
created_at=cloud_type.created_at,
|
|
)
|
|
|
|
|
|
def cloud_out(
|
|
cloud: Cloud,
|
|
*,
|
|
include_private: bool = True,
|
|
favorite_count: int | None = None,
|
|
is_favorited: bool = False,
|
|
) -> CloudOut:
|
|
cloud_type = cloud.cloud_type
|
|
owner = cloud.user
|
|
type_name = cloud_type.name if cloud_type else (cloud.custom_cloud_type or "未知")
|
|
rarity = cloud_type.rarity if cloud_type else "common"
|
|
return CloudOut(
|
|
id=cloud.id,
|
|
user_id=cloud.user_id,
|
|
cloud_type_id=cloud.cloud_type_id,
|
|
custom_cloud_type=cloud.custom_cloud_type,
|
|
image_url=media_url(cloud.image_path) or "",
|
|
thumbnail_url=media_url(cloud.thumbnail_path) or "",
|
|
latitude=float(cloud.latitude) if cloud.latitude is not None else None,
|
|
longitude=float(cloud.longitude) if cloud.longitude is not None else None,
|
|
location_name=cloud.location_name,
|
|
description=cloud.description,
|
|
captured_at=cloud.captured_at,
|
|
status=cloud.status if include_private else "approved",
|
|
is_hidden=cloud.is_hidden if include_private else False,
|
|
created_at=cloud.created_at,
|
|
updated_at=cloud.updated_at,
|
|
cloud_type=cloud_type_summary(cloud_type) if cloud_type else None,
|
|
owner=CloudOwnerOut(id=owner.id, username=owner.username),
|
|
cloud_type_name=type_name,
|
|
cloud_type_rarity=rarity,
|
|
username=owner.username,
|
|
favorite_count=favorite_count if favorite_count is not None else 0,
|
|
is_favorited=is_favorited,
|
|
)
|