from __future__ import annotations import logging import time from dataclasses import dataclass, field from typing import Any logger = logging.getLogger(__name__) @dataclass class ApprovalRequest: id: str initiator_id: str action: str description: str created_at: float = field(default_factory=time.time) status: str = "pending" class QQBotApprovalManager: def __init__(self, config: dict, account_id: str = "default"): self._config = config self._account_id = account_id self._requests: dict[str, ApprovalRequest] = {} @property def enabled(self) -> bool: approval_cfg = self._get_approval_config() return approval_cfg.get("enabled", False) in (True, "auto") @property def approvers(self) -> list[str]: return self._get_approval_config().get("approvers", []) def is_approver(self, peer_id: str) -> bool: return peer_id in self.approvers def create_request(self, initiator_id: str, action: str, description: str) -> ApprovalRequest: import uuid req_id = uuid.uuid4().hex[:12] req = ApprovalRequest( id=req_id, initiator_id=initiator_id, action=action, description=description, ) self._requests[req_id] = req logger.info( "Approval request created: id=%s, initiator=%s, action=%s", req_id, initiator_id, action, ) return req def handle_decision(self, request_id: str, decision: str) -> ApprovalRequest | None: req = self._requests.get(request_id) if req is None: return None if decision in ("allow-once", "allow-always", "always"): req.status = "approved" elif decision == "deny": req.status = "denied" else: req.status = "unknown" logger.info( "Approval decision: id=%s, decision=%s, status=%s", request_id, decision, req.status, ) return req def get_request(self, request_id: str) -> ApprovalRequest | None: return self._requests.get(request_id) def _get_approval_config(self) -> dict: channel_cfg = self._config.get("channels", {}).get("qqbot", {}) accounts = channel_cfg.get("accounts", {}) account = accounts.get(self._account_id, {}) return account.get("exec_approvals", {})