Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[새기능] 입학등록원 & 금연서약서 제출 및 조회 #166

Merged
merged 13 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 42 additions & 1 deletion src/docs/asciidoc/form.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -316,8 +316,49 @@ include::{snippets}/form-controller-test/원서_서류를_업로드할_때_파
===== pdf 파일이 아닌 경우
include::{snippets}/form-controller-test/원서_서류를_업로드할_때_콘텐츠_타입이_다르다면_에러가_발생한다/http-response.adoc[]

=== 입학등록원 및 금연서약서 다운로드
최종합격한 지원자는 입학등록원 및 금연서약서를 다운로드 받을 수 있습니다.

==== 요청 형식
===== Request Header
include::{snippets}/form-controller-test/최종합격자가_입학등록원_및_금연서약서를_다운받는다/request-headers.adoc[]

==== 요청
include::{snippets}/form-controller-test/최종합격자가_입학등록원_및_금연서약서를_다운받는다/http-request.adoc[]

==== 응답
===== 정상 응답
include::{snippets}/form-controller-test/최종합격자가_입학등록원_및_금연서약서를_다운받는다/http-response.adoc[]

===== 원서 상태가 최종합격이 아닌 경우
include::{snippets}/form-controller-test/최종합격자가_아닌_사람이_입학등록원_및_금연서약서를_다운받으면_에러가_발생한다/http-response.adoc[]

===== pdf 파일로 변환에 실패한 경우
include::{snippets}/form-controller-test/입학등록원_및_금연서약서를_다운받을_때_pdf변환에_실패했다면_에러가_발생한다/http-response.adoc[]

=== 입학등록원 및 금연서약서 업로드
최종합격한 지원자는 입학등록원 및 금연서약서를 업로드할 수 있습니다.

==== 요청 형식

===== Request Header
include::{snippets}/form-controller-test/입학등록원_및_금연서약서를_업로드한다/request-headers.adoc[]

==== 요청
include::{snippets}/form-controller-test/입학등록원_및_금연서약서를_업로드한다/http-request.adoc[]

==== 응답
===== 정상 응답
include::{snippets}/form-controller-test/입학등록원_및_금연서약서를_업로드한다/http-response.adoc[]

===== 원서 상태가 합격이 아닌 경우
include::{snippets}/form-controller-test/최종합격자가_아닌_지원자가_입학등록원_및_금연서약서를_업로드하면_에러가_발생한다/http-response.adoc[]

===== 업로드를 실패한 경우
include::{snippets}/form-controller-test/입학등록원_및_금연서약서_업로드가_실패한다/http-response.adoc[]

=== 원서 다운로드
원서가 제출하기 전 원서를 다운로드 받을 수 있습니다.
원서를 최종제출하기 전 원서를 다운로드 받을 수 있습니다.

==== 요청 형식

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.bamdoliro.maru.application.form;

import com.bamdoliro.maru.domain.form.domain.Form;
import com.bamdoliro.maru.domain.form.exception.InvalidFormStatusException;
import com.bamdoliro.maru.domain.form.service.FormFacade;
import com.bamdoliro.maru.domain.user.domain.User;
import com.bamdoliro.maru.infrastructure.pdf.GeneratePdfService;
import com.bamdoliro.maru.infrastructure.pdf.MergePdfService;
import com.bamdoliro.maru.infrastructure.thymeleaf.ProcessTemplateService;
import com.bamdoliro.maru.infrastructure.thymeleaf.Templates;
import com.bamdoliro.maru.shared.annotation.UseCase;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.utils.PdfMerger;
import lombok.RequiredArgsConstructor;
import org.springframework.core.io.ByteArrayResource;

import java.io.ByteArrayOutputStream;
import java.util.Map;
import java.util.List;

