Skip to content

Commit

Permalink
Merge pull request #8 from byeolhaha/feat/1
Browse files Browse the repository at this point in the history
feat : 상담원 회원가입, 로그인, 상담 완료 구현 및 Etag와 로컬 캐시 적용
  • Loading branch information
byeolhaha authored May 13, 2024
2 parents b669966 + bb61622 commit 0159213
Show file tree
Hide file tree
Showing 45 changed files with 1,389 additions and 78 deletions.
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ dependencies {
// Aho-corasick algorithm
implementation 'org.ahocorasick:ahocorasick:0.6.3'

// caffeine 캐시
implementation 'org.springframework.boot:spring-boot-starter-cache'
implementation 'com.github.ben-manes.caffeine:caffeine'

}
ext {
set('springCloudVersion', "2022.0.3")
Expand Down
45 changes: 44 additions & 1 deletion src/docs/asciidoc/members.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,47 @@ include::{snippets}/match-consultant/http-request.adoc[]
=== Response (Success)

include::{snippets}/match-consultant/http-response.adoc[]
include::{snippets}/match-consultant/response-fields.adoc[]
include::{snippets}/match-consultant/response-fields.adoc[]


== 상담원 상담 가능 상태로 바꿔주는 API
상담이 끝나면 상담원의 상담 가능 상태를
UNAVAILABLE에서 AVAILABLE로 바꿔줍니다.

=== Request

include::{snippets}/end-consultation-and-change-available/http-request.adoc[]
include::{snippets}/end-consultation-and-change-available/path-parameters.adoc[]

=== Response (Success)

include::{snippets}/end-consultation-and-change-available/http-response.adoc[]

== 상담원 회원가입 API

상담원 회원가입 API
사원 번호는 미리 받은 상태입니다.

=== Request

include::{snippets}/sign-up-consultant/http-request.adoc[]
include::{snippets}/sign-up-consultant/request-fields.adoc[]

=== Response (Success)

include::{snippets}/sign-up-consultant/http-response.adoc[]
include::{snippets}/sign-up-consultant/response-fields.adoc[]

== 상담원 로그인 API

상담원 로그인 API

=== Request

include::{snippets}/login-consultant/http-request.adoc[]
include::{snippets}/login-consultant/request-fields.adoc[]

=== Response (Success)

include::{snippets}/login-consultant/http-response.adoc[]
include::{snippets}/login-consultant/response-fields.adoc[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.hellomeritz.chat.controller;

import com.hellomeritz.chat.service.BanWordService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@RequestMapping("/banwords")
public class BanWordController {

private final BanWordService banWordService;

public BanWordController(BanWordService banWordService) {
this.banWordService = banWordService;
}

@PatchMapping
public ResponseEntity<Void> uploadBanWord( ) {
banWordService.uploadBanWordsToMemory();

return ResponseEntity.status(HttpStatus.CREATED)
.build();
}

}
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
package com.hellomeritz.chat.controller.dto.request;

import com.hellomeritz.chat.domain.ChatRoomPassword;
import com.hellomeritz.chat.service.dto.param.ChatRoomCreateParam;
import com.hellomeritz.global.encryption.PassWord;
import com.hellomeritz.chat.service.dto.param.ChatRoomPasswordCreateParam;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import org.springframework.web.bind.annotation.PathVariable;

import java.time.LocalDateTime;

Expand All @@ -17,7 +13,7 @@ public record ChatRoomPasswordCreateRequest(

public ChatRoomPasswordCreateParam toChatRoomPasswordCreateParam(Long chatRoomId) {
return new ChatRoomPasswordCreateParam(
ChatRoomPassword.of(chatRoomPassword),
PassWord.of(chatRoomPassword),
chatRoomId,
LocalDateTime.now()
);
Expand Down
18 changes: 2 additions & 16 deletions src/main/java/com/hellomeritz/chat/service/ChatService.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
package com.hellomeritz.chat.service;

import com.hellomeritz.chat.domain.ChatMessage;
import com.hellomeritz.chat.domain.ChatRoom;
import com.hellomeritz.chat.global.stt.SttManager;
import com.hellomeritz.chat.global.stt.SttManagerHandler;
import com.hellomeritz.chat.global.stt.SttProvider;
import com.hellomeritz.chat.global.stt.dto.SttResponse;
import com.hellomeritz.chat.global.translator.TranslateProvider;
import com.hellomeritz.chat.global.translator.TranslationResponse;
import com.hellomeritz.chat.global.translator.Translator;
import com.hellomeritz.chat.global.translator.TranslatorHandler;
import com.hellomeritz.chat.global.uploader.AudioUploadResponse;
import com.hellomeritz.chat.global.uploader.AudioUploader;
import com.hellomeritz.chat.repository.chatentry.ChatRoomEntryLocalRepository;
import com.hellomeritz.chat.repository.chatentry.ChatRoomEntryRepository;
import com.hellomeritz.chat.repository.chatmessage.ChatMessageRepository;
import com.hellomeritz.chat.repository.chatmessage.dto.ChatMessageGetRepositoryResponses;
Expand All @@ -26,13 +14,11 @@
import com.hellomeritz.chat.repository.chatsession.ChatSessionRepository;
import com.hellomeritz.chat.service.dto.param.*;
import com.hellomeritz.chat.service.dto.result.*;
import com.hellomeritz.global.CircuitBreakerBot;
import com.hellomeritz.member.global.IpSensor;
import com.hellomeritz.member.global.encryption.PasswordEncoder;
import com.hellomeritz.member.global.encryption.dto.EncryptionResponse;
import com.hellomeritz.global.encryption.PasswordEncoder;
import com.hellomeritz.global.encryption.dto.EncryptionResponse;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;

import java.util.ArrayList;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.hellomeritz.chat.service.dto.param;

import com.hellomeritz.chat.domain.ChatRoomPassword;
import com.hellomeritz.global.encryption.PassWord;
import com.hellomeritz.chat.repository.chatroom.dto.ChatRoomPasswordInfo;
import com.hellomeritz.member.global.encryption.dto.PasswordMatchRequest;
import com.hellomeritz.global.encryption.dto.PasswordMatchRequest;

import java.time.LocalDateTime;

Expand All @@ -20,7 +20,7 @@ public PasswordMatchRequest toPasswordMatchRequest(ChatRoomPasswordInfo chatRoom

public ChatRoomPasswordCreateParam toChatRoomPasswordCreateRequest() {
return new ChatRoomPasswordCreateParam(
ChatRoomPassword.of(chatRoomPassword),
PassWord.of(chatRoomPassword),
chatRoomId,
LocalDateTime.now()
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
package com.hellomeritz.chat.service.dto.param;

import com.hellomeritz.chat.domain.ChatRoomPassword;
import com.hellomeritz.member.global.encryption.dto.EncryptionRequest;
import com.hellomeritz.global.encryption.PassWord;
import com.hellomeritz.global.encryption.dto.EncryptionRequest;

import java.time.LocalDateTime;

public record ChatRoomPasswordCreateParam(
ChatRoomPassword chatRoomPassWord,
PassWord chatRoomPassWord,
long chatRoomId,
LocalDateTime enterChatRoomDateTime
) {
public EncryptionRequest toEncryptionRequest(String ipAddress) {
return new EncryptionRequest(
chatRoomPassWord.getChatRoomPassword(),
chatRoomPassWord.getPassword(),
ipAddress,
enterChatRoomDateTime
);
Expand Down
39 changes: 34 additions & 5 deletions src/main/java/com/hellomeritz/global/WebConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import com.hellomeritz.member.global.IpSensor;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.CacheControl;
import org.springframework.web.filter.ShallowEtagHeaderFilter;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
Expand All @@ -23,15 +29,38 @@ public WebConfig(ObjectMapper objectMapper) {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH")
.maxAge(3600);
.allowedOriginPatterns("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH")
.maxAge(3600);
}

@Override
public void addInterceptors(InterceptorRegistry registry){
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/")
.setCacheControl(CacheControl.maxAge(10, TimeUnit.SECONDS).mustRevalidate());
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new IpSensor(objectMapper))
.addPathPatterns("/users/*");
.addPathPatterns("/users/*");
registry.addInterceptor(new HandlerInterceptor() {
@Override
@PostConstruct
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (request.getMethod().equals("GET")) {
response.setHeader("Cache-Control", "no-cache");
}
return HandlerInterceptor.super.preHandle(request, response, handler);
}
});
}

@Bean
public ShallowEtagHeaderFilter shallowEtagHeaderFilter() {
return new ShallowEtagHeaderFilter();
}

}
35 changes: 35 additions & 0 deletions src/main/java/com/hellomeritz/global/cache/CacheConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.hellomeritz.global.cache;

import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Configuration
@EnableCaching
public class CacheConfig {

@Bean
public List<CaffeineCache> caffeineCaches() {
return Arrays.stream(CacheType.values())
.map(cache -> new CaffeineCache(cache.getCacheName(), Caffeine.newBuilder().recordStats()
.expireAfterWrite(cache.getExpiredHourAfterWrite(), TimeUnit.HOURS)
.maximumSize(cache.getMaximumSize())
.build()))
.toList();
}
@Bean
public CacheManager cacheManager(List<CaffeineCache> caffeineCaches) {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(caffeineCaches);

return cacheManager;
}
}
19 changes: 19 additions & 0 deletions src/main/java/com/hellomeritz/global/cache/CacheType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.hellomeritz.global.cache;

import lombok.Getter;

@Getter
public enum CacheType {
FOREIGNER_PROFILE("foreigner", 1, 10000),
CONSULTANT_PROFILE("consultant", 3, 1000);

private final String cacheName;
private final int expiredHourAfterWrite;
private final int maximumSize;

CacheType(String cacheName, int expiredHourAfterWrite, int maximumSize) {
this.cacheName = cacheName;
this.expiredHourAfterWrite = expiredHourAfterWrite;
this.maximumSize = maximumSize;
}
}
Original file line number Diff line number Diff line change
@@ -1,47 +1,47 @@
package com.hellomeritz.chat.domain;
package com.hellomeritz.global.encryption;

import lombok.Getter;
import org.springframework.util.Assert;

@Getter
public class ChatRoomPassword {
public class PassWord {

private static final int MIN_PASSWORD_LENGTH = 10;
private String chatRoomPassword;
private String password;

private ChatRoomPassword() {
private PassWord() {
}

private ChatRoomPassword(
String chatRoomPassword
private PassWord(
String password
) {
this.chatRoomPassword = chatRoomPassword;
this.password = password;
}

public static ChatRoomPassword of(
String chatRoomPassword
public static PassWord of(
String password
) {
Assert.hasLength(chatRoomPassword, "비밀번호는 빈값이나 null 일 수 없습니다.");
checkLength(chatRoomPassword);
isContainEngAndSpecialCharAndDigit(chatRoomPassword);
Assert.hasLength(password, "비밀번호는 빈값이나 null 일 수 없습니다.");
checkLength(password);
isContainEngAndSpecialCharAndDigit(password);

return new ChatRoomPassword(chatRoomPassword);
return new PassWord(password);
}

private static void checkLength(String chatRoomPassword) {
int passwordLength = chatRoomPassword.length();
private static void checkLength(String password) {
int passwordLength = password.length();
if (passwordLength < MIN_PASSWORD_LENGTH) {
throw new IllegalArgumentException(String.format("password의 자릿수가 %d를 넘지 않습니다. " +
"현재 자릿수는 %d 입니다.", MIN_PASSWORD_LENGTH, passwordLength));
}
}

private static void isContainEngAndSpecialCharAndDigit(String chatRoomPassword) {
private static void isContainEngAndSpecialCharAndDigit(String password) {
boolean hasEnglish = false;
boolean hasSpecialCharacter = false;
boolean hasDigit = false;

for (char ch : chatRoomPassword.toCharArray()) {
for (char ch : password.toCharArray()) {
if (Character.isLetter(ch)) {
hasEnglish = true;
} else if (Character.isDigit(ch)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package com.hellomeritz.member.global.encryption;
package com.hellomeritz.global.encryption;

import com.hellomeritz.member.global.encryption.dto.EncryptionRequest;
import com.hellomeritz.member.global.encryption.dto.EncryptionResponse;
import com.hellomeritz.member.global.encryption.dto.PasswordMatchRequest;
import com.hellomeritz.member.global.encryption.dto.SaltRequest;
import org.springframework.beans.factory.annotation.Value;
import com.hellomeritz.global.encryption.dto.EncryptionResponse;
import com.hellomeritz.global.encryption.dto.SaltRequest;
import com.hellomeritz.global.encryption.dto.EncryptionRequest;
import com.hellomeritz.global.encryption.dto.PasswordMatchRequest;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKeyFactory;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.hellomeritz.member.global.encryption.dto;
package com.hellomeritz.global.encryption.dto;

import java.time.LocalDateTime;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.hellomeritz.member.global.encryption.dto;
package com.hellomeritz.global.encryption.dto;

public record EncryptionResponse(
String password,
Expand Down
Loading

0 comments on commit 0159213

Please sign in to comment.