mirror of https://github.com/kortix-ai/suna.git
165 lines
6.2 KiB
Python
165 lines
6.2 KiB
Python
from typing import List, Optional, Dict, Any
|
|
from uuid import UUID
|
|
from ..protocols import ProfileRepository, ExternalUserIdGeneratorService, MCPQualifiedNameService, ProfileConfigurationService, ConnectionStatusService, Logger
|
|
from ..domain.entities import Profile
|
|
from ..domain.value_objects import ExternalUserId, AppSlug, ProfileName, EncryptedConfig, ConfigHash
|
|
from ..domain.exceptions import ProfileNotFoundError, ProfileAlreadyExistsError
|
|
import json
|
|
|
|
|
|
class ProfileService:
|
|
def __init__(
|
|
self,
|
|
profile_repo: ProfileRepository,
|
|
external_user_id_service: ExternalUserIdGeneratorService,
|
|
mcp_qualified_name_service: MCPQualifiedNameService,
|
|
profile_config_service: ProfileConfigurationService,
|
|
connection_status_service: ConnectionStatusService,
|
|
logger: Logger
|
|
):
|
|
self._profile_repo = profile_repo
|
|
self._external_user_id_service = external_user_id_service
|
|
self._mcp_qualified_name_service = mcp_qualified_name_service
|
|
self._profile_config_service = profile_config_service
|
|
self._connection_status_service = connection_status_service
|
|
self._logger = logger
|
|
|
|
async def create_profile(
|
|
self,
|
|
account_id: UUID,
|
|
profile_name: str,
|
|
app_slug: str,
|
|
app_name: str,
|
|
description: Optional[str] = None,
|
|
is_default: bool = False,
|
|
oauth_app_id: Optional[str] = None,
|
|
enabled_tools: Optional[List[str]] = None,
|
|
external_user_id: Optional[str] = None
|
|
) -> Profile:
|
|
app_slug_vo = AppSlug(app_slug)
|
|
profile_name_vo = ProfileName(profile_name)
|
|
|
|
if external_user_id:
|
|
external_user_id_vo = ExternalUserId(external_user_id)
|
|
else:
|
|
external_user_id_vo = self._external_user_id_service.generate(
|
|
str(account_id), app_slug_vo, profile_name_vo
|
|
)
|
|
|
|
mcp_qualified_name = self._mcp_qualified_name_service.generate(app_slug_vo)
|
|
|
|
config = {
|
|
"app_slug": app_slug,
|
|
"app_name": app_name,
|
|
"external_user_id": external_user_id_vo.value,
|
|
"oauth_app_id": oauth_app_id,
|
|
"enabled_tools": enabled_tools or [],
|
|
"description": description
|
|
}
|
|
|
|
if not self._profile_config_service.validate_config(config):
|
|
raise ValueError("Invalid profile configuration")
|
|
|
|
config_json = json.dumps(config)
|
|
|
|
profile = Profile(
|
|
profile_id=UUID(int=0),
|
|
account_id=account_id,
|
|
mcp_qualified_name=mcp_qualified_name,
|
|
profile_name=profile_name_vo,
|
|
display_name=profile_name,
|
|
encrypted_config=EncryptedConfig("placeholder"),
|
|
config_hash=ConfigHash.from_config(config_json),
|
|
app_slug=app_slug_vo,
|
|
app_name=app_name,
|
|
external_user_id=external_user_id_vo,
|
|
enabled_tools=enabled_tools or [],
|
|
is_default=is_default
|
|
)
|
|
|
|
if is_default:
|
|
await self._profile_repo.set_default(account_id, profile.profile_id, mcp_qualified_name)
|
|
|
|
created_profile = await self._profile_repo.create(profile)
|
|
self._logger.info(f"Created profile {created_profile.profile_id} for app {app_slug}")
|
|
|
|
return created_profile
|
|
|
|
async def get_profile(self, account_id: UUID, profile_id: UUID) -> Optional[Profile]:
|
|
profile = await self._profile_repo.get_by_id(account_id, profile_id)
|
|
if profile:
|
|
return await self._connection_status_service.update_connection_status(profile)
|
|
return None
|
|
|
|
async def get_profiles(
|
|
self,
|
|
account_id: UUID,
|
|
app_slug: Optional[str] = None,
|
|
is_active: Optional[bool] = None
|
|
) -> List[Profile]:
|
|
app_slug_vo = AppSlug(app_slug) if app_slug else None
|
|
profiles = await self._profile_repo.find_by_account(account_id, app_slug_vo, is_active)
|
|
|
|
updated_profiles = []
|
|
for profile in profiles:
|
|
updated_profile = await self._connection_status_service.update_connection_status(profile)
|
|
updated_profiles.append(updated_profile)
|
|
|
|
return updated_profiles
|
|
|
|
async def update_profile(
|
|
self,
|
|
account_id: UUID,
|
|
profile_id: UUID,
|
|
profile_name: Optional[str] = None,
|
|
display_name: Optional[str] = None,
|
|
is_active: Optional[bool] = None,
|
|
is_default: Optional[bool] = None,
|
|
enabled_tools: Optional[List[str]] = None
|
|
) -> Profile:
|
|
profile = await self._profile_repo.get_by_id(account_id, profile_id)
|
|
if not profile:
|
|
raise ProfileNotFoundError(str(profile_id))
|
|
|
|
if profile_name:
|
|
profile.profile_name = ProfileName(profile_name)
|
|
if display_name:
|
|
profile.display_name = display_name
|
|
if is_active is not None:
|
|
if is_active:
|
|
profile.activate()
|
|
else:
|
|
profile.deactivate()
|
|
if is_default is not None:
|
|
if is_default:
|
|
await self._profile_repo.set_default(account_id, profile_id, profile.mcp_qualified_name)
|
|
profile.set_as_default()
|
|
else:
|
|
profile.unset_as_default()
|
|
if enabled_tools is not None:
|
|
profile.enabled_tools = enabled_tools
|
|
|
|
updated_profile = await self._profile_repo.update(profile)
|
|
self._logger.info(f"Updated profile {profile_id}")
|
|
|
|
return updated_profile
|
|
|
|
async def delete_profile(self, account_id: UUID, profile_id: UUID) -> bool:
|
|
success = await self._profile_repo.delete(account_id, profile_id)
|
|
if success:
|
|
self._logger.info(f"Deleted profile {profile_id}")
|
|
return success
|
|
|
|
async def get_profile_by_app(
|
|
self,
|
|
account_id: UUID,
|
|
app_slug: str,
|
|
profile_name: Optional[str] = None
|
|
) -> Optional[Profile]:
|
|
app_slug_vo = AppSlug(app_slug)
|
|
profile_name_vo = ProfileName(profile_name) if profile_name else None
|
|
|
|
profile = await self._profile_repo.get_by_app_slug(account_id, app_slug_vo, profile_name_vo)
|
|
if profile:
|
|
return await self._connection_status_service.update_connection_status(profile)
|
|
return None |