lab_resource_manager/application/usecases/
grant_user_resource_access.rs

1use crate::application::error::ApplicationError;
2use crate::domain::aggregates::identity_link::{
3    entity::IdentityLink,
4    value_objects::{ExternalIdentity, ExternalSystem},
5};
6use crate::domain::common::EmailAddress;
7use crate::domain::ports::repositories::IdentityLinkRepository;
8use crate::domain::ports::resource_collection_access::{
9    ResourceCollectionAccessError, ResourceCollectionAccessService,
10};
11use std::sync::Arc;
12
13/// ユーザーにリソースアクセス権を付与するUseCase
14///
15/// 外部システムのユーザーとメールアドレスを紐付け、すべてのリソースコレクションへのアクセス権を付与する。
16pub struct GrantUserResourceAccessUseCase {
17    identity_repo: Arc<dyn IdentityLinkRepository>,
18    collection_access: Arc<dyn ResourceCollectionAccessService>,
19    /// アクセス権を付与するコレクションIDのリスト
20    collection_ids: Vec<String>,
21}
22
23impl GrantUserResourceAccessUseCase {
24    pub fn new(
25        identity_repo: Arc<dyn IdentityLinkRepository>,
26        collection_access: Arc<dyn ResourceCollectionAccessService>,
27        collection_ids: Vec<String>,
28    ) -> Self {
29        Self {
30            identity_repo,
31            collection_access,
32            collection_ids,
33        }
34    }
35
36    pub async fn execute(
37        &self,
38        external_system: ExternalSystem,
39        external_user_id: String,
40        email: EmailAddress,
41    ) -> Result<(), ApplicationError> {
42        let mut identity = self.resolve_or_create_identity_link(&email).await?;
43        self.link_external_identity(&mut identity, external_system, external_user_id)?;
44
45        // アクセス権付与を先に実行(全て成功した場合のみIdentityLinkを保存)
46        self.grant_access_to_all_resources(&email).await?;
47
48        // 成功した場合のみIdentityLinkを保存
49        self.save_identity_link(identity).await?;
50        Ok(())
51    }
52
53    async fn resolve_or_create_identity_link(
54        &self,
55        email: &EmailAddress,
56    ) -> Result<IdentityLink, ApplicationError> {
57        match self.identity_repo.find_by_email(email).await? {
58            Some(existing) => Ok(existing),
59            None => Ok(IdentityLink::new(email.clone())),
60        }
61    }
62
63    fn link_external_identity(
64        &self,
65        identity: &mut IdentityLink,
66        external_system: ExternalSystem,
67        external_user_id: String,
68    ) -> Result<(), ApplicationError> {
69        // 既に指定された外部システムと紐付いているかチェック
70        if identity.has_identity_for_system(&external_system) {
71            return Err(ApplicationError::ExternalSystemAlreadyLinked {
72                email: identity.email().as_str().to_string(),
73                external_system: external_system.as_str().to_string(),
74            });
75        }
76
77        let external_identity = ExternalIdentity::new(external_system, external_user_id);
78        identity.link_external_identity(external_identity)?;
79        Ok(())
80    }
81
82    async fn grant_access_to_all_resources(
83        &self,
84        email: &EmailAddress,
85    ) -> Result<(), ApplicationError> {
86        for collection_id in &self.collection_ids {
87            match self
88                .collection_access
89                .grant_access(collection_id, email)
90                .await
91            {
92                Ok(_) => {
93                    // 成功した場合は次へ
94                }
95                Err(ResourceCollectionAccessError::AlreadyGranted(_)) => {
96                    // 既にアクセス権がある場合は成功とみなす
97                }
98                Err(e) => {
99                    // その他のエラーは警告を出すが処理は継続
100                    tracing::warn!(
101                        "Failed to grant access to collection '{}' for {}: {}",
102                        collection_id,
103                        email.as_str(),
104                        e
105                    );
106                }
107            }
108        }
109
110        Ok(())
111    }
112
113    async fn save_identity_link(&self, identity: IdentityLink) -> Result<(), ApplicationError> {
114        self.identity_repo.save(identity).await?;
115        Ok(())
116    }
117}