refactor: 统一插件迁移与 Passkey 模块命名

This commit is contained in:
jxxghp
2026-08-27 20:38:55 +08:00
parent e82ce8447c
commit f888aab2c9
12 changed files with 94 additions and 103 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ from app.application.security.auth import (
AuthService,
AuthUserRepository,
)
from app.application.security.passkeys import PasskeyRepository, PasskeyService
from app.application.security.passkey import PasskeyRepository, PasskeyService
from app.application.security.user import (
AsyncUnitOfWork,
UserRepository,
+1 -3
View File
@@ -22,12 +22,10 @@ from app.application.security.otp import OtpUtils
from app.application.security.passkey import (
PasskeyChallengeStore,
PassKeyHelper,
PasskeyService,
PassKeyRegistrationOriginMismatchError,
PassKeyRegistrationVerificationError,
)
from app.application.security.passkeys import (
PasskeyService,
)
from app.application.security.token import verify_password
from app.application.security.user import (
UserService,
@@ -1,4 +1,4 @@
"""存量插件来源身份的一次性启动迁移。"""
"""存量插件来源身份的幂等启动迁移。"""
from __future__ import annotations
+71 -1
View File
@@ -7,7 +7,7 @@ import json
import secrets
import threading
from dataclasses import dataclass
from typing import Any, Dict, List, Literal, Optional, Tuple
from typing import Any, Dict, List, Literal, Optional, Protocol, Tuple
from urllib.parse import urlparse
from webauthn import (
@@ -451,3 +451,73 @@ class PassKeyHelper:
except Exception as e:
logger.error(f"验证认证响应失败: {e}")
return False, credential_current_sign_count
class PasskeyRepository(Protocol):
"""PassKey 用例需要的最小同步数据端口。"""
def list(self) -> list[Any]:
"""列出全部启用凭证。"""
def list_by_user_id(self, user_id: int) -> list[Any]:
"""列出指定用户凭证。"""
def get_by_credential_id(self, credential_id: str) -> Optional[Any]:
"""按凭证 ID 查找凭证。"""
def create(self, payload: dict[str, Any]) -> Any:
"""创建凭证。"""
def update_last_used(self, passkey: Any, sign_count: int) -> bool:
"""更新凭证使用计数。"""
def delete_by_id(self, passkey_id: int, user_id: int) -> bool:
"""删除用户凭证。"""
class PasskeyService:
"""编排 PassKey 凭证生命周期。"""
def __init__(self, repository: PasskeyRepository) -> None:
"""注入 PassKey 数据端口。"""
self._repository = repository
def list(self) -> list[Any]:
"""列出全部启用凭证。"""
return self._repository.list()
def list_by_user_id(self, user_id: int) -> list[Any]:
"""列出指定用户凭证。"""
return self._repository.list_by_user_id(user_id)
def get_by_credential_id(self, credential_id: str) -> Optional[Any]:
"""按凭证 ID 查找凭证。"""
return self._repository.get_by_credential_id(credential_id)
def create(self, payload: dict[str, Any]) -> Any:
"""创建凭证。"""
return self._repository.create(payload)
def update_last_used(self, passkey: Any, sign_count: int) -> bool:
"""更新凭证使用计数。"""
return self._repository.update_last_used(passkey, sign_count)
def delete_by_id(self, passkey_id: int, user_id: int) -> bool:
"""删除用户凭证。"""
return self._repository.delete_by_id(passkey_id, user_id)
_configured_passkey_service: Optional[PasskeyService] = None
def configure_passkey_service(service: PasskeyService) -> None:
"""由启动组合根登记 PassKey 应用服务。"""
global _configured_passkey_service
_configured_passkey_service = service
def get_configured_passkey_service() -> PasskeyService:
"""返回启动阶段登记的 PassKey 应用服务。"""
if _configured_passkey_service is None:
raise RuntimeError("PassKey 服务尚未配置")
return _configured_passkey_service
-75
View File
@@ -1,75 +0,0 @@
"""PassKey 认证凭证应用服务。"""
from __future__ import annotations
from typing import Any, Optional, Protocol
class PasskeyRepository(Protocol):
"""PassKey 用例需要的最小同步数据端口。"""
def list(self) -> list[Any]:
"""列出全部启用凭证。"""
def list_by_user_id(self, user_id: int) -> list[Any]:
"""列出指定用户凭证。"""
def get_by_credential_id(self, credential_id: str) -> Optional[Any]:
"""按凭证 ID 查找凭证。"""
def create(self, payload: dict[str, Any]) -> Any:
"""创建凭证。"""
def update_last_used(self, passkey: Any, sign_count: int) -> bool:
"""更新凭证使用计数。"""
def delete_by_id(self, passkey_id: int, user_id: int) -> bool:
"""删除用户凭证。"""
class PasskeyService:
"""编排 PassKey 凭证生命周期。"""
def __init__(self, repository: PasskeyRepository) -> None:
"""注入 PassKey 数据端口。"""
self._repository = repository
def list(self) -> list[Any]:
"""列出全部启用凭证。"""
return self._repository.list()
def list_by_user_id(self, user_id: int) -> list[Any]:
"""列出指定用户凭证。"""
return self._repository.list_by_user_id(user_id)
def get_by_credential_id(self, credential_id: str) -> Optional[Any]:
"""按凭证 ID 查找凭证。"""
return self._repository.get_by_credential_id(credential_id)
def create(self, payload: dict[str, Any]) -> Any:
"""创建凭证。"""
return self._repository.create(payload)
def update_last_used(self, passkey: Any, sign_count: int) -> bool:
"""更新凭证使用计数。"""
return self._repository.update_last_used(passkey, sign_count)
def delete_by_id(self, passkey_id: int, user_id: int) -> bool:
"""删除用户凭证。"""
return self._repository.delete_by_id(passkey_id, user_id)
_configured_passkey_service: PasskeyService | None = None
def configure_passkey_service(service: PasskeyService) -> None:
"""由启动组合根登记 PassKey 应用服务。"""
global _configured_passkey_service
_configured_passkey_service = service
def get_configured_passkey_service() -> PasskeyService:
"""返回启动阶段登记的 PassKey 应用服务。"""
if _configured_passkey_service is None:
raise RuntimeError("PassKey 服务尚未配置")
return _configured_passkey_service
+1 -1
View File
@@ -89,7 +89,7 @@ from app.application.outbox import (
)
from app.application.plugin.runtime import configure_plugin_runtime
from app.application.security.auth import AuthService, build_superuser_token_payload, configure_auth_service
from app.application.security.passkeys import PasskeyService, configure_passkey_service
from app.application.security.passkey import PasskeyService, configure_passkey_service
from app.application.security.url import close_image_proxy_block_log_coalescer
from app.application.security.user import configure_user_lookups
from app.application.security.userconfig import (
+1 -1
View File
@@ -30,7 +30,7 @@ from app.application.plugin.identity import (
TrustedPluginSourceType,
normalize_physical_plugin_id,
)
from app.application.plugin.identity_migration import (
from app.application.plugin.migration import (
PluginIdentityMigrationService,
configure_plugin_identity_migration,
get_plugin_identity_migration,
+1 -1
View File
@@ -69,7 +69,7 @@ MoviePilot V3 已经形成较清晰的模块化单体:`foundation`、`domain`
| 指标 | 当前值 | 解释 |
|---|---:|---|
| 宿主 Python 模块 / 内部依赖边 | 843 / 6,883 | `dependency-baseline.json` 当前快照 |
| 宿主 Python 模块 / 内部依赖边 | 842 / 6,882 | `dependency-baseline.json` 当前快照 |
| 非平凡 SCC | 2 | 新增 Chain 包根环;另一个是隔离的 29 模块 TMDB 移植包环 |
| 跨层 DB 边界债务 | 0 | Application、Chain、API、Agent、Runtime、Workflow 到 DB 的受控债务均为零 |
| Model/Oper 事务债务 | 0 | 自建 Session、自动事务装饰器、直接 commit/rollback 等基线均为零 |
+2 -2
View File
@@ -704,8 +704,8 @@ flowchart LR
| 指标 | 当前值 |
|---|---:|
| Python 模块 | 843 |
| 内部导入边 | 6,883 |
| Python 模块 | 842 |
| 内部导入边 | 6,882 |
| 非平凡 SCC | 2`ARCH-107` 临时 Chain 包根环;精确 containment 的 TMDB 移植包环) |
| Direct egress | 6612 条待迁移债务,54 条精确 containment |
| Module Contract V2 spec | 217(其中 215 个进入 `run_module` 观察面) |
+1 -1
View File
@@ -69,7 +69,7 @@ to make the directory tree look symmetrical.
| `app/application/agentdata.py` | Named Agent data ports; canonical Agent consumers use `get_agent_*_port()` and do not alias legacy proxies to Oper classes |
| `app/application/outbox.py` | Durable intent and Outbox repository/dispatcher contracts for post-commit side effects |
| `app/application/transfer_execution.py` | Durable transfer execution contracts: stable operation identity, step/checkpoint state, retry/manual-review commands and terminal-settlement DTOs; contains no SQLAlchemy or external I/O |
| `app/application/plugin/` | Plugin market catalog, installation command, installed-plugin identity contract, runtime port, folder operations and dynamic-route use cases; filenames remain single words (`catalog.py`, `identity.py`, `install.py`, `runtime.py`, `folders.py`, `routes.py`) |
| `app/application/plugin/` | Plugin market catalog, installation command, installed-plugin identity contract and startup migration, runtime port, folder operations and dynamic-route use cases; filenames remain single words (`catalog.py`, `identity.py`, `migration.py`, `install.py`, `runtime.py`, `folders.py`, `routes.py`) |
| `app/application/server/` | MoviePilot Server reporting and sharing use cases; local data readers and transport callbacks are injected by startup |
| `app/application/site/` | Configured site catalog, authentication level and index-resource capability; the generated extension and its data bundle stay together here |
| `app/application/messaging/` | Message rendering/routing, interactions and the Agent-to-message bridge: `ingress.py` owns the single channel-to-host loopback boundary; `interaction.py` shared interaction contracts and view helpers; `router.py` unified interaction priority and callback dispatch; `site.py`/`subscribe.py`/`skill.py` per-command sessions, input parsing and views; `media.py` media interaction state while the business workflow stays in `MediaInteractionChain`; `plugin.py` plugin input capture and plugin button callbacks; `agent.py` agent choice state, callback protocol and WebAgent bridge; `message.py` notification rendering, templates and queue. Not a public SDK recommended for direct plugin use |
+13 -15
View File
@@ -1441,8 +1441,8 @@
"runtime_only": true
}
},
"edge_count": 6883,
"edge_sha256": "f44ae63f222eda2fc1b8ce805ab5138550a560bef6c266e3f2fae6338a243cd2",
"edge_count": 6882,
"edge_sha256": "602a73df30503fec4f4f01e28020222497cdadcad731dfedca40a3e4b1133c0d",
"edges": [
"app -> app.runtime",
"app -> app.runtime.compat",
@@ -3003,7 +3003,7 @@
"app.api.dependencies.auth -> app.application",
"app.api.dependencies.auth -> app.application.security",
"app.api.dependencies.auth -> app.application.security.auth",
"app.api.dependencies.auth -> app.application.security.passkeys",
"app.api.dependencies.auth -> app.application.security.passkey",
"app.api.dependencies.auth -> app.application.security.user",
"app.api.dependencies.auth -> app.schemas",
"app.api.dependencies.auth -> app.schemas.token",
@@ -3468,7 +3468,6 @@
"app.api.endpoints.mfa -> app.application.security.auth",
"app.api.endpoints.mfa -> app.application.security.otp",
"app.api.endpoints.mfa -> app.application.security.passkey",
"app.api.endpoints.mfa -> app.application.security.passkeys",
"app.api.endpoints.mfa -> app.application.security.token",
"app.api.endpoints.mfa -> app.application.security.user",
"app.api.endpoints.mfa -> app.runtime",
@@ -4215,12 +4214,6 @@
"app.application.plugin.identity -> app.application",
"app.application.plugin.identity -> app.application.plugin",
"app.application.plugin.identity -> app.application.plugin.declaration",
"app.application.plugin.identity_migration -> app.application",
"app.application.plugin.identity_migration -> app.application.plugin",
"app.application.plugin.identity_migration -> app.application.plugin.identity",
"app.application.plugin.identity_migration -> app.application.plugin.source",
"app.application.plugin.identity_migration -> app.runtime",
"app.application.plugin.identity_migration -> app.runtime.log",
"app.application.plugin.install -> app.application",
"app.application.plugin.install -> app.application.plugin",
"app.application.plugin.install -> app.application.plugin.admission",
@@ -4239,6 +4232,12 @@
"app.application.plugin.inventory -> app.application.plugin.source",
"app.application.plugin.inventory -> app.foundation",
"app.application.plugin.inventory -> app.foundation.environment",
"app.application.plugin.migration -> app.application",
"app.application.plugin.migration -> app.application.plugin",
"app.application.plugin.migration -> app.application.plugin.identity",
"app.application.plugin.migration -> app.application.plugin.source",
"app.application.plugin.migration -> app.runtime",
"app.application.plugin.migration -> app.runtime.log",
"app.application.plugin.recovery -> app.application",
"app.application.plugin.recovery -> app.application.plugin",
"app.application.plugin.recovery -> app.application.plugin.install",
@@ -7935,7 +7934,7 @@
"app.startup.initializers.modules -> app.application.plugin.transaction",
"app.startup.initializers.modules -> app.application.security",
"app.startup.initializers.modules -> app.application.security.auth",
"app.startup.initializers.modules -> app.application.security.passkeys",
"app.startup.initializers.modules -> app.application.security.passkey",
"app.startup.initializers.modules -> app.application.security.url",
"app.startup.initializers.modules -> app.application.security.user",
"app.startup.initializers.modules -> app.application.security.userconfig",
@@ -8046,10 +8045,10 @@
"app.startup.initializers.plugins -> app.application.plugin.data",
"app.startup.initializers.plugins -> app.application.plugin.gateway",
"app.startup.initializers.plugins -> app.application.plugin.identity",
"app.startup.initializers.plugins -> app.application.plugin.identity_migration",
"app.startup.initializers.plugins -> app.application.plugin.install",
"app.startup.initializers.plugins -> app.application.plugin.inventory",
"app.startup.initializers.plugins -> app.application.plugin.lifecycle",
"app.startup.initializers.plugins -> app.application.plugin.migration",
"app.startup.initializers.plugins -> app.application.plugin.recovery",
"app.startup.initializers.plugins -> app.application.plugin.routes",
"app.startup.initializers.plugins -> app.application.plugin.runtime",
@@ -8328,7 +8327,7 @@
"app.workflow.actions.transfer_file -> app.workflow",
"app.workflow.actions.transfer_file -> app.workflow.actions"
],
"module_count": 843,
"module_count": 842,
"modules": [
"app",
"app.adapters",
@@ -8627,10 +8626,10 @@
"app.application.plugin.folders",
"app.application.plugin.gateway",
"app.application.plugin.identity",
"app.application.plugin.identity_migration",
"app.application.plugin.install",
"app.application.plugin.inventory",
"app.application.plugin.lifecycle",
"app.application.plugin.migration",
"app.application.plugin.recovery",
"app.application.plugin.routes",
"app.application.plugin.runtime",
@@ -8647,7 +8646,6 @@
"app.application.security.cookie",
"app.application.security.otp",
"app.application.security.passkey",
"app.application.security.passkeys",
"app.application.security.token",
"app.application.security.twofactor",
"app.application.security.url",
@@ -18,7 +18,7 @@ from app.application.plugin.identity import (
PluginPayloadSourceType,
TrustedPluginSourceType,
)
from app.application.plugin.identity_migration import PluginIdentityMigrationService
from app.application.plugin.migration import PluginIdentityMigrationService
from app.application.plugin.source import (
CandidateInventory,
LocalCandidateRead,