Skip to content
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/prod-server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ jobs:
-e JWT_ACCESS_TOKEN_VALIDITY="${{secrets.JWT_ACCESS_TOKEN_VALIDITY}}" \
-e JWT_REFRESH_TOKEN_VALIDITY="${{secrets.JWT_REFRESH_TOKEN_VALIDITY}}" \
-e FRONT_REDIRECT_DOMAIN="${{secrets.FRONT_REDIRECT_DOMAIN}}" \
-e ELASTIC_HOST="${{secrets.PROD_ELASTIC_HOST}}" \
ghcr.io/${{ github.repository }}/zoopzoop:latest


Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test-server-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ jobs:
-e JWT_ACCESS_TOKEN_VALIDITY="${{secrets.JWT_ACCESS_TOKEN_VALIDITY}}" \
-e JWT_REFRESH_TOKEN_VALIDITY="${{secrets.JWT_REFRESH_TOKEN_VALIDITY}}" \
-e FRONT_REDIRECT_DOMAIN="${{secrets.FRONT_REDIRECT_DOMAIN}}" \
-e ELASTIC_HOST="${{secrets.TEST_ELASTIC_HOST}}" \
ghcr.io/${{ github.repository }}/zoopzoop:latest

# 헬스체크
Expand Down
15 changes: 13 additions & 2 deletions .github/workflows/test-server-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@ jobs:
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}


# CI 작업이 실행되는 동안 RabbitMQ 서비스 컨테이너를 함께 실행
services:
# CI 작업이 실행되는 동안 RabbitMQ 서비스 컨테이너를 함께 실행
rabbitmq:
image: rabbitmq:3-management
ports:
Expand All @@ -37,6 +36,16 @@ jobs:
--health-timeout 5s
--health-retries 5

# CI 작업이 실행되는 동안 ElasticSearch 서비스 컨테이너 함께 실행
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.18.5
ports:
- 9200:9200
options: >-
--env discovery.type=single-node
--env xpack.security.enabled=false
--env ES_JAVA_OPTS="-Xms512m -Xmx512m"

steps:
# 1. 소스 코드 체크아웃
- name: Checkout source code
Expand Down Expand Up @@ -73,6 +82,8 @@ jobs:
SPRING_RABBITMQ_HOST: localhost
SPRING_RABBITMQ_USERNAME: guest
SPRING_RABBITMQ_PASSWORD: guest
SPRING_DATA_ELASTICSEARCH_HOST: localhost
SPRING_DATA_ELASTICSEARCH_PORT: 9200
KAKAO_CLIENT_ID: ${{ secrets.OAUTH_KAKAO_CLIENT_ID }}
GOOGLE_CLIENT_ID: ${{ secrets.OAUTH_GOOGLE_CLIENT_ID }}
GOOGLE_CLIENT_SECRET: ${{ secrets.OAUTH_GOOGLE_CLIENT_SECRET }}
Expand Down
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ dependencies {

// Awaitility (비동기 테스트 지원)
testImplementation 'org.awaitility:awaitility:4.2.0'

// Elastic Search
implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'
}

