Skip to content

Commit

Permalink
Merge branch 'refs/heads/develop_back_core' into refact/common_dto-B-…
Browse files Browse the repository at this point in the history
…#479

# Conflicts:
#	backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/api/GroupCapsuleApi.java
#	backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/service/GroupCapsuleService.java
#	backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/CapsuleFixture.java
#	backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleQueryRepositoryTest.java
#	backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/group_capsule/service/GroupCapsuleServiceTest.java
  • Loading branch information
seokho-1116 committed Jun 11, 2024
2 parents 9a5602f + e5680e4 commit 71c3635
Show file tree
Hide file tree
Showing 20 changed files with 359 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -120,26 +119,24 @@ public void open() {
this.isOpened = Boolean.TRUE;
}

public boolean isTimeCapsule() {
return dueDate != null;
}

public boolean canOpen() {
return dueDate == null || dueDate.isBefore(ZonedDateTimeSupplier.utc().get());
public boolean isNotTimeCapsule() {
return dueDate == null;
}

public boolean isAllGroupMemberOpened(Long memberId, Long capsuleId) {
if (groupCapsuleOpens.isEmpty()) {
throw new GroupCapsuleOpenNotFoundException();
}

return groupCapsuleOpens.stream()
.allMatch(groupCapsuleOpen -> {
if (groupCapsuleOpen.matched(capsuleId, memberId)) {
groupCapsuleOpen.open();
}
boolean isCapsuleOpened = true;
for (GroupCapsuleOpen groupCapsuleOpen : groupCapsuleOpens) {
if (groupCapsuleOpen.matched(capsuleId, memberId)) {
groupCapsuleOpen.open();
}

isCapsuleOpened = isCapsuleOpened && groupCapsuleOpen.getIsOpened();
}

return groupCapsuleOpen.getIsOpened();
});
return isCapsuleOpened;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.util.Objects;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import site.timecapsulearchive.core.domain.group.entity.Group;
import site.timecapsulearchive.core.domain.member.entity.Member;
import site.timecapsulearchive.core.global.entity.BaseEntity;

Expand All @@ -39,16 +38,9 @@ public class GroupCapsuleOpen extends BaseEntity {
@JoinColumn(name = "member_id", nullable = false)
private Member member;

@Builder
private GroupCapsuleOpen(Boolean isOpened, Capsule capsule, Member member) {
this.isOpened = Objects.requireNonNull(isOpened);
this.capsule = Objects.requireNonNull(capsule);
this.member = Objects.requireNonNull(member);
}

public static GroupCapsuleOpen createOf(Member member, Capsule capsule, Boolean isOpened) {
return new GroupCapsuleOpen(isOpened, capsule, member);
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "group_id", nullable = false)
private Group group;

public void open() {
this.isOpened = Boolean.TRUE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,35 @@ ResponseEntity<ApiSpec<MyGroupCapsuleSliceResponse>> getMyGroupCapsules(
ZonedDateTime createAt
);

@Operation(
summary = "그룹원의 그룹 캡슐 개봉 상태 확인",
description = """
그룹원의 그룹 캡슐 개봉 상태를 확인한다.
""",
security = {@SecurityRequirement(name = "user_token")},
tags = {"group capsule"}
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "처리 완료"
),
@ApiResponse(
responseCode = "404",
description = "그룹 캡슐의 개봉 상태를 찾을 수 없는 경우 예외가 발생한다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))
)
})
ResponseEntity<ApiSpec<GroupMemberCapsuleOpenStatusListResponse>> getGroupCapsuleOpenStatus(
Long memberId,

@Parameter(in = ParameterIn.PATH, description = "개봉 상태를 확인할 캡슐 아이디", required = true)
Long capsuleId,

@Parameter(in = ParameterIn.QUERY, description = "생성할 그룹 아이디", required = true)
Long groupId
);

@Operation(
summary = "그룹 캡슐 개봉",
description = """
Expand All @@ -177,7 +206,7 @@ ResponseEntity<ApiSpec<GroupCapsuleOpenStateResponse>> openCapsule(
Long memberId,

@Parameter(in = ParameterIn.PATH, description = "개봉할 그룹 캡슐 아이디", required = true)
@PathVariable("capsule_id") Long capsuleId
Long capsuleId
);

@Operation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import jakarta.validation.Valid;
import java.time.ZonedDateTime;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Slice;
import org.springframework.http.ResponseEntity;
Expand All @@ -18,12 +19,15 @@
import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupCapsuleOpenStateDto;
import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupCapsuleSliceRequestDto;
import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupCapsuleSummaryDto;
import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupMemberCapsuleOpenStatusDto;
import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.MyGroupCapsuleDto;
import site.timecapsulearchive.core.domain.capsule.group_capsule.data.reqeust.GroupCapsuleCreateRequest;
import site.timecapsulearchive.core.domain.capsule.group_capsule.data.reqeust.GroupCapsuleUpdateRequest;
import site.timecapsulearchive.core.domain.capsule.group_capsule.data.response.GroupCapsuleDetailResponse;
import site.timecapsulearchive.core.domain.capsule.group_capsule.data.response.GroupCapsuleOpenStateResponse;
import site.timecapsulearchive.core.domain.capsule.group_capsule.data.response.GroupCapsuleSliceResponse;
import site.timecapsulearchive.core.domain.capsule.group_capsule.data.response.GroupCapsuleSummaryResponse;
import site.timecapsulearchive.core.domain.capsule.group_capsule.data.response.GroupMemberCapsuleOpenStatusListResponse;
import site.timecapsulearchive.core.domain.capsule.group_capsule.data.response.MyGroupCapsuleSliceResponse;
import site.timecapsulearchive.core.domain.capsule.group_capsule.facade.GroupCapsuleFacade;
import site.timecapsulearchive.core.domain.capsule.group_capsule.service.GroupCapsuleService;
Expand Down Expand Up @@ -163,6 +167,24 @@ public ResponseEntity<ApiSpec<MyGroupCapsuleSliceResponse>> getMyGroupCapsules(
);
}

@GetMapping(value = "/{capsule_id}/open-status", produces = {"application/json"})
@Override
public ResponseEntity<ApiSpec<GroupMemberCapsuleOpenStatusListResponse>> getGroupCapsuleOpenStatus(
@AuthenticationPrincipal final Long memberId,
@PathVariable("capsule_id") final Long capsuleId,
@RequestParam("group_id") final Long groupId
) {
List<GroupMemberCapsuleOpenStatusDto> groupMemberCapsuleOpenStatus = groupCapsuleService.findGroupMemberCapsuleOpenStatus(
memberId, capsuleId, groupId);

return ResponseEntity.ok(
ApiSpec.success(
SuccessCode.SUCCESS,
GroupMemberCapsuleOpenStatusListResponse.create(groupMemberCapsuleOpenStatus)
)
);
}

@PostMapping("/{capsule_id}/open")
@Override
public ResponseEntity<ApiSpec<GroupCapsuleOpenStateResponse>> openCapsule(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@
import site.timecapsulearchive.core.domain.capsule.group_capsule.data.response.GroupCapsuleOpenStateResponse;

public record GroupCapsuleOpenStateDto(
CapsuleOpenStatus capsuleOpenStatus
CapsuleOpenStatus capsuleOpenStatus,
boolean isIndividuallyOpened
) {

public static GroupCapsuleOpenStateDto opened() {
return new GroupCapsuleOpenStateDto(CapsuleOpenStatus.OPEN);
return new GroupCapsuleOpenStateDto(CapsuleOpenStatus.OPEN, true);
}

public static GroupCapsuleOpenStateDto notOpened() {
return new GroupCapsuleOpenStateDto(CapsuleOpenStatus.NOT_OPEN);
public static GroupCapsuleOpenStateDto notOpened(boolean isIndividuallyOpened) {
return new GroupCapsuleOpenStateDto(CapsuleOpenStatus.NOT_OPEN, isIndividuallyOpened);
}

public GroupCapsuleOpenStateResponse toResponse() {
return new GroupCapsuleOpenStateResponse(
capsuleOpenStatus,
capsuleOpenStatus.getStatusMessage()
capsuleOpenStatus.getStatusMessage(),
isIndividuallyOpened
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto;

import site.timecapsulearchive.core.domain.capsule.group_capsule.data.response.GroupMemberCapsuleOpenStatusResponse;

public record GroupMemberCapsuleOpenStatusDto(
Long memberId,
String nickname,
String profileUrl,
boolean isOpened
) {

public GroupMemberCapsuleOpenStatusResponse toResponse() {
return GroupMemberCapsuleOpenStatusResponse.builder()
.memberId(memberId)
.nickname(nickname)
.profileUrl(profileUrl)
.isOpened(isOpened)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
package site.timecapsulearchive.core.domain.capsule.group_capsule.data.response;

import io.swagger.v3.oas.annotations.media.Schema;
import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.CapsuleOpenStatus;

@Schema(description = "그룹 캡슐 개봉 상태 응답")
public record GroupCapsuleOpenStateResponse(

@Schema(description = "캡슐 개봉 상태")
CapsuleOpenStatus capsuleOpenStatus,
String statusMessage

@Schema(description = "캡슐 개봉 상태 메시지")
String statusMessage,

@Schema(description = "현재 요청한 사용자의 개별적인 캡슐 개봉 상태")
boolean isIndividuallyOpened
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package site.timecapsulearchive.core.domain.capsule.group_capsule.data.response;

import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupMemberCapsuleOpenStatusDto;

@Schema(description = "그룹원들 캡슐 개봉 상태")
public record GroupMemberCapsuleOpenStatusListResponse(
List<GroupMemberCapsuleOpenStatusResponse> groupMemberCapsuleOpenStatus
) {

public static GroupMemberCapsuleOpenStatusListResponse create(
List<GroupMemberCapsuleOpenStatusDto> groupMemberCapsuleOpenStatus) {
List<GroupMemberCapsuleOpenStatusResponse> groupMemberCapsuleOpenStatusResponses = groupMemberCapsuleOpenStatus.stream()
.map(GroupMemberCapsuleOpenStatusDto::toResponse)
.toList();

return new GroupMemberCapsuleOpenStatusListResponse(groupMemberCapsuleOpenStatusResponses);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package site.timecapsulearchive.core.domain.capsule.group_capsule.data.response;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;

@Schema(description = "그룹원별 캡슐 개봉 상태")
@Builder
public record GroupMemberCapsuleOpenStatusResponse(

@Schema(description = "회원 아이디")
Long memberId,

@Schema(description = "회원 닉네임")
String nickname,

@Schema(description = "회원 프로필")
String profileUrl,

@Schema(description = "개봉 상태")
boolean isOpened
) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,6 @@ public void saveGroupCapsule(

final List<Long> groupMemberIds = memberGroupQueryService.findGroupMemberIds(groupId);

groupCapsuleOpenService.bulkSave(groupMemberIds, capsule);
groupCapsuleOpenService.bulkSave(groupId, groupMemberIds, capsule);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package site.timecapsulearchive.core.domain.capsule.group_capsule.repository;

import static site.timecapsulearchive.core.domain.capsule.entity.QGroupCapsuleOpen.groupCapsuleOpen;
import static site.timecapsulearchive.core.domain.member.entity.QMember.member;

import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
Expand All @@ -11,19 +16,26 @@
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import site.timecapsulearchive.core.domain.capsule.entity.Capsule;
import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupMemberCapsuleOpenStatusDto;
import site.timecapsulearchive.core.domain.member.entity.QMember;

@Repository
@RequiredArgsConstructor
public class GroupCapsuleOpenQueryRepository {

private final JdbcTemplate jdbcTemplate;
private final JPAQueryFactory jpaQueryFactory;

public void bulkSave(final List<Long> groupMemberIds, final Capsule capsule) {
public void bulkSave(
final Long groupId,
final List<Long> groupMemberIds,
final Capsule capsule
) {
jdbcTemplate.batchUpdate(
"""
INSERT INTO group_capsule_open (
group_capsule_open_id, is_opened, member_id, capsule_id, created_at, updated_at
) values (?, ? ,? ,? ,?, ?)
group_capsule_open_id, is_opened, member_id, capsule_id, group_id, created_at, updated_at
) values (?, ? ,? ,? ,?, ?, ?)
""",
new BatchPreparedStatementSetter() {
@Override
Expand All @@ -34,8 +46,9 @@ public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setBoolean(2, isOpened);
ps.setLong(3, groupMemberIds.get(i));
ps.setLong(4, capsule.getId());
ps.setTimestamp(5, Timestamp.valueOf(ZonedDateTime.now().toLocalDateTime()));
ps.setLong(5, groupId);
ps.setTimestamp(6, Timestamp.valueOf(ZonedDateTime.now().toLocalDateTime()));
ps.setTimestamp(7, Timestamp.valueOf(ZonedDateTime.now().toLocalDateTime()));
}

@Override
Expand All @@ -45,4 +58,26 @@ public int getBatchSize() {
}
);
}

public List<GroupMemberCapsuleOpenStatusDto> findGroupMemberCapsuleOpenStatus(
final Long capsuleId,
final Long groupId
) {
return jpaQueryFactory
.select(
Projections.constructor(
GroupMemberCapsuleOpenStatusDto.class,
groupCapsuleOpen.member.id,
groupCapsuleOpen.member.nickname,
groupCapsuleOpen.member.profileUrl,
groupCapsuleOpen.isOpened
)
)
.from(groupCapsuleOpen)
.join(groupCapsuleOpen.member, member)
.where(groupCapsuleOpen.group.id.eq(groupId)
.and(groupCapsuleOpen.capsule.id.eq(capsuleId))
)
.fetch();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ public class GroupCapsuleOpenService {

private final GroupCapsuleOpenQueryRepository repository;

public void bulkSave(final List<Long> groupMemberIds, final Capsule capsule) {
repository.bulkSave(groupMemberIds, capsule);
public void bulkSave(
final Long groupId,
final List<Long> groupMemberIds,
final Capsule capsule
) {
repository.bulkSave(groupId, groupMemberIds, capsule);
}
}
Loading

0 comments on commit 71c3635

Please sign in to comment.