Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

version 0.1.3 #14

Merged
merged 18 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ jobs:
-e LOG_PATH=${{ secrets.LOG_PATH }} \
-e LOG_LEVEL=${{ secrets.LOG_LEVEL }} \
-e DISCORD_WEB_HOOK_URL=${{ secrets.DISCORD_WEB_HOOK_URL }} \
-e MONGODB_URI=${{ secrets.MONGODB_URI }} \
-v ${{ secrets.DOCKER_MOUNT_PATH }}:${{ secrets.LOG_PATH }} \
${{ secrets.DOCKER_USERNAME }}/${{ secrets.PROJECT_NAME }}
docker rm $(docker ps --filter 'status=exited' -a -q)
Expand Down
6 changes: 5 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ dependencies {

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.mysql:mysql-connector-j'
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'

// swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0'
Expand Down Expand Up @@ -61,6 +62,9 @@ dependencies {
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"

// WebSocket
implementation 'org.springframework.boot:spring-boot-starter-websocket'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

Expand All @@ -79,4 +83,4 @@ processResources {
filesMatching('**/application.properties') {
expand(project.properties)
}
}
}
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version=0.1.2
version=0.1.3
10 changes: 6 additions & 4 deletions src/main/java/com/swygbro/trip/backend/BackendApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.mongodb.config.EnableMongoAuditing;

@SpringBootApplication
@EnableJpaAuditing
@EnableMongoAuditing
@EnableFeignClients
public class BackendApplication {

public static void main(String[] args) {
SpringApplication.run(BackendApplication.class, args);
}
public static void main(String[] args) {
SpringApplication.run(BackendApplication.class, args);
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.swygbro.trip.backend.domain.chat.api;

import com.swygbro.trip.backend.domain.chat.application.ChatHistoryService;
import com.swygbro.trip.backend.domain.chat.application.ChatService;
import com.swygbro.trip.backend.domain.chat.dto.ChatDto;
import com.swygbro.trip.backend.domain.chat.dto.ChatRequest;
import com.swygbro.trip.backend.domain.chat.dto.ChatRoomRequest;
import com.swygbro.trip.backend.domain.user.domain.User;
import com.swygbro.trip.backend.global.jwt.CurrentUser;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/api/v1/chat")
@RequiredArgsConstructor
@Tag(name = "Chat")
public class ChatController {
private final ChatService chatService;
private final ChatHistoryService chatHistoryService;

@MessageMapping("/chat/{chatRoomId}")
@SendTo("/topic/chat/{chatRoomId}")
public ChatRequest message(
@DestinationVariable Long chatRoomId,
@Payload ChatRequest request) {
chatHistoryService.saveChat(request);

return request;
}

@PostMapping("/room")
@PreAuthorize("isAuthenticated() and hasRole('USER')")
@SecurityRequirement(name = "access-token")
@Operation(summary = "채팅방 생성", description = """
# 채팅방 생성 및 히스토리 조회

- 가이드와의 채팅방 생성 혹은 기존 채팅방 조회를 위한 API 입니다.
- 여행객만 가이드와의 채팅방을 생성할 수 있습니다.
- 가이드의 이메일 정보를 통해 채팅방을 생성하거나 조회합니다.

## 응답

- 정상 조회 시 `200` 코드와 함께 채팅 내역을 반환합니다.
- 새로운 채팅방일 경우 빈 리스트를 반환합니다.

""")
public List<ChatDto> joinChatRoom(@CurrentUser User user, ChatRoomRequest chatRoomRequest) {
return chatService.joinChatRoom(user, chatRoomRequest);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.swygbro.trip.backend.domain.chat.application;

import com.swygbro.trip.backend.domain.chat.domain.ChatHistory;
import com.swygbro.trip.backend.domain.chat.domain.ChatHistoryRepository;
import com.swygbro.trip.backend.domain.chat.dto.ChatDto;
import com.swygbro.trip.backend.domain.chat.dto.ChatRequest;
import com.swygbro.trip.backend.domain.user.domain.User;
import com.swygbro.trip.backend.domain.user.domain.UserRepository;
import com.swygbro.trip.backend.domain.user.excepiton.UserNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class ChatHistoryService {
private final ChatHistoryRepository chatHistoryRepository;
private final UserRepository userRepository;

public void saveChat(ChatRequest chatRequest) {
ChatHistory chatHistory = ChatHistory.builder()
.chatRoomId(chatRequest.getChatRoomId())
.senderId(userRepository.findByEmail(chatRequest.getSenderEmail()).get().getId())
.payload(chatRequest.getPayload())
.messageType(chatRequest.getType())
.build();

chatHistoryRepository.save(chatHistory);
}

public List<ChatDto> getChatHistory(Long chatRoomId) {
List<com.swygbro.trip.backend.domain.chat.domain.ChatHistory> chatHistory = chatHistoryRepository.findByChatRoomId(chatRoomId);
return chatHistory.stream().map(
chat -> {
User chatUser = userRepository.findById(chat.getSenderId()).orElseThrow(
() -> new UserNotFoundException(chat.getSenderId())
);

return ChatDto.builder()
.senderEmail(chatUser.getEmail())
.payload(chat.getPayload())
.type(chat.getMessageType())
.createdAt(chat.getCreatedAt())
.build();
}
).collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.swygbro.trip.backend.domain.chat.application;

import com.swygbro.trip.backend.domain.chat.domain.ChatRoom;
import com.swygbro.trip.backend.domain.chat.domain.ChatRoomRepository;
import com.swygbro.trip.backend.domain.chat.dto.ChatDto;
import com.swygbro.trip.backend.domain.chat.dto.ChatRoomRequest;
import com.swygbro.trip.backend.domain.user.domain.User;
import com.swygbro.trip.backend.domain.user.domain.UserRepository;
import com.swygbro.trip.backend.domain.user.excepiton.UserNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@RequiredArgsConstructor
public class ChatService {
private final ChatRoomRepository chatRoomRepository;
private final UserRepository userRepository;
private final ChatHistoryService chatHistoryService;

public List<ChatDto> joinChatRoom(User user, ChatRoomRequest chatRoomRequest) {
User guide = userRepository.findByEmail(chatRoomRequest.getEmail()).orElseThrow(
() -> new UserNotFoundException(chatRoomRequest.getEmail())
);

ChatRoom chatRoom = chatRoomRepository.findChatRoomByClientAndGuide(user.getId(), guide.getId());
if (chatRoom == null) {
chatRoom = ChatRoom.builder()
.client(user)
.guide(guide)
.build();
chatRoom = chatRoomRepository.save(chatRoom);
return List.of();
}

return chatHistoryService.getChatHistory(chatRoom.getId());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.swygbro.trip.backend.domain.chat.domain;

import com.swygbro.trip.backend.domain.chat.dto.MessageType;
import jakarta.persistence.Id;
import lombok.Builder;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.mongodb.core.mapping.Document;

import java.time.LocalDateTime;

@Document(collection = "chatHistory")
@Builder
@Getter
public class ChatHistory {
@Id
private String id;
private Long chatRoomId;
private Long senderId;
private MessageType messageType;
private String payload;

@CreatedDate
private LocalDateTime createdAt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.swygbro.trip.backend.domain.chat.domain;

import org.springframework.data.mongodb.repository.MongoRepository;

import java.util.List;

public interface ChatHistoryRepository extends MongoRepository<ChatHistory, Long> {
List<ChatHistory> findByChatRoomId(Long chatRoomId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.swygbro.trip.backend.domain.chat.domain;

import com.swygbro.trip.backend.domain.user.domain.User;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class ChatRoom {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
private User client;

@ManyToOne(fetch = FetchType.LAZY)
private User guide;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.swygbro.trip.backend.domain.chat.domain;

public interface ChatRoomCustomRepository {
ChatRoom findChatRoomByClientAndGuide(Long clientId, Long guideId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.swygbro.trip.backend.domain.chat.domain;

import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import static com.swygbro.trip.backend.domain.chat.domain.QChatRoom.chatRoom;

@Repository
@RequiredArgsConstructor
public class ChatRoomCustomRepositoryImpl implements ChatRoomCustomRepository {
private final JPAQueryFactory queryFactory;

@Override
public ChatRoom findChatRoomByClientAndGuide(Long clientId, Long guideId) {
return queryFactory
.selectFrom(chatRoom)
.where(chatRoom.client.id.eq(clientId)
.and(chatRoom.guide.id.eq(guideId)))
.fetchOne();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.swygbro.trip.backend.domain.chat.domain;

import org.springframework.data.jpa.repository.JpaRepository;

public interface ChatRoomRepository extends JpaRepository<ChatRoom, Long>, ChatRoomCustomRepository {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.swygbro.trip.backend.domain.chat.dto;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ChatDto {
@JsonFormat(shape = JsonFormat.Shape.STRING)
private String senderEmail;

@JsonFormat(shape = JsonFormat.Shape.STRING)
private String payload;

@JsonFormat(shape = JsonFormat.Shape.STRING)
private MessageType type;

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
private LocalDateTime createdAt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.swygbro.trip.backend.domain.chat.dto;

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


@Getter
public class ChatRequest {

@Schema(description = "채팅방 ID", example = "1")
private Long chatRoomId;

@Schema(description = "메시지를 보낸 사용자 Email", example = "[email protected]")
private String senderEmail;

@Schema(description = "메시지", example = "Hello, World!")
private String payload;

@Schema(description = "메시지 타입", example = "MESSAGE")
private MessageType type;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.swygbro.trip.backend.domain.chat.dto;

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

@Getter
public class ChatRoomRequest {
@Schema(description = "채팅 생성을 위한 가이드 Email", example = "[email protected]")
private String email;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.swygbro.trip.backend.domain.chat.dto;

public enum MessageType {
MESSAGE,
NOTICE
}
Loading