@RequiredArgsConstructor
@UseCase
public class DownloadAdmissionAndPledgeFormatUseCase {

private final MergePdfService mergePdfService;
private final FormFacade formFacade;
private final ProcessTemplateService processTemplateService;
private final GeneratePdfService generatePdfService;

public ByteArrayResource execute(User user) {
Form form = formFacade.getForm(user);
validate(form);

Map<String, Object> formMap = Map.of(
"form", form
);

List<String> templates = List.of(
Templates.REGISTRATION,
Templates.NO_SMOKING
);


ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PdfDocument mergedDocument = new PdfDocument(new PdfWriter(outputStream));
PdfMerger pdfMerger = new PdfMerger(mergedDocument);

templates
.stream()
.map((t) -> processTemplateService.execute(t, formMap))
.map(generatePdfService::execute)
.forEach((s) -> mergePdfService.execute(pdfMerger, s));

mergedDocument.close();
pdfMerger.close();

return new ByteArrayResource(outputStream.toByteArray());
Comment on lines +45 to +58
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요거 왠지 공통 메서드일 거 같은데 분리하는 거 고려해봐도 좋을 거 같아욤

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

마루 운영 끝난 후 반영하도록 하겠습니다 :)

}

private void validate(Form form) {
if (!form.isPassedNow())
throw new InvalidFormStatusException();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.bamdoliro.maru.application.form;

import com.bamdoliro.maru.domain.form.domain.Form;
import com.bamdoliro.maru.domain.form.exception.InvalidFormStatusException;
import com.bamdoliro.maru.domain.form.service.FormFacade;
import com.bamdoliro.maru.domain.user.domain.User;
import com.bamdoliro.maru.infrastructure.s3.FileService;
import com.bamdoliro.maru.infrastructure.s3.constants.FolderConstant;
import com.bamdoliro.maru.infrastructure.s3.dto.response.UrlResponse;
import com.bamdoliro.maru.shared.annotation.UseCase;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@UseCase
public class UploadAdmissionAndPledgeUseCase {

private final FileService fileService;
private final FormFacade formFacade;

public UrlResponse execute(User user) {
Form form = formFacade.getForm(user);
validate(form);

return fileService.getPresignedUrl(FolderConstant.ADMISSION_AND_PLEDGE, user.getUuid().toString());
}

private void validate(Form form) {
if(!form.isPassedNow())
throw new InvalidFormStatusException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ public class FolderConstant {
public static final String IDENTIFICATION_PICTURE = "identification-picture";
public static final String FORM = "form";
public static final String NOTICE_FILE = "notice-file";
public static final String ADMISSION_AND_PLEDGE = "admission-and-pledge";
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public class Templates {
public static final String PROOF_OF_APPLICATION = "proof-of-application";
public static final String GRADE_TABLE = "grade-table";
public static final String WRITTEN_OATH = "written-oath";
public static final String NO_SMOKING = "no-smoking";
public static final String SPECIAL_ADMISSION = "special-admission";
public static final String CONFIRMATION = "confirmation";
public static final String REGISTRATION = "registration";
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ public class FormController {
private final UploadIdentificationPictureUseCase uploadIdentificationPictureUseCase;
private final UploadFormUseCase uploadFormUseCase;
private final ExportFormUseCase exportFormUseCase;
private final DownloadAdmissionAndPledgeFormatUseCase downloadAdmissionAndPledgeFormatUseCase;
private final UploadAdmissionAndPledgeUseCase uploadAdmissionAndPledgeUseCase;
private final QueryAllFormUseCase queryAllFormUseCase;
private final QueryFirstFormResultUseCase queryFirstFormResultUseCase;
private final QueryFinalFormResultUseCase queryFinalFormResultUseCase;
Expand Down Expand Up @@ -187,6 +189,24 @@ public ResponseEntity<Resource> exportForm(
.body(exportFormUseCase.execute(user));
}

@GetMapping(value = "/admission-and-pledge")
public ResponseEntity<Resource> downloadAdmissionAndPledgeFormat(
@AuthenticationPrincipal(authority = Authority.USER) User user
) {
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_PDF)
.body(downloadAdmissionAndPledgeFormatUseCase.execute(user));
}

@PostMapping(value = "/admission-and-pledge")
public SingleCommonResponse<UrlResponse> uploadAdmissionAndPledge(
@AuthenticationPrincipal(authority = Authority.USER) User user
) {
return SingleCommonResponse.ok(
uploadAdmissionAndPledgeUseCase.execute(user)
);
}

@GetMapping
public ListCommonResponse<FormSimpleResponse> getFormList(
@AuthenticationPrincipal(authority = Authority.ADMIN) User user,
Expand Down
153 changes: 153 additions & 0 deletions src/main/resources/templates/no-smoking.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" lang="ko">
<head>
<meta charset="UTF-8"/>
<style>
@page {
size: A4;
margin: 70px;
}
* {
font-family: SUIT, sans-serif;
margin: 0;
padding: 0;
box-sizing: border-box;
}
table {
border: none;
border-collapse: collapse;
width: 100%;
font-size: 14px;
text-align: center;
line-height: normal;
}
tr {
vertical-align: middle;
}
td {
padding: 8px 0;
}
th {
background-color: #ECF2FA;
font-weight: 500;
padding: 8px 0;
}
.ba {
border: #000000 1px solid;
}
caption {
font-weight: bold;
font-size: 28px;
line-height: 48px;
text-align: center;
}
.left {
text-align: left;
}
.right {
text-align: right;
}
.center {
text-align: center;
}
.text-box {
padding: 15px 10px;
vertical-align: text-top;
}
.middle {
font-size: 18px;
line-height: 160%;
}
.school {
font-weight: bold;
font-size: 24px;
}
.guide {
font-size: 11px;
color: #BBBCC2;
font-weight: 300;
}
.indent {
text-indent: 18px;
font-size: 22px;
word-break: keep-all;
}
.red {
color: #F44336;
font-weight: 600;
}
.padding {
padding: 16px;
}
</style>
<title>원서</title>
</head>
<body>
<table>
<caption>금연 동의서</caption>
<tr>
<th scope="row" class="ba" style="width:15%;">성명</th>
<td class="ba" style="width:35%;" th:text="${form.applicant.name}"></td>
<th scope="row" class="ba" style="width:15%;">수험번호</th>
<td class="ba" style="width:35%;" th:text="${form.getExaminationNumber()}">1000</td>
</tr>
<tr>
<th scope="row" class="ba">출신중학교</th>
<td class="ba" colspan="3" th:text="${form.education.school.name}"></td>
</tr>
<tr>
<td style="height: 24px"></td>
</tr>
<tr>
<td class="ba text-box middle left padding" colspan="4">
<p>하나. 나 자신의 건강을 위해서 흡연을 하지 않겠습니다.</p>
<p>하나. 흡연의 유혹에 절대로 흔들리지 않겠습니다.</p>
<p>하나. 흡연을 하는 친구가 있으면 충고하여 금연을 할 수 있도록 돕겠습니다.</p>
<div style="height: 48px;"></div>
<p class="indent">나 <span th:text="${form.applicant.name}"></span>은(는) 이 시대를 이끌어갈 SW 분야 영 마이스터가 되기 위해 <span class="red">흡연을 하지 않겠습니다.</span></p>
<p class="indent">보호자는 지원자의 건강한 성장과 발전을 위해 용기와 도움을 줄 것을 약속합니다.</p>
<div style="height: 48px;"></div>
<p id="security">■ 개인 정보 수집&#183;이용 동의</p>
<table aria-describedby="security">
<tr>
<th scope="col" class="ba" style="width: 35%">항목</th>
<th scope="col" class="ba" style="width: 30%">수집목적</th>
<th scope="col" class="ba" style="width: 35%">보유기간</th>
</tr>
<tr>
<td class="ba">학생(성명, 출신중학교)</td>
<td class="ba">금연동의서</td>
<td class="ba">3년</td>
</tr>
<tr>
<td class="left" colspan="3">
※ 개인정보 수집·이용에 대한 동의를 거부할 권리가 있습니다.<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;그러나 동의를 거부할 경우 최종입학에 제한을 받을 수 있습니다.
<div style="height: 24px;"></div>
</td>
</tr>
<tr>
<th scope="row" class="ba">개인정보 수집&#183;이용 동의</th>
<td class="ba" colspan="2">□ 예&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;□ 아니오</td>
</tr>
</table>
<div style="height: 48px;"></div>
<p class="middle center" th:text="${#dates.format(#dates.createNow(),'YYYY년 MM월 dd일')}"></p>
<div style="height: 54px;"></div>
<p class="right">
지원자&nbsp;&nbsp;
<span th:text="${form.applicant.name}"></span>&nbsp;&nbsp;&nbsp;
<span class="guide">(서명)</span>
</p>
<p class="right">
보호자&nbsp;&nbsp;
<span th:text="${form.parent.name}"></span>&nbsp;&nbsp;&nbsp;
<span class="guide">(서명)</span>
</p>
<div style="height: 54px;"></div>
<p class="school left">부산소프트웨어마이스터고등학교장 귀하</p>
</td>
</tr>
</table>
</body>
</html>
Loading
Loading