dependencyManagement {
Expand Down
14 changes: 14 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,19 @@ services:
volumes:
- rabbitmq-data:/var/lib/rabbitmq

elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.18.5
container_name: local-elasticsearch
ports:
- "9200:9200"
environment:
discovery.type: single-node
xpack.security.enabled: "false"
ES_JAVA_OPTS: "-Xms512m -Xmx512m"
restart: unless-stopped
volumes:
- elasticsearch-data:/usr/share/elasticsearch/data

volumes:
rabbitmq-data:
elasticsearch-data:
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,16 @@ public void onAuthenticationFailure(HttpServletRequest request,
String source = request.getParameter("source");

if("extension".equals(source)){
String redirectUrl = redirect_domain + "/extension/callback "
String redirectUrl =
"https://" + redirect_domain + "/extension/callback "
+ "?success=false"
+ "&error=" + URLEncoder.encode(exception.getMessage(), "UTF-8");
response.sendRedirect(redirectUrl);
return;
}

String redirectUrl =
redirect_domain + "/auth/callback"
"https://" + redirect_domain + "/auth/callback"
+ "?success=false"
+ "&error=" + URLEncoder.encode(exception.getMessage(), "UTF-8");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
// 확장 프로그램에서 로그인 했을 경우.
if ("extension".equals(source)) {
authResult.put(customState, accessToken, sessionId);
response.sendRedirect(redirect_domain + "/extension/success");
response.sendRedirect("https://" + redirect_domain + "/extension/success");
response.flushBuffer();
return;
}
Expand Down Expand Up @@ -132,7 +132,7 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo

// 로그인 성공 후 리다이렉트.
// 배포 시에 프론트엔드와 조율이 필요한 부분일 듯 함.
response.sendRedirect(redirect_domain + "/api/auth/callback");
response.sendRedirect("https://" + redirect_domain + "/api/auth/callback");
}
// 보안을 좀 더 강화하고자 한다면 CSRF 토큰 같은 걸 생각해볼 수 있겠으나,
// 일단은 구현하지 않음.(개발 과정 중에 번거로워질 수 있을 듯 함.)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.tuna.zoopzoop.backend.domain.member.controller;

import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.tuna.zoopzoop.backend.domain.member.dto.res.ResBodyForSearchMember;
import org.tuna.zoopzoop.backend.domain.member.entity.MemberDocument;
import org.tuna.zoopzoop.backend.domain.member.service.MemberSearchService;
import org.tuna.zoopzoop.backend.domain.member.service.MemberService;
import org.tuna.zoopzoop.backend.global.rsData.RsData;

import java.util.List;

@RestController
@RequiredArgsConstructor
@RequestMapping("api/v1/member")
public class ApiV1MemberSearchController {
private final MemberSearchService memberSearchService;
private final MemberService memberService;

@GetMapping("/search")
public ResponseEntity<RsData<List<ResBodyForSearchMember>>> searchMembers(
@RequestParam String keyword
) {
List<MemberDocument> memberDocuments = memberSearchService.searchByName(keyword);
List<ResBodyForSearchMember> memberDtos = memberDocuments.stream()
.map(ResBodyForSearchMember::new)
.toList();
return ResponseEntity
.status(HttpStatus.OK)
.body(
new RsData<>(
"200",
"검색 조건에 맞는 사용자들을 조회 했습니다.",
memberDtos
)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.tuna.zoopzoop.backend.domain.member.dto.res;

import org.tuna.zoopzoop.backend.domain.member.entity.MemberDocument;

public record ResBodyForSearchMember(
int id,
String name
) {
public ResBodyForSearchMember(int id, String name) {
this.id = id;
this.name = name;
}
public ResBodyForSearchMember(MemberDocument memberDocument){
this(memberDocument.getId(), memberDocument.getName());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.tuna.zoopzoop.backend.domain.member.entity;

import jakarta.persistence.Id;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.Setting;

@Document(indexName = "member")
@Setting(settingPath = "ngram.json")
@Getter
@Setter
public class MemberDocument {
@Id
private int id;

@Field(type = FieldType.Text, analyzer = "ngram_analyzer", searchAnalyzer = "standard")
private String name;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.tuna.zoopzoop.backend.domain.member.repository;

import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.tuna.zoopzoop.backend.domain.member.entity.MemberDocument;

import java.util.List;

public interface MemberSearchRepository extends ElasticsearchRepository<MemberDocument, Integer> {
List<MemberDocument> findByNameContaining(String name);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.tuna.zoopzoop.backend.domain.member.service;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.tuna.zoopzoop.backend.domain.member.entity.MemberDocument;
import org.tuna.zoopzoop.backend.domain.member.repository.MemberSearchRepository;

import java.util.List;

@Service
@RequiredArgsConstructor
public class MemberSearchService {
private final MemberSearchRepository memberSearchRepository;

public List<MemberDocument> searchByName(String name) {
return memberSearchRepository.findByNameContaining(name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
import org.tuna.zoopzoop.backend.domain.datasource.repository.DataSourceRepository;
import org.tuna.zoopzoop.backend.domain.datasource.repository.TagRepository;
import org.tuna.zoopzoop.backend.domain.member.entity.Member;
import org.tuna.zoopzoop.backend.domain.member.entity.MemberDocument;
import org.tuna.zoopzoop.backend.domain.member.enums.Provider;
import org.tuna.zoopzoop.backend.domain.member.repository.MemberRepository;
import org.tuna.zoopzoop.backend.domain.member.repository.MemberSearchRepository;
import org.tuna.zoopzoop.backend.global.aws.S3Service;

import java.io.IOException;
Expand All @@ -23,6 +25,7 @@
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
private final MemberSearchRepository memberSearchRepository;
private final S3Service s3Service;
private final TagRepository tagRepository;
private final DataSourceRepository dataSourceRepository;
Expand Down Expand Up @@ -83,7 +86,16 @@ public Member createMember(String name, String profileUrl, String key, Provider
.providerKey(key)
.provider(provider)
.build();
return memberRepository.save(member);

Member saved = memberRepository.save(member);

// ElasticSearch용 document 생성.
MemberDocument doc = new MemberDocument();
doc.setId(saved.getId());
doc.setName(saved.getName());
memberSearchRepository.save(doc);

return saved;
}

//사용자 이름 수정
Expand All @@ -94,6 +106,11 @@ public void updateMemberName(Member member, String newName){
}
member.updateName(generateUniqueUserNameTag(newName));
memberRepository.save(member);

MemberDocument doc = new MemberDocument();
doc.setId(member.getId());
doc.setName(member.getName());
memberSearchRepository.save(doc);
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.tuna.zoopzoop.backend.global.config.elasticSearch;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;

@Slf4j
@Configuration
@EnableElasticsearchRepositories(basePackages = "org.springframework.data.elasticsearch.repository")
public class ElasticSearchConfig extends ElasticsearchConfiguration {

@Value("${spring.data.elasticsearch.host}")
private String host;

@Value("${spring.data.elasticsearch.port}")
private int port;

@Override
public ClientConfiguration clientConfiguration() {
log.info("Connecting to Elasticsearch at {}:{}", host, port);
return ClientConfiguration.builder()
.connectedTo(host + ":" + port)
.build();
}
}
6 changes: 6 additions & 0 deletions src/main/resources/application-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ spring:
host: localhost
port: 6379
timeout: 6000
elasticsearch:
host: localhost
port: 9200

security:
oauth2:
Expand All @@ -28,6 +31,9 @@ app:
seed:
enabled: true

front:
redirect_domain: http://localhost:3000

sentry:
send-default-pii: true
environment: local
Expand Down
3 changes: 3 additions & 0 deletions src/main/resources/application-server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ spring:
port: 6379
timeout: 6000
password: ${REDIS_PASSWORD}
elasticsearch:
host: ${ELASTIC_HOST}
port: 9200

cache: #Spring Cache를 사용하기 위한 Redis
type: redis
Expand Down
5 changes: 5 additions & 0 deletions src/main/resources/application-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ spring:
password:
driver-class-name: org.h2.Driver

data:
elasticsearch:
host: localhost
port: 9200

jpa:
hibernate:
ddl-auto: create-drop
Expand Down
18 changes: 18 additions & 0 deletions src/main/resources/ngram.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"analysis": {
"analyzer": {
"ngram_analyzer": {
"tokenizer": "ngram_tokenizer",
"filter": ["lowercase"]
}
},
"tokenizer": {
"ngram_tokenizer": {
"type": "ngram",
"min_gram": 2,
"max_gram": 3,
"token_chars": ["letter", "digit"]
}
}
}
}
Loading