Skip to content

Commit

Permalink
Merge pull request #206 from Open-Eye-Im-Developer/develop
Browse files Browse the repository at this point in the history
Alpha Update
  • Loading branch information
tidavid1 committed Mar 4, 2024
2 parents 49a33e6 + 55a6548 commit 356a21c
Show file tree
Hide file tree
Showing 63 changed files with 1,005 additions and 209 deletions.
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb:3.1.8'
// Spring Boot WebSocket
implementation 'org.springframework.boot:spring-boot-starter-websocket:3.1.8'
// Flyway
implementation 'org.flywaydb:flyway-core:10.8.1'
implementation 'org.flywaydb:flyway-mysql:10.8.1'

// SpringBoot Test
testImplementation 'org.springframework.boot:spring-boot-starter-test:3.1.8'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,28 @@ ResponseEntity<CursorPaginationResult<ChatDataRes>> getChatData(
@Parameter(in = ParameterIn.PATH) String chatRoomId,
@Parameter(hidden = true) Long userId,
@Parameter(hidden = true) CursorPaginationInfoReq pageable);

@Operation(summary = "채팅방 나가기", description = "채팅방에 참여중인 사용자가 채팅방을 나가기 위해 사용하는 API")
@ApiResponses(value = {
@ApiResponse(responseCode = "204", description = "채팅방 나가기 성공"),
@ApiResponse(responseCode = "400", description = "요청한 데이터가 유효하지 않음",
content = @Content(
mediaType = APPLICATION_JSON_VALUE,
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(name = "E110102", value = SwaggerChatErrorExamples.CHAT_ROOM_USER_CANNOT_DUPLICATE)
)),
@ApiResponse(responseCode = "404", description = "요청한 데이터가 유효하지 않음",
content = @Content(
mediaType = APPLICATION_JSON_VALUE,
schema = @Schema(implementation = ErrorResponse.class),
examples = {
@ExampleObject(name = "E020301", value = SwaggerUserErrorExamples.USER_NOT_FOUND),
@ExampleObject(name = "E110301", value = SwaggerChatErrorExamples.CHAT_ROOM_NOT_FOUND)
}
))
})
ResponseEntity<Void> leaveChatRoom(
@Parameter(hidden = true) Long userId,
@Parameter(in = ParameterIn.PATH) String chatRoomId
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@

import io.oeid.mogakgo.common.base.CursorPaginationInfoReq;
import io.oeid.mogakgo.common.base.CursorPaginationResult;
import io.oeid.mogakgo.core.properties.swagger.error.SwaggerNotificationErrorExamples;
import io.oeid.mogakgo.core.properties.swagger.error.SwaggerUserErrorExamples;
import io.oeid.mogakgo.domain.notification.application.dto.res.NotificationCheckedRes;
import io.oeid.mogakgo.domain.notification.presentation.dto.req.FCMTokenApiRequest;
import io.oeid.mogakgo.domain.notification.presentation.dto.res.NotificationPublicApiRes;
import io.oeid.mogakgo.exception.dto.ErrorResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
Expand Down Expand Up @@ -51,4 +54,18 @@ ResponseEntity<Void> manageFCMToken(@Parameter(hidden = true) Long userId,
ResponseEntity<CursorPaginationResult<NotificationPublicApiRes>> getByUserId(
@Parameter(hidden = true) Long id,
@Parameter(hidden = true) CursorPaginationInfoReq pageable);

@Operation(summary = "알림 확인", description = "회원의 알림을 확인할 때 사용하는 API")
@ApiResponse(responseCode = "200", description = "알림 확인 성공")
@ApiResponse(responseCode = "404", description = "요청한 유저가 존재하지 않음", content = @Content(
mediaType = APPLICATION_JSON_VALUE,
schema = @Schema(implementation = ErrorResponse.class),
examples = {
@ExampleObject(name = "E020301", value = SwaggerUserErrorExamples.USER_NOT_FOUND),
@ExampleObject(name = "E060302", value = SwaggerNotificationErrorExamples.NOTIFICATION_NOT_FOUND)
})
)
ResponseEntity<NotificationCheckedRes> markCheckedNotification(
@Parameter(hidden = true) Long userId,
@Parameter(in = ParameterIn.PATH) Long notificationId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package io.oeid.mogakgo.common.swagger.template;

import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;

import io.oeid.mogakgo.core.properties.swagger.error.SwaggerProjectErrorExamples;
import io.oeid.mogakgo.core.properties.swagger.error.SwaggerReviewErrorExamples;
import io.oeid.mogakgo.core.properties.swagger.error.SwaggerUserErrorExamples;
import io.oeid.mogakgo.domain.review.presentation.dto.req.ReviewCreateApiReq;
import io.oeid.mogakgo.domain.review.presentation.dto.res.ReviewCreateApiRes;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;

@Tag(name = "Review", description = "리뷰 관련 API")
@SuppressWarnings("unused")
public interface ReviewSwagger {

@Operation(summary = "리뷰 생성")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "리뷰 생성 성공",
content = @Content(schema = @Schema(implementation = ReviewCreateApiRes.class))),
@ApiResponse(responseCode = "400", description = "요청한 데이터가 유효하지 않음",
content = @Content(
mediaType = APPLICATION_JSON_VALUE,
schema = @Schema(implementation = ResponseEntity.class),
examples = {
@ExampleObject(name = "E120101", value = SwaggerReviewErrorExamples.REVIEW_SENDER_OR_RECEIVER_NOT_FOUND),
@ExampleObject(name = "E120102", value = SwaggerReviewErrorExamples.REVIEW_USER_DUPLICATED),
@ExampleObject(name = "E120103", value = SwaggerReviewErrorExamples.REVIEW_PROJECT_NOT_NULL),
@ExampleObject(name = "E120104", value = SwaggerReviewErrorExamples.REVIEW_ALREADY_EXISTS),
@ExampleObject(name = "E120105", value = SwaggerReviewErrorExamples.REVIEW_USER_NOT_MATCH),
@ExampleObject(name = "E120106", value = SwaggerReviewErrorExamples.REVIEW_RATING_INVALID),
})),
@ApiResponse(responseCode = "404", description = "해당 데이터가 존재하지 않음",
content = @Content(
mediaType = APPLICATION_JSON_VALUE,
schema = @Schema(implementation = ResponseEntity.class),
examples = {
@ExampleObject(name = "E020301", value = SwaggerUserErrorExamples.USER_NOT_FOUND),
@ExampleObject(name = "E030301", value = SwaggerProjectErrorExamples.PROJECT_NOT_FOUND)
}
)),
})
ResponseEntity<ReviewCreateApiRes> createReviewApi(
@Parameter(hidden = true) Long userId,
ReviewCreateApiReq request);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@

import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;

import io.oeid.mogakgo.core.properties.swagger.error.SwaggerAchievementErrorExamples;
import io.oeid.mogakgo.core.properties.swagger.error.SwaggerUserAchievementErrorExamples;
import io.oeid.mogakgo.core.properties.swagger.error.SwaggerUserErrorExamples;
import io.oeid.mogakgo.domain.user.application.dto.res.UserJandiRateRes;
import io.oeid.mogakgo.domain.user.presentation.dto.req.UserAchievementUpdateApiRequest;
import io.oeid.mogakgo.domain.user.presentation.dto.req.UserSignUpApiReq;
import io.oeid.mogakgo.domain.user.presentation.dto.req.UserUpdateApiReq;
import io.oeid.mogakgo.domain.user.presentation.dto.res.UserAchievementUpdateApiResponse;
import io.oeid.mogakgo.domain.user.presentation.dto.res.UserDevelopLanguageApiRes;
import io.oeid.mogakgo.domain.user.presentation.dto.res.UserMatchingStatus;
import io.oeid.mogakgo.domain.user.presentation.dto.res.UserPublicApiResponse;
Expand Down Expand Up @@ -124,5 +128,37 @@ ResponseEntity<UserUpdateApiRes> userUpdateApi(@Parameter(hidden = true) Long us
examples = @ExampleObject(name = "E020301", value = SwaggerUserErrorExamples.USER_NOT_FOUND))),
})
ResponseEntity<UserJandiRateRes> userJandiRateApi(@Parameter(in = ParameterIn.PATH) Long userId);


