Skip to content

Commit 0c38f98

Browse files
committed
feat: 졸업 논문 제출 API
1 parent 781e93a commit 0c38f98

File tree

12 files changed

+172
-0
lines changed

12 files changed

+172
-0
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package kgu.developers.api.thesis.presentation;
2+
3+
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
4+
5+
import org.springframework.http.ResponseEntity;
6+
import org.springframework.web.bind.annotation.RequestPart;
7+
import org.springframework.web.multipart.MultipartFile;
8+
9+
import io.swagger.v3.oas.annotations.Operation;
10+
import io.swagger.v3.oas.annotations.Parameter;
11+
import io.swagger.v3.oas.annotations.media.Content;
12+
import io.swagger.v3.oas.annotations.media.Schema;
13+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
14+
import io.swagger.v3.oas.annotations.tags.Tag;
15+
import kgu.developers.api.thesis.presentation.request.ThesisSubmitRequest;
16+
import kgu.developers.api.thesis.presentation.response.ThesisPersistResponse;
17+
18+
@Tag(name = "Thesis", description = "졸업 논문 API")
19+
public interface ThesisController {
20+
21+
@Operation(
22+
summary = "졸업 논문 파일 제출 API", description = """
23+
- Description : 이 API는 졸업 논문 파일을 제출합니다.
24+
- Assignee : 이한음
25+
""")
26+
@ApiResponse(
27+
responseCode = "201",
28+
content = @Content(schema = @Schema(implementation = ThesisPersistResponse.class)))
29+
ResponseEntity<ThesisPersistResponse> submitThesisAndSaveFile(
30+
@Parameter(
31+
description = "졸업 논문 첨부 파일",
32+
content = @Content(mediaType = MULTIPART_FORM_DATA_VALUE),
33+
required = true
34+
) @RequestPart(value = "file") MultipartFile file,
35+
@RequestPart ThesisSubmitRequest request
36+
);
37+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package kgu.developers.api.thesis.presentation;
2+
3+
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
4+
5+
import org.springframework.http.ResponseEntity;
6+
import org.springframework.web.bind.annotation.PostMapping;
7+
import org.springframework.web.bind.annotation.RequestMapping;
8+
import org.springframework.web.bind.annotation.RequestPart;
9+
import org.springframework.web.bind.annotation.RestController;
10+
import org.springframework.web.multipart.MultipartFile;
11+
12+
import kgu.developers.api.thesis.presentation.request.ThesisSubmitRequest;
13+
import kgu.developers.api.thesis.presentation.response.ThesisPersistResponse;
14+
import kgu.developers.domain.thesis.application.command.ThesisCommandService;
15+
import lombok.RequiredArgsConstructor;
16+
17+
@RestController
18+
@RequestMapping("/api/v1/thesis")
19+
@RequiredArgsConstructor
20+
public class ThesisControllerImpl implements ThesisController {
21+
private final ThesisCommandService thesisCommandService;
22+
23+
@Override
24+
@PostMapping(consumes = MULTIPART_FORM_DATA_VALUE)
25+
public ResponseEntity<ThesisPersistResponse> submitThesisAndSaveFile(
26+
@RequestPart(value = "file") MultipartFile file,
27+
@RequestPart ThesisSubmitRequest request
28+
) {
29+
Long id = thesisCommandService.submitThesis(file, request.scheduleId());
30+
return ResponseEntity.ok(
31+
ThesisPersistResponse.of(id)
32+
);
33+
}
34+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package kgu.developers.api.thesis.presentation.request;
2+
3+
public record ThesisSubmitRequest(
4+
Long scheduleId
5+
) {
6+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package kgu.developers.api.thesis.presentation.response;
2+
3+
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
4+
5+
import io.swagger.v3.oas.annotations.media.Schema;
6+
import lombok.Builder;
7+
8+
@Builder
9+
public record ThesisPersistResponse(
10+
@Schema(description = "졸업 논문 객체 id", example = "1", requiredMode = REQUIRED)
11+
Long id
12+
) {
13+
public static ThesisPersistResponse of(Long id) {
14+
return ThesisPersistResponse.builder().id(id).build();
15+
}
16+
}

aics-common/src/main/java/kgu/developers/common/config/SecurityConfig.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
8282
"/api/v1/labs",
8383
"/api/v1/comments",
8484
"/api/v1/carousels",
85+
"/api/v1/thesis",
8586
};
8687

8788
CorsConfigurationSource corsConfigurationSource() {

aics-domain/src/main/java/kgu/developers/domain/file/domain/FileDomain.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public enum FileDomain {
1111
POST("게시글"),
1212
LAB("연구실"),
1313
CLUB("동아리"),
14+
THESIS("논문")
1415
;
1516

1617
private final String description;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package kgu.developers.domain.thesis.application.command;
2+
3+
import org.springframework.stereotype.Service;
4+
import org.springframework.web.multipart.MultipartFile;
5+
6+
import kgu.developers.domain.file.application.command.FileCommandService;
7+
import kgu.developers.domain.file.domain.FileDomain;
8+
import kgu.developers.domain.file.infrastructure.repository.FileStorageService;
9+
import kgu.developers.domain.schedule.application.query.ScheduleQueryService;
10+
import kgu.developers.domain.thesis.domain.Thesis;
11+
import kgu.developers.domain.thesis.domain.ThesisRepository;
12+
import lombok.RequiredArgsConstructor;
13+
14+
@Service
15+
@RequiredArgsConstructor
16+
public class ThesisCommandService {
17+
private final ThesisRepository thesisRepository;
18+
private final FileStorageService fileStorageService;
19+
private final FileCommandService fileCommandService;
20+
private final ScheduleQueryService scheduleQueryService;
21+
22+
public Long submitThesis(MultipartFile file, Long scheduleId) {
23+
String storedPath = fileStorageService.store(file, FileDomain.THESIS);
24+
Long fileId = fileCommandService.saveFile(file, storedPath).getId();
25+
scheduleQueryService.checkExistsOrThrow(scheduleId);
26+
27+
Thesis thesis = Thesis.create(scheduleId, fileId);
28+
return thesisRepository.save(thesis);
29+
}
30+
31+
}

aics-domain/src/main/java/kgu/developers/domain/thesis/domain/Thesis.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@
33
import java.time.LocalDateTime;
44

55
import lombok.AccessLevel;
6+
import lombok.AllArgsConstructor;
7+
import lombok.Builder;
68
import lombok.Getter;
79
import lombok.NoArgsConstructor;
810

911
@Getter
12+
@Builder
1013
@NoArgsConstructor(access = AccessLevel.PRIVATE)
14+
@AllArgsConstructor(access = AccessLevel.PRIVATE)
1115
public class Thesis {
1216
private Long id;
1317
private Long scheduleId;
@@ -17,6 +21,14 @@ public class Thesis {
1721
private LocalDateTime updatedAt;
1822
private LocalDateTime deletedAt;
1923

24+
public static Thesis create(Long scheduleId, Long thesisFileId) {
25+
return Thesis.builder()
26+
.scheduleId(scheduleId)
27+
.thesisFileId(thesisFileId)
28+
.approval(false)
29+
.build();
30+
}
31+
2032
public static Thesis of(
2133
Long id,
2234
Long scheduleId,
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package kgu.developers.domain.thesis.domain;
2+
3+
public interface ThesisRepository {
4+
Long save(Thesis thesis);
5+
}

aics-domain/src/main/java/kgu/developers/domain/thesis/infrastructure/entity/ThesisJpaEntity.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
import kgu.developers.domain.thesis.domain.Thesis;
1515
import lombok.AllArgsConstructor;
1616
import lombok.Builder;
17+
import lombok.Getter;
1718
import lombok.NoArgsConstructor;
1819

20+
@Getter
1921
@Builder
2022
@Entity
2123
@Table(

0 commit comments

Comments
 (0)