diff --git a/backend/bang-ggood/build.gradle b/backend/bang-ggood/build.gradle index 8c12e928b..543fff752 100644 --- a/backend/bang-ggood/build.gradle +++ b/backend/bang-ggood/build.gradle @@ -1,31 +1,33 @@ plugins { - id 'java' - id 'org.springframework.boot' version '3.3.2' - id 'io.spring.dependency-management' version '1.1.6' + id 'java' + id 'org.springframework.boot' version '3.3.2' + id 'io.spring.dependency-management' version '1.1.6' } group = 'com.bang-ggood' version = '0.0.1-SNAPSHOT' java { - toolchain { - languageVersion = JavaLanguageVersion.of(17) - } + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } } repositories { - mavenCentral() + mavenCentral() } dependencies { - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0' - runtimeOnly 'com.h2database:h2' - testImplementation 'org.springframework.boot:spring-boot-starter-test' - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0' + implementation 'org.springframework.boot:spring-boot-starter-validation' + runtimeOnly 'com.h2database:h2' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'io.rest-assured:rest-assured:5.3.1' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } tasks.named('test') { - useJUnitPlatform() + useJUnitPlatform() } diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/Application.java b/backend/bang-ggood/src/main/java/com/bang_ggood/Application.java index d6f4ca2d1..c6b0b749c 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/Application.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/Application.java @@ -8,8 +8,8 @@ @SpringBootApplication public class Application { - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } } diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/BaseEntity.java b/backend/bang-ggood/src/main/java/com/bang_ggood/BaseEntity.java index e97c6b62c..167f3c42c 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/BaseEntity.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/BaseEntity.java @@ -2,10 +2,10 @@ import jakarta.persistence.EntityListeners; import jakarta.persistence.MappedSuperclass; +import java.time.LocalDateTime; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import java.time.LocalDateTime; @MappedSuperclass @EntityListeners(AuditingEntityListener.class) diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/controller/ChecklistController.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/controller/ChecklistController.java new file mode 100644 index 000000000..7a80723cb --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/controller/ChecklistController.java @@ -0,0 +1,26 @@ +package com.bang_ggood.checklist.controller; + +import com.bang_ggood.checklist.dto.ChecklistCreateRequest; +import com.bang_ggood.checklist.service.ChecklistService; +import jakarta.validation.Valid; +import java.net.URI; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ChecklistController { + + private final ChecklistService checklistService; + + public ChecklistController(ChecklistService checklistService) { + this.checklistService = checklistService; + } + + @PostMapping("/checklists") + public ResponseEntity createChecklist(@Valid @RequestBody ChecklistCreateRequest checklistCreateRequest) { + long checklistId = checklistService.createChecklist(checklistCreateRequest); + return ResponseEntity.created(URI.create("/checklists/" + checklistId)).build(); + } +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/Checklist.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/Checklist.java new file mode 100644 index 000000000..d8d2eb177 --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/Checklist.java @@ -0,0 +1,110 @@ +package com.bang_ggood.checklist.domain; + +import com.bang_ggood.BaseEntity; +import com.bang_ggood.room.domain.Room; +import com.bang_ggood.user.domain.User; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToOne; +import java.util.Objects; + + +@Entity +public class Checklist extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private User user; + + @OneToOne(fetch = FetchType.LAZY) + private Room room; + + private Integer deposit; + + private Integer rent; + + private Integer contractTerm; + + private String realEstate; + + public Checklist(User user, Room room, Integer deposit, Integer rent, Integer contractTerm, String realEstate) { + this.user = user; + this.room = room; + this.deposit = deposit; + this.rent = rent; + this.contractTerm = contractTerm; + this.realEstate = realEstate; + } + + public Checklist(Integer deposit, Integer rent, Integer contractTerm, String realEstate) { + this(null, null, deposit, rent, contractTerm, realEstate); + } + + protected Checklist() { + } + + public Long getId() { + return id; + } + + public User getUser() { + return user; + } + + public Room getRoom() { + return room; + } + + public Integer getDeposit() { + return deposit; + } + + public Integer getRent() { + return rent; + } + + public Integer getContractTerm() { + return contractTerm; + } + + public String getRealEstate() { + return realEstate; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Checklist checklist = (Checklist) o; + return Objects.equals(id, checklist.id); + } + + @Override + public int hashCode() { + return Objects.hashCode(id); + } + + @Override + public String toString() { + return "Checklist{" + + "id=" + id + + ", user=" + user + + ", room=" + room + + ", deposit=" + deposit + + ", rent=" + rent + + ", contractTerm=" + contractTerm + + ", realEstate='" + realEstate + '\'' + + '}'; + } +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/ChecklistOption.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/ChecklistOption.java new file mode 100644 index 000000000..8ce32723f --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/ChecklistOption.java @@ -0,0 +1,72 @@ +package com.bang_ggood.checklist.domain; + +import com.bang_ggood.BaseEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import java.util.Objects; + + +@Entity +public class ChecklistOption extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private Checklist checklist; + + @Column(nullable = false) + private Integer optionId; + + public ChecklistOption(Checklist checklist, Integer optionId) { + this.checklist = checklist; + this.optionId = optionId; + } + + protected ChecklistOption() { + } + + public Long getId() { + return id; + } + + public Checklist getChecklist() { + return checklist; + } + + public Integer getOptionId() { + return optionId; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ChecklistOption that = (ChecklistOption) o; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return Objects.hashCode(id); + } + + @Override + public String toString() { + return "ChecklistOption{" + + "id=" + id + + ", checklist=" + checklist + + ", optionId=" + optionId + + '}'; + } +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/ChecklistQuestion.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/ChecklistQuestion.java new file mode 100644 index 000000000..b6639de37 --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/ChecklistQuestion.java @@ -0,0 +1,78 @@ +package com.bang_ggood.checklist.domain; + +import com.bang_ggood.BaseEntity; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import java.util.Objects; + + +@Entity +public class ChecklistQuestion extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private Checklist checklist; + + private int questionId; + + private String answer; + + public ChecklistQuestion(Checklist checklist, int questionId, String answer) { + this.checklist = checklist; + this.questionId = questionId; + this.answer = answer; + } + + protected ChecklistQuestion() { + } + + public Long getId() { + return id; + } + + public Checklist getChecklist() { + return checklist; + } + + public int getQuestionId() { + return questionId; + } + + public String getAnswer() { + return answer; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ChecklistQuestion that = (ChecklistQuestion) o; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return Objects.hashCode(id); + } + + @Override + public String toString() { + return "ChecklistQuestion{" + + "id=" + id + + ", checklist=" + checklist + + ", questionId=" + questionId + + ", answer=" + answer + + '}'; + } +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/Grade.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/Grade.java new file mode 100644 index 000000000..25d3b49f4 --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/Grade.java @@ -0,0 +1,11 @@ +package com.bang_ggood.checklist.domain; + +public enum Grade { + + GOOD(3), + SOSO(2), + BAD(1); + + Grade(int score) { + } +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/Option.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/Option.java new file mode 100644 index 000000000..0eca5d189 --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/Option.java @@ -0,0 +1,34 @@ +package com.bang_ggood.checklist.domain; + +import java.util.Arrays; + +public enum Option { + + AIR_CONDITIONER(1, "에어컨"), + REFRIGERATOR(2, "냉장고"), + MICROWAVE_OVEN(3, "전자레인지"), + WASHING_MACHINE(4, "세탁기"), + SINK(5, "싱크대"), + GAS_STOVE(6, "가스레인지/인덕션"), + INTERNET(7, "인터넷"), + BED(8, "침대"), + DESK(9, "책상"), + CLOSET(10, "옷장"), + SHOE_RACK(11, "신발장"), + ELEVATOR(12, "엘리베이터"), + DRYER(13, "건조기"), + TV(14, "TV"); + + private final int id; + private final String name; + + Option(int id, String name) { + this.id = id; + this.name = name; + } + + public static boolean contains(int id) { + return Arrays.stream(Option.values()) + .anyMatch(option -> option.id == id); + } +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/Question.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/Question.java new file mode 100644 index 000000000..0840637b4 --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/Question.java @@ -0,0 +1,20 @@ +package com.bang_ggood.checklist.domain; + +public class Question { + + private final String title; + private final String subtitle; + + public Question(String title, String subtitle) { + this.title = title; + this.subtitle = subtitle; + } + + public String getTitle() { + return title; + } + + public String getSubtitle() { + return subtitle; + } +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/Questionlist.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/Questionlist.java new file mode 100644 index 000000000..e08b23f61 --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/Questionlist.java @@ -0,0 +1,79 @@ +package com.bang_ggood.checklist.domain; + +import java.util.HashMap; +import java.util.Map; +import org.springframework.stereotype.Component; + +@Component +public class Questionlist { + + public Map questions; + + public Questionlist() { + questions = new HashMap<>(); + initClean(); + initRoomCondition(); + initAmenity(); + initOption(); + initEnvironment(); + initSecurity(); + initEconomic(); + } + + public boolean contains(int questionId) { + return questions.containsKey(questionId); + } + + private void initClean() { + questions.put(1, new Question("방 안에 물이 새거나 곰팡이가 핀 곳은 없나요?", "천장, 벽면, 가구 뒤, 장판을 확인하세요.")); + questions.put(2, new Question("방에서 불쾌한 냄새가 나지는 않나요?", "싱크대, 화장실 배수구를 확인하세요.")); + questions.put(3, new Question("에어컨 내부는 깨끗한가요?", null)); + questions.put(4, new Question("벌레가 나온 흔적은 없나요?", "벌레 퇴치약이 부착되어있는지, 싱크대 하부장 경첩에 배설물이 있는지 확인하세요.")); + questions.put(5, new Question("창문 밖에서 불쾌한 냄새가 들어오진 않나요?", "하천, 배수구, 음식물 쓰레기통이 있지 않은지 확인하세요.")); + } + + private void initRoomCondition() { + questions.put(6, new Question("수압 및 배수가 괜찮은가요?", "싱크대와 화장실에서 동시에 물을 틀어보세요.")); + questions.put(7, new Question("온수가 잘 나오나요?", null)); + questions.put(8, new Question("파손된 시설 (창문 / 방충망 / 벽)이 있지 않나요?", null)); + questions.put(9, new Question("보일러가 잘 동작하나요?", null)); + questions.put(10, new Question("콘센트 위치와 갯수가 적절한가요?", null)); + questions.put(11, new Question("벽지 상태가 양호한가요?", null)); + } + + private void initAmenity() { + questions.put(12, new Question("지하철역과 버스 정류장이 가까운 곳에 있나요?", null)); + questions.put(13, new Question("편의점, 마트, 세탁소, 공원이 가까운 곳에 있나요?", null)); + questions.put(14, new Question("병원이나 약국이 가까운 곳에 있나요?", null)); + } + + private void initOption() { + questions.put(15, new Question("옵션 가구들의 상태는 양호하나요?", "정상 작동 여부를 확인하세요.")); + questions.put(16, new Question("필요한 물품들을 충분히 수납할 수 있는 공간이 있나요?", null)); + } + + private void initEnvironment() { + questions.put(17, new Question("햇빛이 잘 들어오나요?", null)); + questions.put(18, new Question("환기가 잘 되는 구조인가요?", "창문의 크기와 방향을 확인하세요.")); + questions.put(19, new Question("방음이 잘 되나요?", "벽을 두드려서 가벽이 아닌지 확인하세요.")); + questions.put(20, new Question("주변에 소음 시설이 있나요?", "유흥시설, 놀이터, 공사장이 있는지 확인하세요.")); + questions.put(21, new Question("1층에 음식점이 있지는 않나요?", null)); + questions.put(22, new Question("집가는 길이 언덕이진 않나요?", null)); + } + + private void initSecurity() { + questions.put(23, new Question("출입구와 복도에 CCTV가 설치되어 있나요?", null)); + questions.put(24, new Question("집에 방범창이나 이중 잠금장치가 설치되어 있나요?", null)); + questions.put(25, new Question("자취방의 보안 시설이 잘 갖추어져 있나요? (도어락, 창문 잠금장치 등)", null)); + questions.put(26, new Question("화재 경보기나 소화기 등의 안전 시설이 설치되어 있나요?", null)); + questions.put(27, new Question("주변 도로가 밤에도 충분히 밝은가요?", null)); + questions.put(28, new Question("화면이 달린 인터폰이 제공되나요?", null)); + questions.put(29, new Question("옆 건물에서 잘 보이는 구조는 아닌가요?", null)); + questions.put(30, new Question("관리자분이 함께 상주하시나요?", null)); + } + + private void initEconomic() { + questions.put(31, new Question("보증금/전월세 비용이 합리적인가요?", "관리비도 포함하여 고려하세요.")); + questions.put(32, new Question("교통 비용(지하철, 버스, 자가용)이 추가적으로 들지 않나요?", "주차 비용을 확인하세요.")); + } +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/ChecklistCreateRequest.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/ChecklistCreateRequest.java new file mode 100644 index 000000000..246b1bb86 --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/ChecklistCreateRequest.java @@ -0,0 +1,18 @@ +package com.bang_ggood.checklist.dto; + +import com.bang_ggood.room.domain.Room; +import com.bang_ggood.room.dto.RoomCreateRequest; +import jakarta.validation.Valid; +import java.util.List; + +public record ChecklistCreateRequest(@Valid RoomCreateRequest room, List options, + @Valid List questions) { + + public Room toRoomEntity() { + return room.toRoomEntity(); + } + + public ChecklistInfo toChecklistInfo() { + return new ChecklistInfo(room.deposit(), room.rent(), room.contractTerm(), room.realEstate()); + } +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/ChecklistInfo.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/ChecklistInfo.java new file mode 100644 index 000000000..b3ba6dd31 --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/ChecklistInfo.java @@ -0,0 +1,4 @@ +package com.bang_ggood.checklist.dto; + +public record ChecklistInfo(Integer deposit, Integer rent, Integer contractTerm, String realEstate) { +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/QuestionCreateRequest.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/QuestionCreateRequest.java new file mode 100644 index 000000000..26beec952 --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/QuestionCreateRequest.java @@ -0,0 +1,6 @@ +package com.bang_ggood.checklist.dto; + +import jakarta.validation.constraints.NotNull; + +public record QuestionCreateRequest(@NotNull Integer questionId, String answer) { +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/repository/ChecklistOptionRepository.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/repository/ChecklistOptionRepository.java new file mode 100644 index 000000000..8ed6404d4 --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/repository/ChecklistOptionRepository.java @@ -0,0 +1,7 @@ +package com.bang_ggood.checklist.repository; + +import com.bang_ggood.checklist.domain.ChecklistOption; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ChecklistOptionRepository extends JpaRepository { +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/repository/ChecklistQuestionRepository.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/repository/ChecklistQuestionRepository.java new file mode 100644 index 000000000..771ecc025 --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/repository/ChecklistQuestionRepository.java @@ -0,0 +1,7 @@ +package com.bang_ggood.checklist.repository; + +import com.bang_ggood.checklist.domain.ChecklistQuestion; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ChecklistQuestionRepository extends JpaRepository { +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/repository/ChecklistRepository.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/repository/ChecklistRepository.java new file mode 100644 index 000000000..189bf3765 --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/repository/ChecklistRepository.java @@ -0,0 +1,7 @@ +package com.bang_ggood.checklist.repository; + +import com.bang_ggood.checklist.domain.Checklist; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ChecklistRepository extends JpaRepository { +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/service/ChecklistService.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/service/ChecklistService.java new file mode 100644 index 000000000..d5ded2bda --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/service/ChecklistService.java @@ -0,0 +1,122 @@ +package com.bang_ggood.checklist.service; + +import com.bang_ggood.checklist.domain.Checklist; +import com.bang_ggood.checklist.domain.ChecklistOption; +import com.bang_ggood.checklist.domain.ChecklistQuestion; +import com.bang_ggood.checklist.domain.Option; +import com.bang_ggood.checklist.domain.Questionlist; +import com.bang_ggood.checklist.dto.ChecklistCreateRequest; +import com.bang_ggood.checklist.dto.ChecklistInfo; +import com.bang_ggood.checklist.dto.QuestionCreateRequest; +import com.bang_ggood.checklist.repository.ChecklistOptionRepository; +import com.bang_ggood.checklist.repository.ChecklistQuestionRepository; +import com.bang_ggood.checklist.repository.ChecklistRepository; +import com.bang_ggood.exception.BangggoodException; +import com.bang_ggood.exception.ExceptionCode; +import com.bang_ggood.room.domain.Room; +import com.bang_ggood.room.repository.RoomRepository; +import com.bang_ggood.user.domain.User; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class ChecklistService { + + private final ChecklistRepository checklistRepository; + private final RoomRepository roomRepository; + private final ChecklistOptionRepository checklistOptionRepository; + private final ChecklistQuestionRepository checklistQuestionRepository; + private final Questionlist questionList; + + public ChecklistService(ChecklistRepository checklistRepository, RoomRepository roomRepository, + ChecklistOptionRepository checklistOptionRepository, + ChecklistQuestionRepository checklistQuestionRepository, Questionlist questionList) { + this.checklistRepository = checklistRepository; + this.roomRepository = roomRepository; + this.checklistOptionRepository = checklistOptionRepository; + this.checklistQuestionRepository = checklistQuestionRepository; + this.questionList = questionList; + } + + + @Transactional + public long createChecklist(ChecklistCreateRequest checklistCreateRequest) { + Room room = roomRepository.save(checklistCreateRequest.toRoomEntity()); + + ChecklistInfo checklistInfo = checklistCreateRequest.toChecklistInfo(); + Checklist checklist = new Checklist(new User(1L, "방방이"), room, checklistInfo.deposit(), checklistInfo.rent(), + checklistInfo.contractTerm(), checklistInfo.realEstate()); + checklistRepository.save(checklist); + + createChecklistOptions(checklistCreateRequest, checklist); + createChecklistQuestions(checklistCreateRequest, checklist); + return checklist.getId(); + } + + private void createChecklistOptions(ChecklistCreateRequest checklistCreateRequest, Checklist checklist) { + List optionIds = checklistCreateRequest.options(); + validateOptions(optionIds); + List checklistOptions = optionIds.stream() + .map(option -> new ChecklistOption(checklist, option)) + .toList(); + checklistOptionRepository.saveAll(checklistOptions); + } + + private void validateOptions(List optionIds) { + validateOptionDuplicate(optionIds); + validateOptionInvalid(optionIds); + } + + private void validateOptionDuplicate(List optionIds) { + Set set = new HashSet<>(); + optionIds.forEach(id -> { + if (!set.add(id)) { + throw new BangggoodException(ExceptionCode.OPTION_DUPLICATED); + } + }); + } + + private void validateOptionInvalid(List optionIds) { + for (Integer optionId : optionIds) { + if (!Option.contains(optionId)) { + throw new BangggoodException(ExceptionCode.INVALID_OPTION); + } + } + } + + private void createChecklistQuestions(ChecklistCreateRequest checklistCreateRequest, Checklist checklist) { + List questions = checklistCreateRequest.questions(); + validateQuestion(questions); + for (QuestionCreateRequest questionCreateRequest : questions) { + Integer questionId = questionCreateRequest.questionId(); + ChecklistQuestion checklistQuestion = new ChecklistQuestion(checklist, questionId, + questionCreateRequest.answer()); + checklistQuestionRepository.save(checklistQuestion); + } + } + + private void validateQuestion(List questions) { + validateQuestionDuplicate(questions); + validateQuestionInvalid(questions); + } + + private void validateQuestionDuplicate(List questions) { + Set set = new HashSet<>(); + questions.forEach(question -> { + if (!set.add(question.questionId())) { + throw new BangggoodException(ExceptionCode.QUESTION_DUPLICATED); + } + }); + } + + private void validateQuestionInvalid(List questions) { + for (QuestionCreateRequest questionCreateRequest : questions) { + if (!questionList.contains(questionCreateRequest.questionId())) { + throw new BangggoodException(ExceptionCode.INVALID_QUESTION); + } + } + } +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/exception/ExceptionCode.java b/backend/bang-ggood/src/main/java/com/bang_ggood/exception/ExceptionCode.java index 6caa1dcb0..33befed7f 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/exception/ExceptionCode.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/exception/ExceptionCode.java @@ -5,6 +5,10 @@ public enum ExceptionCode { INVALID_PARAMETER(HttpStatus.BAD_REQUEST, "잘못된 인자입니다."), + INVALID_OPTION(HttpStatus.BAD_REQUEST, "잘못된 옵션 ID입니다."), + OPTION_DUPLICATED(HttpStatus.BAD_REQUEST, "중복된 옵션이 존재합니다."), + INVALID_QUESTION(HttpStatus.BAD_REQUEST, "잘못된 질문 ID입니다."), + QUESTION_DUPLICATED(HttpStatus.BAD_REQUEST, "중복된 질문이 존재합니다."), USER_NOT_FOUND(HttpStatus.BAD_REQUEST, "유저가 존재하지 않습니다."), CATEGORY_PRIORITY_INVALID_COUNT(HttpStatus.BAD_REQUEST, "카테고리 개수가 유효하지 않습니다."), CATEGORY_NOT_FOUND(HttpStatus.BAD_REQUEST, "카테코리가 존재하지 않습니다."), diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/exception/GlobalExceptionHandler.java b/backend/bang-ggood/src/main/java/com/bang_ggood/exception/GlobalExceptionHandler.java index 732aabde0..9ebbcc99f 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/exception/GlobalExceptionHandler.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/exception/GlobalExceptionHandler.java @@ -3,6 +3,7 @@ import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -10,7 +11,8 @@ public class GlobalExceptionHandler { @ExceptionHandler(BangggoodException.class) - public ResponseEntity handleBangggoodException(BangggoodException exception, HttpServletRequest request) { + public ResponseEntity handleBangggoodException(BangggoodException exception, + HttpServletRequest request) { ExceptionResponse response = new ExceptionResponse( request.getMethod(), request.getRequestURI(), @@ -28,4 +30,16 @@ public ResponseEntity handleRuntimeException(HttpServletReque return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(response); } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity handleMethodArgumentNotValidException( + MethodArgumentNotValidException exception, + HttpServletRequest request) { + ExceptionResponse response = new ExceptionResponse( + request.getMethod(), + request.getRequestURI(), + exception.getMessage()); + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(response); + } } diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/room/domain/Room.java b/backend/bang-ggood/src/main/java/com/bang_ggood/room/domain/Room.java new file mode 100644 index 000000000..4f69a535f --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/room/domain/Room.java @@ -0,0 +1,90 @@ +package com.bang_ggood.room.domain; + +import com.bang_ggood.BaseEntity; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import java.util.Objects; + +@Entity +public class Room extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + + private Integer floor; + + private String address; + + private String station; + + private Integer walkingTime; + + protected Room() { + } + + public Room(String name, Integer floor, String address, String station, Integer walkingTime) { + this.name = name; + this.floor = floor; + this.address = address; + this.station = station; + this.walkingTime = walkingTime; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public Integer getFloor() { + return floor; + } + + public String getAddress() { + return address; + } + + public String getStation() { + return station; + } + + public Integer getWalkingTime() { + return walkingTime; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Room room = (Room) o; + return Objects.equals(id, room.id); + } + + @Override + public int hashCode() { + return Objects.hashCode(id); + } + + @Override + public String toString() { + return "Room{" + + "id=" + id + + ", name='" + name + '\'' + + ", floor=" + floor + + ", address='" + address + '\'' + + ", station='" + station + '\'' + + ", walkingTime=" + walkingTime + + '}'; + } +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/room/dto/RoomCreateRequest.java b/backend/bang-ggood/src/main/java/com/bang_ggood/room/dto/RoomCreateRequest.java new file mode 100644 index 000000000..8837cc721 --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/room/dto/RoomCreateRequest.java @@ -0,0 +1,13 @@ +package com.bang_ggood.room.dto; + +import com.bang_ggood.room.domain.Room; +import jakarta.validation.constraints.NotNull; + +public record RoomCreateRequest(@NotNull(message = "방 이름이 존재하지 않습니다.") String name, + Integer deposit, Integer rent, Integer contractTerm, Integer floor, + String address, String station, Integer walkingTime, String realEstate) { + + public Room toRoomEntity() { + return new Room(name, floor, address, station, walkingTime); + } +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/room/repository/RoomRepository.java b/backend/bang-ggood/src/main/java/com/bang_ggood/room/repository/RoomRepository.java new file mode 100644 index 000000000..4818c8a1c --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/room/repository/RoomRepository.java @@ -0,0 +1,7 @@ +package com.bang_ggood.room.repository; + +import com.bang_ggood.room.domain.Room; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RoomRepository extends JpaRepository { +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/user/domain/User.java b/backend/bang-ggood/src/main/java/com/bang_ggood/user/domain/User.java index a5796317c..67bd71867 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/user/domain/User.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/user/domain/User.java @@ -20,12 +20,17 @@ public class User extends BaseEntity { @Column(nullable = false) private String name; - protected User() { + public User(Long id, String name) { + this.id = id; + this.name = name; } public User(String name) { this.name = name; } + + protected User() { + } @Override public boolean equals(Object o) { @@ -41,7 +46,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(id); + return Objects.hashCode(id); } @Override diff --git a/backend/bang-ggood/src/main/resources/schema.sql b/backend/bang-ggood/src/main/resources/schema.sql index a318875f2..39833ee3d 100644 --- a/backend/bang-ggood/src/main/resources/schema.sql +++ b/backend/bang-ggood/src/main/resources/schema.sql @@ -1,12 +1,68 @@ +-- Drop tables if they exist +DROP TABLE IF EXISTS checklist CASCADE; +DROP TABLE IF EXISTS checklist_option CASCADE; +DROP TABLE IF EXISTS checklist_question CASCADE; +DROP TABLE IF EXISTS room CASCADE; +DROP TABLE IF EXISTS users CASCADE; + +-- Create tables +CREATE TABLE room +( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + floor INTEGER, + walking_time INTEGER, + created_at TIMESTAMP(6), + modified_at TIMESTAMP(6), + address VARCHAR(255), + name VARCHAR(255), + station VARCHAR(255) +); + CREATE TABLE users ( - id bigint generated by default as identity, - name varchar(255) not null, - created_at TIMESTAMP not null, - modified_at TIMESTAMP not null, - primary key (id) + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(255) NOT NULL, + created_at TIMESTAMP(6), + modified_at TIMESTAMP(6) ); +CREATE TABLE checklist +( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + contract_term INTEGER, + deposit INTEGER, + rent INTEGER, + created_at TIMESTAMP(6), + modified_at TIMESTAMP(6), + room_id BIGINT NOT NULL UNIQUE, + user_id BIGINT NOT NULL, + real_estate VARCHAR(255), + FOREIGN KEY (room_id) REFERENCES room (id), + FOREIGN KEY (user_id) REFERENCES users (id) +); + +CREATE TABLE checklist_option +( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + option_id INTEGER NOT NULL, + checklist_id BIGINT NOT NULL, + created_at TIMESTAMP(6), + modified_at TIMESTAMP(6), + FOREIGN KEY (checklist_id) REFERENCES checklist (id) +); + +CREATE TABLE checklist_question +( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + question_id INTEGER NOT NULL, + checklist_id BIGINT NOT NULL, + created_at TIMESTAMP(6), + modified_at TIMESTAMP(6), + answer VARCHAR(255), + FOREIGN KEY (checklist_id) REFERENCES checklist (id) +); + + CREATE TABLE category_priority ( id bigint generated by default as identity, diff --git a/backend/bang-ggood/src/test/java/com/bang_ggood/AcceptanceTest.java b/backend/bang-ggood/src/test/java/com/bang_ggood/AcceptanceTest.java new file mode 100644 index 000000000..b03d6c029 --- /dev/null +++ b/backend/bang-ggood/src/test/java/com/bang_ggood/AcceptanceTest.java @@ -0,0 +1,22 @@ +package com.bang_ggood; + +import io.restassured.RestAssured; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; + +@ActiveProfiles("test") +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@Sql(scripts = {"/schema-test.sql", "/data-test.sql"}) +public abstract class AcceptanceTest { + + @LocalServerPort + private int port; + + @BeforeEach + void setPort() { + RestAssured.port = port; + } +} diff --git a/backend/bang-ggood/src/test/java/com/bang_ggood/IntegrationTestSupport.java b/backend/bang-ggood/src/test/java/com/bang_ggood/IntegrationTestSupport.java index 903186620..c02b03a44 100644 --- a/backend/bang-ggood/src/test/java/com/bang_ggood/IntegrationTestSupport.java +++ b/backend/bang-ggood/src/test/java/com/bang_ggood/IntegrationTestSupport.java @@ -1,11 +1,12 @@ package com.bang_ggood; - import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; @ActiveProfiles("test") @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@Sql(scripts = {"/schema-test.sql", "/data-test.sql"}) public abstract class IntegrationTestSupport { } diff --git a/backend/bang-ggood/src/test/java/com/bang_ggood/JpaAuditingTest.java b/backend/bang-ggood/src/test/java/com/bang_ggood/JpaAuditingTest.java index f2b231d7c..74ffa146e 100644 --- a/backend/bang-ggood/src/test/java/com/bang_ggood/JpaAuditingTest.java +++ b/backend/bang-ggood/src/test/java/com/bang_ggood/JpaAuditingTest.java @@ -1,5 +1,8 @@ package com.bang_ggood; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; diff --git a/backend/bang-ggood/src/test/java/com/bang_ggood/checklist/ChecklistFixture.java b/backend/bang-ggood/src/test/java/com/bang_ggood/checklist/ChecklistFixture.java new file mode 100644 index 000000000..bf62a9fb9 --- /dev/null +++ b/backend/bang-ggood/src/test/java/com/bang_ggood/checklist/ChecklistFixture.java @@ -0,0 +1,76 @@ +package com.bang_ggood.checklist; + +import com.bang_ggood.checklist.dto.ChecklistCreateRequest; +import com.bang_ggood.checklist.dto.QuestionCreateRequest; +import com.bang_ggood.room.RoomFixture; +import java.util.List; + +public class ChecklistFixture { + + public static final QuestionCreateRequest QUESTION_1_CREATE_REQUEST = new QuestionCreateRequest( + 1, "GOOD" + ); + + public static final QuestionCreateRequest QUESTION_2_CREATE_REQUEST = new QuestionCreateRequest( + 2, "SOSO" + ); + + public static final QuestionCreateRequest QUESTION_3_CREATE_REQUEST = new QuestionCreateRequest( + 3, "BAD" + ); + + public static final QuestionCreateRequest QUESTION_5_CREATE_REQUEST = new QuestionCreateRequest( + 5, null + ); + + public static final QuestionCreateRequest QUESTION_CREATE_REQUEST_NO_ID = new QuestionCreateRequest( + null, null + ); + + public static final QuestionCreateRequest QUESTION_CREATE_REQUEST_INVALID_ID = new QuestionCreateRequest( + 9999, "SOSO" + ); + + + public static final ChecklistCreateRequest CHECKLIST_CREATE_REQUEST = new ChecklistCreateRequest( + RoomFixture.ROOM_CREATE_REQUEST, List.of(1, 2, 3, 5), + List.of(QUESTION_1_CREATE_REQUEST, QUESTION_2_CREATE_REQUEST, + QUESTION_3_CREATE_REQUEST, QUESTION_5_CREATE_REQUEST) + ); + + public static final ChecklistCreateRequest CHECKLIST_CREATE_REQUEST_NO_ROOM_NAME = new ChecklistCreateRequest( + RoomFixture.ROOM_CREATE_REQUEST_NO_ROOM_NAME, List.of(1, 2, 3, 5), + List.of(QUESTION_1_CREATE_REQUEST, QUESTION_2_CREATE_REQUEST, + QUESTION_3_CREATE_REQUEST, QUESTION_5_CREATE_REQUEST) + ); + + public static final ChecklistCreateRequest CHECKLIST_CREATE_REQUEST_NO_QUESTION_ID = new ChecklistCreateRequest( + RoomFixture.ROOM_CREATE_REQUEST, List.of(1, 2, 3, 5), + List.of(QUESTION_1_CREATE_REQUEST, QUESTION_2_CREATE_REQUEST, + QUESTION_3_CREATE_REQUEST, QUESTION_CREATE_REQUEST_NO_ID) + ); + + public static final ChecklistCreateRequest CHECKLIST_CREATE_REQUEST_INVALID_QUESTION_ID = new ChecklistCreateRequest( + RoomFixture.ROOM_CREATE_REQUEST, List.of(1, 2, 3, 5), + List.of(QUESTION_1_CREATE_REQUEST, QUESTION_2_CREATE_REQUEST, + QUESTION_3_CREATE_REQUEST, QUESTION_CREATE_REQUEST_INVALID_ID) + ); + + public static final ChecklistCreateRequest CHECKLIST_CREATE_REQUEST_INVALID_OPTION_ID = new ChecklistCreateRequest( + RoomFixture.ROOM_CREATE_REQUEST, List.of(1, 2, 3, 9999), + List.of(QUESTION_1_CREATE_REQUEST, QUESTION_2_CREATE_REQUEST, + QUESTION_3_CREATE_REQUEST, QUESTION_5_CREATE_REQUEST) + ); + + public static final ChecklistCreateRequest CHECKLIST_CREATE_REQUEST_DUPLICATED_QUESTION_ID = new ChecklistCreateRequest( + RoomFixture.ROOM_CREATE_REQUEST, List.of(1, 2, 3, 5), + List.of(QUESTION_1_CREATE_REQUEST, QUESTION_2_CREATE_REQUEST, + QUESTION_3_CREATE_REQUEST, QUESTION_3_CREATE_REQUEST) + ); + + public static final ChecklistCreateRequest CHECKLIST_CREATE_REQUEST_DUPLICATED_OPTION_ID = new ChecklistCreateRequest( + RoomFixture.ROOM_CREATE_REQUEST, List.of(1, 2, 3, 3), + List.of(QUESTION_1_CREATE_REQUEST, QUESTION_2_CREATE_REQUEST, + QUESTION_3_CREATE_REQUEST, QUESTION_5_CREATE_REQUEST) + ); +} diff --git a/backend/bang-ggood/src/test/java/com/bang_ggood/checklist/controller/ChecklistE2ETest.java b/backend/bang-ggood/src/test/java/com/bang_ggood/checklist/controller/ChecklistE2ETest.java new file mode 100644 index 000000000..cb658da64 --- /dev/null +++ b/backend/bang-ggood/src/test/java/com/bang_ggood/checklist/controller/ChecklistE2ETest.java @@ -0,0 +1,44 @@ +package com.bang_ggood.checklist.controller; + +import com.bang_ggood.AcceptanceTest; +import com.bang_ggood.checklist.ChecklistFixture; +import io.restassured.RestAssured; +import io.restassured.http.ContentType; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class ChecklistE2ETest extends AcceptanceTest { + + @DisplayName("체크리스트 방 정보 작성 성공") + @Test + void createChecklist() { + RestAssured.given().log().all() + .contentType(ContentType.JSON) + .body(ChecklistFixture.CHECKLIST_CREATE_REQUEST) + .when().post("/checklists") + .then().log().all() + .statusCode(201); + } + + @DisplayName("체크리스트 방 정보 작성 실패: 방 이름을 넣지 않은 경우") + @Test + void createChecklist_noRoomName_exception() { + RestAssured.given().log().all() + .contentType(ContentType.JSON) + .body(ChecklistFixture.CHECKLIST_CREATE_REQUEST_NO_ROOM_NAME) + .when().post("/checklists") + .then().log().all() + .statusCode(400); + } + + @DisplayName("체크리스트 방 정보 작성 실패: 질문 ID를 넣지 않은 경우") + @Test + void createChecklist_noQuestionId_exception() { + RestAssured.given().log().all() + .contentType(ContentType.JSON) + .body(ChecklistFixture.CHECKLIST_CREATE_REQUEST_NO_QUESTION_ID) + .when().post("/checklists") + .then().log().all() + .statusCode(400); + } +} diff --git a/backend/bang-ggood/src/test/java/com/bang_ggood/checklist/domain/OptionTest.java b/backend/bang-ggood/src/test/java/com/bang_ggood/checklist/domain/OptionTest.java new file mode 100644 index 000000000..c9643e807 --- /dev/null +++ b/backend/bang-ggood/src/test/java/com/bang_ggood/checklist/domain/OptionTest.java @@ -0,0 +1,21 @@ +package com.bang_ggood.checklist.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class OptionTest { + + @DisplayName("옵션 포함 성공: 포함하는 경우") + @Test + void contains_true() { + assertThat(Option.contains(1)).isTrue(); + } + + @DisplayName("옵션 포함 성공 : 포함하지 않는 경우") + @Test + void contains_false() { + assertThat(Option.contains(9999)).isFalse(); + } +} diff --git a/backend/bang-ggood/src/test/java/com/bang_ggood/checklist/domain/QuestionlistTest.java b/backend/bang-ggood/src/test/java/com/bang_ggood/checklist/domain/QuestionlistTest.java new file mode 100644 index 000000000..733b7d436 --- /dev/null +++ b/backend/bang-ggood/src/test/java/com/bang_ggood/checklist/domain/QuestionlistTest.java @@ -0,0 +1,29 @@ +package com.bang_ggood.checklist.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class QuestionlistTest { + + private Questionlist questionList; + + @BeforeEach + void init() { + questionList = new Questionlist(); + } + + @DisplayName("질문 리스트 포함 성공: 포함하는 경우") + @Test + void contains_true() { + assertThat(questionList.contains(1)).isTrue(); + } + + @DisplayName("질문 리스트 포함 성공 : 포함하지 않는 경우") + @Test + void contains_false() { + assertThat(questionList.contains(9999)).isFalse(); + } +} diff --git a/backend/bang-ggood/src/test/java/com/bang_ggood/checklist/service/ChecklistServiceTest.java b/backend/bang-ggood/src/test/java/com/bang_ggood/checklist/service/ChecklistServiceTest.java new file mode 100644 index 000000000..ed5c3359d --- /dev/null +++ b/backend/bang-ggood/src/test/java/com/bang_ggood/checklist/service/ChecklistServiceTest.java @@ -0,0 +1,69 @@ +package com.bang_ggood.checklist.service; + + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.bang_ggood.IntegrationTestSupport; +import com.bang_ggood.checklist.ChecklistFixture; +import com.bang_ggood.exception.BangggoodException; +import com.bang_ggood.exception.ExceptionCode; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class ChecklistServiceTest extends IntegrationTestSupport { + + @Autowired + private ChecklistService checklistService; + + @DisplayName("체크리스트 방 정보 작성 성공") + @Test + void createChecklist() { + //given & when + long checklistId = checklistService.createChecklist(ChecklistFixture.CHECKLIST_CREATE_REQUEST); + + //then + assertThat(checklistId).isEqualTo(1); + } + + @DisplayName("체크리스트 방 정보 작성 실패: 질문 id가 유효하지 않을 경우") + @Test + void createChecklist_invalidQuestionId_exception() { + //given & when & then + assertThatThrownBy( + () -> checklistService.createChecklist(ChecklistFixture.CHECKLIST_CREATE_REQUEST_INVALID_QUESTION_ID)) + .isInstanceOf(BangggoodException.class) + .hasMessage(ExceptionCode.INVALID_QUESTION.getMessage()); + } + + @DisplayName("체크리스트 방 정보 작성 실패: 질문 id가 중복일 경우") + @Test + void createChecklist_duplicatedQuestionId_exception() { + //given & when & then + assertThatThrownBy( + () -> checklistService.createChecklist(ChecklistFixture.CHECKLIST_CREATE_REQUEST_DUPLICATED_QUESTION_ID)) + .isInstanceOf(BangggoodException.class) + .hasMessage(ExceptionCode.QUESTION_DUPLICATED.getMessage()); + } + + @DisplayName("체크리스트 방 정보 작성 실패: 옵션 id가 유효하지 않을 경우") + @Test + void createChecklist_invalidOptionId_exception() { + //given & when & then + assertThatThrownBy( + () -> checklistService.createChecklist(ChecklistFixture.CHECKLIST_CREATE_REQUEST_INVALID_OPTION_ID)) + .isInstanceOf(BangggoodException.class) + .hasMessage(ExceptionCode.INVALID_OPTION.getMessage()); + } + + @DisplayName("체크리스트 방 정보 작성 실패: 옵션 id가 중복일 경우") + @Test + void createChecklist_duplicatedOptionId_exception() { + //given & when & then + assertThatThrownBy( + () -> checklistService.createChecklist(ChecklistFixture.CHECKLIST_CREATE_REQUEST_DUPLICATED_OPTION_ID)) + .isInstanceOf(BangggoodException.class) + .hasMessage(ExceptionCode.OPTION_DUPLICATED.getMessage()); + } +} diff --git a/backend/bang-ggood/src/test/java/com/bang_ggood/room/RoomFixture.java b/backend/bang-ggood/src/test/java/com/bang_ggood/room/RoomFixture.java new file mode 100644 index 000000000..942106964 --- /dev/null +++ b/backend/bang-ggood/src/test/java/com/bang_ggood/room/RoomFixture.java @@ -0,0 +1,16 @@ +package com.bang_ggood.room; + +import com.bang_ggood.room.dto.RoomCreateRequest; + +public class RoomFixture { + + public static final RoomCreateRequest ROOM_CREATE_REQUEST = new RoomCreateRequest( + "방이름", 1000, 50, 12, 3, + "부산광역시 루터회관", "잠실역", 10, "방끗공인중개사" + ); + + public static final RoomCreateRequest ROOM_CREATE_REQUEST_NO_ROOM_NAME = new RoomCreateRequest( + null, 1000, 50, 12, 3, + "부산광역시 루터회관", "잠실역", 10, "방끗공인중개사" + ); +} diff --git a/backend/bang-ggood/src/test/resources/schema-test.sql b/backend/bang-ggood/src/test/resources/schema-test.sql index a4583caf7..2dfaae518 100644 --- a/backend/bang-ggood/src/test/resources/schema-test.sql +++ b/backend/bang-ggood/src/test/resources/schema-test.sql @@ -1,10 +1,66 @@ -CREATE TABLE if not exists users +-- Drop tables if they exist +DROP TABLE IF EXISTS checklist CASCADE; +DROP TABLE IF EXISTS checklist_option CASCADE; +DROP TABLE IF EXISTS checklist_question CASCADE; +DROP TABLE IF EXISTS room CASCADE; +DROP TABLE IF EXISTS users CASCADE; +DROP TABLE IF EXISTS test_entity CASCADE; + +-- Create tables +CREATE TABLE room ( - id bigint generated by default as identity, - name varchar(255) not null, - created_at TIMESTAMP not null, - modified_at TIMESTAMP not null, - primary key (id) + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + floor INTEGER, + walking_time INTEGER, + created_at TIMESTAMP(6), + modified_at TIMESTAMP(6), + address VARCHAR(255), + name VARCHAR(255), + station VARCHAR(255) +); + +CREATE TABLE users +( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(255) NOT NULL, + created_at TIMESTAMP(6), + modified_at TIMESTAMP(6) +); + +CREATE TABLE checklist +( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + contract_term INTEGER, + deposit INTEGER, + rent INTEGER, + created_at TIMESTAMP(6), + modified_at TIMESTAMP(6), + room_id BIGINT NOT NULL UNIQUE, + user_id BIGINT NOT NULL, + real_estate VARCHAR(255), + FOREIGN KEY (room_id) REFERENCES room (id), + FOREIGN KEY (user_id) REFERENCES users (id) +); + +CREATE TABLE checklist_option +( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + option_id INTEGER NOT NULL, + checklist_id BIGINT NOT NULL, + created_at TIMESTAMP(6), + modified_at TIMESTAMP(6), + FOREIGN KEY (checklist_id) REFERENCES checklist (id) +); + +CREATE TABLE checklist_question +( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + question_id INTEGER NOT NULL, + checklist_id BIGINT NOT NULL, + created_at TIMESTAMP(6), + modified_at TIMESTAMP(6), + answer VARCHAR(255), + FOREIGN KEY (checklist_id) REFERENCES checklist (id) ); CREATE TABLE if not exists category_priority @@ -27,4 +83,3 @@ CREATE TABLE test_entity modified_at TIMESTAMP not null, primary key (id) ); -