feat(weibo): 增加工作台独占与快捷操作
This commit is contained in:
@@ -7,6 +7,7 @@ import os
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from loguru import logger
|
||||
from sqlalchemy import or_
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy.orm import Session, defer
|
||||
|
||||
from core.weibo import WeiboAuthError, WeiboError, WeiboExchangeUncertainError
|
||||
@@ -94,6 +95,7 @@ def _apply_account_filters(
|
||||
query,
|
||||
*,
|
||||
search: str,
|
||||
tag: str,
|
||||
bind_status: str,
|
||||
enabled: bool | None,
|
||||
):
|
||||
@@ -109,6 +111,9 @@ def _apply_account_filters(
|
||||
WeiboAccount.remark.ilike(pattern),
|
||||
)
|
||||
)
|
||||
tag_value = _query_str(tag)
|
||||
if tag_value:
|
||||
query = query.filter(WeiboAccount.tag == tag_value)
|
||||
if isinstance(enabled, bool):
|
||||
query = query.filter(WeiboAccount.is_enabled.is_(enabled))
|
||||
bind_value = _query_str(bind_status)
|
||||
@@ -192,6 +197,7 @@ def _record_audit_safely(
|
||||
@router.get("/accounts")
|
||||
def list_accounts(
|
||||
search: str = Query(""),
|
||||
tag: str = Query(""),
|
||||
bind_status: str = Query(""),
|
||||
enabled: bool | None = Query(None),
|
||||
page: int = Query(1, ge=1),
|
||||
@@ -205,6 +211,7 @@ def list_accounts(
|
||||
query = _apply_account_filters(
|
||||
db.query(WeiboAccount),
|
||||
search=search,
|
||||
tag=tag,
|
||||
bind_status=bind_status,
|
||||
enabled=enabled,
|
||||
)
|
||||
@@ -214,6 +221,7 @@ def list_accounts(
|
||||
@router.get("/workbench/accounts")
|
||||
def list_workbench_accounts(
|
||||
search: str = Query(""),
|
||||
tag: str = Query(""),
|
||||
bind_status: str = Query(""),
|
||||
enabled: bool | None = Query(None),
|
||||
page: int = Query(1, ge=1),
|
||||
@@ -235,6 +243,7 @@ def list_workbench_accounts(
|
||||
query = _apply_account_filters(
|
||||
query,
|
||||
search=search,
|
||||
tag=tag,
|
||||
bind_status=bind_status,
|
||||
enabled=enabled,
|
||||
)
|
||||
@@ -244,6 +253,7 @@ def list_workbench_accounts(
|
||||
@router.get("/workbench/pool")
|
||||
def list_workbench_pool(
|
||||
search: str = Query(""),
|
||||
tag: str = Query(""),
|
||||
page: int = Query(1, ge=1),
|
||||
page_size: int = Query(20, ge=1, le=200),
|
||||
db: Session = Depends(get_db),
|
||||
@@ -252,18 +262,42 @@ def list_workbench_pool(
|
||||
"""查看可加入当前用户工作台、且尚未加入的账号池账号。"""
|
||||
|
||||
_require_weibo_perm(current, "weibo:workbench")
|
||||
selected = db.query(WeiboWorkbenchAccount.account_id).filter(
|
||||
WeiboWorkbenchAccount.user_id == current.id
|
||||
)
|
||||
occupied = db.query(WeiboWorkbenchAccount.account_id)
|
||||
query = _apply_account_filters(
|
||||
db.query(WeiboAccount).filter(WeiboAccount.id.not_in(selected)),
|
||||
db.query(WeiboAccount).filter(WeiboAccount.id.not_in(occupied)),
|
||||
search=search,
|
||||
tag=tag,
|
||||
bind_status="",
|
||||
enabled=True,
|
||||
)
|
||||
return _paginated_accounts(query, page=page, page_size=page_size)
|
||||
|
||||
|
||||
@router.get("/workbench/tags")
|
||||
def list_workbench_tags(
|
||||
db: Session = Depends(get_db),
|
||||
current: User = Depends(get_current_user),
|
||||
):
|
||||
"""返回当前用户工作台中已有的标签。"""
|
||||
|
||||
_require_weibo_perm(current, "weibo:workbench")
|
||||
rows = (
|
||||
db.query(WeiboAccount.tag)
|
||||
.join(
|
||||
WeiboWorkbenchAccount,
|
||||
WeiboWorkbenchAccount.account_id == WeiboAccount.id,
|
||||
)
|
||||
.filter(
|
||||
WeiboWorkbenchAccount.user_id == current.id,
|
||||
WeiboAccount.tag != "",
|
||||
)
|
||||
.distinct()
|
||||
.order_by(WeiboAccount.tag.asc())
|
||||
.all()
|
||||
)
|
||||
return {"tags": [tag for (tag,) in rows if tag]}
|
||||
|
||||
|
||||
@router.post("/workbench/accounts")
|
||||
def add_workbench_accounts(
|
||||
req: WeiboWorkbenchAccountsRequest,
|
||||
@@ -287,6 +321,20 @@ def add_workbench_accounts(
|
||||
missing = sorted(set(account_ids) - existing_ids)
|
||||
if missing:
|
||||
raise HTTPException(status_code=404, detail=f"账号不存在: {missing}")
|
||||
taken = {
|
||||
account_id
|
||||
for (account_id,) in db.query(WeiboWorkbenchAccount.account_id)
|
||||
.filter(
|
||||
WeiboWorkbenchAccount.user_id != current.id,
|
||||
WeiboWorkbenchAccount.account_id.in_(account_ids),
|
||||
)
|
||||
.all()
|
||||
}
|
||||
if taken:
|
||||
raise HTTPException(
|
||||
status_code=409,
|
||||
detail="部分账号已在其他人的工作台中使用,请先让原使用人移出",
|
||||
)
|
||||
selected_ids = {
|
||||
account_id
|
||||
for (account_id,) in db.query(WeiboWorkbenchAccount.account_id)
|
||||
@@ -303,7 +351,14 @@ def add_workbench_accounts(
|
||||
if account_id not in selected_ids
|
||||
]
|
||||
)
|
||||
db.commit()
|
||||
try:
|
||||
db.commit()
|
||||
except IntegrityError as exc:
|
||||
db.rollback()
|
||||
raise HTTPException(
|
||||
status_code=409,
|
||||
detail="账号已被其他工作台占用,请刷新后重试",
|
||||
) from exc
|
||||
_record_audit_safely(
|
||||
db,
|
||||
current,
|
||||
@@ -379,6 +434,24 @@ def batch_tag_accounts(
|
||||
return {"updated": len(accounts), "tag": tag, "success": True}
|
||||
|
||||
|
||||
@router.get("/accounts/tags")
|
||||
def list_account_tags(
|
||||
db: Session = Depends(get_db),
|
||||
current: User = Depends(get_current_user),
|
||||
):
|
||||
"""返回全局账号池已有的标签。"""
|
||||
|
||||
_require_weibo_perm(current, "weibo:view")
|
||||
rows = (
|
||||
db.query(WeiboAccount.tag)
|
||||
.filter(WeiboAccount.tag != "")
|
||||
.distinct()
|
||||
.order_by(WeiboAccount.tag.asc())
|
||||
.all()
|
||||
)
|
||||
return {"tags": [tag for (tag,) in rows if tag]}
|
||||
|
||||
|
||||
@router.get("/accounts/{account_id}", response_model=WeiboAccountOut)
|
||||
def get_account(
|
||||
account_id: int,
|
||||
@@ -482,6 +555,8 @@ def import_cookies(
|
||||
req.text,
|
||||
req.tag,
|
||||
WEIBO_DEFAULT_ACTIVITY,
|
||||
req.update_existing,
|
||||
current.id,
|
||||
)
|
||||
typed_errors = [
|
||||
WeiboImportError(line=item.line, message=item.message) for item in errors
|
||||
@@ -499,13 +574,13 @@ def import_cookies(
|
||||
"errors": len(errors),
|
||||
},
|
||||
)
|
||||
message = f"成功导入/更新 {len(accounts)} 个微博账号"
|
||||
message = f"成功导入 {len(accounts)} 个微博账号"
|
||||
if errors:
|
||||
message += f",失败 {len(errors)} 条"
|
||||
if skipped:
|
||||
message += f",跳过 {skipped} 条重复"
|
||||
return WeiboImportResult(
|
||||
success=bool(accounts),
|
||||
success=bool(accounts) or (skipped > 0 and not errors),
|
||||
message=message,
|
||||
count=len(accounts),
|
||||
skipped=skipped,
|
||||
|
||||
Reference in New Issue
Block a user