Files
findreve/services/object.py

164 lines
4.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
物品相关业务逻辑。
"""
from typing import List
from uuid import UUID
from fastapi import status
from loguru import logger
from sqlmodel.ext.asyncio.session import AsyncSession
from model import Item, ItemDataResponse, Setting, User
from model.item import ItemDataUpdateRequest, ItemTypeEnum
from pkg.sender import ServerChatBot, WeChatBot
from pkg import utils
async def list_items(
session: AsyncSession,
user: User,
item_id: int | None = None,
key: str | None = None,
) -> List[Item]:
"""
根据条件获取当前用户的物品列表。
"""
if item_id is not None:
results = await Item.get(session, (Item.id == item_id) & (Item.user_id == user.id))
results = [results] if results else []
elif key is not None:
results = await Item.get(session, (Item.key == key) & (Item.user_id == user.id))
results = [results] if results else []
else:
results = await Item.get(session, Item.user_id == user.id, fetch_mode="all")
if not results:
return []
items: list[Item] = []
for obj in results:
items.append(
Item(
id=obj.id,
type=obj.type,
key=obj.id,
name=obj.name,
icon=obj.icon or "",
status=obj.status or "",
phone=obj.phone if obj.phone and obj.phone.isdigit() else None,
lost_description=obj.description,
find_ip=obj.find_ip,
create_time=obj.created_at.isoformat(),
lost_time=obj.lost_at.isoformat() if obj.lost_at else None,
)
)
return items
async def create_item(
session: AsyncSession,
user: User,
request: ItemDataUpdateRequest,
) -> None:
"""
创建新的物品信息。
"""
try:
request_dict = request.model_dump()
request_dict["user"] = user
request_dict["user_id"] = user.id
await Item.add(session, Item.model_validate(request_dict))
except Exception as exc: # noqa: BLE001
logger.error(f"Failed to add item: {exc}")
utils.raise_internal_error(str(exc))
async def update_item(
session: AsyncSession,
user: User,
item_id: UUID,
request: ItemDataUpdateRequest,
) -> None:
"""
更新物品信息。
"""
obj = await Item.get(session, (Item.id == item_id) & (Item.user_id == user.id))
if not obj:
utils.raise_not_found("Item not found or access denied")
await obj.update(session, request, exclude_unset=True)
async def delete_item(
session: AsyncSession,
user: User,
item_id: UUID,
) -> None:
"""
删除指定物品。
"""
obj = await Item.get(session, (Item.id == item_id) & (Item.user_id == user.id))
if not obj:
utils.raise_not_found("Item not found or access denied")
await Item.delete(session, obj)
async def retrieve_object(
session: AsyncSession,
item_id: UUID,
client_host: str,
) -> ItemDataResponse:
"""
根据物品 ID 获取物品信息并视情况更新寻找者 IP。
"""
object_data = await Item.get(session, Item.id == item_id)
if not object_data:
utils.raise_not_found("物品不存在或出现异常")
if object_data.status == "lost":
object_data.find_ip = client_host
object_data = await object_data.save(session)
return ItemDataResponse.model_validate(object_data)
async def notify_move_car(
session: AsyncSession,
item_id: UUID,
phone: str | None = None,
) -> int:
"""
向车主发送挪车通知。
"""
item_data = await Item.get_exist_one(session=session, id=item_id)
if item_data.type != ItemTypeEnum.car:
utils.raise_bad_request("Item is not car")
server_chan_key = await Setting.get(session, Setting.name == "server_chan_key")
wechat_bot_key = await Setting.get(session, Setting.name == "wechat_bot_key")
if not (server_chan_key.value or wechat_bot_key.value):
utils.raise_internal_error("未配置Server酱无法发送挪车通知")
title = "挪车通知 - Findreve"
description = (
f"您的车辆“{item_data.name}”被请求挪车。\n"
f"{f'请求挪车者电话:[{phone}](tel:{phone})' if phone else ''}\n"
"请尽快联系请求者并挪车。"
)
mentioned_channel = (await Setting.get(session, Setting.name == "mentioned_channel")).value
if mentioned_channel == "server_chan":
await ServerChatBot.send_text(session=session, title=title, description=description)
elif mentioned_channel == "wechat_bot":
await WeChatBot.send_markdown(
session=session,
markdown=f"# {title}\n\n{description}",
version="v1",
)
return status.HTTP_204_NO_CONTENT