dify/api/services/account_education_service.py
非法操作 ef92cb7c65
refactor(api): complete account education boundary (#41153)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-08-25 01:48:12 +00:00

100 lines
3.3 KiB
Python

"""Application service for account education-discount use cases."""
from typing import Protocol
from machinery.context import RequestContext
from machinery.errors import ActiveWorkspaceRequiredError
from services.account_errors import AccountNotFoundError, EducationRateLimitExceededError
from services.account_ports import AccountRepository
from services.entities.account_entities import (
AccountEducationActivation,
AccountEducationAutocomplete,
AccountEducationStatus,
AccountEducationVerification,
)
class AccountEducationRateLimiter(Protocol):
def is_rate_limited(self, key: str, /) -> bool: ...
def increment_rate_limit(self, key: str, /) -> None: ...
class AccountEducationGateway(Protocol):
def verify(self, *, account_id: str) -> AccountEducationVerification: ...
def activate(
self,
*,
account_id: str,
tenant_id: str,
token: str,
institution: str,
role: str,
) -> AccountEducationActivation: ...
def status(self, account_id: str) -> AccountEducationStatus: ...
def autocomplete(self, *, keywords: str, page: int, limit: int) -> AccountEducationAutocomplete: ...
class AccountEducationService:
def __init__(
self,
*,
accounts: AccountRepository,
education: AccountEducationGateway,
verification_rate_limiter: AccountEducationRateLimiter,
activation_rate_limiter: AccountEducationRateLimiter,
) -> None:
self._accounts = accounts
self._education = education
self._verification_rate_limiter = verification_rate_limiter
self._activation_rate_limiter = activation_rate_limiter
def verify(self, context: RequestContext) -> AccountEducationVerification:
account = self._accounts.get(context.account_id)
if account is None:
raise AccountNotFoundError
if self._verification_rate_limiter.is_rate_limited(account.email):
raise EducationRateLimitExceededError
self._verification_rate_limiter.increment_rate_limit(account.email)
return self._education.verify(account_id=account.id)
def activate(
self,
context: RequestContext,
*,
token: str,
institution: str,
role: str,
) -> AccountEducationActivation:
account = self._accounts.get(context.account_id)
if account is None:
raise AccountNotFoundError
if context.active_workspace_id is None:
raise ActiveWorkspaceRequiredError
if self._activation_rate_limiter.is_rate_limited(account.email):
raise EducationRateLimitExceededError
self._activation_rate_limiter.increment_rate_limit(account.email)
return self._education.activate(
account_id=account.id,
tenant_id=context.active_workspace_id,
token=token,
institution=institution,
role=role,
)
def status(self, context: RequestContext) -> AccountEducationStatus:
return self._education.status(context.account_id)
def autocomplete(
self,
context: RequestContext,
*,
keywords: str,
page: int,
limit: int,
) -> AccountEducationAutocomplete:
return self._education.autocomplete(keywords=keywords, page=page, limit=limit)