过期时间
This commit is contained in:
parent
35f91a7d03
commit
a22211da32
@ -196,9 +196,9 @@ async def check_bot_access(bot_id: str, user_id: str, required_permission: str)
|
|||||||
if await cursor.fetchone():
|
if await cursor.fetchone():
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# 检查是否在分享列表中
|
# 检查是否在分享列表中(同<EFBFBD><EFBFBD>检查过期时间)
|
||||||
await cursor.execute("""
|
await cursor.execute("""
|
||||||
SELECT role FROM bot_shares
|
SELECT role, expires_at FROM bot_shares
|
||||||
WHERE bot_id = %s AND user_id = %s
|
WHERE bot_id = %s AND user_id = %s
|
||||||
""", (bot_id, user_id))
|
""", (bot_id, user_id))
|
||||||
row = await cursor.fetchone()
|
row = await cursor.fetchone()
|
||||||
@ -206,7 +206,16 @@ async def check_bot_access(bot_id: str, user_id: str, required_permission: str)
|
|||||||
if not row:
|
if not row:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
role = row[0]
|
role, expires_at = row
|
||||||
|
|
||||||
|
# 检查是否已过期
|
||||||
|
if expires_at is not None:
|
||||||
|
# 获取当前时间(考虑时区)
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
now = datetime.now(timezone.utc)
|
||||||
|
if expires_at < now:
|
||||||
|
# 分享已过期,拒绝访问
|
||||||
|
return False
|
||||||
|
|
||||||
# 权限矩阵
|
# 权限矩阵
|
||||||
permissions = {
|
permissions = {
|
||||||
@ -401,6 +410,7 @@ class BotResponse(BaseModel):
|
|||||||
owner: Optional[dict] = None # {id, username}
|
owner: Optional[dict] = None # {id, username}
|
||||||
role: Optional[str] = None # 'viewer', 'editor', None for owner
|
role: Optional[str] = None # 'viewer', 'editor', None for owner
|
||||||
shared_at: Optional[str] = None
|
shared_at: Optional[str] = None
|
||||||
|
expires_at: Optional[str] = None # 分享过期时间
|
||||||
description: Optional[str] = None # 从 settings 中提取
|
description: Optional[str] = None # 从 settings 中提取
|
||||||
avatar_url: Optional[str] = None # 从 settings 中提取
|
avatar_url: Optional[str] = None # 从 settings 中提取
|
||||||
created_at: str
|
created_at: str
|
||||||
@ -502,6 +512,7 @@ class BotShareCreate(BaseModel):
|
|||||||
"""创建分享请求"""
|
"""创建分享请求"""
|
||||||
user_ids: List[str]
|
user_ids: List[str]
|
||||||
role: str = "viewer" # 'viewer' or 'editor'
|
role: str = "viewer" # 'viewer' or 'editor'
|
||||||
|
expires_at: Optional[str] = None # ISO 8601 格式的过期时间,None 表示永不过期
|
||||||
|
|
||||||
|
|
||||||
class BotShareResponse(BaseModel):
|
class BotShareResponse(BaseModel):
|
||||||
@ -514,6 +525,7 @@ class BotShareResponse(BaseModel):
|
|||||||
role: str
|
role: str
|
||||||
shared_at: str
|
shared_at: str
|
||||||
shared_by: Optional[str] = None
|
shared_by: Optional[str] = None
|
||||||
|
expires_at: Optional[str] = None # 过期时间
|
||||||
|
|
||||||
|
|
||||||
class BotSharesListResponse(BaseModel):
|
class BotSharesListResponse(BaseModel):
|
||||||
@ -609,6 +621,7 @@ async def migrate_bot_owner_and_shares():
|
|||||||
shared_by UUID NOT NULL REFERENCES agent_user(id) ON DELETE SET NULL,
|
shared_by UUID NOT NULL REFERENCES agent_user(id) ON DELETE SET NULL,
|
||||||
role VARCHAR(50) DEFAULT 'viewer' CHECK (role IN ('viewer', 'editor')),
|
role VARCHAR(50) DEFAULT 'viewer' CHECK (role IN ('viewer', 'editor')),
|
||||||
shared_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
shared_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||||
|
expires_at TIMESTAMP WITH TIME ZONE,
|
||||||
UNIQUE(bot_id, user_id)
|
UNIQUE(bot_id, user_id)
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
@ -618,6 +631,21 @@ async def migrate_bot_owner_and_shares():
|
|||||||
await cursor.execute("CREATE INDEX idx_bot_shares_shared_by ON bot_shares(shared_by)")
|
await cursor.execute("CREATE INDEX idx_bot_shares_shared_by ON bot_shares(shared_by)")
|
||||||
|
|
||||||
logger.info("bot_shares table created successfully")
|
logger.info("bot_shares table created successfully")
|
||||||
|
else:
|
||||||
|
# 为已存在的表添加 expires_at 字段
|
||||||
|
await cursor.execute("""
|
||||||
|
SELECT column_name
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_name = 'bot_shares' AND column_name = 'expires_at'
|
||||||
|
""")
|
||||||
|
has_expires_column = await cursor.fetchone()
|
||||||
|
if not has_expires_column:
|
||||||
|
logger.info("Adding expires_at column to bot_shares table")
|
||||||
|
await cursor.execute("""
|
||||||
|
ALTER TABLE bot_shares
|
||||||
|
ADD COLUMN expires_at TIMESTAMP WITH TIME ZONE
|
||||||
|
""")
|
||||||
|
logger.info("expires_at column added successfully")
|
||||||
|
|
||||||
# 4. 创建 agent_user_tokens 表
|
# 4. 创建 agent_user_tokens 表
|
||||||
await cursor.execute("""
|
await cursor.execute("""
|
||||||
@ -1235,15 +1263,16 @@ async def get_bots(authorization: Optional[str] = Header(None)):
|
|||||||
for row in rows
|
for row in rows
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
# 用户只能看到拥有的 Bot 和分享给自己的 Bot
|
# 用户只能看到拥有的 Bot 和分享给自己的 Bot(且未过期)
|
||||||
await cursor.execute("""
|
await cursor.execute("""
|
||||||
SELECT b.id, b.name, b.bot_id, b.created_at, b.updated_at, b.settings,
|
SELECT b.id, b.name, b.bot_id, b.created_at, b.updated_at, b.settings,
|
||||||
u.id as owner_id, u.username as owner_username,
|
u.id as owner_id, u.username as owner_username,
|
||||||
s.role, s.shared_at
|
s.role, s.shared_at, s.expires_at
|
||||||
FROM agent_bots b
|
FROM agent_bots b
|
||||||
LEFT JOIN agent_user u ON b.owner_id = u.id
|
LEFT JOIN agent_user u ON b.owner_id = u.id
|
||||||
LEFT JOIN bot_shares s ON b.id = s.bot_id AND s.user_id = %s
|
LEFT JOIN bot_shares s ON b.id = s.bot_id AND s.user_id = %s
|
||||||
WHERE b.owner_id = %s OR s.user_id = %s
|
WHERE b.owner_id = %s
|
||||||
|
OR (s.user_id = %s AND (s.expires_at IS NULL OR s.expires_at > NOW()))
|
||||||
ORDER BY b.created_at DESC
|
ORDER BY b.created_at DESC
|
||||||
""", (user_id, user_id, user_id))
|
""", (user_id, user_id, user_id))
|
||||||
rows = await cursor.fetchall()
|
rows = await cursor.fetchall()
|
||||||
@ -1258,6 +1287,7 @@ async def get_bots(authorization: Optional[str] = Header(None)):
|
|||||||
owner={"id": str(row[6]), "username": row[7]} if row[6] else None,
|
owner={"id": str(row[6]), "username": row[7]} if row[6] else None,
|
||||||
role=row[8] if row[8] else None,
|
role=row[8] if row[8] else None,
|
||||||
shared_at=datetime_to_str(row[9]) if row[9] else None,
|
shared_at=datetime_to_str(row[9]) if row[9] else None,
|
||||||
|
expires_at=row[10].isoformat() if row[10] else None,
|
||||||
description=row[5].get('description') if row[5] else None,
|
description=row[5].get('description') if row[5] else None,
|
||||||
avatar_url=row[5].get('avatar_url') if row[5] else None,
|
avatar_url=row[5].get('avatar_url') if row[5] else None,
|
||||||
created_at=datetime_to_str(row[3]),
|
created_at=datetime_to_str(row[3]),
|
||||||
@ -2823,7 +2853,7 @@ async def get_bot_shares(
|
|||||||
async with pool.connection() as conn:
|
async with pool.connection() as conn:
|
||||||
async with conn.cursor() as cursor:
|
async with conn.cursor() as cursor:
|
||||||
await cursor.execute("""
|
await cursor.execute("""
|
||||||
SELECT s.id, s.bot_id, s.user_id, u.username, u.email, s.role, s.shared_at, su.username
|
SELECT s.id, s.bot_id, s.user_id, u.username, u.email, s.role, s.shared_at, s.expires_at, su.username
|
||||||
FROM bot_shares s
|
FROM bot_shares s
|
||||||
JOIN agent_user u ON s.user_id = u.id
|
JOIN agent_user u ON s.user_id = u.id
|
||||||
LEFT JOIN agent_user su ON s.shared_by = su.id
|
LEFT JOIN agent_user su ON s.shared_by = su.id
|
||||||
@ -2841,7 +2871,8 @@ async def get_bot_shares(
|
|||||||
email=row[4],
|
email=row[4],
|
||||||
role=row[5],
|
role=row[5],
|
||||||
shared_at=row[6].isoformat() if row[6] else "",
|
shared_at=row[6].isoformat() if row[6] else "",
|
||||||
shared_by=row[7] if row[7] is None else str(row[7])
|
expires_at=row[7].isoformat() if row[7] else None,
|
||||||
|
shared_by=row[8] if row[8] is None else str(row[8])
|
||||||
)
|
)
|
||||||
for row in rows
|
for row in rows
|
||||||
]
|
]
|
||||||
@ -2904,12 +2935,13 @@ async def add_bot_share(
|
|||||||
for target_user_id in request.user_ids:
|
for target_user_id in request.user_ids:
|
||||||
try:
|
try:
|
||||||
await cursor.execute("""
|
await cursor.execute("""
|
||||||
INSERT INTO bot_shares (bot_id, user_id, shared_by, role)
|
INSERT INTO bot_shares (bot_id, user_id, shared_by, role, expires_at)
|
||||||
VALUES (%s, %s, %s, %s)
|
VALUES (%s, %s, %s, %s, %s)
|
||||||
ON CONFLICT (bot_id, user_id) DO UPDATE SET
|
ON CONFLICT (bot_id, user_id) DO UPDATE SET
|
||||||
role = EXCLUDED.role,
|
role = EXCLUDED.role,
|
||||||
shared_by = EXCLUDED.shared_by
|
shared_by = EXCLUDED.shared_by,
|
||||||
""", (bot_uuid, target_user_id, user_id, request.role))
|
expires_at = EXCLUDED.expires_at
|
||||||
|
""", (bot_uuid, target_user_id, user_id, request.role, request.expires_at))
|
||||||
added_count += 1
|
added_count += 1
|
||||||
except Exception:
|
except Exception:
|
||||||
pass # 忽略重复的
|
pass # 忽略重复的
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user