feat: 统一生产初始化流程并保护系统管理员

This commit is contained in:
Cheng Zhou
2026-03-27 17:17:32 +08:00
parent f2f856ea24
commit a67991740e
14 changed files with 492 additions and 10 deletions
+8
View File
@@ -107,6 +107,7 @@ async def delete(db: AsyncSession, study_id: uuid.UUID) -> None:
from app.models.finance_contract import FinanceContract
from app.models.finance_special import FinanceSpecial
from app.models.contract_fee import ContractFee
from app.models.contract_fee_payment import ContractFeePayment
from app.models.special_expense import SpecialExpense
from app.models.milestone import Milestone
from app.models.document import Document
@@ -157,6 +158,13 @@ async def delete(db: AsyncSession, study_id: uuid.UUID) -> None:
# 9. 删除财务相关
await db.execute(sa_delete(SpecialExpense).where(SpecialExpense.project_id == study_id))
await db.execute(
sa_delete(ContractFeePayment).where(
ContractFeePayment.contract_fee_id.in_(
select(ContractFee.id).where(ContractFee.project_id == study_id)
)
)
)
await db.execute(sa_delete(ContractFee).where(ContractFee.project_id == study_id))
await db.execute(sa_delete(FinanceSpecial).where(FinanceSpecial.study_id == study_id))
await db.execute(sa_delete(FinanceContract).where(FinanceContract.study_id == study_id))
+19 -5
View File
@@ -4,6 +4,12 @@ from typing import Sequence
from sqlalchemy import delete, func, select, update
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.config import (
PROTECTED_ADMIN_DEFAULT_PASSWORD,
PROTECTED_ADMIN_DEPARTMENT,
PROTECTED_ADMIN_EMAIL,
PROTECTED_ADMIN_FULL_NAME,
)
from app.core.security import hash_password
from app.models.study_member import StudyMember
from app.models.user import User, UserRole, UserStatus
@@ -15,6 +21,14 @@ async def get_by_email(db: AsyncSession, email: str) -> User | None:
return result.scalar_one_or_none()
def is_protected_admin_email(email: str | None) -> bool:
return (email or "").strip().lower() == PROTECTED_ADMIN_EMAIL
def is_protected_admin_user(user: User | None) -> bool:
return user is not None and is_protected_admin_email(user.email)
async def get_by_id(db: AsyncSession, user_id: uuid.UUID) -> User | None:
result = await db.execute(select(User).where(User.id == user_id))
return result.scalar_one_or_none()
@@ -90,17 +104,17 @@ async def list_users_by_status(
return result.scalars().all()
async def ensure_admin_exists(db: AsyncSession, *, default_password: str = "admin123") -> None:
result = await db.execute(select(User).where(User.role == UserRole.ADMIN))
async def ensure_admin_exists(db: AsyncSession, *, default_password: str = PROTECTED_ADMIN_DEFAULT_PASSWORD) -> None:
result = await db.execute(select(User).where(User.email == PROTECTED_ADMIN_EMAIL))
admin = result.scalar_one_or_none()
if admin:
return
new_admin = User(
email="admin@example.com",
email=PROTECTED_ADMIN_EMAIL,
password_hash=hash_password(default_password),
full_name="System Admin",
full_name=PROTECTED_ADMIN_FULL_NAME,
role=UserRole.ADMIN,
department="SYSTEM",
department=PROTECTED_ADMIN_DEPARTMENT,
status=UserStatus.ACTIVE,
)
db.add(new_admin)