| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- """方案计划文档管理系统(DMS)后端模块。"""
- from __future__ import annotations
- import logging
- from pathlib import Path
- from flask import Flask
- from dms.api.v1 import api_v1
- from dms.api.v1.blueprint import (
- register_dms_response_headers,
- register_dms_routing_error_handlers,
- )
- from dms.config import (
- load_dms_config,
- resolve_backup_config_path,
- resolve_env_path,
- )
- from dms.extensions import db
- from dms.services.backup_service import BackupEngine, BackupOutcome
- from dms.services.document_relation_service import load_relation_presets
- from dms.services.ui_dictionary_service import load_ui_dictionary_config
- from dms.storage.paths import ensure_storage_directories
- from dms.services.document_converter import create_converter
- logger = logging.getLogger(__name__)
- def init_dms(app: Flask) -> None:
- """初始化独立DMS基础设施并注册 ``/api/v1`` Blueprint。"""
- app.config.from_mapping(load_dms_config())
- app.extensions["dms_ui_dictionaries"] = load_ui_dictionary_config(
- app.config["DMS_UI_DICTIONARY_CONFIG_PATH"]
- )
- app.extensions["dms_relation_presets"] = load_relation_presets(
- app.config["DMS_DOCUMENT_RELATION_PRESET_CONFIG_PATH"]
- )
- app.extensions["dms_document_converter"] = create_converter(app.config)
- db.init_app(app)
- # 导入模型以确保SQLAlchemy metadata完整;不触发数据库连接。
- import dms.models # noqa: F401
- ensure_storage_directories(app.config["DMS_STORAGE_ROOT"])
- app.register_blueprint(api_v1)
- register_dms_routing_error_handlers(app)
- register_dms_response_headers(app)
- backup_engine = BackupEngine(
- storage_root=Path(app.config["DMS_STORAGE_ROOT"]),
- business_timezone=app.config["DMS_BUSINESS_TIMEZONE"],
- database_url=app.config["SQLALCHEMY_DATABASE_URI"],
- backup_config_path=resolve_backup_config_path(),
- env_path=resolve_env_path(),
- )
- app.extensions["dms_backup_engine"] = backup_engine
- backup_engine.start_scheduler(
- lambda outcome: _write_schedule_audit(app, outcome)
- )
- def _write_schedule_audit(app: Flask, outcome: BackupOutcome) -> None:
- """定时备份终态审计落库(无请求上下文,独立短事务)。"""
- from dms.common.enums import AuditAction, AuditResult, AuditTarget
- from dms.models import AuditLog
- try:
- with app.app_context():
- db.session.add(
- AuditLog(
- username="system",
- action_type=AuditAction.BACKUP_CREATE.value,
- target_type=AuditTarget.BACKUP.value,
- target_id=0,
- target_name=outcome.type,
- operation_result=(
- AuditResult.SUCCESS.value
- if outcome.success
- else AuditResult.FAILURE.value
- ),
- failure_reason=(
- None
- if outcome.success or outcome.error is None
- else outcome.error[:1000]
- ),
- operation_detail={
- "type": outcome.type,
- "trigger": outcome.trigger,
- "backupId": outcome.backup_id,
- },
- )
- )
- db.session.commit()
- except Exception: # noqa: BLE001 - 审计失败不否定已触发的备份
- logger.warning("定时备份审计写入失败", exc_info=True)
- with app.app_context():
- db.session.rollback()
- __all__ = ["init_dms"]
|