Skip to content

Commit

Permalink
v1.6.0 (#310)
Browse files Browse the repository at this point in the history
  • Loading branch information
kdomo authored Feb 10, 2024
2 parents 1906dcf + d0576e0 commit cd143c4
Show file tree
Hide file tree
Showing 12 changed files with 194 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.depromeet.domain.common.constants;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class PushNotificationConstants {
public static final String PUSH_SERVICE_TITLE = "10MM";
public static final String PUSH_SERVICE_CONTENT = "%s님이 회원님을 팔로우하기 시작했습니다🥳";
public static final String PUSH_NON_COMPLETE_MISSION_SERVICE_CONTENT =
"아직 오늘 미션을 완료하지 않았어요! 10분 동안 빠르게 완료해볼까요?";
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ public static FeedOneByProfileResponse of(MissionRecord record) {
record.getMission().getName(),
record.getImageUrl(),
record.getDuration().toMinutes(),
Duration.between(record.getStartedAt(), LocalDateTime.now()).toDays() + 1,
Duration.between(record.getMission().getStartedAt(), LocalDateTime.now()).toDays()
+ 1,
record.getStartedAt(),
record.getFinishedAt());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ public ResponseEntity<Void> followCreate(@Valid @RequestBody FollowCreateRequest

@DeleteMapping
@Operation(summary = "팔로우 취소", description = "팔로우를 취소합니다.")
public void followDelete(@Valid @RequestBody FollowDeleteRequest request) {
followService.deleteFollow(request);
public ResponseEntity<FollowerDeletedResponse> followDelete(
@Valid @RequestBody FollowDeleteRequest request) {
return ResponseEntity.ok(followService.deleteFollow(request));
}

@GetMapping("/{targetId}")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.depromeet.domain.follow.application;

import static com.depromeet.domain.common.constants.PushNotificationConstants.*;

import com.depromeet.domain.follow.dao.MemberRelationRepository;
import com.depromeet.domain.follow.domain.MemberRelation;
import com.depromeet.domain.follow.dto.request.FollowCreateRequest;
Expand Down Expand Up @@ -34,9 +36,6 @@ public class FollowService {
private final MemberRelationRepository memberRelationRepository;
private final FcmService fcmService;

private static final String PUSH_SERVICE_TITLE = "10MM";
private static final String PUSH_SERVICE_CONTENT = "%s님이 회원님을 팔로우하기 시작했습니다🥳";

public void createFollow(FollowCreateRequest request) {
final Member currentMember = memberUtil.getCurrentMember();
Member targetMember = getTargetMember(request.targetId());
Expand All @@ -62,7 +61,7 @@ public void createFollow(FollowCreateRequest request) {
memberRelationRepository.save(memberRelation);
}

public void deleteFollow(FollowDeleteRequest request) {
public FollowerDeletedResponse deleteFollow(FollowDeleteRequest request) {
final Member currentMember = memberUtil.getCurrentMember();
Member targetMember = getTargetMember(request.targetId());

Expand All @@ -79,6 +78,14 @@ public void deleteFollow(FollowDeleteRequest request) {
notificationRepository.delete(notification);
}
memberRelationRepository.delete(memberRelation);

Optional<MemberRelation> optionalMemberRelation =
memberRelationRepository.findBySourceIdAndTargetId(
targetMember.getId(), currentMember.getId());

return optionalMemberRelation.isPresent()
? FollowerDeletedResponse.from(FollowStatus.FOLLOWED_BY_ME)
: FollowerDeletedResponse.from(FollowStatus.NOT_FOLLOWING);
}

@Transactional(readOnly = true)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.depromeet.domain.member.application;

import static com.depromeet.domain.common.constants.PushNotificationConstants.*;

import com.depromeet.domain.auth.dao.RefreshTokenRepository;
import com.depromeet.domain.auth.dto.request.UsernameCheckRequest;
import com.depromeet.domain.follow.dao.MemberRelationRepository;
Expand All @@ -14,9 +16,11 @@
import com.depromeet.domain.member.dto.response.MemberFindOneResponse;
import com.depromeet.domain.member.dto.response.MemberSearchResponse;
import com.depromeet.domain.member.dto.response.MemberSocialInfoResponse;
import com.depromeet.global.config.fcm.FcmService;
import com.depromeet.global.error.exception.CustomException;
import com.depromeet.global.error.exception.ErrorCode;
import com.depromeet.global.util.MemberUtil;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
Expand All @@ -37,6 +41,7 @@ public class MemberService {
private final RefreshTokenRepository refreshTokenRepository;
private final MemberRelationRepository memberRelationRepository;
private final MemberUtil memberUtil;
private final FcmService fcmService;

@Transactional(readOnly = true)
public MemberFindOneResponse findMemberInfo() {
Expand Down Expand Up @@ -184,6 +189,21 @@ public void updateFcmToken(UpdateFcmTokenRequest updateFcmTokenRequest) {
currentMember.updateFcmToken(currentMember.getFcmInfo(), updateFcmTokenRequest.fcmToken());
}

@Transactional(readOnly = true)
public void pushNotificationMissionRequest() {
LocalDateTime today = LocalDateTime.now();
List<Member> nonMissionNonCompletedMembers =
memberRepository.findMissionNonCompletedMembers(today);
List<String> tokenList =
nonMissionNonCompletedMembers.stream()
.map(member -> member.getFcmInfo().getFcmToken())
.toList();
if (!tokenList.isEmpty()) {
fcmService.sendGroupMessageAsync(
tokenList, PUSH_SERVICE_TITLE, PUSH_NON_COMPLETE_MISSION_SERVICE_CONTENT);
}
}

private String escapeSpecialCharacters(String nickname) {
// 여기서 특수문자를 '_'로 대체할 수 있도록 정규표현식을 활용하여 구현
return nickname == null ? "" : nickname.replaceAll("[^0-9a-zA-Z가-힣 ]", "_");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

public interface MemberRepository extends JpaRepository<Member, Long> {
public interface MemberRepository extends JpaRepository<Member, Long>, MemberRepositoryCustom {

Optional<Member> findByOauthInfoAndStatus(OauthInfo oauthInfo, MemberStatus status);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.depromeet.domain.member.dao;

import com.depromeet.domain.member.domain.Member;
import java.time.LocalDateTime;
import java.util.List;

public interface MemberRepositoryCustom {
List<Member> findMissionNonCompletedMembers(LocalDateTime today);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.depromeet.domain.member.dao;

import static com.depromeet.domain.member.domain.QMember.*;
import static com.depromeet.domain.mission.domain.QMission.*;
import static com.depromeet.domain.missionRecord.domain.QMissionRecord.*;

import com.depromeet.domain.member.domain.Member;
import com.depromeet.domain.missionRecord.domain.ImageUploadStatus;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.time.LocalDateTime;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

@Repository
@RequiredArgsConstructor
public class MemberRepositoryImpl implements MemberRepositoryCustom {

private final JPAQueryFactory jpaQueryFactory;

@Override
public List<Member> findMissionNonCompletedMembers(LocalDateTime today) {
LocalDateTime start = today.toLocalDate().atStartOfDay();
LocalDateTime end = today.toLocalDate().atTime(23, 59, 59);
return jpaQueryFactory
.selectFrom(member)
.leftJoin(member.missions, mission)
.fetchJoin()
.leftJoin(mission.missionRecords, missionRecord)
.on(missionRecord.createdAt.between(start, end))
.where(
missionRecord
.isNull()
.or(missionRecord.uploadStatus.ne(ImageUploadStatus.COMPLETE)),
member.fcmInfo.fcmToken.isNotNull(),
mission.startedAt.loe(today),
mission.finishedAt.goe(today))
.fetch();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import com.depromeet.domain.mission.domain.Mission;
import com.depromeet.domain.mission.domain.MissionCategory;
import com.depromeet.domain.mission.domain.MissionVisibility;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.LocalDateTime;

public record MissionFindResponse(
@Schema(description = "미션 ID", defaultValue = "1") Long missionId,
Expand All @@ -16,7 +18,25 @@ public record MissionFindResponse(
@Schema(description = "미션 진행 여부", defaultValue = "IN_PROGRESS")
DurationStatus durationStatus,
@Schema(description = "미션 아카이빙 상태", defaultValue = "NONE") ArchiveStatus status,
@Schema(description = "미션 정렬 값", defaultValue = "1") Integer sort) {
@Schema(description = "미션 정렬 값", defaultValue = "1") Integer sort,
@JsonFormat(
shape = JsonFormat.Shape.STRING,
pattern = "yyyy-MM-dd HH:mm:ss",
timezone = "Asia/Seoul")
@Schema(
description = "미션 시작 시간",
defaultValue = "2023-01-03 00:00:00",
type = "string")
LocalDateTime startedAt,
@JsonFormat(
shape = JsonFormat.Shape.STRING,
pattern = "yyyy-MM-dd HH:mm:ss",
timezone = "Asia/Seoul")
@Schema(
description = "미션 종료 시간",
defaultValue = "2024-01-03 00:34:00",
type = "string")
LocalDateTime finishedAt) {

public static MissionFindResponse from(Mission mission) {
return new MissionFindResponse(
Expand All @@ -27,6 +47,8 @@ public static MissionFindResponse from(Mission mission) {
mission.getVisibility(),
mission.getDurationStatus(),
mission.getArchiveStatus(),
mission.getSort());
mission.getSort(),
mission.getStartedAt(),
mission.getFinishedAt());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.depromeet.scheduler.member;

import com.depromeet.domain.member.application.MemberService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
@Slf4j
public class MemberBatchScheduler {
private final MemberService memberService;

@Scheduled(cron = "0 0 22 * * *")
public void pushNotificationByMissionRequest() {
log.info("PushNotification MissionRequest execute");
memberService.pushNotificationMissionRequest();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,55 @@ class 팔로우를_취소할_때 {
.hasMessage(ErrorCode.FOLLOW_NOT_EXIST.getMessage());
}

@Test
void 상대가_나를_팔로우_하고_있다면_FOLLOW_STATUE가_FOLLOWED_BY_ME로_응답한다() {
Long targetId = 2L;
FollowDeleteRequest request = new FollowDeleteRequest(targetId);
Member currentMember =
memberRepository.save(
Member.createNormalMember(
Profile.createProfile("testNickname1", "testImageUrl1")));
Member targetMember =
memberRepository.save(
Member.createNormalMember(
Profile.createProfile("testNickname2", "testImageUrl2")));
MemberRelation memberRelation =
MemberRelation.createMemberRelation(currentMember, targetMember);
MemberRelation memberRelation2 =
MemberRelation.createMemberRelation(targetMember, currentMember);
memberRelationRepository.save(memberRelation);
memberRelationRepository.save(memberRelation2);

// when
FollowerDeletedResponse response = followService.deleteFollow(request);

// then
assertEquals(FollowStatus.FOLLOWED_BY_ME, response.followStatus());
}

@Test
void 상대가_나를_팔로우_하고_있지_않다면_FOLLOW_STATUE가_NOT_FOLLOWING로_응답한다() {
Long targetId = 2L;
FollowDeleteRequest request = new FollowDeleteRequest(targetId);
Member currentMember =
memberRepository.save(
Member.createNormalMember(
Profile.createProfile("testNickname1", "testImageUrl1")));
Member targetMember =
memberRepository.save(
Member.createNormalMember(
Profile.createProfile("testNickname2", "testImageUrl2")));
MemberRelation memberRelation =
MemberRelation.createMemberRelation(currentMember, targetMember);
memberRelationRepository.save(memberRelation);

// when
FollowerDeletedResponse response = followService.deleteFollow(request);

// then
assertEquals(FollowStatus.NOT_FOLLOWING, response.followStatus());
}

@Test
void 정상적이라면_팔로우가_취소된다() {
Long targetId = 2L;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ class MissionControllerTest {
MissionVisibility.ALL,
DurationStatus.IN_PROGRESS,
ArchiveStatus.NONE,
1));
1,
LocalDateTime.of(2024, 01, 01, 1, 5, 0),
LocalDateTime.of(2024, 01, 15, 1, 5, 0)));

// when, then
ResultActions perform =
Expand Down

0 comments on commit cd143c4

Please sign in to comment.