@Operation(summary = "사용자의 대표 업적 변경", description = "사용자가 자신의 대표 업적을 변경하고 싶을 때 사용하는 API")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "대표 업적 변경 성공"),
@ApiResponse(responseCode = "400", description = "요청한 데이터가 유효하지 않음",
content = @Content(
mediaType = APPLICATION_JSON_VALUE,
schema = @Schema(implementation = ErrorResponse.class),
examples = {
@ExampleObject(name = "E140101", value = SwaggerUserAchievementErrorExamples.NON_ACHIEVED_USER_ACHIEVEMENT),
@ExampleObject(name = "E140102", value = SwaggerUserAchievementErrorExamples.ACHIEVEMENT_SHOULD_BE_DIFFERENT)
}
)),
@ApiResponse(responseCode = "403", description = "사용자의 대표 업적을 변경할 권한이 없음",
content = @Content(
mediaType = APPLICATION_JSON_VALUE,
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(name = "E020201", value = SwaggerUserErrorExamples.USER_FORBIDDEN_OPERATION)
)),
@ApiResponse(responseCode = "404", description = "요청한 데이터가 존재하지 않음",
content = @Content(
mediaType = APPLICATION_JSON_VALUE,
schema = @Schema(implementation = ErrorResponse.class),
examples = {
@ExampleObject(name = "E130301", value = SwaggerAchievementErrorExamples.ACHIEVEMENT_NOT_FOUND),
@ExampleObject(name = "E020301", value = SwaggerUserErrorExamples.USER_NOT_FOUND)
}
))
})
ResponseEntity<UserAchievementUpdateApiResponse> updateUserMainAchievement(
@Parameter(hidden = true) Long userId,
UserAchievementUpdateApiRequest request
);
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
package io.oeid.mogakgo.core.configuration;

