From 7fbea8e626df3e6886ec2f98d62fc0538cbf2d40 Mon Sep 17 00:00:00 2001 From: Arata Date: Thu, 25 Jul 2024 18:48:31 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=9B=9E=E7=AD=94=E3=81=8C=E3=81=82?= =?UTF-8?q?=E3=81=A3=E3=81=A6=E3=82=82=E3=80=81SOS=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E8=80=85=E3=81=8C=E7=94=B3=E8=AB=8B=E3=82=92=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/sos24-domain/src/entity/permission.rs | 31 +++---- .../src/form/interactor/update.rs | 87 ++++++++++++++++--- 2 files changed, 89 insertions(+), 29 deletions(-) diff --git a/crates/sos24-domain/src/entity/permission.rs b/crates/sos24-domain/src/entity/permission.rs index 107a4e8..d988d70 100644 --- a/crates/sos24-domain/src/entity/permission.rs +++ b/crates/sos24-domain/src/entity/permission.rs @@ -25,25 +25,26 @@ bitflags! { const CREATE_FORM = 1 << 11; const READ_FORM_ALL = 1 << 12; const UPDATE_FORM_ALL = 1 << 13; - const DELETE_FORM_ALL = 1 << 14; + const UPDATE_FORM_ALL_ANSWERED = 1 << 14; + const DELETE_FORM_ALL = 1 << 15; - const CREATE_INVITATION = 1 << 15; - const CREATE_INVITATION_ANYTIME = 1 << 16; - const READ_INVITATION_ALL = 1 << 17; - const UPDATE_INVITATION_ALL = 1 << 18; - const DELETE_INVITATION_ALL = 1 << 19; + const CREATE_INVITATION = 1 << 16; + const CREATE_INVITATION_ANYTIME = 1 << 17; + const READ_INVITATION_ALL = 1 << 18; + const UPDATE_INVITATION_ALL = 1 << 19; + const DELETE_INVITATION_ALL = 1 << 20; - const CREATE_FORM_ANSWER = 1 << 20; - const READ_FORM_ANSWER_ALL = 1 << 21; - const UPDATE_FORM_ANSWER_ALL = 1 << 22; - const UPDATE_FORM_ANSWER_ANYTIME = 1 << 23; + const CREATE_FORM_ANSWER = 1 << 21; + const READ_FORM_ANSWER_ALL = 1 << 22; + const UPDATE_FORM_ANSWER_ALL = 1 << 23; + const UPDATE_FORM_ANSWER_ANYTIME = 1 << 24; - const CREATE_FILE_PRIVATE = 1 << 24; - const CREATE_FILE_PUBLIC = 1 << 25; - const READ_FILE_ALL = 1 << 26; - const DELETE_FILE_ALL = 1 << 27; + const CREATE_FILE_PRIVATE = 1 << 25; + const CREATE_FILE_PUBLIC = 1 << 26; + const READ_FILE_ALL = 1 << 27; + const DELETE_FILE_ALL = 1 << 28; - const CREATE_PROJECT_ANYTIME = 1 << 28; + const CREATE_PROJECT_ANYTIME = 1 << 29; } } diff --git a/crates/sos24-use-case/src/form/interactor/update.rs b/crates/sos24-use-case/src/form/interactor/update.rs index 34199c3..a3d9688 100644 --- a/crates/sos24-use-case/src/form/interactor/update.rs +++ b/crates/sos24-use-case/src/form/interactor/update.rs @@ -52,7 +52,10 @@ impl FormUseCase { .form_answer_repository() .find_by_form_id(id.clone()) .await?; - if !answers.is_empty() { + let has_answer = !answers.is_empty(); + + // 回答がある場合、SOS管理者以外は変更できない + if has_answer && !actor.has_permission(Permissions::UPDATE_FORM_ALL_ANSWERED) { return Err(FormUseCaseError::HasAnswers); } @@ -63,18 +66,23 @@ impl FormUseCase { new_form.set_ends_at(&actor, DateTime::try_from(form_data.ends_at)?)?; new_form.set_categories(&actor, ProjectCategories::from(form_data.categories))?; new_form.set_attributes(&actor, ProjectAttributes::from(form_data.attributes))?; - let new_items = form_data - .items - .into_iter() - .map(FormItem::try_from) - .collect::>()?; - new_form.set_items(&actor, new_items)?; - let new_attachments = form_data - .attachments - .into_iter() - .map(FileId::try_from) - .collect::>()?; - new_form.set_attachments(&actor, new_attachments)?; + { + let new_attachments = form_data + .attachments + .into_iter() + .map(FileId::try_from) + .collect::>()?; + new_form.set_attachments(&actor, new_attachments)?; + } + // 回答がない場合のみ、申請項目を更新 + if !has_answer { + let new_items = form_data + .items + .into_iter() + .map(FormItem::try_from) + .collect::>()?; + new_form.set_items(&actor, new_items)?; + } self.repositories.form_repository().update(new_form).await?; Ok(()) @@ -186,7 +194,7 @@ mod tests { } #[tokio::test] - async fn 回答がある申請は更新できない() { + async fn 実委人管理者は回答がある申請を更新できない() { let mut repositories = MockRepositories::default(); repositories .form_repository_mut() @@ -230,4 +238,55 @@ mod tests { .await; assert!(matches!(res, Err(FormUseCaseError::HasAnswers))); } + + #[tokio::test] + #[allow(non_snake_case)] + async fn SOS管理者は回答がある申請を更新できる() { + let mut repositories = MockRepositories::default(); + repositories + .form_repository_mut() + .expect_find_by_id() + .returning(|_| Ok(Some(fixture::form::form1_opened()))); + repositories + .form_answer_repository_mut() + .expect_find_by_form_id() + .returning(|_| { + Ok(vec![fixture::form_answer::form_answer1( + fixture::project::id1(), + )]) + }); + repositories + .form_repository_mut() + .expect_update() + .returning(|_| Ok(())); + let adapters = MockAdapters::default(); + let use_case = FormUseCase::new(Arc::new(repositories), Arc::new(adapters)); + + let ctx = TestContext::new(fixture::actor::actor1(UserRole::Administrator)); + let res = use_case + .update( + &ctx, + UpdateFormCommand { + id: fixture::form::id1().value().to_string(), + title: fixture::form::title2().value(), + description: fixture::form::description2().value(), + starts_at: fixture::form::starts_at2().value().to_rfc3339(), + ends_at: fixture::form::ends_at2().value().to_rfc3339(), + categories: ProjectCategoriesDto::from(fixture::form::categories2()), + attributes: ProjectAttributesDto::from(fixture::form::attributes2()), + items: vec![NewFormItemDto::new( + fixture::form::formitem_name1().value(), + Some(fixture::form::description1().value()), + fixture::form::formitem_required1().value(), + FormItemKindDto::from(fixture::form::formitem_kind1()), + )], + attachments: fixture::form::attachments2() + .into_iter() + .map(|it| it.value().to_string()) + .collect(), + }, + ) + .await; + assert!(res.is_ok()); + } }