diff --git a/.github/workflows/stag-client-api-deploy.yml b/.github/workflows/stag-client-api-deploy.yml new file mode 100644 index 00000000..f6f98d9e --- /dev/null +++ b/.github/workflows/stag-client-api-deploy.yml @@ -0,0 +1,48 @@ +name: stag-client-api-deploy + +on: + push: + branches: [ "stag/client" ] + workflow_dispatch: + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 + with: + distribution: 'corretto' + java-version: '17' + + - name: app clean + run: ./gradlew clean + + - name: client api build + run: ./gradlew :likelion-client:build -x test + + - name: Docker login + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_EMAIL }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + + - name: Build and push + uses: docker/build-push-action@v3 + with: + context: ./likelion-client + push: true + tags: ${{ secrets.DOCKER_CLIENT_API_STAG_IMAGE }} + build-args: PROFILE=stag + + - name: client-api-deploy + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.HOST }} + username: ubuntu + key: ${{ secrets.KEY }} + script: | + sudo docker rm -f ${{ secrets.DOCKER_CLIENT_API_STAG_CONTAINER }} + sudo docker rmi ${{ secrets.DOCKER_CLIENT_API_STAG_IMAGE }} + docker-compose -f ${{ secrets.DOCKER_COMPOSE_DIRECTORY }} up -d + docker image prune -f diff --git a/likelion-admin/Dockerfile b/likelion-admin/Dockerfile index 4de98a9b..92de7192 100644 --- a/likelion-admin/Dockerfile +++ b/likelion-admin/Dockerfile @@ -1,6 +1,5 @@ FROM openjdk:17 -ARG JAR_FILE=build/libs/*.jar +ARG JAR_FILE=./build/libs/*.jar COPY ${JAR_FILE} app.jar -EXPOSE 8090 -ENTRYPOINT ["java","-jar","-Duser.timezone=Asia/Seoul","-Dspring.profiles.active=${PROFILE}","/app.jar"] \ No newline at end of file +ENTRYPOINT ["java","-jar","-Duser.timezone=Asia/Seoul","-Dspring.profiles.active=${PROFILE}","/app.jar"] diff --git a/likelion-client/Dockerfile b/likelion-client/Dockerfile index 3c790882..28c361b4 100644 --- a/likelion-client/Dockerfile +++ b/likelion-client/Dockerfile @@ -1,5 +1,4 @@ FROM openjdk:17 -ARG JAR_FILE=build/libs/*.jar -COPY ${JAR_FILE} app.jar +COPY ./build/libs/*.jar app.jar -ENTRYPOINT ["java","-jar","-Duser.timezone=Asia/Seoul","-Dspring.profiles.active=${PROFILE}","/app.jar"] \ No newline at end of file +ENTRYPOINT ["java","-jar","-Duser.timezone=Asia/Seoul","-Dspring.profiles.active=${PROFILE}","/app.jar"] diff --git a/likelion-client/src/main/java/likelion/univ/LikelionClientApplication.java b/likelion-client/src/main/java/likelion/univ/LikelionClientApplication.java index f4beb2af..e6ed9749 100644 --- a/likelion-client/src/main/java/likelion/univ/LikelionClientApplication.java +++ b/likelion-client/src/main/java/likelion/univ/LikelionClientApplication.java @@ -4,9 +4,13 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; @EnableCaching @EnableJpaAuditing +@EnableScheduling +@EnableAsync @SpringBootApplication public class LikelionClientApplication { diff --git a/likelion-client/src/main/java/likelion/univ/alarm/controller/AlarmController.java b/likelion-client/src/main/java/likelion/univ/alarm/controller/AlarmController.java new file mode 100644 index 00000000..847cb5cc --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/alarm/controller/AlarmController.java @@ -0,0 +1,25 @@ +package likelion.univ.alarm.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import likelion.univ.alarm.dto.request.AlarmRegisterRequestDto; +import likelion.univ.alarm.usecase.RegisterAlarmUseCase; +import likelion.univ.response.SuccessResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +@RequestMapping(value = "/v1/alarm") +@Tag(name = "알람", description = "알람 API") +public class AlarmController { + private final RegisterAlarmUseCase registerAlarmUseCase; + + @Operation(summary = "알람 등록", description = "이메일과 알람 타입을 입력받아 해당 기수의 알람을 등록합니다.") + @PostMapping("/{ordinal}/register") + public SuccessResponse registerAlarm(@PathVariable Long ordinal, + @RequestBody AlarmRegisterRequestDto alarmRegisterRequestDto){ + registerAlarmUseCase.execute(ordinal, alarmRegisterRequestDto); + return SuccessResponse.empty(); + } +} diff --git a/likelion-client/src/main/java/likelion/univ/alarm/dto/request/AlarmRegisterRequestDto.java b/likelion-client/src/main/java/likelion/univ/alarm/dto/request/AlarmRegisterRequestDto.java new file mode 100644 index 00000000..d7454965 --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/alarm/dto/request/AlarmRegisterRequestDto.java @@ -0,0 +1,32 @@ +package likelion.univ.alarm.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import likelion.univ.domain.alarm.entity.Alarm; +import likelion.univ.domain.alarm.entity.AlarmType; +import likelion.univ.domain.alarm.entity.SendStatus; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.jetbrains.annotations.NotNull; + +import static likelion.univ.domain.alarm.entity.SendStatus.NOT_SENT; + +@Getter +@NoArgsConstructor +public class AlarmRegisterRequestDto { + @NotNull + @Schema(description = "이메일", example = "tmfrk0426@gmail.com", required = true) + private String email; + + @NotNull + @Schema(description = "알람 타입", example = "NEW_UNIVERSITY_RECRUITING", required = true, enumAsRef = true) + private AlarmType alarmType; + + public static Alarm toEntity(Long ordinal, AlarmRegisterRequestDto alarmRegisterRequestDto){ + return Alarm.builder() + .ordinal(ordinal) + .email(alarmRegisterRequestDto.getEmail()) + .alarmType(alarmRegisterRequestDto.getAlarmType()) + .sendStatus(NOT_SENT) + .build(); + } +} diff --git a/likelion-client/src/main/java/likelion/univ/alarm/usecase/RegisterAlarmUseCase.java b/likelion-client/src/main/java/likelion/univ/alarm/usecase/RegisterAlarmUseCase.java new file mode 100644 index 00000000..0c7e9e7c --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/alarm/usecase/RegisterAlarmUseCase.java @@ -0,0 +1,22 @@ +package likelion.univ.alarm.usecase; + +import likelion.univ.alarm.dto.request.AlarmRegisterRequestDto; +import likelion.univ.annotation.UseCase; +import likelion.univ.domain.alarm.adaptor.AlarmAdaptor; +import likelion.univ.domain.alarm.entity.Alarm; +import likelion.univ.domain.alarm.service.AlarmDomainService; +import lombok.RequiredArgsConstructor; + +@UseCase +@RequiredArgsConstructor +public class RegisterAlarmUseCase { + private final AlarmAdaptor alarmAdaptor; + private final AlarmDomainService alarmDomainService; + + public void execute(Long ordinal, AlarmRegisterRequestDto alarmRegisterRequestDto){ + alarmAdaptor.existsByOrdinalAndEmailAndAlarmType(ordinal, + alarmRegisterRequestDto.getEmail(), alarmRegisterRequestDto.getAlarmType()); + Alarm newAlarm = AlarmRegisterRequestDto.toEntity(ordinal, alarmRegisterRequestDto); + alarmDomainService.createAlarm(newAlarm); + } +} \ No newline at end of file diff --git a/likelion-client/src/main/java/likelion/univ/auth/controller/AuthController.java b/likelion-client/src/main/java/likelion/univ/auth/controller/AuthController.java index 25f4283c..5a171bf3 100644 --- a/likelion-client/src/main/java/likelion/univ/auth/controller/AuthController.java +++ b/likelion-client/src/main/java/likelion/univ/auth/controller/AuthController.java @@ -3,11 +3,9 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import likelion.univ.auth.dto.response.AccountTokenDto; +import likelion.univ.auth.dto.response.AccountUserInfoDto; import likelion.univ.auth.dto.response.IdTokenDto; -import likelion.univ.auth.usecase.LoginUseCase; -import likelion.univ.auth.usecase.RefreshTokenUseCase; -import likelion.univ.auth.usecase.RequestIdTokenUseCase; -import likelion.univ.auth.usecase.SignUpUseCase; +import likelion.univ.auth.usecase.*; import likelion.univ.auth.dto.request.SignUpRequestDto; import likelion.univ.response.SuccessResponse; import likelion.univ.utils.AuthentiatedUserUtils; @@ -24,7 +22,7 @@ public class AuthController { private final RequestIdTokenUseCase requestIdTokenUseCase; private final SignUpUseCase signUpUseCase; private final RefreshTokenUseCase refreshTokenUseCase; - private final AuthentiatedUserUtils userUtils; + private final GetUserInfoUseCase getUserInfoUsecase; @Operation(summary = "id token 발급", description = "인가 코드로 id token을 발급받습니다.") @GetMapping("/{logintype}/idtoken") @@ -55,6 +53,13 @@ public SuccessResponse signUp( return SuccessResponse.of(accountTokenDto); } + @Operation(summary = "유저 정보 조회", description = "간단한 유저정보를 조회합니다.") + @GetMapping("/userinfo") + public SuccessResponse getUserInfo(){ + AccountUserInfoDto accountUserInfoDto = getUserInfoUsecase.execute(); + return SuccessResponse.of(accountUserInfoDto); + } + @Operation(summary = "토큰 재발급", description = "refresh token으로 access token을 재발급합니다.") @PostMapping("/refresh") public SuccessResponse refreshToken( @@ -62,10 +67,4 @@ public SuccessResponse refreshToken( AccountTokenDto accountTokenDto = refreshTokenUseCase.execute(refreshToken); return SuccessResponse.of(accountTokenDto); } - - @Operation(summary = "로그인 유저 Id 반환", description = "(for client only) 로그인 중인 유저의 Id를 얻습니다.") - @GetMapping("/loginuserid") - public SuccessResponse getLoginUserId() { - return SuccessResponse.of(userUtils.getCurrentUserId()); - } } diff --git a/likelion-client/src/main/java/likelion/univ/auth/dto/response/AccountUserInfoDto.java b/likelion-client/src/main/java/likelion/univ/auth/dto/response/AccountUserInfoDto.java new file mode 100644 index 00000000..5553f3f9 --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/auth/dto/response/AccountUserInfoDto.java @@ -0,0 +1,22 @@ +package likelion.univ.auth.dto.response; + +import likelion.univ.domain.user.entity.User; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class AccountUserInfoDto { + private Long userId; + private String profileImage; + private String name; + + public static AccountUserInfoDto of(User user){ + return AccountUserInfoDto.builder() + .userId(user.getId()) + .profileImage(user.getProfile().getProfileImage()) + .name(user.getProfile().getName()) + .build(); + } + +} diff --git a/likelion-client/src/main/java/likelion/univ/auth/usecase/processor/GenerateAccountTokenProcessor.java b/likelion-client/src/main/java/likelion/univ/auth/processor/GenerateAccountTokenProcessor.java similarity index 96% rename from likelion-client/src/main/java/likelion/univ/auth/usecase/processor/GenerateAccountTokenProcessor.java rename to likelion-client/src/main/java/likelion/univ/auth/processor/GenerateAccountTokenProcessor.java index f870f8a7..3e8e2345 100644 --- a/likelion-client/src/main/java/likelion/univ/auth/usecase/processor/GenerateAccountTokenProcessor.java +++ b/likelion-client/src/main/java/likelion/univ/auth/processor/GenerateAccountTokenProcessor.java @@ -1,4 +1,4 @@ -package likelion.univ.auth.usecase.processor; +package likelion.univ.auth.processor; import likelion.univ.annotation.Processor; import likelion.univ.auth.dto.response.AccountTokenDto; diff --git a/likelion-client/src/main/java/likelion/univ/auth/usecase/processor/LoginByIdTokenProcessor.java b/likelion-client/src/main/java/likelion/univ/auth/processor/LoginByIdTokenProcessor.java similarity index 97% rename from likelion-client/src/main/java/likelion/univ/auth/usecase/processor/LoginByIdTokenProcessor.java rename to likelion-client/src/main/java/likelion/univ/auth/processor/LoginByIdTokenProcessor.java index f80cbe0d..3c5e3633 100644 --- a/likelion-client/src/main/java/likelion/univ/auth/usecase/processor/LoginByIdTokenProcessor.java +++ b/likelion-client/src/main/java/likelion/univ/auth/processor/LoginByIdTokenProcessor.java @@ -1,4 +1,4 @@ -package likelion.univ.auth.usecase.processor; +package likelion.univ.auth.processor; import likelion.univ.annotation.Processor; import likelion.univ.feign.oauth.oidc.PublicKeyDto; diff --git a/likelion-client/src/main/java/likelion/univ/auth/usecase/processor/PublicKeyProcessor.java b/likelion-client/src/main/java/likelion/univ/auth/processor/PublicKeyProcessor.java similarity index 96% rename from likelion-client/src/main/java/likelion/univ/auth/usecase/processor/PublicKeyProcessor.java rename to likelion-client/src/main/java/likelion/univ/auth/processor/PublicKeyProcessor.java index c3a00403..d4e4b49b 100644 --- a/likelion-client/src/main/java/likelion/univ/auth/usecase/processor/PublicKeyProcessor.java +++ b/likelion-client/src/main/java/likelion/univ/auth/processor/PublicKeyProcessor.java @@ -1,4 +1,4 @@ -package likelion.univ.auth.usecase.processor; +package likelion.univ.auth.processor; import likelion.univ.annotation.Processor; import likelion.univ.feign.oauth.google.RequestGooglePublicKeysClient; diff --git a/likelion-client/src/main/java/likelion/univ/auth/usecase/GetUserInfoUseCase.java b/likelion-client/src/main/java/likelion/univ/auth/usecase/GetUserInfoUseCase.java new file mode 100644 index 00000000..a9b5dadd --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/auth/usecase/GetUserInfoUseCase.java @@ -0,0 +1,19 @@ +package likelion.univ.auth.usecase; + +import likelion.univ.annotation.UseCase; +import likelion.univ.auth.dto.response.AccountUserInfoDto; +import likelion.univ.domain.user.entity.User; +import likelion.univ.utils.AuthentiatedUserUtils; +import lombok.RequiredArgsConstructor; + +@UseCase +@RequiredArgsConstructor +public class GetUserInfoUseCase { + + private final AuthentiatedUserUtils authentiatedUserUtils; + + public AccountUserInfoDto execute(){ + User user = authentiatedUserUtils.getCurrentUser(); + return AccountUserInfoDto.of(user); + } +} diff --git a/likelion-client/src/main/java/likelion/univ/auth/usecase/LoginUseCase.java b/likelion-client/src/main/java/likelion/univ/auth/usecase/LoginUseCase.java index 1e0c5554..2f0d1e9b 100644 --- a/likelion-client/src/main/java/likelion/univ/auth/usecase/LoginUseCase.java +++ b/likelion-client/src/main/java/likelion/univ/auth/usecase/LoginUseCase.java @@ -2,8 +2,8 @@ import likelion.univ.annotation.UseCase; import likelion.univ.auth.dto.response.AccountTokenDto; -import likelion.univ.auth.usecase.processor.GenerateAccountTokenProcessor; -import likelion.univ.auth.usecase.processor.LoginByIdTokenProcessor; +import likelion.univ.auth.processor.GenerateAccountTokenProcessor; +import likelion.univ.auth.processor.LoginByIdTokenProcessor; import likelion.univ.domain.user.adaptor.UserAdaptor; import likelion.univ.domain.user.entity.LoginType; import likelion.univ.domain.user.entity.User; diff --git a/likelion-client/src/main/java/likelion/univ/auth/usecase/RefreshTokenUseCase.java b/likelion-client/src/main/java/likelion/univ/auth/usecase/RefreshTokenUseCase.java index 9fa48afc..9f1dcc33 100644 --- a/likelion-client/src/main/java/likelion/univ/auth/usecase/RefreshTokenUseCase.java +++ b/likelion-client/src/main/java/likelion/univ/auth/usecase/RefreshTokenUseCase.java @@ -2,7 +2,7 @@ import likelion.univ.annotation.UseCase; import likelion.univ.auth.dto.response.AccountTokenDto; -import likelion.univ.auth.usecase.processor.GenerateAccountTokenProcessor; +import likelion.univ.auth.processor.GenerateAccountTokenProcessor; import likelion.univ.domain.user.adaptor.UserAdaptor; import likelion.univ.domain.user.entity.User; import likelion.univ.exception.InvalidTokenException; diff --git a/likelion-client/src/main/java/likelion/univ/auth/usecase/SignUpUseCase.java b/likelion-client/src/main/java/likelion/univ/auth/usecase/SignUpUseCase.java index e77d320e..f22d634c 100644 --- a/likelion-client/src/main/java/likelion/univ/auth/usecase/SignUpUseCase.java +++ b/likelion-client/src/main/java/likelion/univ/auth/usecase/SignUpUseCase.java @@ -3,8 +3,8 @@ import likelion.univ.annotation.UseCase; import likelion.univ.auth.dto.request.SignUpRequestDto; import likelion.univ.auth.dto.response.AccountTokenDto; -import likelion.univ.auth.usecase.processor.GenerateAccountTokenProcessor; -import likelion.univ.auth.usecase.processor.LoginByIdTokenProcessor; +import likelion.univ.auth.processor.GenerateAccountTokenProcessor; +import likelion.univ.auth.processor.LoginByIdTokenProcessor; import likelion.univ.domain.university.adaptor.UniversityAdaptor; import likelion.univ.domain.university.entity.University; import likelion.univ.domain.user.adaptor.UserAdaptor; diff --git a/likelion-client/src/main/java/likelion/univ/comment/controller/CommentController.java b/likelion-client/src/main/java/likelion/univ/comment/controller/CommentController.java index d2498f3b..2d410d28 100644 --- a/likelion-client/src/main/java/likelion/univ/comment/controller/CommentController.java +++ b/likelion-client/src/main/java/likelion/univ/comment/controller/CommentController.java @@ -20,7 +20,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/v1/community/comments") -@Tag(name = "댓글", description = "댓글 API") +@Tag(name = "댓글", description = "커뮤니티 APIs") public class CommentController { private final CreateParentCommentUseCase createParentCommentUseCase; private final CreateChildCommentUseCase createChildCommentUseCase; diff --git a/likelion-client/src/main/java/likelion/univ/follow/controller/FollowController.java b/likelion-client/src/main/java/likelion/univ/follow/controller/FollowController.java new file mode 100644 index 00000000..33a7cbc9 --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/follow/controller/FollowController.java @@ -0,0 +1,33 @@ +package likelion.univ.follow.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import likelion.univ.follow.usecase.CancelFollowUseCase; +import likelion.univ.follow.usecase.FollowUserUseCase; +import likelion.univ.response.SuccessResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +@RequestMapping(value = "/v1/follow") +@Tag(name = "팔로우", description = "팔로우 관련 API입니다.") +public class FollowController { + private final FollowUserUseCase followUserUseCase; + private final CancelFollowUseCase cancelFollowUseCase; + + @Operation(summary = "팔로우 ", description = "해당 유저를 팔로우 합니다.") + @PostMapping("/{userId}") + public SuccessResponse follow(@PathVariable("userId") Long userId){ + followUserUseCase.execute(userId); + return SuccessResponse.empty(); + } + + @Operation(summary = "팔로우 취소", description = "해당 유저를 팔로우 취소 합니다.") + @DeleteMapping("/{userId}") + public SuccessResponse deleteFollow(@PathVariable("userId") Long userId) { + cancelFollowUseCase.execute(userId); + return SuccessResponse.empty(); + } +} + diff --git a/likelion-client/src/main/java/likelion/univ/follow/usecase/CancelFollowUseCase.java b/likelion-client/src/main/java/likelion/univ/follow/usecase/CancelFollowUseCase.java new file mode 100644 index 00000000..31b38569 --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/follow/usecase/CancelFollowUseCase.java @@ -0,0 +1,33 @@ +package likelion.univ.follow.usecase; + +import likelion.univ.annotation.UseCase; +import likelion.univ.domain.follow.adaptor.FollowAdaptor; +import likelion.univ.follow.dao.FollowNumRedisDao; +import likelion.univ.follow.entity.FollowNum; +import likelion.univ.follow.service.FollowNumRedisService; +import likelion.univ.utils.AuthentiatedUserUtils; +import lombok.RequiredArgsConstructor; + +import java.util.Optional; + +@UseCase +@RequiredArgsConstructor +public class CancelFollowUseCase { + private final AuthentiatedUserUtils authentiatedUserUtils; + private final FollowAdaptor followAdaptor; + private final FollowNumRedisDao followNumRedisDao; + private final FollowNumRedisService followNumRedisService; + + public void execute(Long userId){ + Long currentUserId = authentiatedUserUtils.getCurrentUserId(); + followAdaptor.delete(currentUserId, userId); + updateFollowNumRedis(currentUserId, userId); + } + + private void updateFollowNumRedis(Long currentUserId, Long userId){ + Optional myFollowNum = followNumRedisDao.findById(currentUserId); + if(myFollowNum.isPresent()) followNumRedisService.followingDown(currentUserId, myFollowNum.get()); + Optional targetFollowNum = followNumRedisDao.findById(userId); + if(targetFollowNum.isPresent()) followNumRedisService.followerDown(userId, targetFollowNum.get()); + } +} \ No newline at end of file diff --git a/likelion-client/src/main/java/likelion/univ/follow/usecase/FollowUserUseCase.java b/likelion-client/src/main/java/likelion/univ/follow/usecase/FollowUserUseCase.java new file mode 100644 index 00000000..3726330c --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/follow/usecase/FollowUserUseCase.java @@ -0,0 +1,33 @@ +package likelion.univ.follow.usecase; + +import likelion.univ.annotation.UseCase; +import likelion.univ.domain.follow.adaptor.FollowAdaptor; +import likelion.univ.follow.dao.FollowNumRedisDao; +import likelion.univ.follow.entity.FollowNum; +import likelion.univ.follow.service.FollowNumRedisService; +import likelion.univ.utils.AuthentiatedUserUtils; +import lombok.RequiredArgsConstructor; + +import java.util.Optional; + +@UseCase +@RequiredArgsConstructor +public class FollowUserUseCase { + private final AuthentiatedUserUtils authentiatedUserUtils; + private final FollowAdaptor followAdaptor; + private final FollowNumRedisDao followNumRedisDao; + private final FollowNumRedisService followNumRedisService; + + public void execute(Long userId){ + Long currentUserId = authentiatedUserUtils.getCurrentUserId(); + followAdaptor.save(currentUserId, userId); + updateFollowNumRedis(currentUserId, userId); + } + + private void updateFollowNumRedis(Long currentUserId, Long userId){ + Optional myFollowNum = followNumRedisDao.findById(currentUserId); + if(myFollowNum.isPresent()) followNumRedisService.followingUp(currentUserId, myFollowNum.get()); + Optional targetFollowNum = followNumRedisDao.findById(userId); + if(targetFollowNum.isPresent()) followNumRedisService.followerUp(userId, targetFollowNum.get()); + } +} \ No newline at end of file diff --git a/likelion-client/src/main/java/likelion/univ/like/commentlike/controller/CommentLikeController.java b/likelion-client/src/main/java/likelion/univ/like/commentlike/controller/CommentLikeController.java index 85c638ba..42e4a2dd 100644 --- a/likelion-client/src/main/java/likelion/univ/like/commentlike/controller/CommentLikeController.java +++ b/likelion-client/src/main/java/likelion/univ/like/commentlike/controller/CommentLikeController.java @@ -15,7 +15,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/v1/community/commentlike") -@Tag(name = "댓글 좋아요", description = "댓글 좋아요 API") +@Tag(name = "댓글 좋아요", description = "커뮤니티 APIs") public class CommentLikeController { private final CreateCommentLikeUseCase createCommentLikeUseCase; private final SwitchCommentLikeUseCase switchCommentLikeUseCase; diff --git a/likelion-client/src/main/java/likelion/univ/like/postlike/controller/PostLikeController.java b/likelion-client/src/main/java/likelion/univ/like/postlike/controller/PostLikeController.java index 9d9086c4..d491716b 100644 --- a/likelion-client/src/main/java/likelion/univ/like/postlike/controller/PostLikeController.java +++ b/likelion-client/src/main/java/likelion/univ/like/postlike/controller/PostLikeController.java @@ -2,6 +2,7 @@ import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import likelion.univ.domain.like.postlike.dto.PostLikeResponseDto; import likelion.univ.like.postlike.dto.PostLikeRequestDto; import likelion.univ.like.postlike.usecase.CreatePostLikeUseCase; @@ -13,6 +14,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/v1/community/likepost") +@Tag(name = "게시글 좋아요", description = "커뮤니티 APIs") public class PostLikeController { private final CreatePostLikeUseCase createPostLikeUseCase; private final DeletePostLikeUseCase deletePostLikeUseCase; diff --git a/likelion-client/src/main/java/likelion/univ/post/controller/PostController.java b/likelion-client/src/main/java/likelion/univ/post/controller/PostController.java index 6f18ff17..d9517629 100644 --- a/likelion-client/src/main/java/likelion/univ/post/controller/PostController.java +++ b/likelion-client/src/main/java/likelion/univ/post/controller/PostController.java @@ -2,6 +2,7 @@ import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import likelion.univ.domain.post.dto.response.PostDetailResponseDto; import likelion.univ.domain.post.dto.response.PostCommandResponseDto; import likelion.univ.domain.post.entity.enums.MainCategory; @@ -22,6 +23,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/v1/community/posts") +@Tag(name = "게시글", description = "커뮤니티, 마이페이지 APIs") public class PostController { private final PostCreateUseCase postCreateUseCase; @@ -30,14 +32,17 @@ public class PostController { private final PostReadRepository postReadRepository; /* read */ - @Operation(summary = "(커뮤니티) 카테고리별 posts 최신순 조회", description = "카테고리가 일치하는 게시글 최신순으로 조회") + @Operation(summary = "(커뮤니티) 카테고리별 posts 최신순 조회", description = "카테고리 params\n- maincatstr : 메인 카테고리 문자열(HQ_BOARD, FREE_BOARD, OVERFLOW)\n- subcatstr : 서브 카테고리 문자열(post 생성 참고)\n\n페이지네이션 params\n- page : 0 이상의 정수 \n- size : 양수") @GetMapping("") - public SuccessResponse findCategorizedPosts(@RequestParam MainCategory mainCategory, @RequestParam SubCategory subCategory, @RequestParam Integer page, @RequestParam Integer size) { + public SuccessResponse findCategorizedPosts(@RequestParam String maincatstr, @RequestParam String subcatstr, @RequestParam Integer page, @RequestParam Integer size) { PageRequest pageRequest = PageRequest.of(page, size); + MainCategory mainCategory = MainCategory.valueOf(maincatstr); + SubCategory subCategory = SubCategory.valueOf(subcatstr); + List response = postReadRepository.findAll(mainCategory, subCategory, pageRequest); return SuccessResponse.of(response); } - @Operation(summary = "(마이페이지) 유저별 posts 최신순 조회", description = "유저Id를 param으로 넣어서, 유저별로 작성한 게시글을 최신순으로 조회") + @Operation(summary = "(마이페이지) 유저별 posts 최신순 조회", description = "유저Id를 param으로 넣어서, 유저별로 작성한 게시글을 최신순으로 조회 \n- page : 0 이상의 정수 \n- size : 양수") @GetMapping("/author/{userId}") public SuccessResponse findAuthorPosts(@PathVariable Long userId, @RequestParam Integer page, @RequestParam Integer size) { PageRequest pageRequest = PageRequest.of(page, size); @@ -45,7 +50,7 @@ public SuccessResponse findAuthorPosts(@PathVariable Long userId, @RequestPar return SuccessResponse.of(response); } - @Operation(summary = "(마이페이지) 유저가 댓글을 단 posts 최신순 조회", description = "(로그인된 유저 기준 only) 댓글 단 posts 최신순 조회") + @Operation(summary = "(마이페이지) 유저가 댓글을 단 posts 최신순 조회", description = "(로그인된 유저 기준 only) 댓글 단 posts 최신순 조회 \n- page : 0 이상의 정수 \n- size : 양수") @GetMapping("/commented") public SuccessResponse findCommentedPosts(@RequestParam Integer page, @RequestParam Integer size) { PageRequest pageRequest = PageRequest.of(page, size); @@ -53,7 +58,7 @@ public SuccessResponse findCommentedPosts(@RequestParam Integer page, @Reques return SuccessResponse.of(response); } - @Operation(summary = "(마이페이지) 유저가 좋아요한 posts 최신순 조회", description = "(로그인된 유저 기준 only) 좋아요를 누른 posts 최신순 조회") + @Operation(summary = "(마이페이지) 유저가 좋아요한 posts 최신순 조회", description = "(로그인된 유저 기준 only) 좋아요를 누른 posts 최신순 조회 \n- page : 0 이상의 정수 \n- size : 양수") @GetMapping("/liked") public SuccessResponse findLikedPosts(@RequestParam Integer page, @RequestParam Integer size) { PageRequest pageRequest = PageRequest.of(page, size); @@ -62,7 +67,7 @@ public SuccessResponse findLikedPosts(@RequestParam Integer page, @RequestPar } /* command */ - @Operation(summary = "게시글을 생성", description = "(작업중 - 카테고리 반영 필요)") + @Operation(summary = "게시글을 생성", description = "Main Category\n- HQ_BOARD(멋대 중앙)\n- FREE_BOARD(자유게시판)\n- OVERFLOW(멋사 오버플로우) \n\nSub Category\n- HQ_BOARD : NOTICE(공지사항), QNA(질문건의), HQ_INFO(정보공유)\n- FREE_BOARD : FREE_INFO(정보공유), GET_MEMBER(팀원구함), GET_PROJECT(프로젝트 구함), SHOWOFF(프로젝트 자랑)\n- OVERFLOW : FRONTEND(프론트엔드), BACKEND(백엔드), PM(기획), UXUI(디자인), ETC(기타)") @PostMapping("/new") public SuccessResponse createPost(@RequestBody @Valid PostCreateRequestDto request/*, BindingResult bindingResult*/) { PostCommandResponseDto response = postCreateUseCase.execute(request); diff --git a/likelion-client/src/main/java/likelion/univ/post/dto/PostCreateRequestDto.java b/likelion-client/src/main/java/likelion/univ/post/dto/PostCreateRequestDto.java index a8974660..3bdf5d8a 100644 --- a/likelion-client/src/main/java/likelion/univ/post/dto/PostCreateRequestDto.java +++ b/likelion-client/src/main/java/likelion/univ/post/dto/PostCreateRequestDto.java @@ -21,9 +21,9 @@ public class PostCreateRequestDto { @Schema(description = "썸네일 이미지", example = "string") private String thumbnail; @NotNull - @Schema(description = "메인 카테고리", example = "자유게시판", required = true) + @Schema(description = "메인 카테고리", example = "FREE_BOARD", required = true) private String mainCategory; @NotNull - @Schema(description = "서브 카테고리", example = "백엔드", required = true) + @Schema(description = "서브 카테고리", example = "FREE_INFO", required = true) private String subCategory; } diff --git a/likelion-client/src/main/java/likelion/univ/post/processor/GetOrCreatePostCountInfoProcessor.java b/likelion-client/src/main/java/likelion/univ/post/processor/GetOrCreatePostCountInfoProcessor.java new file mode 100644 index 00000000..c244c84d --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/post/processor/GetOrCreatePostCountInfoProcessor.java @@ -0,0 +1,30 @@ +package likelion.univ.post.processor; + +import likelion.univ.annotation.Processor; +import likelion.univ.domain.comment.adaptor.CommentAdaptor; +import likelion.univ.domain.like.postlike.adaptor.PostLikeAdaptor; +import likelion.univ.post.dao.PostCountInfoRedisDao; +import likelion.univ.post.entity.PostCountInfo; +import likelion.univ.post.service.PostCountInfoRedisService; +import lombok.RequiredArgsConstructor; + +import java.util.Optional; + +@Processor +@RequiredArgsConstructor +public class GetOrCreatePostCountInfoProcessor { + + private final PostCountInfoRedisDao postCountInfoRedisDao; + private final PostCountInfoRedisService postCountInfoRedisService; + private final CommentAdaptor commentAdaptor; + private final PostLikeAdaptor postLikeAdaptor; + + public PostCountInfo execute(Long postId){ + Optional postCountInfo = postCountInfoRedisDao.findById(postId); + if(postCountInfo.isEmpty()){ + Long commentCount = commentAdaptor.countByPostId(postId); + Long likeCount = postLikeAdaptor.countByPostId(postId); + return postCountInfoRedisService.save(postId, commentCount, likeCount); + }else return postCountInfo.get(); + } +} diff --git a/likelion-client/src/main/java/likelion/univ/post/repository/PostReadRepositoryCustomImpl.java b/likelion-client/src/main/java/likelion/univ/post/repository/PostReadRepositoryCustomImpl.java index 3d6551c3..e925bab4 100644 --- a/likelion-client/src/main/java/likelion/univ/post/repository/PostReadRepositoryCustomImpl.java +++ b/likelion-client/src/main/java/likelion/univ/post/repository/PostReadRepositoryCustomImpl.java @@ -1,6 +1,6 @@ package likelion.univ.post.repository; -import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; import likelion.univ.domain.post.dto.response.PostDetailResponseDto; import likelion.univ.domain.post.dto.response.QPostDetailResponseDto; import likelion.univ.domain.post.entity.enums.MainCategory; @@ -9,7 +9,6 @@ import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; import org.springframework.data.domain.Pageable; -import com.querydsl.jpa.impl.JPAQueryFactory; import org.springframework.stereotype.Repository; import java.util.List; @@ -120,6 +119,7 @@ private static QPostDetailResponseDto postDetailResponseDto() { post.title, post.body, post.thumbnail, + post.postLikes.size(), post.mainCategory, post.subCategory, post.createdDate, diff --git a/likelion-client/src/main/java/likelion/univ/user/controller/UserController.java b/likelion-client/src/main/java/likelion/univ/user/controller/UserController.java new file mode 100644 index 00000000..c5367389 --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/user/controller/UserController.java @@ -0,0 +1,117 @@ +package likelion.univ.user.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import likelion.univ.common.response.PageResponse; +import likelion.univ.common.response.SliceResponse; +import likelion.univ.user.dto.request.ProfileEditRequestDto; +import likelion.univ.user.dto.response.FollowUserInfoDto; +import likelion.univ.user.dto.response.UserPagePostsDto; +import likelion.univ.user.dto.response.ProfileDetailsDto; +import likelion.univ.user.dto.response.UserSearchResultDto; +import likelion.univ.user.usecase.*; +import likelion.univ.response.SuccessResponse; +import lombok.RequiredArgsConstructor; +import org.springdoc.api.annotations.ParameterObject; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +@RequestMapping(value = "/v1/user") +@Tag(name = "유저페이지", description = "유저페이지관련 API입니다.") +public class UserController { + private final GetProfileUseCase getProfileUseCase; + private final EditProfileUseCase editProfileUseCase; + private final GetUserPostsUseCase getMyPostsUseCase; + private final GetPostsCommentedByMeUseCase getPostsCommentedByMeUseCase; + private final GetFollowInfoUseCase getFollowingListUseCase; + private final SearchUserByNameUseCase searchUserByNameUseCase; + private final GetUserLikedPostsUseCase getUserLikedPostsUseCase; + + @Operation(summary = "유저페이지 프로필 조회", description = "해당 유저의 프로필 정보를 조회합니다.") + @GetMapping("/{userId}/profile") + public SuccessResponse getProfile(@PathVariable Long userId){ + ProfileDetailsDto profileDetailsDto = getProfileUseCase.execute(userId); + return SuccessResponse.of(profileDetailsDto); + } + + @Operation(summary = "유저페이지 프로필 수정", description = "해당 유저의 프로필 정보를 수정합니다.") + @PatchMapping("/{userId}/profile") + public SuccessResponse editProfile(@PathVariable Long userId, + @RequestBody ProfileEditRequestDto profileEditRequestDto){ + editProfileUseCase.execute(userId,profileEditRequestDto); + return SuccessResponse.empty(); + } + + @Operation(summary = "팔로잉 목록 조회", description = "해당 유저의 팔로잉 목록을 조회합니다.") + @GetMapping("/{userId}/following") + public SuccessResponse getFollowingList(@PathVariable Long userId, + @ParameterObject @PageableDefault(size = 4, page = 1) Pageable pageable){ + SliceResponse followingUsers = getFollowingListUseCase.executeForFollowing(userId,pageable); + return SuccessResponse.of(followingUsers); + } + + @Operation(summary = "팔로워 목록 조회", description = "해당 유저의 팔로워 목록을 조회합니다.") + @GetMapping("/{userId}/follower") + public SuccessResponse getFollowerList(@PathVariable Long userId, + @ParameterObject @PageableDefault(size = 4, page = 1) Pageable pageable){ + SliceResponse followerUsers = getFollowingListUseCase.executeForFollower(userId,pageable); + return SuccessResponse.of(followerUsers); + } + @Operation(summary = "해당 유저가 쓴 게시글 조회", description = "해당 유저가 작성한 게시글을 조회합니다.") + @GetMapping("/{userId}/posts") + public SuccessResponse getPostsWritedByUser(@PathVariable Long userId, + @ParameterObject @PageableDefault(size = 6, page = 1) Pageable pageable){ + PageResponse myPagePostsPage = getMyPostsUseCase.execute(userId, pageable); + return SuccessResponse.of(myPagePostsPage); + } + + @Operation(summary = "해당 유저가 좋아요 누른 게시글 조회", description = "해당 유저가 좋아요를 누른 게시글을 조회합니다.") + @GetMapping("/{userId}/posts/like") + public SuccessResponse getPostsLikedByUser(@PathVariable Long userId, + @ParameterObject @PageableDefault(size = 6, page = 1) Pageable pageable){ + PageResponse myPagePostsPageLikedByUser = getUserLikedPostsUseCase.execute(userId, pageable); + return SuccessResponse.of(myPagePostsPageLikedByUser); + } + + + @Operation(summary = "해당 유저가 댓글 쓴 게시글 조회", description = "해당 유저가 댓글을 작성한 게시글을 조회합니다.") + @GetMapping("/{userId}/posts/comment") + public SuccessResponse getPostsCommentedByUser(@PathVariable Long userId, + @ParameterObject @PageableDefault(size = 6, page = 1) Pageable pageable){ + PageResponse myPagePostsPageCommentedByUser = getPostsCommentedByMeUseCase.execute(userId, pageable); + return SuccessResponse.of(myPagePostsPageCommentedByUser); + } + @Operation(summary = "유저 검색 (Simple Data) (project page)", description = "이름으로 유저를 검색합니다. (프로젝트 페이지 모달)") + @GetMapping("/search") + public SuccessResponse searchUser(@RequestParam(required = false) String name, + @ParameterObject @PageableDefault(size = 4, page = 1) Pageable pageable){ + SliceResponse searchedUsers = searchUserByNameUseCase.execute(name, pageable); + return SuccessResponse.of(searchedUsers); + } + + +// @Operation(summary = "내가 참여한 프로젝트 조회", description = "참여한 프로젝트를 조회합니다.") +// @GetMapping("/projects") +// public SuccessResponse getMyProjects(@ParameterObject @PageableDefault(size = 6, page = 1) Pageable pageable){ +// +// return SuccessResponse.of(); +// } +// +// @Operation(summary = "휴대폰 인증 요청", description = "휴대폰 번호 인증을 위해 서버 내부에 인증번호를 생성합니다.") +// @PostMapping("/phone/certify") +// public SuccessResponse login(@RequestParam("phonenum") String phoneNum){ +// return SuccessResponse.of(); +// } +// +// @Operation(summary = "휴대폰 인증번호 확인", description = "휴대폰 인증번호 확인 후 인증 토큰을 발급합니다.") +// @PostMapping("/phone/certify/check") +// public SuccessResponse getIdToken(@RequestParam("certifynum") Long certifyNum){ +// +// return SuccessResponse.of(); +// } + +} + diff --git a/likelion-client/src/main/java/likelion/univ/user/dto/request/ProfileEditRequestDto.java b/likelion-client/src/main/java/likelion/univ/user/dto/request/ProfileEditRequestDto.java new file mode 100644 index 00000000..3cff2535 --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/user/dto/request/ProfileEditRequestDto.java @@ -0,0 +1,36 @@ +package likelion.univ.user.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import likelion.univ.domain.user.entity.Part; +import likelion.univ.domain.user.entity.Profile; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.jetbrains.annotations.NotNull; + + +@Getter +@NoArgsConstructor +public class ProfileEditRequestDto { + @NotNull + @Schema(description = "이름", example = "김슬기", required = true) + private String name; + + @Schema(description = "한줄 소개", example = "안녕하세요. 김슬기입니다.", required = false) + private String introduction; + + @Schema(description = "프로필 이미지", example = "", required = false) + private String profileImage; + + @NotNull + @Schema(description = "트랙(파트)", example = "BACKEND", required = true, enumAsRef = true) + private Part part; + + public Profile toProfile(){ + return Profile.builder() + .name(name) + .profileImage(profileImage) + .introduction(introduction) + .part(part) + .build(); + } +} \ No newline at end of file diff --git a/likelion-client/src/main/java/likelion/univ/user/dto/response/FollowUserInfoDto.java b/likelion-client/src/main/java/likelion/univ/user/dto/response/FollowUserInfoDto.java new file mode 100644 index 00000000..7259d21a --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/user/dto/response/FollowUserInfoDto.java @@ -0,0 +1,27 @@ +package likelion.univ.user.dto.response; + +import likelion.univ.domain.user.entity.User; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class FollowUserInfoDto { + private Long userId; + private String name; + private String profileImage; + private Long ordinal; + private String part; + private Boolean isFollowed; + + public static FollowUserInfoDto of(User user, Boolean isFollowed){ + return FollowUserInfoDto.builder() + .userId(user.getId()) + .name(user.getProfile().getName()) + .profileImage(user.getProfile().getProfileImage()) + .ordinal(user.getUniversityInfo().getOrdinal()) + .part(user.getProfile().getPart().toString()) + .isFollowed(isFollowed) + .build(); + } +} diff --git a/likelion-client/src/main/java/likelion/univ/user/dto/response/ProfileDetailsDto.java b/likelion-client/src/main/java/likelion/univ/user/dto/response/ProfileDetailsDto.java new file mode 100644 index 00000000..de0b2128 --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/user/dto/response/ProfileDetailsDto.java @@ -0,0 +1,41 @@ +package likelion.univ.user.dto.response; + +import likelion.univ.domain.user.entity.User; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class ProfileDetailsDto { + private Long id; + private String profileImage; + private String name; + private String role; + private String phoneNum; + private String universityName; + private String major; + private Long ordinal; + private String part; + private Long followerNum; + private Long followingNum; + private String introduction; + private Boolean isMine; + + public static ProfileDetailsDto of(User user, Boolean isMine,Long followerNum, Long followingNum){ + return ProfileDetailsDto.builder() + .id(user.getId()) + .profileImage(user.getProfile().getProfileImage()) + .name(user.getProfile().getName()) + .role(user.getAuthInfo().getRole().getValue()) + .phoneNum(user.getAuthInfo().getPhoneNumber()) + .universityName(user.getUniversityInfo().getUniversity().getName()) + .major(user.getUniversityInfo().getMajor()) + .ordinal(user.getUniversityInfo().getOrdinal()) + .part(user.getProfile().getPart().toString()) + .followerNum(followerNum) + .followingNum(followingNum) + .introduction(user.getProfile().getIntroduction()) + .isMine(isMine) + .build(); + } +} diff --git a/likelion-client/src/main/java/likelion/univ/user/dto/response/UserPagePostsDto.java b/likelion-client/src/main/java/likelion/univ/user/dto/response/UserPagePostsDto.java new file mode 100644 index 00000000..d519ff6e --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/user/dto/response/UserPagePostsDto.java @@ -0,0 +1,41 @@ +package likelion.univ.user.dto.response; + +import likelion.univ.domain.post.entity.Post; +import likelion.univ.post.entity.PostCountInfo; +import lombok.Builder; +import lombok.Getter; + +import java.time.LocalDate; + + +@Getter +@Builder +public class UserPagePostsDto { + private Long id; + private String title; + private String body; + private String thumbnail; + private Boolean isAuthor; + private LocalDate createdDate; + private Long likeCount; + private Long commentCount; + + public static UserPagePostsDto of(Post post, Long likeCount, Long commentCount, Boolean isAuthor){ + return UserPagePostsDto.builder() + .id(post.getId()) + .title(post.getTitle()) + .body(post.getBody()) + .thumbnail(post.getThumbnail()) + .isAuthor(isAuthor) + .createdDate(post.getCreatedDate().toLocalDate()) + .likeCount(likeCount) + .commentCount(commentCount) + .build(); + } + + public static UserPagePostsDto of(Post post, Long userId, PostCountInfo postCountInfo){ + if(post.getAuthor().getId().equals(userId)) + return UserPagePostsDto.of(post, postCountInfo.getLikeCount(), postCountInfo.getCommentCount(),true); + else return UserPagePostsDto.of(post, postCountInfo.getLikeCount(), postCountInfo.getCommentCount(),false); + } +} diff --git a/likelion-client/src/main/java/likelion/univ/user/dto/response/UserSearchResultDto.java b/likelion-client/src/main/java/likelion/univ/user/dto/response/UserSearchResultDto.java new file mode 100644 index 00000000..052e767d --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/user/dto/response/UserSearchResultDto.java @@ -0,0 +1,28 @@ +package likelion.univ.user.dto.response; + +import likelion.univ.domain.user.entity.User; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class UserSearchResultDto { + private Long userId; + private String name; + private String profileImage; + private String universityName; + private Long ordinal; + private String part; + + public static UserSearchResultDto of(User user){ + return UserSearchResultDto.builder() + .userId(user.getId()) + .name(user.getProfile().getName()) + .profileImage(user.getProfile().getProfileImage()) + .universityName(user.getUniversityInfo().getUniversity().getName()) + .ordinal(user.getUniversityInfo().getOrdinal()) + .part(user.getProfile().getPart().getValue()) + .build(); + } + +} diff --git a/likelion-client/src/main/java/likelion/univ/user/scheduler/UserPageScheduler.java b/likelion-client/src/main/java/likelion/univ/user/scheduler/UserPageScheduler.java new file mode 100644 index 00000000..45bb7cd9 --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/user/scheduler/UserPageScheduler.java @@ -0,0 +1,4 @@ +package likelion.univ.user.scheduler; + +//public class MyPageScheduler { +//} diff --git a/likelion-client/src/main/java/likelion/univ/user/usecase/EditProfileUseCase.java b/likelion-client/src/main/java/likelion/univ/user/usecase/EditProfileUseCase.java new file mode 100644 index 00000000..0b9df489 --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/user/usecase/EditProfileUseCase.java @@ -0,0 +1,24 @@ +package likelion.univ.user.usecase; + +import likelion.univ.annotation.UseCase; +import likelion.univ.domain.user.entity.Profile; +import likelion.univ.domain.user.entity.User; +import likelion.univ.domain.user.service.UserDomainService; +import likelion.univ.user.dto.request.ProfileEditRequestDto; +import likelion.univ.user.dto.response.ProfileDetailsDto; +import likelion.univ.utils.AuthentiatedUserUtils; +import lombok.RequiredArgsConstructor; + +@UseCase +@RequiredArgsConstructor +public class EditProfileUseCase { + private final AuthentiatedUserUtils authentiatedUserUtils; + private final UserDomainService userDomainService; + + public void execute(Long userId, ProfileEditRequestDto profileEditRequestDto){ + authentiatedUserUtils.checkidentification(userId); + + Profile profile = profileEditRequestDto.toProfile(); + User user = userDomainService.editProfile(userId, profile); + } +} diff --git a/likelion-client/src/main/java/likelion/univ/user/usecase/GetFollowInfoUseCase.java b/likelion-client/src/main/java/likelion/univ/user/usecase/GetFollowInfoUseCase.java new file mode 100644 index 00000000..8a963a36 --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/user/usecase/GetFollowInfoUseCase.java @@ -0,0 +1,45 @@ +package likelion.univ.user.usecase; + +import likelion.univ.annotation.UseCase; +import likelion.univ.common.response.SliceResponse; +import likelion.univ.domain.user.adaptor.UserAdaptor; +import likelion.univ.domain.user.entity.User; +import likelion.univ.user.dto.response.FollowUserInfoDto; +import likelion.univ.utils.AuthentiatedUserUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; + +import java.util.List; + +@UseCase +@RequiredArgsConstructor +public class GetFollowInfoUseCase { + private final AuthentiatedUserUtils authentiatedUserUtils; + private final UserAdaptor userAdaptor; + + public SliceResponse executeForFollowing(Long userId, Pageable pageable){ + Slice userSlice = userAdaptor.findFollowingUsersByFollowerID(userId, pageable); + List myFollowingUsers = getMyFollowingUsers(userSlice); + + return SliceResponse.of(userSlice.map(u -> + FollowUserInfoDto.of(u, checkIFollowingTarget(u, myFollowingUsers)))); + } + + public SliceResponse executeForFollower(Long userId, Pageable pageable){ + Slice userSlice = userAdaptor.findFollowerUsersByFollowingID(userId, pageable); + List myFollowingUsers = getMyFollowingUsers(userSlice); + + return SliceResponse.of(userSlice.map(u -> + FollowUserInfoDto.of(u, checkIFollowingTarget(u, myFollowingUsers)))); + } + private List getMyFollowingUsers(Slice userSlice){ + Long currentUserId = authentiatedUserUtils.getCurrentUserId(); + List followingUserIds = userSlice.getContent().stream().map(user -> user.getId()).toList(); + return userAdaptor.findMyFollowingUsersByFollowingIdIn(currentUserId, followingUserIds); + } + + private Boolean checkIFollowingTarget(User target, List myFollowingUsers){ + return myFollowingUsers.stream().anyMatch(u -> u.getId().equals(target.getId())); + } +} diff --git a/likelion-client/src/main/java/likelion/univ/user/usecase/GetPostsCommentedByMeUseCase.java b/likelion-client/src/main/java/likelion/univ/user/usecase/GetPostsCommentedByMeUseCase.java new file mode 100644 index 00000000..f1eb8761 --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/user/usecase/GetPostsCommentedByMeUseCase.java @@ -0,0 +1,32 @@ +package likelion.univ.user.usecase; + +import likelion.univ.annotation.UseCase; +import likelion.univ.common.response.PageResponse; +import likelion.univ.domain.post.adaptor.PostAdaptor; +import likelion.univ.domain.post.entity.Post; +import likelion.univ.post.processor.GetOrCreatePostCountInfoProcessor; +import likelion.univ.user.dto.response.UserPagePostsDto; +import likelion.univ.domain.comment.adaptor.CommentAdaptor; +import likelion.univ.domain.like.postlike.adaptor.PostLikeAdaptor; +import likelion.univ.post.dao.PostCountInfoRedisDao; +import likelion.univ.post.entity.PostCountInfo; +import likelion.univ.post.service.PostCountInfoRedisService; +import likelion.univ.utils.AuthentiatedUserUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import java.util.Optional; + +@UseCase +@RequiredArgsConstructor +public class GetPostsCommentedByMeUseCase { + private final AuthentiatedUserUtils authentiatedUserUtils; + private final PostAdaptor postAdaptor; + private final GetOrCreatePostCountInfoProcessor getOrCreatePostCountInfoProcessor; + + public PageResponse execute(Long userId, Pageable pageable){ + Long currentUserId = authentiatedUserUtils.getCurrentUserId(); + Page posts = postAdaptor.findByCommentAuthorId(userId, pageable); + return PageResponse.of(posts.map(p-> UserPagePostsDto.of(p, currentUserId, getOrCreatePostCountInfoProcessor.execute(p.getId())))); + } +} diff --git a/likelion-client/src/main/java/likelion/univ/user/usecase/GetProfileUseCase.java b/likelion-client/src/main/java/likelion/univ/user/usecase/GetProfileUseCase.java new file mode 100644 index 00000000..325bc2ac --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/user/usecase/GetProfileUseCase.java @@ -0,0 +1,48 @@ +package likelion.univ.user.usecase; + +import likelion.univ.annotation.UseCase; +import likelion.univ.domain.follow.adaptor.FollowAdaptor; +import likelion.univ.domain.user.adaptor.UserAdaptor; +import likelion.univ.domain.user.entity.User; +import likelion.univ.follow.dao.FollowNumRedisDao; +import likelion.univ.user.dto.response.ProfileDetailsDto; +import likelion.univ.follow.entity.FollowNum; +import likelion.univ.follow.service.FollowNumRedisService; +import likelion.univ.utils.AuthentiatedUserUtils; +import lombok.RequiredArgsConstructor; + +import java.util.Optional; + +@UseCase +@RequiredArgsConstructor +public class GetProfileUseCase { + private final AuthentiatedUserUtils authentiatedUserUtils; + private final UserAdaptor userAdaptor; + private final FollowNumRedisDao followNumRedisDao; + private final FollowNumRedisService followNumRedisService; + private final FollowAdaptor followAdaptor; + + public ProfileDetailsDto execute(Long userId){ + Long currentUserId = authentiatedUserUtils.getCurrentUserId(); + User user = userAdaptor.findByIdWithUniversity(userId); + + return createDto(user, currentUserId); + } + + private ProfileDetailsDto createDto(User user, Long currentUserId){ + FollowNum followNum = getUserFollowNum(user.getId()); + + if (user.getId().equals(currentUserId)) + return ProfileDetailsDto.of(user, true, followNum.getFollowerNum(), followNum.getFollowingNum()); + else return ProfileDetailsDto.of(user, false, followNum.getFollowerNum(), followNum.getFollowingNum()); + } + + private FollowNum getUserFollowNum(Long userId){ + Optional userFollowNum = followNumRedisDao.findById(userId); + if(userFollowNum.isEmpty()){ + Long followerNum = followAdaptor.countByFollowingId(userId); + Long followingNum = followAdaptor.countByFollowerId(userId); + return followNumRedisService.save(userId, followerNum, followingNum); + }else return userFollowNum.get(); + } +} diff --git a/likelion-client/src/main/java/likelion/univ/user/usecase/GetUserLikedPostsUseCase.java b/likelion-client/src/main/java/likelion/univ/user/usecase/GetUserLikedPostsUseCase.java new file mode 100644 index 00000000..da6649bf --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/user/usecase/GetUserLikedPostsUseCase.java @@ -0,0 +1,28 @@ +package likelion.univ.user.usecase; + +import likelion.univ.annotation.UseCase; +import likelion.univ.common.response.PageResponse; +import likelion.univ.domain.post.adaptor.PostAdaptor; +import likelion.univ.domain.post.entity.Post; +import likelion.univ.post.processor.GetOrCreatePostCountInfoProcessor; +import likelion.univ.user.dto.response.UserPagePostsDto; +import likelion.univ.utils.AuthentiatedUserUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +@UseCase +@RequiredArgsConstructor +public class GetUserLikedPostsUseCase { + private final AuthentiatedUserUtils authentiatedUserUtils; + private final PostAdaptor postAdaptor; + private final GetOrCreatePostCountInfoProcessor getOrCreatePostCountInfoProcessor; + + public PageResponse execute(Long userId, Pageable pageable){ + Long currentUserId = authentiatedUserUtils.getCurrentUserId(); + Page posts = postAdaptor.findByPostLikeAuthorId(userId, pageable); + + return PageResponse.of(posts.map(p-> UserPagePostsDto.of(p, currentUserId, getOrCreatePostCountInfoProcessor.execute(p.getId())))); + } + +} \ No newline at end of file diff --git a/likelion-client/src/main/java/likelion/univ/user/usecase/GetUserPostsUseCase.java b/likelion-client/src/main/java/likelion/univ/user/usecase/GetUserPostsUseCase.java new file mode 100644 index 00000000..a8009063 --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/user/usecase/GetUserPostsUseCase.java @@ -0,0 +1,29 @@ +package likelion.univ.user.usecase; + +import likelion.univ.annotation.UseCase; +import likelion.univ.common.response.PageResponse; +import likelion.univ.domain.post.adaptor.PostAdaptor; +import likelion.univ.domain.post.entity.Post; +import likelion.univ.post.processor.GetOrCreatePostCountInfoProcessor; +import likelion.univ.user.dto.response.UserPagePostsDto; +import likelion.univ.utils.AuthentiatedUserUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + + +@UseCase +@RequiredArgsConstructor +public class GetUserPostsUseCase { + + private final AuthentiatedUserUtils authentiatedUserUtils; + private final PostAdaptor postAdaptor; + private final GetOrCreatePostCountInfoProcessor getOrCreatePostCountInfoProcessor; + + public PageResponse execute(Long userId, Pageable pageable){ + Long currentUserIdId = authentiatedUserUtils.getCurrentUserId(); + Page posts = postAdaptor.findAllByAuthor_Id(userId, pageable); + return PageResponse.of(posts.map(p-> UserPagePostsDto.of(p, currentUserIdId, + getOrCreatePostCountInfoProcessor.execute(p.getId())))); + } +} diff --git a/likelion-client/src/main/java/likelion/univ/user/usecase/SearchUserByNameUseCase.java b/likelion-client/src/main/java/likelion/univ/user/usecase/SearchUserByNameUseCase.java new file mode 100644 index 00000000..9a803181 --- /dev/null +++ b/likelion-client/src/main/java/likelion/univ/user/usecase/SearchUserByNameUseCase.java @@ -0,0 +1,22 @@ +package likelion.univ.user.usecase; + +import likelion.univ.annotation.UseCase; +import likelion.univ.common.response.SliceResponse; +import likelion.univ.domain.user.adaptor.UserAdaptor; +import likelion.univ.domain.user.entity.User; +import likelion.univ.user.dto.response.UserSearchResultDto; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; + +@UseCase +@RequiredArgsConstructor +public class SearchUserByNameUseCase { + private final UserAdaptor userAdaptor; + + public SliceResponse execute(String name, Pageable pageable){ + System.out.println(name); + Slice userSlice = userAdaptor.searchByName(name, pageable); + return SliceResponse.of(userSlice.map(u -> UserSearchResultDto.of(u))); + } +} diff --git a/likelion-client/src/main/java/likelion/univ/utils/AuthentiatedUserUtils.java b/likelion-client/src/main/java/likelion/univ/utils/AuthentiatedUserUtils.java index 489dc643..0bfc856f 100644 --- a/likelion-client/src/main/java/likelion/univ/utils/AuthentiatedUserUtils.java +++ b/likelion-client/src/main/java/likelion/univ/utils/AuthentiatedUserUtils.java @@ -2,6 +2,7 @@ import likelion.univ.domain.user.adaptor.UserAdaptor; import likelion.univ.domain.user.entity.User; +import likelion.univ.domain.user.exception.UserNotMatchException; import likelion.univ.security.SecurityUtils; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; @@ -18,4 +19,9 @@ public Long getCurrentUserId() { public User getCurrentUser() { return userAdaptor.findById(getCurrentUserId()); } + + public void checkidentification(Long userId){ + if(!SecurityUtils.getCurrentUserId().equals(userId)) + throw new UserNotMatchException(); + } } diff --git a/likelion-client/src/main/resources/application.yml b/likelion-client/src/main/resources/application.yml index 5fb5850e..066b827b 100644 --- a/likelion-client/src/main/resources/application.yml +++ b/likelion-client/src/main/resources/application.yml @@ -7,11 +7,6 @@ spring: - infrastructure - security - redis -# data: -# web: -# pageable: ##페이징 -# default-page-size: 5 #기획에 따라 5페이지가 기본 -# one-indexed-parameters: true #1페이지부터 시작, default:0페이지 # 황제철의견 : 동작원리가 안보이는데 이게 원하는대로 동작하고 있지 않는 것 같아요. 원하는 효과가 간단해서 일단 그냥 로직에 포함하겠습니다. server: servlet: @@ -19,7 +14,6 @@ server: springdoc: default-consumes-media-type: application/json;charset=UTF-8 - default-produces-media-type: application/json;charset=UTF-8 api-docs: enabled: ${SWAGGER_ENABLED} path: '/swagger' diff --git a/likelion-core/build.gradle b/likelion-core/build.gradle index ad09a576..47634f29 100644 --- a/likelion-core/build.gradle +++ b/likelion-core/build.gradle @@ -12,11 +12,11 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1' runtimeOnly 'com.h2database:h2' implementation group: 'com.mysql', name: 'mysql-connector-j' - - // Querydsl + // Querydsl api 'com.querydsl:querydsl-jpa' api 'com.querydsl:querydsl-core' - // Querydsl JPAAnnotationProcessor 사용 지정 + implementation project(path: ':likelion-common') + // Querydsl JPAAnnotationProcessor 사용 지정 annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa" annotationProcessor("jakarta.persistence:jakarta.persistence-api") // java.lang.NoClassDefFoundError(javax.annotation.Entity) 발생 대응 annotationProcessor("jakarta.annotation:jakarta.annotation-api") // java.lang.NoClassDefFoundError (javax.annotation.Generated) 발생 대응 diff --git a/likelion-core/src/main/java/likelion/univ/common/processor/ConvertSliceProcessor.java b/likelion-core/src/main/java/likelion/univ/common/processor/ConvertSliceProcessor.java new file mode 100644 index 00000000..8e273610 --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/common/processor/ConvertSliceProcessor.java @@ -0,0 +1,25 @@ +package likelion.univ.common.processor; + +import likelion.univ.annotation.Processor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.domain.SliceImpl; + +import java.util.List; + +@Processor +public class ConvertSliceProcessor { + + public Slice execute(List contents, Pageable pageable) { + if (hasNext(contents, pageable)) + return new SliceImpl<>(subContentOne(contents, pageable), pageable, true); + else return new SliceImpl<>(contents, pageable, false); + } + + private Boolean hasNext(List content, Pageable pageable) { + return pageable.isPaged() && content.size() > pageable.getPageSize(); + } + private List subContentOne(List content, Pageable pageable) { + return content.subList(0, pageable.getPageSize()); + } +} diff --git a/likelion-core/src/main/java/likelion/univ/common/response/PageResponse.java b/likelion-core/src/main/java/likelion/univ/common/response/PageResponse.java new file mode 100644 index 00000000..07e35a10 --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/common/response/PageResponse.java @@ -0,0 +1,34 @@ +package likelion.univ.common.response; + +import lombok.Builder; +import lombok.Getter; +import org.springframework.data.domain.Page; + +import java.util.List; + +@Getter +@Builder +public class PageResponse { + private int totalPage; + private Long totalElements; + private int pagingSize; + private int currentPage; + private Boolean isFirst; + private Boolean isLast; + private Boolean isEmpty; + private List data; + + + public static PageResponse of(Page page) { + return PageResponse.builder() + .totalPage(page.getTotalPages()) + .totalElements(page.getTotalElements()) + .pagingSize(page.getSize()) + .currentPage(page.getNumber()+1) + .isFirst(page.isFirst()) + .isLast(page.isLast()) + .isEmpty(page.isEmpty()) + .data(page.getContent()) + .build(); + } +} \ No newline at end of file diff --git a/likelion-core/src/main/java/likelion/univ/common/response/SliceResponse.java b/likelion-core/src/main/java/likelion/univ/common/response/SliceResponse.java new file mode 100644 index 00000000..3869e0b3 --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/common/response/SliceResponse.java @@ -0,0 +1,26 @@ +package likelion.univ.common.response; + +import lombok.Builder; +import lombok.Getter; +import org.springframework.data.domain.Slice; + +import java.util.List; + +@Getter +@Builder +public class SliceResponse { + + private int currentPage; + private int size; + private Boolean hasNext; + private List data; + + public static SliceResponse of(Slice slice) { + return SliceResponse.builder() + .currentPage(slice.getNumber()+1) + .size(slice.getNumberOfElements()) + .hasNext(slice.hasNext()) + .data(slice.getContent()) + .build(); + } +} diff --git a/likelion-core/src/main/java/likelion/univ/config/QueryDslConfig.java b/likelion-core/src/main/java/likelion/univ/config/QueryDslConfig.java index ab3b334d..3f7d8d3e 100644 --- a/likelion-core/src/main/java/likelion/univ/config/QueryDslConfig.java +++ b/likelion-core/src/main/java/likelion/univ/config/QueryDslConfig.java @@ -5,16 +5,12 @@ import org.springframework.context.annotation.Configuration; import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; @Configuration public class QueryDslConfig { - - @PersistenceContext - private EntityManager entityManager; - @Bean - public JPAQueryFactory jpaQueryFactory () { + public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) { return new JPAQueryFactory(entityManager); } } + diff --git a/likelion-core/src/main/java/likelion/univ/config/QuerydslConfig.java b/likelion-core/src/main/java/likelion/univ/config/QuerydslConfig.java deleted file mode 100644 index 56502ebd..00000000 --- a/likelion-core/src/main/java/likelion/univ/config/QuerydslConfig.java +++ /dev/null @@ -1,15 +0,0 @@ -package likelion.univ.config; - -import com.querydsl.jpa.impl.JPAQueryFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import javax.persistence.EntityManager; - -@Configuration -public class QuerydslConfig { - @Bean - public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) { - return new JPAQueryFactory(entityManager); - } -} diff --git a/likelion-core/src/main/java/likelion/univ/domain/alarm/adaptor/AlarmAdaptor.java b/likelion-core/src/main/java/likelion/univ/domain/alarm/adaptor/AlarmAdaptor.java new file mode 100644 index 00000000..8e76a1a1 --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/domain/alarm/adaptor/AlarmAdaptor.java @@ -0,0 +1,21 @@ +package likelion.univ.domain.alarm.adaptor; + +import likelion.univ.annotation.Adaptor; +import likelion.univ.domain.alarm.entity.Alarm; +import likelion.univ.domain.alarm.entity.AlarmType; +import likelion.univ.domain.alarm.exception.EmailAlreadyRegisteredAsAlarmException; +import likelion.univ.domain.alarm.repository.AlarmRepository; +import lombok.RequiredArgsConstructor; + +@Adaptor +@RequiredArgsConstructor +public class AlarmAdaptor { + private final AlarmRepository alarmRepository; + + public Alarm save(Alarm alarm){ return alarmRepository.save(alarm);} + + public void existsByOrdinalAndEmailAndAlarmType(Long ordinal, String email, AlarmType alarmType) { + if (alarmRepository.existsByOrdinalAndEmailAndAlarmType(ordinal, email, alarmType)) + throw new EmailAlreadyRegisteredAsAlarmException(); + } +} diff --git a/likelion-core/src/main/java/likelion/univ/domain/alarm/entity/Alarm.java b/likelion-core/src/main/java/likelion/univ/domain/alarm/entity/Alarm.java new file mode 100644 index 00000000..4ba12003 --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/domain/alarm/entity/Alarm.java @@ -0,0 +1,28 @@ +package likelion.univ.domain.alarm.entity; +import likelion.univ.common.entity.BaseTimeEntity; +import lombok.*; + +import javax.persistence.*; + +import static likelion.univ.domain.alarm.entity.SendStatus.NOT_SENT; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Builder +@AllArgsConstructor +@Entity +public class Alarm extends BaseTimeEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private Long ordinal; + + private String email; + + @Enumerated(EnumType.STRING) + private AlarmType alarmType; + + @Enumerated(EnumType.STRING) + private SendStatus sendStatus; +} diff --git a/likelion-core/src/main/java/likelion/univ/domain/alarm/entity/AlarmType.java b/likelion-core/src/main/java/likelion/univ/domain/alarm/entity/AlarmType.java new file mode 100644 index 00000000..4602f7f4 --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/domain/alarm/entity/AlarmType.java @@ -0,0 +1,13 @@ +package likelion.univ.domain.alarm.entity; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum AlarmType { + NEW_UNIVERSITY_RECRUITING("신규 대학 모집 알람"), + EXISTING_UNIVERSITY_RECRUITING("기존 대학 재신청 알람"); + + private String value; +} diff --git a/likelion-core/src/main/java/likelion/univ/domain/alarm/entity/SendStatus.java b/likelion-core/src/main/java/likelion/univ/domain/alarm/entity/SendStatus.java new file mode 100644 index 00000000..889b5e8c --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/domain/alarm/entity/SendStatus.java @@ -0,0 +1,14 @@ +package likelion.univ.domain.alarm.entity; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum SendStatus { + NOT_SENT("NOT_SENT"), + RESERVED("RESERVED"), + SENT("SENT"); + + private String value; +} diff --git a/likelion-core/src/main/java/likelion/univ/domain/alarm/exception/AlarmErrorCode.java b/likelion-core/src/main/java/likelion/univ/domain/alarm/exception/AlarmErrorCode.java new file mode 100644 index 00000000..beaabada --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/domain/alarm/exception/AlarmErrorCode.java @@ -0,0 +1,18 @@ +package likelion.univ.domain.alarm.exception; + +import likelion.univ.exception.base.BaseErrorCode; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import static likelion.univ.constant.StaticValue.*; + +@Getter +@AllArgsConstructor +public enum AlarmErrorCode implements BaseErrorCode { + EMAIL_ALREADY_REGISTERED_AS_ALARM(BAD_REQUEST, "ALARM_409", "해당 이메일은 이미 신청되어 있습니다."); + + + private final int httpStatus; + private final String code; + private final String message; +} diff --git a/likelion-core/src/main/java/likelion/univ/domain/alarm/exception/EmailAlreadyRegisteredAsAlarmException.java b/likelion-core/src/main/java/likelion/univ/domain/alarm/exception/EmailAlreadyRegisteredAsAlarmException.java new file mode 100644 index 00000000..5478c7a1 --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/domain/alarm/exception/EmailAlreadyRegisteredAsAlarmException.java @@ -0,0 +1,9 @@ +package likelion.univ.domain.alarm.exception; + +import likelion.univ.exception.base.BaseException; + +public class EmailAlreadyRegisteredAsAlarmException extends BaseException { + public EmailAlreadyRegisteredAsAlarmException() { + super(AlarmErrorCode.EMAIL_ALREADY_REGISTERED_AS_ALARM); + } +} diff --git a/likelion-core/src/main/java/likelion/univ/domain/alarm/repository/AlarmRepository.java b/likelion-core/src/main/java/likelion/univ/domain/alarm/repository/AlarmRepository.java new file mode 100644 index 00000000..12ae20bf --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/domain/alarm/repository/AlarmRepository.java @@ -0,0 +1,9 @@ +package likelion.univ.domain.alarm.repository; + +import likelion.univ.domain.alarm.entity.Alarm; +import likelion.univ.domain.alarm.entity.AlarmType; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface AlarmRepository extends JpaRepository { + boolean existsByOrdinalAndEmailAndAlarmType(Long ordinal, String email, AlarmType alarmType); +} diff --git a/likelion-core/src/main/java/likelion/univ/domain/alarm/service/AlarmDomainService.java b/likelion-core/src/main/java/likelion/univ/domain/alarm/service/AlarmDomainService.java new file mode 100644 index 00000000..63b4a5a5 --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/domain/alarm/service/AlarmDomainService.java @@ -0,0 +1,23 @@ +package likelion.univ.domain.alarm.service; + +import likelion.univ.domain.alarm.adaptor.AlarmAdaptor; +import likelion.univ.domain.alarm.entity.Alarm; +import likelion.univ.domain.alarm.entity.AlarmType; +import likelion.univ.domain.alarm.entity.SendStatus; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import static likelion.univ.domain.alarm.entity.SendStatus.NOT_SENT; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class AlarmDomainService { + private final AlarmAdaptor alarmAdaptor; + + @Transactional + public Alarm createAlarm(Alarm alarm){ + return alarmAdaptor.save(alarm); + } +} diff --git a/likelion-core/src/main/java/likelion/univ/domain/comment/adaptor/CommentAdaptor.java b/likelion-core/src/main/java/likelion/univ/domain/comment/adaptor/CommentAdaptor.java index 9ba6cdb9..89fa64a8 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/comment/adaptor/CommentAdaptor.java +++ b/likelion-core/src/main/java/likelion/univ/domain/comment/adaptor/CommentAdaptor.java @@ -31,4 +31,7 @@ public List findAllByPost(Post post) { return commentRepository.findByPost(post); } + public Long countByPostId(Long postId){ + return commentRepository.countByPostId(postId); + } } diff --git a/likelion-core/src/main/java/likelion/univ/domain/comment/entity/Comment.java b/likelion-core/src/main/java/likelion/univ/domain/comment/entity/Comment.java index 018bc699..a1d39e2b 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/comment/entity/Comment.java +++ b/likelion-core/src/main/java/likelion/univ/domain/comment/entity/Comment.java @@ -16,11 +16,10 @@ @Getter @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) -@Table(name = "comments") +@Table(name = "comment") public class Comment extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "comment_id") private Long id; @ManyToOne(fetch = FetchType.LAZY) @@ -36,12 +35,12 @@ public class Comment extends BaseTimeEntity { private Comment parentComment; @OneToMany(mappedBy = "comment", - cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, orphanRemoval = true) // 안정성 체크해봐야됨 + cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, orphanRemoval = true) private List commentLikes = new ArrayList<>(); @OneToMany(mappedBy = "parentComment", - cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, orphanRemoval = true) // 안정성 체크해봐야됨 + cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, orphanRemoval = true) private List childComments = new ArrayList<>(); @Column(nullable = false, columnDefinition = "TEXT") diff --git a/likelion-core/src/main/java/likelion/univ/domain/comment/repository/CommentRepository.java b/likelion-core/src/main/java/likelion/univ/domain/comment/repository/CommentRepository.java index 4b522ddf..69d71652 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/comment/repository/CommentRepository.java +++ b/likelion-core/src/main/java/likelion/univ/domain/comment/repository/CommentRepository.java @@ -10,4 +10,6 @@ public interface CommentRepository extends JpaRepository { @Query("SELECT c from Comment c JOIN FETCH c.author u JOIN FETCH c.post p JOIN FETCH c.parentComment pc") List findByPost(Post post); + + Long countByPostId(Long postId); } diff --git a/likelion-core/src/main/java/likelion/univ/domain/example/entity/Example.java b/likelion-core/src/main/java/likelion/univ/domain/example/entity/Example.java index 3368c700..6f671abe 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/example/entity/Example.java +++ b/likelion-core/src/main/java/likelion/univ/domain/example/entity/Example.java @@ -15,7 +15,6 @@ public class Example extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "example_id") private Long id; @Column(nullable = false) diff --git a/likelion-core/src/main/java/likelion/univ/domain/follow/adaptor/FollowAdaptor.java b/likelion-core/src/main/java/likelion/univ/domain/follow/adaptor/FollowAdaptor.java new file mode 100644 index 00000000..416feedb --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/domain/follow/adaptor/FollowAdaptor.java @@ -0,0 +1,24 @@ +package likelion.univ.domain.follow.adaptor; + +import likelion.univ.annotation.Adaptor; +import likelion.univ.domain.follow.exception.AlreadyFollowingUserException; +import likelion.univ.domain.follow.repository.FollowRepository; +import lombok.RequiredArgsConstructor; + +@Adaptor +@RequiredArgsConstructor +public class FollowAdaptor { + private final FollowRepository followRepository; + + public Long countByFollowerId(Long followerId){ + return followRepository.countByFollowerId(followerId); + } + public Long countByFollowingId(Long followingId){ + return followRepository.countByFollowingId(followingId); + } + public void save(Long currentUserId, Long userId) { + try { followRepository.save(currentUserId,userId);} + catch(Exception e) { throw new AlreadyFollowingUserException(); } + } + public void delete(Long currentUserId, Long userId) { followRepository.delete(currentUserId,userId);} +} diff --git a/likelion-core/src/main/java/likelion/univ/domain/follow/entity/Follow.java b/likelion-core/src/main/java/likelion/univ/domain/follow/entity/Follow.java index 38b98a5a..f1b6f5b4 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/follow/entity/Follow.java +++ b/likelion-core/src/main/java/likelion/univ/domain/follow/entity/Follow.java @@ -11,11 +11,11 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity +@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"follower_id", "following_id"})}) public class Follow extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "follow_id") private Long id; @ManyToOne(fetch = FetchType.LAZY) @@ -23,8 +23,8 @@ public class Follow extends BaseTimeEntity { private User follower; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "followee_id") - private User followee; + @JoinColumn(name = "following_id") + private User following; } diff --git a/likelion-core/src/main/java/likelion/univ/domain/follow/exception/AlreadyFollowingUserException.java b/likelion-core/src/main/java/likelion/univ/domain/follow/exception/AlreadyFollowingUserException.java new file mode 100644 index 00000000..aa42d0c0 --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/domain/follow/exception/AlreadyFollowingUserException.java @@ -0,0 +1,9 @@ +package likelion.univ.domain.follow.exception; + +import likelion.univ.exception.base.BaseException; + +public class AlreadyFollowingUserException extends BaseException { + public AlreadyFollowingUserException() { + super(FollowErrorCode.ALREADY_FOLLOWING_USER); + } +} diff --git a/likelion-core/src/main/java/likelion/univ/domain/follow/exception/FollowErrorCode.java b/likelion-core/src/main/java/likelion/univ/domain/follow/exception/FollowErrorCode.java new file mode 100644 index 00000000..5cbfce87 --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/domain/follow/exception/FollowErrorCode.java @@ -0,0 +1,18 @@ +package likelion.univ.domain.follow.exception; + +import likelion.univ.exception.base.BaseErrorCode; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import static likelion.univ.constant.StaticValue.*; + +@Getter +@AllArgsConstructor +public enum FollowErrorCode implements BaseErrorCode { + ALREADY_FOLLOWING_USER(BAD_REQUEST, "FOLLOW_400_1", "이미 팔로우하고 있습니다."); + + + private final int httpStatus; + private final String code; + private final String message; +} diff --git a/likelion-core/src/main/java/likelion/univ/domain/follow/repository/FollowRepository.java b/likelion-core/src/main/java/likelion/univ/domain/follow/repository/FollowRepository.java new file mode 100644 index 00000000..93f864e2 --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/domain/follow/repository/FollowRepository.java @@ -0,0 +1,23 @@ +package likelion.univ.domain.follow.repository; + +import likelion.univ.domain.follow.entity.Follow; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + + +public interface FollowRepository extends JpaRepository { + Long countByFollowerId(Long followerId); + Long countByFollowingId(Long followingId); + @Modifying + @Transactional + @Query(value = "insert into follow(created_date, modified_date, follower_id, following_id)" + + "values (now(), now(), :currentId , :userId)", nativeQuery = true) + void save(Long currentId, Long userId); + + @Modifying + @Transactional + @Query("delete from Follow f where f.follower.id = :currentId and f.following.id = :userId") + void delete(Long currentId, Long userId); +} diff --git a/likelion-core/src/main/java/likelion/univ/domain/like/commentlike/entity/CommentLike.java b/likelion-core/src/main/java/likelion/univ/domain/like/commentlike/entity/CommentLike.java index 63404d9a..5b59995d 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/like/commentlike/entity/CommentLike.java +++ b/likelion-core/src/main/java/likelion/univ/domain/like/commentlike/entity/CommentLike.java @@ -15,7 +15,6 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class CommentLike extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "like_comment_id") private Long id; @ManyToOne(fetch = FetchType.LAZY) diff --git a/likelion-core/src/main/java/likelion/univ/domain/like/postlike/adaptor/PostLikeAdaptor.java b/likelion-core/src/main/java/likelion/univ/domain/like/postlike/adaptor/PostLikeAdaptor.java index 07ceeefe..ecc8c911 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/like/postlike/adaptor/PostLikeAdaptor.java +++ b/likelion-core/src/main/java/likelion/univ/domain/like/postlike/adaptor/PostLikeAdaptor.java @@ -28,4 +28,7 @@ public PostLike find(Post post, User author) { public PostLike findById(Long postLikeId) { return postLikeRepository.findById(postLikeId).orElseThrow(() -> new PostLikeNotFoundException()); } + public Long countByPostId(Long postId){ + return postLikeRepository.countByPostId(postId); + } } diff --git a/likelion-core/src/main/java/likelion/univ/domain/like/postlike/entity/PostLike.java b/likelion-core/src/main/java/likelion/univ/domain/like/postlike/entity/PostLike.java index 31787729..f9ef7c8c 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/like/postlike/entity/PostLike.java +++ b/likelion-core/src/main/java/likelion/univ/domain/like/postlike/entity/PostLike.java @@ -16,7 +16,6 @@ @Builder public class PostLike { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "like_post_id") private Long id; @ManyToOne(fetch = FetchType.LAZY) diff --git a/likelion-core/src/main/java/likelion/univ/domain/like/postlike/repository/PostLikeRepository.java b/likelion-core/src/main/java/likelion/univ/domain/like/postlike/repository/PostLikeRepository.java index e1fac128..e5f17658 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/like/postlike/repository/PostLikeRepository.java +++ b/likelion-core/src/main/java/likelion/univ/domain/like/postlike/repository/PostLikeRepository.java @@ -9,4 +9,5 @@ public interface PostLikeRepository extends JpaRepository { Optional findByPostAndAuthor(Post post, User author); + Long countByPostId(Long postId); } diff --git a/likelion-core/src/main/java/likelion/univ/domain/post/adaptor/PostAdaptor.java b/likelion-core/src/main/java/likelion/univ/domain/post/adaptor/PostAdaptor.java index ff7137c8..24e2132c 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/post/adaptor/PostAdaptor.java +++ b/likelion-core/src/main/java/likelion/univ/domain/post/adaptor/PostAdaptor.java @@ -2,21 +2,16 @@ import likelion.univ.annotation.Adaptor; import likelion.univ.domain.post.entity.Post; -import likelion.univ.domain.post.exception.PostNotFoudException; -import likelion.univ.domain.post.repository.PostCommandRepository; -import likelion.univ.domain.user.entity.User; +import likelion.univ.domain.post.repository.PostRepository; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; - -import java.util.List; +import likelion.univ.domain.post.exception.PostNotFoudException; @Adaptor @RequiredArgsConstructor public class PostAdaptor { - - private final PostCommandRepository postRepository; - + private final PostRepository postRepository; public Long save(Post post) { Post savedPost = postRepository.save(post); @@ -31,4 +26,15 @@ public void delete(Post post) { postRepository.delete(post); //예외처리 } + public Page findAllByAuthor_Id(Long userId, Pageable pageable){ + return postRepository.findAllByAuthor_Id(userId,pageable); + } + + public Page findByCommentAuthorId(Long userId, Pageable pageable){ + return postRepository.findByCommentAuthorId(userId,pageable); + } + + public Page findByPostLikeAuthorId(Long userId, Pageable pageable){ + return postRepository.findByPostLikeAuthorId(userId,pageable); + } } diff --git a/likelion-core/src/main/java/likelion/univ/domain/post/dto/response/PostDetailResponseDto.java b/likelion-core/src/main/java/likelion/univ/domain/post/dto/response/PostDetailResponseDto.java index 6e1c3e0d..db1781c4 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/post/dto/response/PostDetailResponseDto.java +++ b/likelion-core/src/main/java/likelion/univ/domain/post/dto/response/PostDetailResponseDto.java @@ -23,6 +23,8 @@ public class PostDetailResponseDto { private String thumbnail; + private Integer likeCount; + private MainCategory mainCategory; private SubCategory subCategory; @@ -32,13 +34,14 @@ public class PostDetailResponseDto { private LocalDateTime modifiedDate; @QueryProjection - public PostDetailResponseDto(Long postId, Long authorId, String authorName, String title, String body, String thumbnail, MainCategory mainCategory, SubCategory subCategory, LocalDateTime createdDate, LocalDateTime modifiedDate) { + public PostDetailResponseDto(Long postId, Long authorId, String authorName, String title, String body, String thumbnail, Integer likeCount, MainCategory mainCategory, SubCategory subCategory, LocalDateTime createdDate, LocalDateTime modifiedDate) { this.postId = postId; this.authorId = authorId; this.authorName = authorName; this.title = title; this.body = body; this.thumbnail = thumbnail; + this.likeCount = likeCount; this.mainCategory = mainCategory; this.subCategory = subCategory; this.createdDate = createdDate; diff --git a/likelion-core/src/main/java/likelion/univ/domain/post/entity/Post.java b/likelion-core/src/main/java/likelion/univ/domain/post/entity/Post.java index 480f6bad..f3a3f234 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/post/entity/Post.java +++ b/likelion-core/src/main/java/likelion/univ/domain/post/entity/Post.java @@ -1,6 +1,7 @@ package likelion.univ.domain.post.entity; import likelion.univ.common.entity.BaseTimeEntity; +import likelion.univ.domain.like.postlike.entity.PostLike; import likelion.univ.domain.post.dto.request.PostUpdateServiceDto; import likelion.univ.domain.post.entity.enums.MainCategory; import likelion.univ.domain.post.entity.enums.SubCategory; @@ -8,6 +9,8 @@ import lombok.*; import javax.persistence.*; +import java.util.ArrayList; +import java.util.List; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @@ -17,7 +20,6 @@ public class Post extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "post_id") private Long id; @ManyToOne(fetch = FetchType.LAZY) @@ -32,6 +34,10 @@ public class Post extends BaseTimeEntity { private String thumbnail; + @OneToMany(mappedBy = "post", + cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, orphanRemoval = true) + private List postLikes = new ArrayList(); + @Enumerated(EnumType.STRING) private MainCategory mainCategory; diff --git a/likelion-core/src/main/java/likelion/univ/domain/post/entity/enums/MainCategory.java b/likelion-core/src/main/java/likelion/univ/domain/post/entity/enums/MainCategory.java index b12d8dc7..bdad3f81 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/post/entity/enums/MainCategory.java +++ b/likelion-core/src/main/java/likelion/univ/domain/post/entity/enums/MainCategory.java @@ -6,10 +6,9 @@ @Getter @RequiredArgsConstructor public enum MainCategory { - HQ("HQ"), - BOARD("BOARD"), - OVERFLOW("OVERFLOW"); - + HQ_BOARD("멋대 중앙"), + FREE_BOARD("자유게시판"), + OVERFLOW("멋사 오버플로우"); private final String value; } diff --git a/likelion-core/src/main/java/likelion/univ/domain/post/entity/enums/SubCategory.java b/likelion-core/src/main/java/likelion/univ/domain/post/entity/enums/SubCategory.java index 4b70fc51..c70c2faa 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/post/entity/enums/SubCategory.java +++ b/likelion-core/src/main/java/likelion/univ/domain/post/entity/enums/SubCategory.java @@ -8,17 +8,25 @@ @Getter @RequiredArgsConstructor public enum SubCategory { - NOTICE("SUBCATEGORY_NOTICE", "공지"), - QNA("SUBCATEGORY_QNA", "질의응답"), - FREEBOARD("SUBCATEGORY_INFO", "정보공유"), - FRONTEND("SUBCATEGORY_FRONTEND", "프론트"), - BACKEND("SUBCATEGORY_BACKEND", "백엔드"), - DESIGN("SUBCATEGORY_DESIGN", "디자인"), - PROJECT("SUBCATEGORY_PROJECT", "프로젝트"); - - - private final String key; - private final String title; + // HQ + NOTICE("공지사항"), + QNA("질문건의"), + HQ_INFO("중앙정보공유"), + + // board + FREE_INFO("멋대정보공유"), + GET_MEMBER("팀원 모집"), + GET_PROJECT("프로젝트 모집"), + SHOWOFF("프로젝트 자랑"), + + // overflow + FRONTEND("프론트"), + BACKEND("백엔드"), + PM("기획"), + UXUI("디자인"), + ETC("기타"); + + private final String value; } diff --git a/likelion-core/src/main/java/likelion/univ/domain/post/repository/PostCommandCustomRepositoryImpl.java b/likelion-core/src/main/java/likelion/univ/domain/post/repository/PostCommandCustomRepositoryImpl.java deleted file mode 100644 index e6a32b85..00000000 --- a/likelion-core/src/main/java/likelion/univ/domain/post/repository/PostCommandCustomRepositoryImpl.java +++ /dev/null @@ -1,18 +0,0 @@ -package likelion.univ.domain.post.repository; - -import likelion.univ.domain.post.entity.Post; -import likelion.univ.domain.user.entity.User; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Repository; - -import java.util.List; - -import static likelion.univ.domain.post.entity.QPost.post; -import static likelion.univ.domain.user.entity.QUser.user; - -@Repository -public class PostCommandCustomRepositoryImpl implements PostCommandCustomRepository { - -} diff --git a/likelion-core/src/main/java/likelion/univ/domain/post/repository/PostCommandRepository.java b/likelion-core/src/main/java/likelion/univ/domain/post/repository/PostCommandRepository.java deleted file mode 100644 index 8e1f2eb7..00000000 --- a/likelion-core/src/main/java/likelion/univ/domain/post/repository/PostCommandRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package likelion.univ.domain.post.repository; - -import likelion.univ.domain.post.entity.Post; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface PostCommandRepository extends JpaRepository, PostCommandCustomRepository { - - -} diff --git a/likelion-core/src/main/java/likelion/univ/domain/post/repository/PostCommandCustomRepository.java b/likelion-core/src/main/java/likelion/univ/domain/post/repository/PostCustomRepository.java similarity index 50% rename from likelion-core/src/main/java/likelion/univ/domain/post/repository/PostCommandCustomRepository.java rename to likelion-core/src/main/java/likelion/univ/domain/post/repository/PostCustomRepository.java index c370bccf..7cb681ba 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/post/repository/PostCommandCustomRepository.java +++ b/likelion-core/src/main/java/likelion/univ/domain/post/repository/PostCustomRepository.java @@ -1,14 +1,10 @@ package likelion.univ.domain.post.repository; import likelion.univ.domain.post.entity.Post; -import likelion.univ.domain.user.entity.User; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; -import java.util.List; - -public interface PostCommandCustomRepository { - - - +public interface PostCustomRepository { + public Page findByCommentAuthorId(Long userId, Pageable pageable); + Page findByPostLikeAuthorId(Long userId, Pageable pageable); } diff --git a/likelion-core/src/main/java/likelion/univ/domain/post/repository/PostRepository.java b/likelion-core/src/main/java/likelion/univ/domain/post/repository/PostRepository.java new file mode 100644 index 00000000..68a16ae6 --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/domain/post/repository/PostRepository.java @@ -0,0 +1,9 @@ +package likelion.univ.domain.post.repository; + +import likelion.univ.domain.post.entity.Post; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +public interface PostRepository extends JpaRepository, PostCustomRepository { + Page findAllByAuthor_Id(Long userId, Pageable pageable); +} diff --git a/likelion-core/src/main/java/likelion/univ/domain/post/repository/impl/PostCustomRepositoryImpl.java b/likelion-core/src/main/java/likelion/univ/domain/post/repository/impl/PostCustomRepositoryImpl.java new file mode 100644 index 00000000..2f7428d9 --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/domain/post/repository/impl/PostCustomRepositoryImpl.java @@ -0,0 +1,57 @@ +package likelion.univ.domain.post.repository.impl; + +import com.querydsl.core.types.Predicate; +import com.querydsl.jpa.impl.JPAQueryFactory; +import likelion.univ.domain.post.entity.Post; +import likelion.univ.domain.post.repository.PostCustomRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; + +import java.util.List; + +import static likelion.univ.domain.comment.entity.QComment.comment; +import static likelion.univ.domain.like.postlike.entity.QPostLike.postLike; +import static likelion.univ.domain.post.entity.QPost.post; +import static likelion.univ.domain.user.entity.QUser.user; + +@RequiredArgsConstructor +public class PostCustomRepositoryImpl implements PostCustomRepository { + + private final JPAQueryFactory queryFactory; + + @Override + public Page findByCommentAuthorId(Long userId, Pageable pageable){ + List ids = getCoveringIndexByComment(comment.author.id.eq(userId) + .and(comment.isDeleted.isFalse())); + return findByCoveringIndex(ids, pageable); + } + + @Override + public Page findByPostLikeAuthorId(Long userId, Pageable pageable){ + List ids = getCoveringIndexByPostLike(postLike.author.id.eq(userId)); + return findByCoveringIndex(ids, pageable); + } + + private List getCoveringIndexByComment(Predicate predicate) { + return queryFactory.select(comment.post.id).from(comment).where(predicate).fetch(); + } + private List getCoveringIndexByPostLike(Predicate predicate) { + return queryFactory.select(postLike.post.id).from(postLike).where(predicate).fetch(); + } + private Page findByCoveringIndex(List ids, Pageable pageable){ + List posts = + queryFactory + .select(post) + .from(post) + .innerJoin(post.author, user).fetchJoin() + .where(post.id.in(ids)) + .offset(pageable.getOffset()) + .orderBy(post.createdDate.desc()) + .limit(pageable.getPageSize()) + .fetch(); + + return new PageImpl<>(posts, pageable, ids.size()); + } +} diff --git a/likelion-core/src/main/java/likelion/univ/domain/post/service/PostDomainService.java b/likelion-core/src/main/java/likelion/univ/domain/post/service/PostDomainService.java index 6a587e78..d91a6787 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/post/service/PostDomainService.java +++ b/likelion-core/src/main/java/likelion/univ/domain/post/service/PostDomainService.java @@ -6,6 +6,8 @@ import likelion.univ.domain.post.dto.request.PostUpdateServiceDto; import likelion.univ.domain.post.dto.response.PostCommandResponseDto; import likelion.univ.domain.post.entity.Post; +import likelion.univ.domain.post.entity.enums.MainCategory; +import likelion.univ.domain.post.entity.enums.SubCategory; import likelion.univ.domain.post.exception.PostNoAuthorizationException; import likelion.univ.domain.user.adaptor.UserAdaptor; import lombok.RequiredArgsConstructor; @@ -54,9 +56,8 @@ private Post createEntity(PostCreateServiceDto request) { .title(request.getTitle()) .body(request.getBody()) .thumbnail(request.getThumbnail()) - // TODO : category 입력되도록 수정 -// .mainCategory(MainCategory.valueOf(request.getMainCategory())) -// .subCategory(SubCategory.valueOf(request.getSubCategory())) + .mainCategory(MainCategory.valueOf(request.getMainCategory())) + .subCategory(SubCategory.valueOf(request.getSubCategory())) .build(); } diff --git a/likelion-core/src/main/java/likelion/univ/domain/project/entity/Image.java b/likelion-core/src/main/java/likelion/univ/domain/project/entity/Image.java index fec1b505..1fe8492d 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/project/entity/Image.java +++ b/likelion-core/src/main/java/likelion/univ/domain/project/entity/Image.java @@ -15,7 +15,6 @@ public class Image { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name="image_id") private long id; @ManyToOne(fetch = FetchType.LAZY) diff --git a/likelion-core/src/main/java/likelion/univ/domain/project/entity/Project.java b/likelion-core/src/main/java/likelion/univ/domain/project/entity/Project.java index b9b43b1e..ad3e6388 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/project/entity/Project.java +++ b/likelion-core/src/main/java/likelion/univ/domain/project/entity/Project.java @@ -18,7 +18,6 @@ public class Project extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name="project_id") private long id; private String thon; diff --git a/likelion-core/src/main/java/likelion/univ/domain/project/entity/ProjectMember.java b/likelion-core/src/main/java/likelion/univ/domain/project/entity/ProjectMember.java index 46257aec..ae540c4f 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/project/entity/ProjectMember.java +++ b/likelion-core/src/main/java/likelion/univ/domain/project/entity/ProjectMember.java @@ -15,7 +15,6 @@ public class ProjectMember { @Id @GeneratedValue - @Column(name = "projectMember_id") private Long id; @ManyToOne(fetch = FetchType.LAZY) diff --git a/likelion-core/src/main/java/likelion/univ/domain/recruit/entity/Recruit.java b/likelion-core/src/main/java/likelion/univ/domain/recruit/entity/Recruit.java index 1b90cba0..4b62e561 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/recruit/entity/Recruit.java +++ b/likelion-core/src/main/java/likelion/univ/domain/recruit/entity/Recruit.java @@ -19,7 +19,6 @@ public class Recruit extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "recruit_id") private Long id; private String name; diff --git a/likelion-core/src/main/java/likelion/univ/domain/university/entity/University.java b/likelion-core/src/main/java/likelion/univ/domain/university/entity/University.java index 23fe663b..f693d51c 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/university/entity/University.java +++ b/likelion-core/src/main/java/likelion/univ/domain/university/entity/University.java @@ -14,7 +14,6 @@ public class University extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "university_id") private Long id; @Column(unique = true) private String name; diff --git a/likelion-core/src/main/java/likelion/univ/domain/user/adaptor/UserAdaptor.java b/likelion-core/src/main/java/likelion/univ/domain/user/adaptor/UserAdaptor.java index 69896568..41e4858c 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/user/adaptor/UserAdaptor.java +++ b/likelion-core/src/main/java/likelion/univ/domain/user/adaptor/UserAdaptor.java @@ -3,10 +3,11 @@ import likelion.univ.annotation.Adaptor; import likelion.univ.domain.user.entity.User; import likelion.univ.domain.user.exception.UserNotFoundException; -import likelion.univ.domain.user.repository.UserQueryRepository; import likelion.univ.domain.user.repository.UserRepository; import likelion.univ.domain.user.repository.searchcondition.UserSearchCondition; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import java.util.List; @@ -14,14 +15,17 @@ @RequiredArgsConstructor public class UserAdaptor { private final UserRepository userRepository; - private final UserQueryRepository userQueryRepository; public User findById(Long id){ return userRepository.findById(id) .orElseThrow(()-> new UserNotFoundException()); } + public User findByIdWithUniversity(Long id){ + return userRepository.findByIdWithUniversity(id) + .orElseThrow(() -> new UserNotFoundException()); + } public User findByEmail(String email){ return userRepository.findByAuthInfoEmail(email) - .orElseThrow(()-> new UserNotFoundException()); + .orElseThrow(() -> new UserNotFoundException()); } public Boolean checkEmail(String email){ return userRepository.existsByAuthInfoEmail(email); @@ -33,6 +37,18 @@ public List findAll() { return userRepository.findAll(); } public List findDynamicUsers(UserSearchCondition condition) { - return userQueryRepository.findDynamicUsers(condition); + return userRepository.findDynamicUsers(condition); + } + public Slice findFollowingUsersByFollowerID(Long userId, Pageable pageable){ + return userRepository.findFollowingUsersByFollowerID(userId, pageable); + } + public Slice findFollowerUsersByFollowingID(Long userId, Pageable pageable){ + return userRepository.findFollowerUsersByFollowingID(userId, pageable); + } + public List findMyFollowingUsersByFollowingIdIn(Long follwerId, List followingIdList){ + return userRepository.findMyFollowingUsersByFollowingIdIn(follwerId, followingIdList); + } + public Slice searchByName(String name, Pageable pageable){ + return userRepository.searchByName(name, pageable); } } diff --git a/likelion-core/src/main/java/likelion/univ/domain/user/entity/AccountStatus.java b/likelion-core/src/main/java/likelion/univ/domain/user/entity/AccountStatus.java index 64062178..6471a4e9 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/user/entity/AccountStatus.java +++ b/likelion-core/src/main/java/likelion/univ/domain/user/entity/AccountStatus.java @@ -6,7 +6,7 @@ @AllArgsConstructor @Getter public enum AccountStatus { - MEMBER("MEMBER"), + ACTIVE("ACTIVE"), Deleted("DELETED"); private String value; diff --git a/likelion-core/src/main/java/likelion/univ/domain/user/entity/AuthInfo.java b/likelion-core/src/main/java/likelion/univ/domain/user/entity/AuthInfo.java index 118f9a20..65ca700e 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/user/entity/AuthInfo.java +++ b/likelion-core/src/main/java/likelion/univ/domain/user/entity/AuthInfo.java @@ -4,7 +4,7 @@ import javax.persistence.*; -import static likelion.univ.domain.user.entity.AccountStatus.MEMBER; +import static likelion.univ.domain.user.entity.AccountStatus.ACTIVE; import static likelion.univ.domain.user.entity.Role.GUEST; @Embeddable @@ -20,6 +20,8 @@ public class AuthInfo { private String email; @Enumerated(EnumType.STRING) private AccountStatus accountStatus; + // 01000000000 형태로 + private String phoneNumber; @Enumerated(EnumType.STRING) private Role role; @@ -28,7 +30,7 @@ public static AuthInfo authInfoForSignUp(LoginType loginType, String email) { return AuthInfo.builder() .loginType(loginType) .email(email) - .accountStatus(MEMBER) + .accountStatus(ACTIVE) .role(GUEST) .build(); } diff --git a/likelion-core/src/main/java/likelion/univ/domain/user/entity/Part.java b/likelion-core/src/main/java/likelion/univ/domain/user/entity/Part.java index fca30d1d..e61323f7 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/user/entity/Part.java +++ b/likelion-core/src/main/java/likelion/univ/domain/user/entity/Part.java @@ -6,12 +6,10 @@ @AllArgsConstructor @Getter public enum Part { - BACKEND("백엔드"), - FRONTEND("프론트엔드"), PM("기획"), DESIGNER("디자인"), - PM_DESIGNER("기획/디자인"); - + PM_DESIGNER("기획/디자인"), + FRONTEND("프론트엔드"), + BACKEND("백엔드"); private String value; - } diff --git a/likelion-core/src/main/java/likelion/univ/domain/user/entity/Profile.java b/likelion-core/src/main/java/likelion/univ/domain/user/entity/Profile.java index 517f7f31..64610b20 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/user/entity/Profile.java +++ b/likelion-core/src/main/java/likelion/univ/domain/user/entity/Profile.java @@ -15,8 +15,6 @@ public class Profile { private String name; - // 010-0000-0000 형태로 - private String phoneNumber; private String profileImage; @Column(columnDefinition = "TEXT") diff --git a/likelion-core/src/main/java/likelion/univ/domain/user/entity/Role.java b/likelion-core/src/main/java/likelion/univ/domain/user/entity/Role.java index 9dc91893..6f97f5db 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/user/entity/Role.java +++ b/likelion-core/src/main/java/likelion/univ/domain/user/entity/Role.java @@ -8,11 +8,10 @@ public enum Role { GUEST("GUEST"), - USER("USER"), - MANAGER("MANAGER"), - ADMIN("ADMIN"), - CODEIT_ADMIN("CODEIT_ADMIN"), - SUPER_ADMIN("SUPER_ADMIN"); + USER("USER"), /* 아기사자 */ + MANAGER("MANAGER"), /* 운영진 */ + UNIVERSITY_ADMIN("UNIVERSITY_ADMIN"), /* 대학대표 (대학관리자) */ + SUPER_ADMIN("SUPER_ADMIN"); /* 총관리자 */ private String value; } diff --git a/likelion-core/src/main/java/likelion/univ/domain/user/entity/UniversityInfo.java b/likelion-core/src/main/java/likelion/univ/domain/user/entity/UniversityInfo.java index 617d9871..aa526c61 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/user/entity/UniversityInfo.java +++ b/likelion-core/src/main/java/likelion/univ/domain/user/entity/UniversityInfo.java @@ -14,7 +14,6 @@ @AllArgsConstructor @Builder public class UniversityInfo { - @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "university_id") private University university; diff --git a/likelion-core/src/main/java/likelion/univ/domain/user/entity/User.java b/likelion-core/src/main/java/likelion/univ/domain/user/entity/User.java index b78ed1e0..951b6c43 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/user/entity/User.java +++ b/likelion-core/src/main/java/likelion/univ/domain/user/entity/User.java @@ -9,12 +9,11 @@ @Builder @AllArgsConstructor @Entity -@Table(name="users", uniqueConstraints = {@UniqueConstraint(columnNames = {"email", "loginType"})}) +@Table(name="user", uniqueConstraints = {@UniqueConstraint(columnNames = {"email", "loginType"})}) public class User extends BaseTimeEntity{ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "user_id") private Long id; @Embedded @@ -26,4 +25,7 @@ public class User extends BaseTimeEntity{ @Embedded private AuthInfo authInfo; + public void editProfile(Profile profile){ + this.profile = profile; + } } diff --git a/likelion-core/src/main/java/likelion/univ/domain/user/exception/UserErrorCode.java b/likelion-core/src/main/java/likelion/univ/domain/user/exception/UserErrorCode.java index afd959fc..4bd6e166 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/user/exception/UserErrorCode.java +++ b/likelion-core/src/main/java/likelion/univ/domain/user/exception/UserErrorCode.java @@ -4,13 +4,13 @@ import lombok.AllArgsConstructor; import lombok.Getter; -import static likelion.univ.constant.StaticValue.BAD_REQUEST; -import static likelion.univ.constant.StaticValue.NOT_FOUND; +import static likelion.univ.constant.StaticValue.*; @Getter @AllArgsConstructor public enum UserErrorCode implements BaseErrorCode{ NOT_SUPPORTED_LOGIN_TYPE(BAD_REQUEST, "LOGIN_TYPE_400", "해당 방식은 지원하지않는 로그인 방식입니다."), + USER_NOT_MATCH(FORBIDDEN, "USER_403", "사용자가 일치하지 않습니다."), USER_NOT_FOUND(NOT_FOUND, "USER_404", "유저를 찾을 수 없습니다."), EMAIL_ALREADY_REGISTERED(NOT_FOUND, "USER_409", "같은 이메일로 회원가입된 계정이 있습니다."); diff --git a/likelion-core/src/main/java/likelion/univ/domain/user/exception/UserNotMatchException.java b/likelion-core/src/main/java/likelion/univ/domain/user/exception/UserNotMatchException.java new file mode 100644 index 00000000..64525922 --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/domain/user/exception/UserNotMatchException.java @@ -0,0 +1,10 @@ +package likelion.univ.domain.user.exception; + +import likelion.univ.exception.base.BaseErrorCode; +import likelion.univ.exception.base.BaseException; + +public class UserNotMatchException extends BaseException { + public UserNotMatchException() { + super(UserErrorCode.USER_NOT_MATCH); + } +} diff --git a/likelion-core/src/main/java/likelion/univ/domain/user/repository/UserCustomRepository.java b/likelion-core/src/main/java/likelion/univ/domain/user/repository/UserCustomRepository.java new file mode 100644 index 00000000..476a70de --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/domain/user/repository/UserCustomRepository.java @@ -0,0 +1,16 @@ +package likelion.univ.domain.user.repository; + +import likelion.univ.domain.user.entity.User; +import likelion.univ.domain.user.repository.searchcondition.UserSearchCondition; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; + +import java.util.List; + +public interface UserCustomRepository { + List findDynamicUsers(UserSearchCondition condition); + Slice findFollowingUsersByFollowerID(Long userId, Pageable pageable); + Slice findFollowerUsersByFollowingID(Long userId, Pageable pageable); + Slice searchByName(String name, Pageable pageable); + List findMyFollowingUsersByFollowingIdIn(Long followerId, List followingIdList); +} diff --git a/likelion-core/src/main/java/likelion/univ/domain/user/repository/UserQueryRepository.java b/likelion-core/src/main/java/likelion/univ/domain/user/repository/UserQueryRepository.java deleted file mode 100644 index c14f8f1a..00000000 --- a/likelion-core/src/main/java/likelion/univ/domain/user/repository/UserQueryRepository.java +++ /dev/null @@ -1,47 +0,0 @@ -package likelion.univ.domain.user.repository; - -import com.querydsl.core.types.dsl.BooleanExpression; -import com.querydsl.jpa.impl.JPAQueryFactory; -import likelion.univ.domain.university.entity.University; -import likelion.univ.domain.user.entity.Part; -import likelion.univ.domain.user.entity.User; -import likelion.univ.domain.user.repository.searchcondition.UserSearchCondition; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Repository; -import org.springframework.util.StringUtils; - -import java.util.List; - -import static likelion.univ.domain.user.entity.QUser.user; - -@Repository -@RequiredArgsConstructor -public class UserQueryRepository { - - private final JPAQueryFactory jpaQueryFactory; - - public List findDynamicUsers(UserSearchCondition condition) { - return jpaQueryFactory - .selectFrom(user) - .where( - containsName(condition.getName()), - eqUniversity(condition.getUniversity()), - eqPart(condition.getPart()) - ) - .fetch(); - } - - private BooleanExpression containsName(String searchName) { - return StringUtils.hasText(searchName) ? user.profile.name.contains(searchName) : null; - } - - private BooleanExpression eqUniversity(String searchUniversity) { - return searchUniversity != null ? user.universityInfo.university.name.eq(searchUniversity) : null; - } - - private BooleanExpression eqPart(String searchPart) { - return searchPart != null ? user.profile.part.eq(Part.valueOf(searchPart)) : null; - } - - -} diff --git a/likelion-core/src/main/java/likelion/univ/domain/user/repository/UserRepository.java b/likelion-core/src/main/java/likelion/univ/domain/user/repository/UserRepository.java index a642764d..f5962274 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/user/repository/UserRepository.java +++ b/likelion-core/src/main/java/likelion/univ/domain/user/repository/UserRepository.java @@ -2,10 +2,14 @@ import likelion.univ.domain.user.entity.User; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import java.util.Optional; -public interface UserRepository extends JpaRepository { +public interface UserRepository extends JpaRepository, UserCustomRepository { Optional findByAuthInfoEmail(String email); Boolean existsByAuthInfoEmail(String email); + + @Query("SELECT u FROM User u join fetch u.universityInfo.university where u.id = :id ") + Optional findByIdWithUniversity(Long id); } diff --git a/likelion-core/src/main/java/likelion/univ/domain/user/repository/impl/UserCustomRepositoryImpl.java b/likelion-core/src/main/java/likelion/univ/domain/user/repository/impl/UserCustomRepositoryImpl.java new file mode 100644 index 00000000..062c394f --- /dev/null +++ b/likelion-core/src/main/java/likelion/univ/domain/user/repository/impl/UserCustomRepositoryImpl.java @@ -0,0 +1,119 @@ +package likelion.univ.domain.user.repository.impl; + +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.core.types.dsl.CaseBuilder; +import com.querydsl.core.types.dsl.NumberExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; +import likelion.univ.common.processor.ConvertSliceProcessor; +import likelion.univ.domain.user.entity.Part; +import likelion.univ.domain.user.entity.User; +import likelion.univ.domain.user.repository.UserCustomRepository; +import likelion.univ.domain.user.repository.searchcondition.UserSearchCondition; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.util.StringUtils; + +import java.util.List; + +import static likelion.univ.domain.follow.entity.QFollow.follow; +import static likelion.univ.domain.university.entity.QUniversity.university; +import static likelion.univ.domain.user.entity.QUser.user; + +@RequiredArgsConstructor +public class UserCustomRepositoryImpl implements UserCustomRepository { + private final JPAQueryFactory queryFactory; + private final ConvertSliceProcessor convertSliceProcessor; + + @Override + public List findDynamicUsers(UserSearchCondition condition) { + return queryFactory + .selectFrom(user) + .where( + containsName(condition.getName()), + eqUniversity(condition.getUniversity()), + eqPart(condition.getPart()) + ) + .fetch(); + } + + private BooleanExpression containsName(String searchName) { + return StringUtils.hasText(searchName) ? user.profile.name.contains(searchName) : null; + } + + private BooleanExpression eqUniversity(String searchUniversity) { + return searchUniversity != null ? user.universityInfo.university.name.eq(searchUniversity) : null; + } + + private BooleanExpression eqPart(String searchPart) { + return searchPart != null ? user.profile.part.eq(Part.valueOf(searchPart)) : null; + } + + + @Override + public Slice findFollowingUsersByFollowerID(Long followerId, Pageable pageable){ + List users = + queryFactory + .select(follow.following) + .from(follow) + .innerJoin(follow.following, user) + .where(follow.follower.id.eq(followerId)) + .offset(pageable.getOffset()) + .orderBy(user.createdDate.desc()) + .limit(pageable.getPageSize() + 1) + .fetch(); + + return convertSliceProcessor.execute(users, pageable); + } + @Override + public Slice findFollowerUsersByFollowingID(Long followingId, Pageable pageable){ + List users = + queryFactory + .select(user) + .from(follow) + .innerJoin(follow.follower, user) + .where(follow.following.id.eq(followingId)) + .offset(pageable.getOffset()) + .orderBy(user.createdDate.desc()) + .limit(pageable.getPageSize() + 1) + .fetch(); + + return convertSliceProcessor.execute(users, pageable); + } + + @Override + public List findMyFollowingUsersByFollowingIdIn(Long followerId, List followingIdList){ + List users = + queryFactory + .select(user) + .from(follow) + .innerJoin(follow.following, user) + .where(follow.follower.id.eq(followerId) + .and(follow.following.id.in(followingIdList))) + .fetch(); + return users; + } + @Override + public Slice searchByName(String name, Pageable pageable){ + NumberExpression partOrder = new CaseBuilder() + .when(user.profile.part.eq(Part.PM)).then(1) + .when(user.profile.part.eq(Part.DESIGNER)).then(2) + .when(user.profile.part.eq(Part.PM_DESIGNER)).then(3) + .when(user.profile.part.eq(Part.FRONTEND)).then(4) + .when(user.profile.part.eq(Part.BACKEND)).then(5) + .otherwise(6); + + List users = + queryFactory + .select(user) + .from(user) + .innerJoin(user.universityInfo.university, university).fetchJoin() + .where(containsName(name)) + .offset(pageable.getOffset()) + .orderBy(partOrder.asc(), user.profile.name.asc()) + .limit(pageable.getPageSize() + 1) + .fetch(); + + return convertSliceProcessor.execute(users, pageable); + } +} \ No newline at end of file diff --git a/likelion-core/src/main/java/likelion/univ/domain/user/service/UserDomainService.java b/likelion-core/src/main/java/likelion/univ/domain/user/service/UserDomainService.java index 504f4550..e99aabb8 100644 --- a/likelion-core/src/main/java/likelion/univ/domain/user/service/UserDomainService.java +++ b/likelion-core/src/main/java/likelion/univ/domain/user/service/UserDomainService.java @@ -34,6 +34,12 @@ public User signUp(Profile profile, AuthInfo authInfo, UniversityInfo university .build(); return userAdaptor.save(user); } + @Transactional + public User editProfile(Long userId, Profile profile){ + User user = userAdaptor.findById(userId); + user.editProfile(profile); + return user; + } public User findByEmail(String email) { return userAdaptor.findByEmail(email); diff --git a/likelion-core/src/main/resources/application-core.yml b/likelion-core/src/main/resources/application-core.yml index 4cc8663b..7715dc11 100644 --- a/likelion-core/src/main/resources/application-core.yml +++ b/likelion-core/src/main/resources/application-core.yml @@ -5,6 +5,11 @@ spring: url: jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT}/${MYSQL_NAME} username: ${MYSQL_USERNAME} password: ${MYSQL_PASSWORD} + + data: + web: + pageable: + one-indexed-parameters: true jpa: show-sql: true database: mysql @@ -17,12 +22,6 @@ spring: default_batch_fetch_size: 1000 format_sql: true -logging: - level: - org.springframework.orm.jpa: DEBUG - org.springframework.transaction: DEBUG - pattern: - console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n" --- ## dev 환경 설정 spring: @@ -30,12 +29,41 @@ spring: activate: on-profile: dev + jpa: + properties: + hibernate: + show_sql: true + format_sql: true + +logging: + level: + org.springframework.orm.jpa: DEBUG + org.springframework.transaction: DEBUG + org: + hibernate: + type: + descriptor: + sql: trace + pattern: + console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n" + --- ## staging환경 설정 spring: config: activate: on-profile: staging + jpa: + properties: + hibernate: + show_sql: false + format_sql: false + +logging: + level: + root: INFO + pattern: + console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n" --- ## prod 환경 설정 spring: config: diff --git a/likelion-redis/src/main/java/likelion/univ/common/base/BaseRedisRepository.java b/likelion-redis/src/main/java/likelion/univ/common/base/BaseRedisRepository.java index 1d40b4db..e1cd4590 100644 --- a/likelion-redis/src/main/java/likelion/univ/common/base/BaseRedisRepository.java +++ b/likelion-redis/src/main/java/likelion/univ/common/base/BaseRedisRepository.java @@ -4,18 +4,24 @@ import org.springframework.data.redis.core.RedisTemplate; import java.util.Optional; +import java.util.concurrent.TimeUnit; + -@Slf4j public abstract class BaseRedisRepository { protected RedisTemplate redisTemplate; protected String prefix; + protected Long ttl; - public void save(Long id, T t) { - redisTemplate.opsForValue().set(generateKeyfromId(id), t); + public void save(Long id, T data) { + redisTemplate.opsForValue().set(generateKeyfromId(id), data, ttl, TimeUnit.SECONDS); } public Optional findById(Long id) { - return Optional.of(redisTemplate.opsForValue().get(generateKeyfromId(id))); + try{ + return Optional.of(redisTemplate.opsForValue().get(generateKeyfromId(id))); + }catch (NullPointerException e){ + return Optional.empty(); + } } public Boolean delete(Long id) { return redisTemplate.delete(generateKeyfromId(id)); diff --git a/likelion-redis/src/main/java/likelion/univ/common/config/RedisCacheManagerConfig.java b/likelion-redis/src/main/java/likelion/univ/common/config/RedisCacheManagerConfig.java index 98540ae3..1ab852f4 100644 --- a/likelion-redis/src/main/java/likelion/univ/common/config/RedisCacheManagerConfig.java +++ b/likelion-redis/src/main/java/likelion/univ/common/config/RedisCacheManagerConfig.java @@ -46,7 +46,6 @@ private Map customConfigurationMap(RedisCacheCo Map customConfigurationMap = new HashMap<>(); customConfigurationMap.put(KAKAO_PUBLIC_KEYS, redisCacheConfiguration.entryTtl(Duration.ofDays(1L))); customConfigurationMap.put(GOOGLE_PUBLIC_KEYS, redisCacheConfiguration.entryTtl(Duration.ofDays(1L))); - customConfigurationMap.put(REFRESH_TOKEN, redisCacheConfiguration.entryTtl(Duration.ofDays(14L))); return customConfigurationMap; } } diff --git a/likelion-redis/src/main/java/likelion/univ/common/constant/RedisKey.java b/likelion-redis/src/main/java/likelion/univ/common/constant/RedisKey.java index 65d5c34e..3f4f8298 100644 --- a/likelion-redis/src/main/java/likelion/univ/common/constant/RedisKey.java +++ b/likelion-redis/src/main/java/likelion/univ/common/constant/RedisKey.java @@ -7,5 +7,9 @@ public class RedisKey { public static final String GOOGLE_PUBLIC_KEYS = "googlePublicKeys"; public static final String REFRESH_TOKEN = "refreshToken"; - public static final int REFRESH_TOKEN_EXPIRE_SEC = 1209600; + public static final String POST_COUNT_INFO = "postCount"; + public static final String USER_FOLLOW_NUM = "userFollowNum"; + public static final Long REFRESH_TOKEN_EXPIRE_SEC = 1209600L; + public static final Long POST_COUNT_INFO_EXPIRE_SEC = 86400L; + public static final Long USER_FOLLOW_NUM_EXPIRE_SEC = 86400L; } diff --git a/likelion-redis/src/main/java/likelion/univ/follow/dao/FollowNumRedisDao.java b/likelion-redis/src/main/java/likelion/univ/follow/dao/FollowNumRedisDao.java new file mode 100644 index 00000000..a8297c35 --- /dev/null +++ b/likelion-redis/src/main/java/likelion/univ/follow/dao/FollowNumRedisDao.java @@ -0,0 +1,19 @@ +package likelion.univ.follow.dao; + +import likelion.univ.annotation.RedisRepository; +import likelion.univ.common.base.BaseRedisRepository; +import likelion.univ.follow.entity.FollowNum; +import org.springframework.data.redis.core.RedisTemplate; + +import static likelion.univ.common.constant.RedisKey.USER_FOLLOW_NUM; +import static likelion.univ.common.constant.RedisKey.USER_FOLLOW_NUM_EXPIRE_SEC; + +@RedisRepository +public class FollowNumRedisDao extends BaseRedisRepository { + + public FollowNumRedisDao(RedisTemplate redisTemplate) { + this.prefix = USER_FOLLOW_NUM + ":"; + this.ttl = USER_FOLLOW_NUM_EXPIRE_SEC; + this.redisTemplate = redisTemplate; + } +} \ No newline at end of file diff --git a/likelion-redis/src/main/java/likelion/univ/follow/entity/FollowNum.java b/likelion-redis/src/main/java/likelion/univ/follow/entity/FollowNum.java new file mode 100644 index 00000000..7c88387a --- /dev/null +++ b/likelion-redis/src/main/java/likelion/univ/follow/entity/FollowNum.java @@ -0,0 +1,15 @@ +package likelion.univ.follow.entity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class FollowNum { + private Long followerNum; + private Long followingNum; +} diff --git a/likelion-redis/src/main/java/likelion/univ/follow/service/FollowNumRedisService.java b/likelion-redis/src/main/java/likelion/univ/follow/service/FollowNumRedisService.java new file mode 100644 index 00000000..b0cb6d41 --- /dev/null +++ b/likelion-redis/src/main/java/likelion/univ/follow/service/FollowNumRedisService.java @@ -0,0 +1,49 @@ +package likelion.univ.follow.service; + +import likelion.univ.follow.dao.FollowNumRedisDao; +import likelion.univ.follow.entity.FollowNum; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class FollowNumRedisService { + private final FollowNumRedisDao followNumRedisDao; + + public FollowNum save(Long userId, Long followerNum, Long followingNum){ + FollowNum followNum = FollowNum.builder() + .followerNum(followerNum) + .followingNum(followingNum) + .build(); + followNumRedisDao.save(userId, followNum); + return followNum; + } + public void followerUp(Long userId, FollowNum followNum){ + FollowNum newFollowNum = FollowNum.builder() + .followerNum(followNum.getFollowerNum() + 1) + .followingNum(followNum.getFollowingNum()) + .build(); + followNumRedisDao.save(userId, newFollowNum); + } + public void followerDown(Long userId, FollowNum followNum){ + FollowNum newFollowNum = FollowNum.builder() + .followerNum(followNum.getFollowerNum() - 1) + .followingNum(followNum.getFollowingNum()) + .build(); + followNumRedisDao.save(userId, newFollowNum); + } + public void followingUp(Long userId, FollowNum followNum){ + FollowNum newFollowNum = FollowNum.builder() + .followerNum(followNum.getFollowerNum()) + .followingNum(followNum.getFollowingNum() + 1) + .build(); + followNumRedisDao.save(userId, newFollowNum); + } + public void followingDown(Long userId, FollowNum followNum){ + FollowNum newFollowNum = FollowNum.builder() + .followerNum(followNum.getFollowerNum()) + .followingNum(followNum.getFollowingNum() - 1) + .build(); + followNumRedisDao.save(userId, newFollowNum); + } +} \ No newline at end of file diff --git a/likelion-redis/src/main/java/likelion/univ/post/dao/PostCountInfoRedisDao.java b/likelion-redis/src/main/java/likelion/univ/post/dao/PostCountInfoRedisDao.java new file mode 100644 index 00000000..b9e9b6e5 --- /dev/null +++ b/likelion-redis/src/main/java/likelion/univ/post/dao/PostCountInfoRedisDao.java @@ -0,0 +1,19 @@ +package likelion.univ.post.dao; + +import likelion.univ.annotation.RedisRepository; +import likelion.univ.common.base.BaseRedisRepository; +import likelion.univ.post.entity.PostCountInfo; +import org.springframework.data.redis.core.RedisTemplate; + +import static likelion.univ.common.constant.RedisKey.POST_COUNT_INFO; +import static likelion.univ.common.constant.RedisKey.POST_COUNT_INFO_EXPIRE_SEC; + +@RedisRepository +public class PostCountInfoRedisDao extends BaseRedisRepository { + + public PostCountInfoRedisDao(RedisTemplate redisTemplate) { + this.prefix = POST_COUNT_INFO + ":"; + this.ttl = POST_COUNT_INFO_EXPIRE_SEC; + this.redisTemplate = redisTemplate; + } +} diff --git a/likelion-redis/src/main/java/likelion/univ/post/entity/PostCountInfo.java b/likelion-redis/src/main/java/likelion/univ/post/entity/PostCountInfo.java new file mode 100644 index 00000000..a7f2158f --- /dev/null +++ b/likelion-redis/src/main/java/likelion/univ/post/entity/PostCountInfo.java @@ -0,0 +1,15 @@ +package likelion.univ.post.entity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PostCountInfo { + private Long commentCount; + private Long likeCount; +} diff --git a/likelion-redis/src/main/java/likelion/univ/post/service/PostCountInfoRedisService.java b/likelion-redis/src/main/java/likelion/univ/post/service/PostCountInfoRedisService.java new file mode 100644 index 00000000..7c3f23a4 --- /dev/null +++ b/likelion-redis/src/main/java/likelion/univ/post/service/PostCountInfoRedisService.java @@ -0,0 +1,21 @@ +package likelion.univ.post.service; + +import likelion.univ.post.dao.PostCountInfoRedisDao; +import likelion.univ.post.entity.PostCountInfo; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class PostCountInfoRedisService { + private final PostCountInfoRedisDao postCountInfoRedisDao; + + public PostCountInfo save(Long postId, Long commentCount, Long likeCount){ + PostCountInfo postCountInfo = PostCountInfo.builder() + .commentCount(commentCount) + .likeCount(likeCount) + .build(); + postCountInfoRedisDao.save(postId, postCountInfo); + return postCountInfo; + } +} diff --git a/likelion-redis/src/main/java/likelion/univ/refreshtoken/adaptor/RefreshTokenRedisAdaptor.java b/likelion-redis/src/main/java/likelion/univ/refreshtoken/adaptor/RefreshTokenRedisAdaptor.java deleted file mode 100644 index 9cf0212c..00000000 --- a/likelion-redis/src/main/java/likelion/univ/refreshtoken/adaptor/RefreshTokenRedisAdaptor.java +++ /dev/null @@ -1,21 +0,0 @@ -package likelion.univ.refreshtoken.adaptor; - -import likelion.univ.annotation.Adaptor; -import likelion.univ.refreshtoken.dao.RefreshTokenRedisDao; -import likelion.univ.refreshtoken.entity.RefreshToken; -import likelion.univ.refreshtoken.exception.ExpiredRefreshTokenException; -import lombok.RequiredArgsConstructor; - -@Adaptor -@RequiredArgsConstructor -public class RefreshTokenRedisAdaptor { - private final RefreshTokenRedisDao refreshTokenRedisDao; - - public void save(Long id, RefreshToken refreshToken){ - refreshTokenRedisDao.save(id, refreshToken); - } - public RefreshToken findById(Long id){ - return refreshTokenRedisDao.findById(id) - .orElseThrow(() -> new ExpiredRefreshTokenException()); - } -} diff --git a/likelion-redis/src/main/java/likelion/univ/refreshtoken/dao/RefreshTokenRedisDao.java b/likelion-redis/src/main/java/likelion/univ/refreshtoken/dao/RefreshTokenRedisDao.java index a3d2da2e..836be70f 100644 --- a/likelion-redis/src/main/java/likelion/univ/refreshtoken/dao/RefreshTokenRedisDao.java +++ b/likelion-redis/src/main/java/likelion/univ/refreshtoken/dao/RefreshTokenRedisDao.java @@ -3,17 +3,17 @@ import likelion.univ.annotation.RedisRepository; import likelion.univ.common.base.BaseRedisRepository; import likelion.univ.refreshtoken.entity.RefreshToken; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Component; import static likelion.univ.common.constant.RedisKey.REFRESH_TOKEN; +import static likelion.univ.common.constant.RedisKey.REFRESH_TOKEN_EXPIRE_SEC; @RedisRepository public class RefreshTokenRedisDao extends BaseRedisRepository { - @Autowired + public RefreshTokenRedisDao(RedisTemplate redisTemplate) { this.prefix = REFRESH_TOKEN + ":"; + this.ttl = REFRESH_TOKEN_EXPIRE_SEC; this.redisTemplate = redisTemplate; } } diff --git a/likelion-redis/src/main/java/likelion/univ/refreshtoken/entity/RefreshToken.java b/likelion-redis/src/main/java/likelion/univ/refreshtoken/entity/RefreshToken.java index f4faccb3..a00e2d38 100644 --- a/likelion-redis/src/main/java/likelion/univ/refreshtoken/entity/RefreshToken.java +++ b/likelion-redis/src/main/java/likelion/univ/refreshtoken/entity/RefreshToken.java @@ -13,7 +13,6 @@ @Builder public class RefreshToken { - private Long userId; private String token; } diff --git a/likelion-redis/src/main/java/likelion/univ/refreshtoken/service/RefreshTokenRedisService.java b/likelion-redis/src/main/java/likelion/univ/refreshtoken/service/RefreshTokenRedisService.java index b44d6809..4545a42d 100644 --- a/likelion-redis/src/main/java/likelion/univ/refreshtoken/service/RefreshTokenRedisService.java +++ b/likelion-redis/src/main/java/likelion/univ/refreshtoken/service/RefreshTokenRedisService.java @@ -1,28 +1,27 @@ package likelion.univ.refreshtoken.service; -import likelion.univ.refreshtoken.adaptor.RefreshTokenRedisAdaptor; +import likelion.univ.refreshtoken.dao.RefreshTokenRedisDao; import likelion.univ.refreshtoken.entity.RefreshToken; +import likelion.univ.refreshtoken.exception.ExpiredRefreshTokenException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor -@Slf4j public class RefreshTokenRedisService { - private final RefreshTokenRedisAdaptor refreshTokenRedisAdaptor; - + private final RefreshTokenRedisDao refreshTokenRedisDao; public void save(Long id, String token){ RefreshToken refreshToken = RefreshToken.builder() .userId(id) .token(token) .build(); - refreshTokenRedisAdaptor.save(id, refreshToken); + refreshTokenRedisDao.save(id, refreshToken); } public Boolean checkToken(Long id, String token){ - RefreshToken refreshToken = refreshTokenRedisAdaptor.findById(id); + RefreshToken refreshToken = refreshTokenRedisDao.findById(id) + .orElseThrow(() -> new ExpiredRefreshTokenException()); if(token.equals(refreshToken.getToken())) return true; else return false; }