修复(权限管理):统一 PM 系统导航与权限校验
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
from typing import Sequence
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import Literal, Sequence
|
||||
|
||||
from sqlalchemy import delete, func, or_, select, update
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
@@ -11,12 +12,14 @@ from app.core.config import (
|
||||
PROTECTED_ADMIN_DEFAULT_PASSWORD,
|
||||
PROTECTED_ADMIN_EMAIL,
|
||||
PROTECTED_ADMIN_FULL_NAME,
|
||||
settings,
|
||||
)
|
||||
from app.core.security import hash_password
|
||||
from app.models.audit_log import AuditLog
|
||||
from app.models.permission_access_log import PermissionAccessLog
|
||||
from app.models.study_member import StudyMember
|
||||
from app.models.user import User, UserStatus
|
||||
from app.models.user_login_session import UserLoginSession
|
||||
from app.schemas.user import UserCreate, UserRegisterRequest, UserUpdate
|
||||
|
||||
|
||||
@@ -81,7 +84,13 @@ async def update_user(db: AsyncSession, user: User, user_in: UserUpdate) -> User
|
||||
return user
|
||||
|
||||
|
||||
def _apply_user_filters(query, *, keyword: str | None = None, status: UserStatus | None = None):
|
||||
def _apply_user_filters(
|
||||
query,
|
||||
*,
|
||||
keyword: str | None = None,
|
||||
status: UserStatus | None = None,
|
||||
login_status: Literal["ONLINE", "OFFLINE"] | None = None,
|
||||
):
|
||||
if keyword:
|
||||
pattern = f"%{keyword.strip()}%"
|
||||
query = query.where(
|
||||
@@ -93,6 +102,18 @@ def _apply_user_filters(query, *, keyword: str | None = None, status: UserStatus
|
||||
)
|
||||
if status is not None:
|
||||
query = query.where(User.status == status)
|
||||
if login_status is not None:
|
||||
cutoff = datetime.now(timezone.utc) - timedelta(seconds=settings.USER_SESSION_ONLINE_SECONDS)
|
||||
has_online_session = (
|
||||
select(UserLoginSession.id)
|
||||
.where(
|
||||
UserLoginSession.user_id == User.id,
|
||||
UserLoginSession.ended_at.is_(None),
|
||||
UserLoginSession.last_seen_at >= cutoff,
|
||||
)
|
||||
.exists()
|
||||
)
|
||||
query = query.where(has_online_session if login_status == "ONLINE" else ~has_online_session)
|
||||
return query
|
||||
|
||||
|
||||
@@ -103,8 +124,9 @@ async def list_users(
|
||||
*,
|
||||
keyword: str | None = None,
|
||||
status: UserStatus | None = None,
|
||||
login_status: Literal["ONLINE", "OFFLINE"] | None = None,
|
||||
) -> Sequence[User]:
|
||||
query = _apply_user_filters(select(User), keyword=keyword, status=status)
|
||||
query = _apply_user_filters(select(User), keyword=keyword, status=status, login_status=login_status)
|
||||
result = await db.execute(query.order_by(User.created_at.desc()).offset(skip).limit(limit))
|
||||
return result.scalars().all()
|
||||
|
||||
@@ -114,8 +136,14 @@ async def count_users(
|
||||
*,
|
||||
keyword: str | None = None,
|
||||
status: UserStatus | None = None,
|
||||
login_status: Literal["ONLINE", "OFFLINE"] | None = None,
|
||||
) -> int:
|
||||
query = _apply_user_filters(select(func.count()).select_from(User), keyword=keyword, status=status)
|
||||
query = _apply_user_filters(
|
||||
select(func.count()).select_from(User),
|
||||
keyword=keyword,
|
||||
status=status,
|
||||
login_status=login_status,
|
||||
)
|
||||
result = await db.execute(query)
|
||||
return int(result.scalar_one() or 0)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user