Skip to content

Commit

Permalink
Merge pull request #300 from sohosai/develop
Browse files Browse the repository at this point in the history
deploy 20240511
  • Loading branch information
arata-nvm authored May 11, 2024
2 parents 8cb5e2b + 7fc1424 commit cf84820
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 61 deletions.
5 changes: 5 additions & 0 deletions crates/sos24-presentation/src/error/convert_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ impl From<FormAnswerUseCaseError> for AppError {
"form-answer/not-project-owner".to_string(),
message,
),
FormAnswerUseCaseError::ExportFailed => AppError::new(
StatusCode::INTERNAL_SERVER_ERROR,
"form-answer/export-failed".to_string(),
message,
),
FormAnswerUseCaseError::FormIdError(e) => e.into(),
FormAnswerUseCaseError::ProjectIdError(e) => e.into(),
FormAnswerUseCaseError::FormUseCaseError(e) => e.into(),
Expand Down
26 changes: 19 additions & 7 deletions crates/sos24-presentation/src/model/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,16 @@ pub struct ProjectToBeExported {
sub_owner_phone_number: Option<String>,
#[serde(rename(serialize = "企画区分"))]
category: String,
#[serde(rename(serialize = "企画属性"))]
attributes: String,
#[serde(rename(serialize = "企画属性 屋内企画"))]
attributes_inside: bool,
#[serde(rename(serialize = "企画属性 屋外企画"))]
attributes_outside: bool,
#[serde(rename(serialize = "企画属性 学術認定企画"))]
attributes_academic: bool,
#[serde(rename(serialize = "企画属性 芸術祭参加企画"))]
attributes_art: bool,
#[serde(rename(serialize = "企画属性 委員会開催企画"))]
attributes_official: bool,
#[serde(rename(serialize = "備考"))]
remarks: Option<String>,
#[serde(rename(serialize = "作成日時"))]
Expand All @@ -173,13 +181,17 @@ impl From<ProjectDto> for ProjectToBeExported {
sub_owner_email: project.sub_owner_email,
sub_owner_phone_number: project.sub_owner_phone_number,
category: project.category.to_string(),
attributes: project
attributes_inside: project.attributes.0.contains(&ProjectAttributeDto::Inside),
attributes_outside: project.attributes.0.contains(&ProjectAttributeDto::Outside),
attributes_academic: project
.attributes
.0
.iter()
.map(ToString::to_string)
.collect::<Vec<String>>()
.join(";"),
.contains(&ProjectAttributeDto::Academic),
attributes_art: project.attributes.0.contains(&ProjectAttributeDto::Art),
attributes_official: project
.attributes
.0
.contains(&ProjectAttributeDto::Official),
remarks: project.remarks,
created_at: project
.created_at
Expand Down
5 changes: 3 additions & 2 deletions crates/sos24-presentation/src/route/form_answer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ pub async fn handle_export(
let data = (|| -> Result<String, CsvSerializationError> {
let mut csv_data = vec![];

let form_item_names_len = form_answer_list.form_item_names.len();
let header: Vec<String> = ["企画番号", "企画名", "企画団体名", "回答日時"]
.into_iter()
.map(ToString::to_string)
Expand All @@ -175,8 +176,8 @@ pub async fn handle_export(
.chain(
form_answer
.form_answer_item_values
.into_iter()
.map(|it| it.unwrap_or_default()),
.unwrap_or_else(|| vec![String::new(); form_item_names_len])
.into_iter(),
)
.collect();
csv_data.push(record);
Expand Down
11 changes: 6 additions & 5 deletions crates/sos24-use-case/src/file/interactor/export_by_form_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ impl<R: Repositories> FileUseCase<R> {
let project = project_with_owners.project.destruct();

let file_items = form_answer.list_file_items();
for (item_id, files) in file_items {
for (index1, (item_id, files)) in file_items.into_iter().enumerate() {
let Some(form_item) = form.find_item(&item_id) else {
return Err(FileUseCaseError::FormItemNotFound(item_id));
};

for (index, file_id) in files.into_iter().enumerate() {
for (index2, file_id) in files.into_iter().enumerate() {
let file = self
.repositories
.file_data_repository()
Expand All @@ -67,13 +67,14 @@ impl<R: Repositories> FileUseCase<R> {
.ok_or(FileUseCaseError::NotFound(file_id))?;
let file = file.destruct();

// {申請項目名}_{通し番号1}/{企画番号}_{企画名}_{通し番号2}_{オリジナルファイル名}
let filename = format!(
"{}/{}_{}_{}_{}_{}",
"{}_{}/{}_{}_{}_{}",
form_item.name().clone().value(),
index1 + 1,
project.index.clone().value(),
project.title.clone().value(),
project.group_name.clone().value(),
index + 1,
index2 + 1,
file.name.clone().value(),
);
file_list.push(ArchiveEntry::new(
Expand Down
2 changes: 2 additions & 0 deletions crates/sos24-use-case/src/form_answer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ pub enum FormAnswerUseCaseError {
FileNotFound(FileId),
#[error("Not a project owner or subowner")]
NotProjectOwner,
#[error("Export failed")]
ExportFailed,

#[error(transparent)]
FileIdError(#[from] FileIdError),
Expand Down
4 changes: 3 additions & 1 deletion crates/sos24-use-case/src/form_answer/dto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,16 +137,18 @@ impl From<FormAnswerItemKind> for FormAnswerItemKindDto {
}
}

#[derive(Debug)]
pub struct FormAnswerToBeExportedListDto {
pub form_title: String,
pub form_item_names: Vec<String>,
pub form_answers: Vec<FormAnswerToBeExportedDto>,
}

#[derive(Debug)]
pub struct FormAnswerToBeExportedDto {
pub project_index: i32,
pub project_title: String,
pub project_group_name: String,
pub form_answer_item_values: Vec<Option<String>>,
pub form_answer_item_values: Option<Vec<String>>,
pub created_at: Option<String>,
}
137 changes: 91 additions & 46 deletions crates/sos24-use-case/src/form_answer/interactor/export_by_form_id.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use chrono_tz::Asia::Tokyo;

use sos24_domain::entity::form::FormId;
use sos24_domain::entity::form_answer::{FormAnswerItem, FormAnswerItemKind};
use sos24_domain::entity::form::{Form, FormId, FormItemKind};
use sos24_domain::entity::form_answer::{FormAnswer, FormAnswerItemKind};
use sos24_domain::repository::form::FormRepository;
use sos24_domain::repository::project::ProjectRepository;
use sos24_domain::{
Expand Down Expand Up @@ -37,13 +37,7 @@ impl<R: Repositories> FormAnswerUseCase<R> {
.filter(|project_with_owners| form.is_sent_to(&project_with_owners.project))
.collect();

let form = form.destruct();
let form_title = form.title.value();
let (form_item_ids, form_item_names): (Vec<_>, Vec<_>) = form
.items
.into_iter()
.map(|item| (item.id().clone(), item.name().clone().value()))
.unzip();
let header = export_header(&form);

let mut form_answers = Vec::new();
for project_with_owner in target_project_list {
Expand All @@ -56,26 +50,17 @@ impl<R: Repositories> FormAnswerUseCase<R> {

let (form_answer_item_values, created_at) = match form_answer {
Some(form_answer) => {
let form_answer = form_answer.destruct();
let values = form_item_ids
.iter()
.map(|item_id| {
form_answer
.items
.iter()
.find(|item| item.item_id() == item_id)
.map(convert_answer_item_to_string)
})
.collect();
let form_answer_item_values = export_record(&form, &form_answer)?;
let created_at = form_answer
.created_at
.created_at()
.clone()
.value()
.with_timezone(&Tokyo)
.format("%Y-%m-%d %H:%M:%S")
.to_string();
(values, Some(created_at))
(Some(form_answer_item_values), Some(created_at))
}
None => (form_item_ids.iter().map(|_| None).collect(), None),
None => (None, None),
};

let project = project_with_owner.project.destruct();
Expand All @@ -88,35 +73,95 @@ impl<R: Repositories> FormAnswerUseCase<R> {
});
}

Ok(FormAnswerToBeExportedListDto {
form_title,
form_item_names,
Ok(dbg!(FormAnswerToBeExportedListDto {
form_title: form.title().clone().value(),
form_item_names: header,
form_answers,
})
}))
}
}

fn export_header(form: &Form) -> Vec<String> {
let mut record = vec![];
for form_item in form.items() {
let form_item_name = form_item.name().clone().value();
match form_item.kind() {
FormItemKind::String(_)
| FormItemKind::Int(_)
| FormItemKind::ChooseOne(_)
| FormItemKind::File(_) => record.push(form_item_name),
FormItemKind::ChooseMany(choose_many) => {
for options in choose_many.options() {
record.push(format!("{} {}", form_item_name, options.clone().value()));
}
}
}
}
record
}

fn convert_answer_item_to_string(item: &FormAnswerItem) -> String {
match item.kind() {
FormAnswerItemKind::String(value) => value.clone().value().to_string(),
FormAnswerItemKind::Int(value) => value.clone().value().to_string(),
FormAnswerItemKind::ChooseOne(value) => value.clone().value().to_string(),
FormAnswerItemKind::ChooseMany(value) => value
.clone()
.value()
fn export_record(
form: &Form,
form_answer: &FormAnswer,
) -> Result<Vec<String>, FormAnswerUseCaseError> {
let mut record = vec![];
for form_item in form.items() {
let form_item_kind = form_item.kind();
let form_answer_item_kind = form_answer
.items()
.iter()
.map(|it| it.to_string())
.collect::<Vec<_>>()
.join(";"),
// TODO: ファイルのリネームを実装した段階で書き換え
FormAnswerItemKind::File(value) => value
.clone()
.value()
.into_iter()
.map(|it| it.value().to_string())
.collect::<Vec<_>>()
.join(";"),
.find(|form_answer_item| form_answer_item.item_id() == form_item.id())
.map(|it| it.kind());

match (form_item_kind, form_answer_item_kind) {
(FormItemKind::String(_), None) => record.push(String::new()),
(FormItemKind::String(_), Some(FormAnswerItemKind::String(value))) => {
record.push(value.clone().value().to_string());
}
(FormItemKind::Int(_), None) => record.push(String::new()),
(FormItemKind::Int(_), Some(FormAnswerItemKind::Int(value))) => {
record.push(value.clone().value().to_string());
}
(FormItemKind::ChooseOne(_), None) => record.push(String::new()),
(FormItemKind::ChooseOne(_), Some(FormAnswerItemKind::ChooseOne(value))) => {
record.push(value.clone().value().to_string());
}
(FormItemKind::ChooseMany(choose_many), None) => {
for _ in choose_many.options() {
record.push(String::new());
}
}
(
FormItemKind::ChooseMany(choose_many),
Some(FormAnswerItemKind::ChooseMany(value)),
) => {
let chosen_options = value.clone().value();
for option in choose_many.options() {
record.push(chosen_options.contains(&option.clone().value()).to_string());
}
}
(FormItemKind::File(_), None) => record.push(String::new()),
(FormItemKind::File(_), Some(FormAnswerItemKind::File(value))) => {
let files = value
.clone()
.value()
.into_iter()
.map(|it| it.value().to_string())
.collect::<Vec<_>>()
.join(";");
record.push(files);
}
_ => {
tracing::error!(
"Export failed: form_item_kind: {:?}, form_answer_item_kind: {:?}",
form_item_kind,
form_answer_item_kind
);
return Err(FormAnswerUseCaseError::ExportFailed);
}
}
}
Ok(record)
}

#[cfg(test)]
Expand Down

0 comments on commit cf84820

Please sign in to comment.