import io.oeid.mogakgo.domain.chat.interceptor.ChatInterceptor;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@RequiredArgsConstructor
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

private final WebSocketHandler webSocketHandler;
private final ChatInterceptor chatInterceptor;

@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(webSocketHandler, "/ws/chat").setAllowedOrigins("*");
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app");
registry.enableSimpleBroker("/topic", "/queue");
}

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").setAllowedOriginPatterns("*");
}

@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(chatInterceptor);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.oeid.mogakgo.core.properties;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
Expand All @@ -11,7 +10,7 @@
@Getter
@Component
@ConfigurationProperties(prefix = "jwt")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor
public class JwtProperties {

private String header;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.oeid.mogakgo.core.properties.swagger.error;

public class SwaggerAchievementErrorExamples {

public static final String ACHIEVEMENT_NOT_FOUND = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":404,\"code\":\"E130301\",\"message\":\"해당 업적이 존재하지 않습니다.\"}";
private SwaggerAchievementErrorExamples() {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
public class SwaggerChatErrorExamples {

public static final String CHAT_ROOM_NOT_FOUND = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":404,\"code\":\"E110301\",\"message\":\"해당 채팅방이 존재하지 않습니다.\"}";
public static final String CHAT_ROOM_USER_CANNOT_DUPLICATE = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E110102\",\"message\":\"채팅방에 같은 유저가 존재할 수 없습니다.\"}";

private SwaggerChatErrorExamples() {
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.oeid.mogakgo.core.properties.swagger.error;

public class SwaggerNotificationErrorExamples {

public static final String NOTIFICATION_FCM_TOKEN_NOT_FOUND = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":404,\"code\":\"E060301\",\"message\":\"해당 유저의 FCM 토큰이 존재하지 않습니다.\"}";
public static final String NOTIFICATION_NOT_FOUND = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":404,\"code\":\"E060302\",\"message\":\"해당 알림이 존재하지 않습니다.\"}";
private SwaggerNotificationErrorExamples() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.oeid.mogakgo.core.properties.swagger.error;

public class SwaggerReviewErrorExamples {

public static final String REVIEW_SENDER_OR_RECEIVER_NOT_FOUND = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E120101\",\"message\":\"리뷰를 작성하기 위한 유저 정보가 존재하지 않습니다.\"}";
public static final String REVIEW_USER_DUPLICATED = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E120102\",\"message\":\"자신에 대한 리뷰는 작성할 수 없습니다.\"}";
public static final String REVIEW_PROJECT_NOT_NULL = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E120103\",\"message\":\"리뷰를 작성하기 위한 프로젝트 정보가 존재하지 않습니다.\"}";
public static final String REVIEW_ALREADY_EXISTS = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E120104\",\"message\":\"이미 작성된 리뷰가 존재합니다.\"}";
public static final String REVIEW_USER_NOT_MATCH = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E120105\",\"message\":\"리뷰 작성자와 리뷰 대상자가 일치하지 않습니다.\"}";
public static final String REVIEW_RATING_INVALID = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E120106\",\"message\":\"유효하지 않은 리뷰 평점입니다.\"}";

private SwaggerReviewErrorExamples() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.oeid.mogakgo.core.properties.swagger.error;

public class SwaggerUserAchievementErrorExamples {

public static final String NON_ACHIEVED_USER_ACHIEVEMENT = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E140101\",\"message\":\"대표 업적으로 미달성 업적을 사용할 수 없습니다.\"}";
public static final String ACHIEVEMENT_SHOULD_BE_DIFFERENT = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E140102\",\"message\":\"해당 업적을 이미 대표 업적으로 사용하고 있습니다.\"}";

private SwaggerUserAchievementErrorExamples() {

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public class SwaggerUserErrorExamples {
public static final String USER_AVAILABLE_LIKE_COUNT_IS_ZERO = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E020107\",\"message\":\"당일 사용 가능한 찔러보기 요청을 모두 소진했습니다.\"}";
public static final String USER_AVAILABLE_LIKE_COUNT_IS_FULL = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E020108\",\"message\":\"당일 사용 가능한 찔러보기 최대 요청 횟수를 초과활 수 없습니다.\"}";
public static final String USER_AVATAR_URL_NOT_NULL = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E020109\",\"message\":\"유저 프로필 이미지는 비어있을 수 없습니다.\"}";
public static final String USER_FORBIDDEN_OPERATION = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":403,\"code\":\"E020201\",\"message\":\"사용자의 정보를 변경할 권한이 없습니다.\"}";
private SwaggerUserErrorExamples() {
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package io.oeid.mogakgo.domain.achievement.domain.entity;

import static io.oeid.mogakgo.exception.code.ErrorCode400.NON_ACHIEVED_USER_ACHIEVEMENT;

import io.oeid.mogakgo.domain.achievement.exception.UserAchievementException;
import io.oeid.mogakgo.domain.user.domain.User;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
Expand Down Expand Up @@ -48,4 +51,10 @@ public class UserAchievement {
@Column(name = "created_at")
private LocalDateTime createdAt;

public void validateAvailableUpdateAchievement() {
if (this.completed.equals(Boolean.FALSE)) {
throw new UserAchievementException(NON_ACHIEVED_USER_ACHIEVEMENT);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.oeid.mogakgo.domain.achievement.exception;

import io.oeid.mogakgo.exception.code.ErrorCode;
import io.oeid.mogakgo.exception.exception_class.CustomException;

public class AchievementException extends CustomException {

public AchievementException(ErrorCode errorCode) {
super(errorCode);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.oeid.mogakgo.domain.achievement.exception;

import io.oeid.mogakgo.exception.code.ErrorCode;
import io.oeid.mogakgo.exception.exception_class.CustomException;

public class UserAchievementException extends CustomException {

public UserAchievementException(ErrorCode errorCode) {
super(errorCode);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.oeid.mogakgo.domain.achievement.infrastructure;

import io.oeid.mogakgo.domain.achievement.domain.entity.UserAchievement;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

public interface UserAchievementJpaRepository extends JpaRepository<UserAchievement, Long> {

@Query("SELECT ua FROM UserAchievement ua WHERE ua.user.id = :userId AND ua.achievement.id = :achievementId")
Optional<UserAchievement> findByUserAndAchievementId(Long userId, Long achievementId);
}
Loading

0 comments on commit 356a21c

Please sign in to comment.