@@ -15,8 +15,11 @@ from __future__ import annotations
|
||||
import uuid
|
||||
from collections.abc import Iterable
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.dialects.postgresql import insert as pg_insert
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from ..models import Member
|
||||
from ..models_ticket import Notification
|
||||
|
||||
TICKET_STATUS_CN = {
|
||||
@@ -48,6 +51,7 @@ async def notify(
|
||||
title: str,
|
||||
body: str = "",
|
||||
actor_id: uuid.UUID | None = None,
|
||||
dedupe_key: str | None = None,
|
||||
) -> int:
|
||||
"""给若干人各写一条通知,返回实际写入条数。
|
||||
|
||||
@@ -67,7 +71,55 @@ async def notify(
|
||||
item_id=item_id,
|
||||
title=title[:120],
|
||||
body=body[:300],
|
||||
dedupe_key=dedupe_key,
|
||||
)
|
||||
)
|
||||
count += 1
|
||||
return count
|
||||
|
||||
|
||||
async def notify_once(
|
||||
session: AsyncSession,
|
||||
*,
|
||||
ws_id: uuid.UUID,
|
||||
user_id: uuid.UUID | None,
|
||||
kind: str,
|
||||
item_id: uuid.UUID | None,
|
||||
title: str,
|
||||
body: str = "",
|
||||
dedupe_key: str,
|
||||
actor_id: uuid.UUID | None = None,
|
||||
) -> bool:
|
||||
"""写一条带幂等键的通知;已经写过就跳过,返回是否真的写入。
|
||||
|
||||
后台提醒循环会反复扫同一批任务,靠 `dedupe_key` 的唯一索引把重复挡在数据库层,
|
||||
比"先查再插"少一次竞态。提醒本身不是业务事实,丢了不致命,重复才烦人。
|
||||
"""
|
||||
if user_id is None or user_id == actor_id:
|
||||
return False
|
||||
result = await session.execute(
|
||||
pg_insert(Notification)
|
||||
.values(
|
||||
workspace_id=ws_id,
|
||||
user_id=user_id,
|
||||
kind=kind,
|
||||
item_id=item_id,
|
||||
title=title[:120],
|
||||
body=body[:300],
|
||||
dedupe_key=dedupe_key,
|
||||
)
|
||||
.on_conflict_do_nothing()
|
||||
)
|
||||
return result.rowcount > 0
|
||||
|
||||
|
||||
async def workspace_admins(session: AsyncSession, ws_id: uuid.UUID) -> list[uuid.UUID]:
|
||||
"""工作区里能"发布/把关"的人:owner + admin,只算正常成员。"""
|
||||
rows = await session.execute(
|
||||
select(Member.user_id).where(
|
||||
Member.workspace_id == ws_id,
|
||||
Member.status == "active",
|
||||
Member.role.in_(("owner", "admin")),
|
||||
)
|
||||
)
|
||||
return [row[0] for row in rows]
|
||||
|
||||
Reference in New Issue
Block a user