diff --git a/src/main/java/com/dnd/accompany/domain/accompany/api/AccompanyBoardController.java b/src/main/java/com/dnd/accompany/domain/accompany/api/AccompanyBoardController.java new file mode 100644 index 0000000..0a1c804 --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/api/AccompanyBoardController.java @@ -0,0 +1,77 @@ +package com.dnd.accompany.domain.accompany.api; + +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.dnd.accompany.domain.accompany.api.dto.AccompanyBoardInfo; +import com.dnd.accompany.domain.accompany.api.dto.CreateAccompanyBoardRequest; +import com.dnd.accompany.domain.accompany.api.dto.CreateAccompanyBoardResponse; +import com.dnd.accompany.domain.accompany.api.dto.CreateAccompanyRequest; +import com.dnd.accompany.domain.accompany.api.dto.PageResponse; +import com.dnd.accompany.domain.accompany.api.dto.ReadAccompanyBoardResponse; +import com.dnd.accompany.domain.accompany.service.AccompanyBoardService; +import com.dnd.accompany.domain.accompany.service.AccompanyRequestService; +import com.dnd.accompany.domain.auth.dto.jwt.JwtAuthentication; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@Tag(name = "AccompanyBoard") +@RestController +@RequestMapping("api/v1/accompany/boards") +@RequiredArgsConstructor +public class AccompanyBoardController { + + private final AccompanyBoardService accompanyBoardService; + private final AccompanyRequestService accompanyRequestService; + + @Operation(summary = "동행글 생성") + @PostMapping + public ResponseEntity create( + @AuthenticationPrincipal JwtAuthentication user, + @RequestBody @Valid CreateAccompanyBoardRequest request) { + return ResponseEntity.ok(accompanyBoardService.create(user.getId(), request)); + } + + @Operation(summary = "동행글 목록 조회") + @GetMapping + public ResponseEntity> readAll( + @RequestParam(value = "page", defaultValue = "0") int page, + @RequestParam(value = "size", defaultValue = "10") int size) { + return ResponseEntity.ok(accompanyBoardService.readAll(page, size)); + } + + @Operation(summary = "동행글 상세 조회") + @GetMapping("/{id}") + public ResponseEntity read(@PathVariable Long id) { + return ResponseEntity.ok(accompanyBoardService.read(id)); + } + + @Operation(summary = "동행 신청") + @PostMapping("/request") + public ResponseEntity request( + @AuthenticationPrincipal JwtAuthentication user, + @RequestBody @Valid CreateAccompanyRequest request) { + accompanyRequestService.save(user.getId(), request); + return ResponseEntity.ok().build(); + } + + @Operation(summary = "동행글 삭제") + @DeleteMapping("/{id}") + public ResponseEntity delete( + @AuthenticationPrincipal JwtAuthentication user, + @PathVariable Long id) { + accompanyBoardService.delete(user.getId(), id); + return ResponseEntity.ok().build(); + } +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/api/dto/AccompanyBoardDetailInfo.java b/src/main/java/com/dnd/accompany/domain/accompany/api/dto/AccompanyBoardDetailInfo.java new file mode 100644 index 0000000..1e05201 --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/api/dto/AccompanyBoardDetailInfo.java @@ -0,0 +1,46 @@ +package com.dnd.accompany.domain.accompany.api.dto; + +import java.time.LocalDateTime; + +import com.dnd.accompany.domain.accompany.entity.enums.Category; +import com.dnd.accompany.domain.accompany.entity.enums.PreferredAge; +import com.dnd.accompany.domain.accompany.entity.enums.PreferredGender; +import com.dnd.accompany.domain.accompany.entity.enums.Region; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class AccompanyBoardDetailInfo { + Long boardId; + String title; + String content; + Region region; + LocalDateTime startDate; + LocalDateTime endDate; + Long headCount; + Long capacity; + Category category; + PreferredAge preferredAge; + PreferredGender preferredGender; + + @Builder + public AccompanyBoardDetailInfo(Long boardId, String title, String content, Region region, LocalDateTime startDate, + LocalDateTime endDate, Long headCount, Long capacity, Category category, PreferredAge preferredAge, + PreferredGender preferredGender) { + this.boardId = boardId; + this.title = title; + this.content = content; + this.region = region; + this.startDate = startDate; + this.endDate = endDate; + this.headCount = headCount; + this.capacity = capacity; + this.category = category; + this.preferredAge = preferredAge; + this.preferredGender = preferredGender; + } +} \ No newline at end of file diff --git a/src/main/java/com/dnd/accompany/domain/accompany/api/dto/AccompanyBoardInfo.java b/src/main/java/com/dnd/accompany/domain/accompany/api/dto/AccompanyBoardInfo.java new file mode 100644 index 0000000..3bead5d --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/api/dto/AccompanyBoardInfo.java @@ -0,0 +1,32 @@ +package com.dnd.accompany.domain.accompany.api.dto; + +import java.time.LocalDateTime; + +import com.dnd.accompany.domain.accompany.entity.enums.Region; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class AccompanyBoardInfo { + private Long boardId; + private String title; + private Region region; + private LocalDateTime startDate; + private LocalDateTime endDate; + private String nickname; + + @Builder + public AccompanyBoardInfo(Long boardId, String title, Region region, LocalDateTime startDate, LocalDateTime endDate, + String nickname) { + this.boardId = boardId; + this.title = title; + this.region = region; + this.startDate = startDate; + this.endDate = endDate; + this.nickname = nickname; + } +} \ No newline at end of file diff --git a/src/main/java/com/dnd/accompany/domain/accompany/api/dto/CreateAccompanyBoardRequest.java b/src/main/java/com/dnd/accompany/domain/accompany/api/dto/CreateAccompanyBoardRequest.java new file mode 100644 index 0000000..4ba4683 --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/api/dto/CreateAccompanyBoardRequest.java @@ -0,0 +1,27 @@ +package com.dnd.accompany.domain.accompany.api.dto; + +import java.time.LocalDateTime; +import java.util.List; + +import com.dnd.accompany.domain.accompany.entity.enums.Category; +import com.dnd.accompany.domain.accompany.entity.enums.PreferredAge; +import com.dnd.accompany.domain.accompany.entity.enums.PreferredGender; +import com.dnd.accompany.domain.accompany.entity.enums.Region; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +public record CreateAccompanyBoardRequest( + @NotNull String title, + @NotNull @Size(max = 2000) String content, + @NotNull Region region, + @NotNull LocalDateTime startDate, + @NotNull LocalDateTime endDate, + @NotNull Long capacity, + @NotNull Category category, + @NotNull PreferredAge preferredAge, + @NotNull PreferredGender preferredGender, + @NotNull @Size(min = 1, max = 5) List<@NotNull @Size(max = 2000) String> imageUrls, + @NotNull @Size(min = 1, max = 5) List<@NotNull @Size(max = 255) String> tagNames +) { +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/api/dto/CreateAccompanyBoardResponse.java b/src/main/java/com/dnd/accompany/domain/accompany/api/dto/CreateAccompanyBoardResponse.java new file mode 100644 index 0000000..57c25d3 --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/api/dto/CreateAccompanyBoardResponse.java @@ -0,0 +1,6 @@ +package com.dnd.accompany.domain.accompany.api.dto; + +public record CreateAccompanyBoardResponse( + Long boardId +) { +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/api/dto/CreateAccompanyRequest.java b/src/main/java/com/dnd/accompany/domain/accompany/api/dto/CreateAccompanyRequest.java new file mode 100644 index 0000000..1dba847 --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/api/dto/CreateAccompanyRequest.java @@ -0,0 +1,11 @@ +package com.dnd.accompany.domain.accompany.api.dto; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +public record CreateAccompanyRequest( + @NotNull Long boardId, + @NotNull @Size(max = 1500) String introduce, + @NotNull String chatLink +) { +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/api/dto/FindDetailInfoResult.java b/src/main/java/com/dnd/accompany/domain/accompany/api/dto/FindDetailInfoResult.java new file mode 100644 index 0000000..4ddd1eb --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/api/dto/FindDetailInfoResult.java @@ -0,0 +1,24 @@ +package com.dnd.accompany.domain.accompany.api.dto; + +import java.time.LocalDateTime; + +import com.dnd.accompany.domain.accompany.entity.enums.Category; +import com.dnd.accompany.domain.accompany.entity.enums.PreferredAge; +import com.dnd.accompany.domain.accompany.entity.enums.PreferredGender; +import com.dnd.accompany.domain.accompany.entity.enums.Region; + +public record FindDetailInfoResult( + Long boardId, + String title, + String content, + Region region, + LocalDateTime startDate, + LocalDateTime endDate, + Long headCount, + Long capacity, + Category category, + PreferredAge preferredAge, + PreferredGender preferredGender, + String nickname +) { +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/api/dto/PageResponse.java b/src/main/java/com/dnd/accompany/domain/accompany/api/dto/PageResponse.java new file mode 100644 index 0000000..556304e --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/api/dto/PageResponse.java @@ -0,0 +1,9 @@ +package com.dnd.accompany.domain.accompany.api.dto; + +import java.util.List; + +public record PageResponse( + boolean hasNext, + List data +) { +} \ No newline at end of file diff --git a/src/main/java/com/dnd/accompany/domain/accompany/api/dto/ReadAccompanyBoardResponse.java b/src/main/java/com/dnd/accompany/domain/accompany/api/dto/ReadAccompanyBoardResponse.java new file mode 100644 index 0000000..ae975fa --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/api/dto/ReadAccompanyBoardResponse.java @@ -0,0 +1,7 @@ +package com.dnd.accompany.domain.accompany.api.dto; + +public record ReadAccompanyBoardResponse( + AccompanyBoardDetailInfo boardInfo, + UserProfileDetailInfo profileInfo +) { +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/api/dto/UserProfileDetailInfo.java b/src/main/java/com/dnd/accompany/domain/accompany/api/dto/UserProfileDetailInfo.java new file mode 100644 index 0000000..d585fce --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/api/dto/UserProfileDetailInfo.java @@ -0,0 +1,17 @@ +package com.dnd.accompany.domain.accompany.api.dto; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class UserProfileDetailInfo { + private String nickname; + + @Builder + public UserProfileDetailInfo(String nickname) { + this.nickname = nickname; + } +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyBoards.java b/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyBoard.java similarity index 79% rename from src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyBoards.java rename to src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyBoard.java index 078986e..eb9b6ed 100644 --- a/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyBoards.java +++ b/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyBoard.java @@ -5,6 +5,10 @@ import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.SQLRestriction; +import com.dnd.accompany.domain.accompany.entity.enums.Category; +import com.dnd.accompany.domain.accompany.entity.enums.PreferredAge; +import com.dnd.accompany.domain.accompany.entity.enums.PreferredGender; +import com.dnd.accompany.domain.accompany.entity.enums.Region; import com.dnd.accompany.domain.common.entity.TimeBaseEntity; import jakarta.persistence.Column; @@ -26,11 +30,10 @@ @Table(name = "accompany_boards") @SQLRestriction("deleted = false") @SQLDelete(sql = "UPDATE accompany_boards SET deleted = true WHERE id = ?") -public class AccompanyBoards extends TimeBaseEntity { +public class AccompanyBoard extends TimeBaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "accompany_boards_id") private Long id; @Column(nullable = false) @@ -42,11 +45,9 @@ public class AccompanyBoards extends TimeBaseEntity { ) private String content; + @Enumerated(EnumType.STRING) @Column(nullable = false) - private String region; - - @Column(nullable = false) - private String district; + private Region region; @Column(nullable = false) private LocalDateTime startDate; @@ -72,16 +73,16 @@ public class AccompanyBoards extends TimeBaseEntity { @Column(nullable = false) private PreferredGender preferredGender; + private boolean deleted = Boolean.FALSE; + @Builder - public AccompanyBoards(Long id, String title, String content, String region, String district, - LocalDateTime startDate, + public AccompanyBoard(Long id, String title, String content, Region region, LocalDateTime startDate, LocalDateTime endDate, Long headCount, Long capacity, Category category, PreferredAge preferredAge, PreferredGender preferredGender) { this.id = id; this.title = title; this.content = content; this.region = region; - this.district = district; this.startDate = startDate; this.endDate = endDate; this.headCount = headCount; @@ -90,16 +91,4 @@ public AccompanyBoards(Long id, String title, String content, String region, Str this.preferredAge = preferredAge; this.preferredGender = preferredGender; } - - public enum PreferredAge { - SAME, ANY - } - - public enum Category { - FULL, PART, LODGING, TOUR, MEAL - } - - public enum PreferredGender { - SAME, ANY - } } diff --git a/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyImages.java b/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyImage.java similarity index 85% rename from src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyImages.java rename to src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyImage.java index e1cc382..9d5718d 100644 --- a/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyImages.java +++ b/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyImage.java @@ -29,24 +29,25 @@ }) @SQLRestriction("deleted = false") @SQLDelete(sql = "UPDATE accompany_images SET deleted = true WHERE id = ?") -public class AccompanyImages { +public class AccompanyImage { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "accompany_images_id") private Long id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "accompany_boards_id", nullable = false, foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) - private AccompanyBoards accompanyBoards; + private AccompanyBoard accompanyBoard; @Column(nullable = false, length = 2000) private String imageUrl; + private boolean deleted = Boolean.FALSE; + @Builder - public AccompanyImages(Long id, AccompanyBoards accompanyBoards, String imageUrl) { + public AccompanyImage(Long id, AccompanyBoard accompanyBoard, String imageUrl) { this.id = id; - this.accompanyBoards = accompanyBoards; + this.accompanyBoard = accompanyBoard; this.imageUrl = imageUrl; } } diff --git a/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyRequests.java b/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyRequest.java similarity index 75% rename from src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyRequests.java rename to src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyRequest.java index 4c4ddea..c8962d3 100644 --- a/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyRequests.java +++ b/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyRequest.java @@ -3,6 +3,7 @@ import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.SQLRestriction; +import com.dnd.accompany.domain.accompany.entity.enums.RequestState; import com.dnd.accompany.domain.common.entity.TimeBaseEntity; import com.dnd.accompany.domain.user.entity.User; @@ -34,11 +35,10 @@ }) @SQLRestriction("deleted = false") @SQLDelete(sql = "UPDATE accompany_requests SET deleted = true WHERE id = ?") -public class AccompanyRequests extends TimeBaseEntity { +public class AccompanyRequest extends TimeBaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "accompany_requests_id") private Long id; @ManyToOne(fetch = FetchType.LAZY) @@ -47,21 +47,33 @@ public class AccompanyRequests extends TimeBaseEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "accompany_boards_id", nullable = false, foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) - private AccompanyBoards accompanyBoards; + private AccompanyBoard accompanyBoard; @Enumerated(EnumType.STRING) @Column(nullable = false) private RequestState requestState; + @Column( + length = 1500, + nullable = false + ) + private String introduce; + + @Column( + length = 2000, + nullable = false) + private String chatLink; + + private boolean deleted = Boolean.FALSE; + @Builder - public AccompanyRequests(Long id, User user, AccompanyBoards accompanyBoards, RequestState requestState) { + public AccompanyRequest(Long id, User user, AccompanyBoard accompanyBoard, RequestState requestState, + String introduce, String chatLink) { this.id = id; this.user = user; - this.accompanyBoards = accompanyBoards; + this.accompanyBoard = accompanyBoard; this.requestState = requestState; - } - - public enum RequestState { - APPROVED, HOLDING, DECLINED + this.introduce = introduce; + this.chatLink = chatLink; } } diff --git a/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyTags.java b/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyTag.java similarity index 85% rename from src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyTags.java rename to src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyTag.java index b388407..c1fcb90 100644 --- a/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyTags.java +++ b/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyTag.java @@ -26,24 +26,25 @@ @Table(name = "accompany_tags", indexes = @Index(name = "IX_accompany_boards_id", columnList = "accompany_boards_id")) @SQLRestriction("deleted = false") @SQLDelete(sql = "UPDATE accompany_tags SET deleted = true WHERE id = ?") -public class AccompanyTags { +public class AccompanyTag { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "accompany_tags_id") private Long id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "accompany_boards_id", nullable = false, foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) - private AccompanyBoards accompanyBoards; + private AccompanyBoard accompanyBoard; @Column(nullable = false) private String name; + private boolean deleted = Boolean.FALSE; + @Builder - public AccompanyTags(Long id, AccompanyBoards accompanyBoards, String name) { + public AccompanyTag(Long id, AccompanyBoard accompanyBoard, String name) { this.id = id; - this.accompanyBoards = accompanyBoards; + this.accompanyBoard = accompanyBoard; this.name = name; } } diff --git a/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyUsers.java b/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyUser.java similarity index 85% rename from src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyUsers.java rename to src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyUser.java index 8ae8951..f4f7ae7 100644 --- a/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyUsers.java +++ b/src/main/java/com/dnd/accompany/domain/accompany/entity/AccompanyUser.java @@ -3,6 +3,7 @@ import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.SQLRestriction; +import com.dnd.accompany.domain.accompany.entity.enums.Role; import com.dnd.accompany.domain.user.entity.User; import jakarta.persistence.Column; @@ -33,11 +34,10 @@ }) @SQLRestriction("deleted = false") @SQLDelete(sql = "UPDATE accompany_users SET deleted = true WHERE id = ?") -public class AccompanyUsers { +public class AccompanyUser { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "accompany_users_id") private Long id; @ManyToOne(fetch = FetchType.LAZY) @@ -46,21 +46,19 @@ public class AccompanyUsers { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "accompany_boards_id", nullable = false, foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) - private AccompanyBoards accompanyBoards; + private AccompanyBoard accompanyBoard; @Enumerated(EnumType.STRING) @Column(nullable = false) private Role role; + private boolean deleted = Boolean.FALSE; + @Builder - public AccompanyUsers(Long id, User user, AccompanyBoards accompanyBoards, Role role) { + public AccompanyUser(Long id, User user, AccompanyBoard accompanyBoard, Role role) { this.id = id; this.user = user; - this.accompanyBoards = accompanyBoards; + this.accompanyBoard = accompanyBoard; this.role = role; } - - public enum Role { - HOST, APPLICANT, PARTICIPANT - } } diff --git a/src/main/java/com/dnd/accompany/domain/accompany/entity/enums/Category.java b/src/main/java/com/dnd/accompany/domain/accompany/entity/enums/Category.java new file mode 100644 index 0000000..dfb49bd --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/entity/enums/Category.java @@ -0,0 +1,5 @@ +package com.dnd.accompany.domain.accompany.entity.enums; + +public enum Category { + FULL, PART, LODGING, TOUR, MEAL +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/entity/enums/PreferredAge.java b/src/main/java/com/dnd/accompany/domain/accompany/entity/enums/PreferredAge.java new file mode 100644 index 0000000..0f164f8 --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/entity/enums/PreferredAge.java @@ -0,0 +1,5 @@ +package com.dnd.accompany.domain.accompany.entity.enums; + +public enum PreferredAge { + SAME, ANY +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/entity/enums/PreferredGender.java b/src/main/java/com/dnd/accompany/domain/accompany/entity/enums/PreferredGender.java new file mode 100644 index 0000000..32f1bcd --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/entity/enums/PreferredGender.java @@ -0,0 +1,5 @@ +package com.dnd.accompany.domain.accompany.entity.enums; + +public enum PreferredGender { + SAME, ANY +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/entity/enums/Region.java b/src/main/java/com/dnd/accompany/domain/accompany/entity/enums/Region.java new file mode 100644 index 0000000..0125de8 --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/entity/enums/Region.java @@ -0,0 +1,18 @@ +package com.dnd.accompany.domain.accompany.entity.enums; + +public enum Region { + SEOUL("서울"), + GYEONGGI_INCHEON("경기·인천"), + CHUNGCHEONG_DAEJEON_SEJONG("충청·대전·세종"), + GANGWON("강원"), + JEOLLA_GWANGJU("전라·광주"), + GYEONGSANG_DAEGU_ULSAN("경상·대구·울산"), + BUSAN("부산"), + JEJU("제주"); + + private String description; + + Region(String description) { + this.description = description; + } +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/entity/enums/RequestState.java b/src/main/java/com/dnd/accompany/domain/accompany/entity/enums/RequestState.java new file mode 100644 index 0000000..5089133 --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/entity/enums/RequestState.java @@ -0,0 +1,5 @@ +package com.dnd.accompany.domain.accompany.entity.enums; + +public enum RequestState { + APPROVED, HOLDING, DECLINED +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/entity/enums/Role.java b/src/main/java/com/dnd/accompany/domain/accompany/entity/enums/Role.java new file mode 100644 index 0000000..ade7302 --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/entity/enums/Role.java @@ -0,0 +1,5 @@ +package com.dnd.accompany.domain.accompany.entity.enums; + +public enum Role { + HOST, APPLICANT, PARTICIPANT +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/exception/AccompanyBoardAccessDeniedException.java b/src/main/java/com/dnd/accompany/domain/accompany/exception/AccompanyBoardAccessDeniedException.java new file mode 100644 index 0000000..81b902b --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/exception/AccompanyBoardAccessDeniedException.java @@ -0,0 +1,9 @@ +package com.dnd.accompany.domain.accompany.exception; + +import com.dnd.accompany.global.common.response.ErrorCode; + +public class AccompanyBoardAccessDeniedException extends AccompanyBoardException { + public AccompanyBoardAccessDeniedException(ErrorCode errorCode) { + super(errorCode); + } +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/exception/AccompanyBoardException.java b/src/main/java/com/dnd/accompany/domain/accompany/exception/AccompanyBoardException.java new file mode 100644 index 0000000..7abd1bd --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/exception/AccompanyBoardException.java @@ -0,0 +1,10 @@ +package com.dnd.accompany.domain.accompany.exception; + +import com.dnd.accompany.global.common.exception.BusinessException; +import com.dnd.accompany.global.common.response.ErrorCode; + +public class AccompanyBoardException extends BusinessException { + public AccompanyBoardException(ErrorCode errorCode) { + super(errorCode); + } +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/exception/AccompanyBoardNotFoundException.java b/src/main/java/com/dnd/accompany/domain/accompany/exception/AccompanyBoardNotFoundException.java new file mode 100644 index 0000000..2b0ef0a --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/exception/AccompanyBoardNotFoundException.java @@ -0,0 +1,9 @@ +package com.dnd.accompany.domain.accompany.exception; + +import com.dnd.accompany.global.common.response.ErrorCode; + +public class AccompanyBoardNotFoundException extends AccompanyBoardException { + public AccompanyBoardNotFoundException(ErrorCode errorCode) { + super(errorCode); + } +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/AccompanyBoardRepository.java b/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/AccompanyBoardRepository.java new file mode 100644 index 0000000..00808dc --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/AccompanyBoardRepository.java @@ -0,0 +1,9 @@ +package com.dnd.accompany.domain.accompany.infrastructure; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.dnd.accompany.domain.accompany.entity.AccompanyBoard; +import com.dnd.accompany.domain.accompany.infrastructure.querydsl.interfaces.AccompanyBoardRepositoryCustom; + +public interface AccompanyBoardRepository extends JpaRepository, AccompanyBoardRepositoryCustom { +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/AccompanyImageRepository.java b/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/AccompanyImageRepository.java new file mode 100644 index 0000000..cc1b89d --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/AccompanyImageRepository.java @@ -0,0 +1,11 @@ +package com.dnd.accompany.domain.accompany.infrastructure; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.dnd.accompany.domain.accompany.entity.AccompanyImage; + +@Repository +public interface AccompanyImageRepository extends JpaRepository { + void deleteByAccompanyBoardId(Long boardId); +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/AccompanyRequestRepository.java b/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/AccompanyRequestRepository.java new file mode 100644 index 0000000..6643c77 --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/AccompanyRequestRepository.java @@ -0,0 +1,11 @@ +package com.dnd.accompany.domain.accompany.infrastructure; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.dnd.accompany.domain.accompany.entity.AccompanyRequest; + +@Repository +public interface AccompanyRequestRepository extends JpaRepository { + void deleteByAccompanyBoardId(Long boardId); +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/AccompanyTagRepository.java b/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/AccompanyTagRepository.java new file mode 100644 index 0000000..2275aca --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/AccompanyTagRepository.java @@ -0,0 +1,11 @@ +package com.dnd.accompany.domain.accompany.infrastructure; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.dnd.accompany.domain.accompany.entity.AccompanyTag; + +@Repository +public interface AccompanyTagRepository extends JpaRepository { + void deleteByAccompanyBoardId(Long boardId); +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/AccompanyUserRepository.java b/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/AccompanyUserRepository.java new file mode 100644 index 0000000..ae7d4ec --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/AccompanyUserRepository.java @@ -0,0 +1,11 @@ +package com.dnd.accompany.domain.accompany.infrastructure; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.dnd.accompany.domain.accompany.entity.AccompanyUser; + +@Repository +public interface AccompanyUserRepository extends JpaRepository { + void deleteByAccompanyBoardId(Long boardId); +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/querydsl/AccompanyBoardRepositoryImpl.java b/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/querydsl/AccompanyBoardRepositoryImpl.java new file mode 100644 index 0000000..b41fcc4 --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/querydsl/AccompanyBoardRepositoryImpl.java @@ -0,0 +1,103 @@ +package com.dnd.accompany.domain.accompany.infrastructure.querydsl; + +import static com.dnd.accompany.domain.accompany.entity.QAccompanyBoard.*; +import static com.dnd.accompany.domain.accompany.entity.QAccompanyUser.*; +import static com.dnd.accompany.domain.accompany.entity.enums.Role.*; +import static com.dnd.accompany.domain.user.entity.QUser.*; + +import java.util.List; +import java.util.Optional; + +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.domain.SliceImpl; +import org.springframework.stereotype.Repository; + +import com.dnd.accompany.domain.accompany.api.dto.AccompanyBoardInfo; +import com.dnd.accompany.domain.accompany.api.dto.FindDetailInfoResult; +import com.dnd.accompany.domain.accompany.infrastructure.querydsl.interfaces.AccompanyBoardRepositoryCustom; +import com.querydsl.core.types.Projections; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; + +import lombok.RequiredArgsConstructor; + +@Repository +@RequiredArgsConstructor +public class AccompanyBoardRepositoryImpl implements AccompanyBoardRepositoryCustom { + + private final JPAQueryFactory queryFactory; + + public static BooleanExpression isHost() { + return accompanyUser.role.eq(HOST); + } + + @Override + public Slice findBoardInfos(Pageable pageable) { + List content = queryFactory.select(Projections.constructor(AccompanyBoardInfo.class, + accompanyBoard.id, + accompanyBoard.title, + accompanyBoard.region, + accompanyBoard.startDate, + accompanyBoard.endDate, + user.nickname)) + .from(accompanyUser) + .join(accompanyUser.accompanyBoard, accompanyBoard) + .join(accompanyUser.user, user) + .where(accompanyUser.role.eq(HOST)) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize() + 1) // 한 페이지에 하나 더 가져와서 hasNext 체크에 사용 + .fetch(); + + boolean hasNext = false; + if (content.size() > pageable.getPageSize()) { + content.remove(pageable.getPageSize()); + hasNext = true; + } + + return new SliceImpl<>(content, pageable, hasNext); + } + + /** + * 동행글, 프로필 정보를 한번에 가져옵니다. + */ + @Override + public Optional findDetailInfo(Long boardId) { + FindDetailInfoResult result = queryFactory + .select(Projections.constructor(FindDetailInfoResult.class, + accompanyBoard.id, + accompanyBoard.title, + accompanyBoard.content, + accompanyBoard.region, + accompanyBoard.startDate, + accompanyBoard.endDate, + accompanyBoard.headCount, + accompanyBoard.capacity, + accompanyBoard.category, + accompanyBoard.preferredAge, + accompanyBoard.preferredGender, + user.nickname)) + .from(accompanyBoard) + .leftJoin(accompanyUser).on(accompanyUser.accompanyBoard.id.eq(accompanyBoard.id) + .and(isHost())) + .leftJoin(user).on(user.id.eq(accompanyUser.user.id)) + .where(accompanyBoard.id.eq(boardId)) + .fetchOne(); + + return Optional.ofNullable(result); + } + + @Override + public boolean isHostOfBoard(Long userId, Long boardId) { + Integer fetchCount = queryFactory.selectOne() + .from(accompanyUser) + .where( + accompanyUser.user.id.eq(userId) + .and(accompanyUser.accompanyBoard.id.eq(boardId)) + .and(isHost()) + ) + .fetchFirst(); + + return fetchCount != null; + } +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/querydsl/interfaces/AccompanyBoardRepositoryCustom.java b/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/querydsl/interfaces/AccompanyBoardRepositoryCustom.java new file mode 100644 index 0000000..cd278f3 --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/infrastructure/querydsl/interfaces/AccompanyBoardRepositoryCustom.java @@ -0,0 +1,17 @@ +package com.dnd.accompany.domain.accompany.infrastructure.querydsl.interfaces; + +import java.util.Optional; + +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; + +import com.dnd.accompany.domain.accompany.api.dto.AccompanyBoardInfo; +import com.dnd.accompany.domain.accompany.api.dto.FindDetailInfoResult; + +public interface AccompanyBoardRepositoryCustom { + Slice findBoardInfos(Pageable pageable); + + Optional findDetailInfo(Long boardId); + + boolean isHostOfBoard(Long userId, Long boardId); +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/service/AccompanyBoardService.java b/src/main/java/com/dnd/accompany/domain/accompany/service/AccompanyBoardService.java new file mode 100644 index 0000000..fc5a764 --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/service/AccompanyBoardService.java @@ -0,0 +1,117 @@ +package com.dnd.accompany.domain.accompany.service; + +import static com.dnd.accompany.domain.accompany.entity.AccompanyBoard.*; +import static com.dnd.accompany.domain.accompany.entity.enums.Role.*; + +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.dnd.accompany.domain.accompany.api.dto.AccompanyBoardDetailInfo; +import com.dnd.accompany.domain.accompany.api.dto.AccompanyBoardInfo; +import com.dnd.accompany.domain.accompany.api.dto.CreateAccompanyBoardRequest; +import com.dnd.accompany.domain.accompany.api.dto.CreateAccompanyBoardResponse; +import com.dnd.accompany.domain.accompany.api.dto.FindDetailInfoResult; +import com.dnd.accompany.domain.accompany.api.dto.PageResponse; +import com.dnd.accompany.domain.accompany.api.dto.ReadAccompanyBoardResponse; +import com.dnd.accompany.domain.accompany.api.dto.UserProfileDetailInfo; +import com.dnd.accompany.domain.accompany.entity.AccompanyBoard; +import com.dnd.accompany.domain.accompany.exception.AccompanyBoardAccessDeniedException; +import com.dnd.accompany.domain.accompany.exception.AccompanyBoardNotFoundException; +import com.dnd.accompany.domain.accompany.infrastructure.AccompanyBoardRepository; +import com.dnd.accompany.global.common.response.ErrorCode; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class AccompanyBoardService { + + private final AccompanyBoardRepository accompanyBoardRepository; + private final AccompanyImageService accompanyImageService; + private final AccompanyTagService accompanyTagService; + private final AccompanyUserService accompanyUserService; + private final AccompanyRequestService accompanyRequestService; + + @Transactional + public CreateAccompanyBoardResponse create(Long userId, CreateAccompanyBoardRequest request) { + AccompanyBoard accompanyBoard = accompanyBoardRepository.save( + builder() + .title(request.title()) + .content(request.content()) + .region(request.region()) + .startDate(request.startDate()) + .endDate(request.endDate()) + .headCount(1L) + .capacity(request.capacity()) + .category(request.category()) + .preferredAge(request.preferredAge()) + .preferredGender(request.preferredGender()) + .build() + ); + accompanyImageService.save(accompanyBoard, request.imageUrls()); + accompanyTagService.save(accompanyBoard, request.tagNames()); + accompanyUserService.save(userId, accompanyBoard, HOST); + + return new CreateAccompanyBoardResponse(accompanyBoard.getId()); + } + + @Transactional(readOnly = true) + public PageResponse readAll(int page, int size) { + Pageable pageable = PageRequest.of(page, size); + Slice sliceResult = accompanyBoardRepository.findBoardInfos(pageable); + + return new PageResponse<>(sliceResult.hasNext(), sliceResult.getContent()); + } + + @Transactional(readOnly = true) + public ReadAccompanyBoardResponse read(Long boardId) { + FindDetailInfoResult detailInfo = accompanyBoardRepository.findDetailInfo(boardId) + .orElseThrow(() -> new AccompanyBoardNotFoundException(ErrorCode.ACCOMPANY_BOARD_NOT_FOUND)); + + AccompanyBoardDetailInfo accompanyBoardDetailInfo = getAccompanyBoardDetailInfo( + detailInfo); + + UserProfileDetailInfo userProfileDetailInfo = getUserProfileDetailInfo( + detailInfo); + + return new ReadAccompanyBoardResponse(accompanyBoardDetailInfo, userProfileDetailInfo); + } + + @Transactional + public void delete(Long userId, Long boardId) { + if (accompanyUserService.isHostOfBoard(userId, boardId)) { + accompanyBoardRepository.deleteById(boardId); + accompanyImageService.deleteByBoardId(boardId); + accompanyUserService.deleteByBoardId(boardId); + accompanyTagService.deleteByBoardId(boardId); + accompanyRequestService.deleteByBoardId(boardId); + } else { + throw new AccompanyBoardAccessDeniedException(ErrorCode.ACCOMPANY_BOARD_ACCESS_DENIED); + } + } + + private static UserProfileDetailInfo getUserProfileDetailInfo(FindDetailInfoResult detailInfo) { + return UserProfileDetailInfo.builder() + .nickname(detailInfo.nickname()) + .build(); + } + + private static AccompanyBoardDetailInfo getAccompanyBoardDetailInfo(FindDetailInfoResult detailInfo) { + return AccompanyBoardDetailInfo.builder() + .boardId(detailInfo.boardId()) + .title(detailInfo.title()) + .content(detailInfo.content()) + .region(detailInfo.region()) + .startDate(detailInfo.startDate()) + .endDate(detailInfo.endDate()) + .headCount(detailInfo.headCount()) + .capacity(detailInfo.capacity()) + .category(detailInfo.category()) + .preferredAge(detailInfo.preferredAge()) + .preferredGender(detailInfo.preferredGender()) + .build(); + } +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/service/AccompanyImageService.java b/src/main/java/com/dnd/accompany/domain/accompany/service/AccompanyImageService.java new file mode 100644 index 0000000..4cdfb97 --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/service/AccompanyImageService.java @@ -0,0 +1,35 @@ +package com.dnd.accompany.domain.accompany.service; + +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.dnd.accompany.domain.accompany.entity.AccompanyBoard; +import com.dnd.accompany.domain.accompany.entity.AccompanyImage; +import com.dnd.accompany.domain.accompany.infrastructure.AccompanyImageRepository; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class AccompanyImageService { + private final AccompanyImageRepository accompanyImageRepository; + + @Transactional + public void save(AccompanyBoard accompanyBoard, List imageUrls) { + List images = imageUrls.stream() + .map(imageUrl -> AccompanyImage.builder() + .accompanyBoard(accompanyBoard) + .imageUrl(imageUrl) + .build()) + .collect(Collectors.toList()); + accompanyImageRepository.saveAll(images); + } + + @Transactional + public void deleteByBoardId(Long boardId) { + accompanyImageRepository.deleteByAccompanyBoardId(boardId); + } +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/service/AccompanyRequestService.java b/src/main/java/com/dnd/accompany/domain/accompany/service/AccompanyRequestService.java new file mode 100644 index 0000000..7c3d743 --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/service/AccompanyRequestService.java @@ -0,0 +1,36 @@ +package com.dnd.accompany.domain.accompany.service; + +import static com.dnd.accompany.domain.accompany.entity.enums.RequestState.*; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.dnd.accompany.domain.accompany.api.dto.CreateAccompanyRequest; +import com.dnd.accompany.domain.accompany.entity.AccompanyBoard; +import com.dnd.accompany.domain.accompany.entity.AccompanyRequest; +import com.dnd.accompany.domain.accompany.infrastructure.AccompanyRequestRepository; +import com.dnd.accompany.domain.user.entity.User; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class AccompanyRequestService { + private final AccompanyRequestRepository accompanyRequestRepository; + + @Transactional + public void save(Long userId, CreateAccompanyRequest request) { + accompanyRequestRepository.save(AccompanyRequest.builder() + .user(User.builder().id(userId).build()) + .accompanyBoard(AccompanyBoard.builder().id(request.boardId()).build()) + .requestState(HOLDING) + .introduce(request.introduce()) + .chatLink(request.chatLink()) + .build()); + } + + @Transactional + public void deleteByBoardId(Long boardId) { + accompanyRequestRepository.deleteByAccompanyBoardId(boardId); + } +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/service/AccompanyTagService.java b/src/main/java/com/dnd/accompany/domain/accompany/service/AccompanyTagService.java new file mode 100644 index 0000000..0a98fd1 --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/service/AccompanyTagService.java @@ -0,0 +1,35 @@ +package com.dnd.accompany.domain.accompany.service; + +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.dnd.accompany.domain.accompany.entity.AccompanyBoard; +import com.dnd.accompany.domain.accompany.entity.AccompanyTag; +import com.dnd.accompany.domain.accompany.infrastructure.AccompanyTagRepository; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class AccompanyTagService { + private final AccompanyTagRepository accompanyTagRepository; + + @Transactional + public void save(AccompanyBoard accompanyBoard, List tagNames) { + List tags = tagNames.stream() + .map(tagName -> AccompanyTag.builder() + .accompanyBoard(accompanyBoard) + .name(tagName) + .build()) + .collect(Collectors.toList()); + accompanyTagRepository.saveAll(tags); + } + + @Transactional + public void deleteByBoardId(Long boardId) { + accompanyTagRepository.deleteByAccompanyBoardId(boardId); + } +} diff --git a/src/main/java/com/dnd/accompany/domain/accompany/service/AccompanyUserService.java b/src/main/java/com/dnd/accompany/domain/accompany/service/AccompanyUserService.java new file mode 100644 index 0000000..9319cce --- /dev/null +++ b/src/main/java/com/dnd/accompany/domain/accompany/service/AccompanyUserService.java @@ -0,0 +1,39 @@ +package com.dnd.accompany.domain.accompany.service; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.dnd.accompany.domain.accompany.entity.AccompanyBoard; +import com.dnd.accompany.domain.accompany.entity.AccompanyUser; +import com.dnd.accompany.domain.accompany.entity.enums.Role; +import com.dnd.accompany.domain.accompany.infrastructure.AccompanyBoardRepository; +import com.dnd.accompany.domain.accompany.infrastructure.AccompanyUserRepository; +import com.dnd.accompany.domain.user.entity.User; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class AccompanyUserService { + private final AccompanyUserRepository accompanyUserRepository; + private final AccompanyBoardRepository accompanyBoardRepository; + + @Transactional + public void save(Long userId, AccompanyBoard accompanyBoard, Role role) { + accompanyUserRepository.save(AccompanyUser.builder() + .accompanyBoard(accompanyBoard) + .user(User.builder().id(userId).build()) + .role(role) + .build()); + } + + @Transactional(readOnly = true) + public boolean isHostOfBoard(Long userId, Long boardId) { + return accompanyBoardRepository.isHostOfBoard(userId, boardId); + } + + @Transactional + public void deleteByBoardId(Long boardId) { + accompanyUserRepository.deleteByAccompanyBoardId(boardId); + } +} diff --git a/src/main/java/com/dnd/accompany/global/common/response/ErrorCode.java b/src/main/java/com/dnd/accompany/global/common/response/ErrorCode.java index 556e097..2cb099d 100644 --- a/src/main/java/com/dnd/accompany/global/common/response/ErrorCode.java +++ b/src/main/java/com/dnd/accompany/global/common/response/ErrorCode.java @@ -28,7 +28,11 @@ public enum ErrorCode { PROFILE_ALREADY_EXISTS(MatripConstant.BAD_REQUEST, "PROFILE-001", "이미 프로필 정보가 존재합니다."), // ---- 네트워크 ---- // - HTTP_CLIENT_REQUEST_FAILED(MatripConstant.INTERNAL_SERVER_ERROR, "NETWORK-001", "서버 요청에 실패하였습니다."); + HTTP_CLIENT_REQUEST_FAILED(MatripConstant.INTERNAL_SERVER_ERROR, "NETWORK-001", "서버 요청에 실패하였습니다."), + + // ---- 동행글 ---- // + ACCOMPANY_BOARD_NOT_FOUND(MatripConstant.NOT_FOUND, "ACCOMPANY_BOARD-001", "동행글을 찾을 수 없습니다."), + ACCOMPANY_BOARD_ACCESS_DENIED(MatripConstant.FORBIDDEN, "ACCOMPANY_BOARD-002", "동행글 접근 권한이 없습니다."); private final Integer status; private final String code;