diff --git a/api/src/main/java/org/yapp/domain/auth/application/oauth/service/OauthService.java b/api/src/main/java/org/yapp/domain/auth/application/oauth/service/OauthService.java index d3d9c234..993017da 100644 --- a/api/src/main/java/org/yapp/domain/auth/application/oauth/service/OauthService.java +++ b/api/src/main/java/org/yapp/domain/auth/application/oauth/service/OauthService.java @@ -3,9 +3,9 @@ import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.yapp.core.auth.AuthToken; import org.yapp.core.auth.AuthTokenGenerator; -import org.yapp.core.auth.jwt.JwtUtil; import org.yapp.core.auth.token.RefreshTokenService; import org.yapp.core.domain.user.RoleStatus; import org.yapp.core.domain.user.User; @@ -13,6 +13,7 @@ import org.yapp.domain.auth.application.oauth.OauthProviderResolver; import org.yapp.domain.auth.presentation.dto.request.OauthLoginRequest; import org.yapp.domain.auth.presentation.dto.response.OauthLoginResponse; +import org.yapp.domain.setting.application.SettingService; import org.yapp.domain.user.dao.UserRepository; @Service @@ -20,11 +21,12 @@ public class OauthService { private final OauthProviderResolver oauthProviderResolver; - private final JwtUtil jwtUtil; private final UserRepository userRepository; private final RefreshTokenService refreshTokenService; private final AuthTokenGenerator authTokenGenerator; + private final SettingService settingService; + @Transactional public OauthLoginResponse login(OauthLoginRequest request) { OauthProvider oauthProvider = oauthProviderResolver.find(request.getProviderName()); String oauthId = @@ -36,6 +38,7 @@ public OauthLoginResponse login(OauthLoginRequest request) { User newUser = User.builder().oauthId(oauthId).role(RoleStatus.NONE.getStatus()).build(); User savedUser = userRepository.save(newUser); Long userId = savedUser.getId(); + settingService.createSetting(userId); AuthToken token = authTokenGenerator.generate(userId, savedUser.getOauthId(), "NONE"); String accessToken = token.accessToken(); String refreshToken = token.refreshToken(); diff --git a/api/src/main/java/org/yapp/domain/match/application/algorithm/GreedyMatchingAlgorithm.java b/api/src/main/java/org/yapp/domain/match/application/algorithm/GreedyMatchingAlgorithm.java index 8f6a8205..1f0cc364 100644 --- a/api/src/main/java/org/yapp/domain/match/application/algorithm/GreedyMatchingAlgorithm.java +++ b/api/src/main/java/org/yapp/domain/match/application/algorithm/GreedyMatchingAlgorithm.java @@ -9,6 +9,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; import org.yapp.core.domain.profile.Profile; import org.yapp.core.domain.profile.ProfileValuePick; import org.yapp.domain.match.application.MatchService; @@ -20,97 +21,98 @@ @Component public class GreedyMatchingAlgorithm implements MatchingAlgorithm { - private final ProfileValuePickService profileValuePickService; - private final MatchService matchService; - private final List blockers; + private final ProfileValuePickService profileValuePickService; + private final MatchService matchService; + private final List blockers; - @Override - public List doMatch(List profiles) { - PriorityQueue priorityEdges = getPriorityEdges(profiles); - Set matchedSet = greedyMatch(priorityEdges); - List unmatchedProfiles = new ArrayList<>(); - for (Profile profile : profiles) { - if (!matchedSet.contains(profile.getUser().getId())) { - unmatchedProfiles.add(profile); - } - } - return unmatchedProfiles; + @Override + @Transactional + public List doMatch(List profiles) { + PriorityQueue priorityEdges = getPriorityEdges(profiles); + Set matchedSet = greedyMatch(priorityEdges); + List unmatchedProfiles = new ArrayList<>(); + for (Profile profile : profiles) { + if (!matchedSet.contains(profile.getUser().getId())) { + unmatchedProfiles.add(profile); + } } + return unmatchedProfiles; + } - private Set greedyMatch(PriorityQueue priorityEdges) { - Set matchedSet = new HashSet<>(); - while (!priorityEdges.isEmpty()) { - Edge edge = priorityEdges.poll(); - if (matchedSet.contains(edge.user1Id) || matchedSet.contains(edge.user2Id)) { - continue; - } - matchedSet.add(edge.user1Id); - matchedSet.add(edge.user2Id); + private Set greedyMatch(PriorityQueue priorityEdges) { + Set matchedSet = new HashSet<>(); + while (!priorityEdges.isEmpty()) { + Edge edge = priorityEdges.poll(); + if (matchedSet.contains(edge.user1Id) || matchedSet.contains(edge.user2Id)) { + continue; + } + matchedSet.add(edge.user1Id); + matchedSet.add(edge.user2Id); - matchService.createMatchInfo(edge.user1Id, edge.user2Id); - } - return matchedSet; + matchService.createMatchInfo(edge.user1Id, edge.user2Id); } + return matchedSet; + } - private PriorityQueue getPriorityEdges(List profiles) { - PriorityQueue priorityEdgeQueue = new PriorityQueue(); - for (Profile profile1 : profiles) { - for (Profile profile2 : profiles) { - if (profile1.getId().equals(profile2.getId())) { - continue; - } - if (checkBlock(profile1.getUser().getId(), profile2.getUser().getId())) { - continue; - } - int weight = calculateWeight(profile1.getId(), profile2.getId()); - priorityEdgeQueue.add( - new Edge(weight, profile1.getUser().getId(), profile2.getUser().getId())); - } + private PriorityQueue getPriorityEdges(List profiles) { + PriorityQueue priorityEdgeQueue = new PriorityQueue(); + for (Profile profile1 : profiles) { + for (Profile profile2 : profiles) { + if (profile1.getId().equals(profile2.getId())) { + continue; + } + if (checkBlock(profile1.getUser().getId(), profile2.getUser().getId())) { + continue; } - return priorityEdgeQueue; + int weight = calculateWeight(profile1.getId(), profile2.getId()); + priorityEdgeQueue.add( + new Edge(weight, profile1.getUser().getId(), profile2.getUser().getId())); + } } + return priorityEdgeQueue; + } - private boolean checkBlock(Long blockingUserId, Long blockedUserId) { - for (Blocker blocker : blockers) { - boolean blocked = - blocker.blocked(blockingUserId, blockedUserId) || blocker.blocked(blockedUserId, - blockingUserId); - if (blocked) { - return true; - } - } - return false; + private boolean checkBlock(Long blockingUserId, Long blockedUserId) { + for (Blocker blocker : blockers) { + boolean blocked = + blocker.blocked(blockingUserId, blockedUserId) || blocker.blocked(blockedUserId, + blockingUserId); + if (blocked) { + return true; + } } + return false; + } - private int calculateWeight(Long fromProfileId, Long toProfileId) { - List profileValuePicksOfFrom = - profileValuePickService.getAllProfileValuePicksByProfileId(fromProfileId); - List profileValuePicksOfTo = profileValuePickService.getAllProfileValuePicksByProfileId( - toProfileId); + private int calculateWeight(Long fromProfileId, Long toProfileId) { + List profileValuePicksOfFrom = + profileValuePickService.getAllProfileValuePicksByProfileId(fromProfileId); + List profileValuePicksOfTo = profileValuePickService.getAllProfileValuePicksByProfileId( + toProfileId); - int valueListSize = profileValuePicksOfFrom.size(); - int sumOfWeight = 0; - for (int i = 0; i < valueListSize; i++) { - ProfileValuePick profileValuePickOfFrom = profileValuePicksOfFrom.get(i); - ProfileValuePick profileValuePickOfTo = profileValuePicksOfTo.get(i); - if (profileValuePickOfFrom.getSelectedAnswer() - .equals(profileValuePickOfTo.getSelectedAnswer())) { - sumOfWeight++; - } - } - return sumOfWeight; + int valueListSize = profileValuePicksOfFrom.size(); + int sumOfWeight = 0; + for (int i = 0; i < valueListSize; i++) { + ProfileValuePick profileValuePickOfFrom = profileValuePicksOfFrom.get(i); + ProfileValuePick profileValuePickOfTo = profileValuePicksOfTo.get(i); + if (profileValuePickOfFrom.getSelectedAnswer() + .equals(profileValuePickOfTo.getSelectedAnswer())) { + sumOfWeight++; + } } + return sumOfWeight; + } - @AllArgsConstructor - private static class Edge implements Comparable { + @AllArgsConstructor + private static class Edge implements Comparable { - private int weight; - private Long user1Id; - private Long user2Id; + private int weight; + private Long user1Id; + private Long user2Id; - @Override - public int compareTo(Edge o) { - return o.weight - this.weight; - } + @Override + public int compareTo(Edge o) { + return o.weight - this.weight; } + } } diff --git a/api/src/main/java/org/yapp/domain/match/application/blocker/AcquaintanceBasedBlocker.java b/api/src/main/java/org/yapp/domain/match/application/blocker/AcquaintanceBasedBlocker.java index 9e5e3fee..5afd454d 100644 --- a/api/src/main/java/org/yapp/domain/match/application/blocker/AcquaintanceBasedBlocker.java +++ b/api/src/main/java/org/yapp/domain/match/application/blocker/AcquaintanceBasedBlocker.java @@ -4,19 +4,25 @@ import org.springframework.stereotype.Component; import org.yapp.core.domain.user.User; import org.yapp.domain.block.application.BlockContactService; +import org.yapp.domain.setting.application.SettingService; import org.yapp.domain.user.application.UserService; @Component @RequiredArgsConstructor public class AcquaintanceBasedBlocker implements Blocker { - private final BlockContactService blockContactService; - private final UserService userService; + private final BlockContactService blockContactService; + private final UserService userService; + private final SettingService settingService; - @Override - public boolean blocked(Long blockingUserId, Long blockedUserId) { - User user = userService.getUserById(blockingUserId); - return blockContactService.checkIfUserBlockedPhoneNumber(blockedUserId, - user.getPhoneNumber()); + @Override + public boolean blocked(Long blockingUserId, Long blockedUserId) { + boolean acquaintanceBlockEnabled = settingService.isAcquaintanceBlockEnabled(blockingUserId); + if (!acquaintanceBlockEnabled) { + return false; } + User user = userService.getUserById(blockingUserId); + return blockContactService.checkIfUserBlockedPhoneNumber(blockedUserId, + user.getPhoneNumber()); + } } diff --git a/api/src/main/java/org/yapp/domain/setting/application/SettingService.java b/api/src/main/java/org/yapp/domain/setting/application/SettingService.java new file mode 100644 index 00000000..8c8ee4ea --- /dev/null +++ b/api/src/main/java/org/yapp/domain/setting/application/SettingService.java @@ -0,0 +1,67 @@ +package org.yapp.domain.setting.application; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.yapp.core.domain.setting.Setting; +import org.yapp.core.exception.ApplicationException; +import org.yapp.core.exception.error.code.SettingErrorCode; +import org.yapp.domain.setting.dao.SettingRepository; +import org.yapp.domain.setting.dto.response.SettingInfoResponse; + +@Service +@RequiredArgsConstructor +public class SettingService { + + private final SettingRepository settingRepository; + + @Transactional + public void setNotificationStatus(Long userId, boolean status) { + Setting userSetting = getUserSetting(userId); + userSetting.updateNotification(status); + } + + @Transactional + public void setMatchNotificationStatus(Long userId, boolean status) { + Setting userSetting = getUserSetting(userId); + userSetting.updateMatchNotification(status); + } + + @Transactional + public void setAcquaintanceBlockStatus(Long userId, boolean status) { + Setting userSetting = getUserSetting(userId); + userSetting.updateAcquaintanceBlock(status); + } + + @Transactional + public void createSetting(Long userId) { + Setting setting = new Setting(userId, true, true, true); + settingRepository.save(setting); + } + + public Setting getUserSetting(Long userId) { + return settingRepository.findByUserId(userId).orElseThrow(() -> new ApplicationException( + SettingErrorCode.NOT_FOUND_SETTING)); + } + + public boolean isUserNotificationEnabled(Long userId) { + Setting userSetting = getUserSetting(userId); + return userSetting.isNotification(); + } + + public boolean isMatchNotificationEnabled(Long userId) { + Setting userSetting = getUserSetting(userId); + return userSetting.isNotification() && userSetting.isMatchNotification(); + } + + public boolean isAcquaintanceBlockEnabled(Long userId) { + Setting userSetting = getUserSetting(userId); + return userSetting.isAcquaintanceBlock(); + } + + public SettingInfoResponse getUserSettingInfo(Long userId) { + Setting userSetting = getUserSetting(userId); + return new SettingInfoResponse(userSetting.isNotification(), userSetting.isMatchNotification(), + userSetting.isAcquaintanceBlock()); + } +} diff --git a/api/src/main/java/org/yapp/domain/setting/dao/SettingRepository.java b/api/src/main/java/org/yapp/domain/setting/dao/SettingRepository.java new file mode 100644 index 00000000..739d3956 --- /dev/null +++ b/api/src/main/java/org/yapp/domain/setting/dao/SettingRepository.java @@ -0,0 +1,10 @@ +package org.yapp.domain.setting.dao; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.yapp.core.domain.setting.Setting; + +public interface SettingRepository extends JpaRepository { + + Optional findByUserId(Long userId); +} diff --git a/api/src/main/java/org/yapp/domain/setting/dto/request/SettingToggleRequest.java b/api/src/main/java/org/yapp/domain/setting/dto/request/SettingToggleRequest.java new file mode 100644 index 00000000..27652299 --- /dev/null +++ b/api/src/main/java/org/yapp/domain/setting/dto/request/SettingToggleRequest.java @@ -0,0 +1,11 @@ +package org.yapp.domain.setting.dto.request; + +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@Getter +public class SettingToggleRequest { + + private Boolean toggle; +} diff --git a/api/src/main/java/org/yapp/domain/setting/dto/response/SettingInfoResponse.java b/api/src/main/java/org/yapp/domain/setting/dto/response/SettingInfoResponse.java new file mode 100644 index 00000000..957391e2 --- /dev/null +++ b/api/src/main/java/org/yapp/domain/setting/dto/response/SettingInfoResponse.java @@ -0,0 +1,13 @@ +package org.yapp.domain.setting.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class SettingInfoResponse { + + private Boolean isNotificationEnabled; + private Boolean isMatchNotificationEnabled; + private Boolean isAcquaintanceBlockEnabled; +} diff --git a/api/src/main/java/org/yapp/domain/setting/presentation/SettingController.java b/api/src/main/java/org/yapp/domain/setting/presentation/SettingController.java new file mode 100644 index 00000000..da8d2a83 --- /dev/null +++ b/api/src/main/java/org/yapp/domain/setting/presentation/SettingController.java @@ -0,0 +1,56 @@ +package org.yapp.domain.setting.presentation; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.yapp.domain.setting.application.SettingService; +import org.yapp.domain.setting.dto.request.SettingToggleRequest; +import org.yapp.domain.setting.dto.response.SettingInfoResponse; +import org.yapp.format.CommonResponse; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/settings") +public class SettingController { + + private final SettingService settingService; + + @GetMapping("/infos") + public ResponseEntity> getInfos( + @AuthenticationPrincipal Long userId) { + SettingInfoResponse userSettingInfo = settingService.getUserSettingInfo(userId); + return ResponseEntity.ok(CommonResponse.createSuccess(userSettingInfo)); + } + + @PutMapping("/notification") + public ResponseEntity> updateMatchNotificationStatus( + @RequestBody SettingToggleRequest toggleRequest, + @AuthenticationPrincipal Long userId) { + settingService.setMatchNotificationStatus(userId, toggleRequest.getToggle()); + return ResponseEntity.ok(CommonResponse.createSuccessWithNoContent()); + } + + @PutMapping("/notification/match") + public ResponseEntity> updateNotificationStatus( + @RequestBody SettingToggleRequest toggleRequest, + @AuthenticationPrincipal Long userId) { + settingService.setNotificationStatus(userId, toggleRequest.getToggle()); + return ResponseEntity.ok(CommonResponse.createSuccessWithNoContent()); + } + + @PutMapping("/block/acquaintance") + public ResponseEntity> updateAcquaintanceBlockStatus( + @RequestBody SettingToggleRequest toggleRequest, + @AuthenticationPrincipal Long userId + ) { + settingService.setAcquaintanceBlockStatus(userId, toggleRequest.getToggle()); + return ResponseEntity.ok(CommonResponse.createSuccessWithNoContent()); + } + + +} diff --git a/core/domain/src/main/java/org/yapp/core/domain/setting/Setting.java b/core/domain/src/main/java/org/yapp/core/domain/setting/Setting.java new file mode 100644 index 00000000..25fbbc3d --- /dev/null +++ b/core/domain/src/main/java/org/yapp/core/domain/setting/Setting.java @@ -0,0 +1,51 @@ +package org.yapp.core.domain.setting; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor +public class Setting { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "user_id") + private Long userId; + + @Column(name = "match_notification") + private boolean matchNotification = true; + + @Column(name = "notification") + private boolean notification = true; + + @Column(name = "acquaintance_block") + private boolean acquaintanceBlock = true; + + public Setting(Long userId, boolean matchNotification, boolean notification, + boolean acquaintanceBlock) { + this.userId = userId; + this.matchNotification = matchNotification; + this.notification = notification; + this.acquaintanceBlock = acquaintanceBlock; + } + + public void updateMatchNotification(boolean status) { + this.matchNotification = status; + } + + public void updateNotification(boolean status) { + this.notification = status; + } + + public void updateAcquaintanceBlock(boolean status) { + this.acquaintanceBlock = status; + } +} diff --git a/core/exception/src/main/java/org/yapp/core/exception/error/code/SettingErrorCode.java b/core/exception/src/main/java/org/yapp/core/exception/error/code/SettingErrorCode.java new file mode 100644 index 00000000..d667456d --- /dev/null +++ b/core/exception/src/main/java/org/yapp/core/exception/error/code/SettingErrorCode.java @@ -0,0 +1,15 @@ +package org.yapp.core.exception.error.code; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; + +@Getter +@RequiredArgsConstructor +public enum SettingErrorCode implements ErrorCode { + NOT_FOUND_SETTING(HttpStatus.BAD_REQUEST, "설정 정보가 존재하지 않습니다."), + ; + + private final HttpStatus httpStatus; + private final String message; +}