Implement slack
This commit is contained in:
parent
e8ec96ed27
commit
8502b95a7d
|
@ -3,6 +3,7 @@ plugins {
|
||||||
id 'idea'
|
id 'idea'
|
||||||
id 'org.springframework.boot' version '2.5.4'
|
id 'org.springframework.boot' version '2.5.4'
|
||||||
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
|
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
|
||||||
|
id 'com.google.cloud.tools.jib' version '3.4.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
group = 'com.myoa.engineering.crawl.shopping'
|
group = 'com.myoa.engineering.crawl.shopping'
|
||||||
|
@ -19,14 +20,16 @@ repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
subprojects {
|
||||||
group = 'com.myoa.engineering.crawl.shopping'
|
group = 'com.myoa.engineering.crawl.shopping'
|
||||||
version = '1.1.1'
|
version = '1.1.1'
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
|
||||||
apply plugin: 'java'
|
apply plugin: 'java'
|
||||||
apply plugin: 'idea'
|
apply plugin: 'idea'
|
||||||
apply plugin: 'org.springframework.boot'
|
apply plugin: 'org.springframework.boot'
|
||||||
apply plugin: 'io.spring.dependency-management'
|
apply plugin: 'io.spring.dependency-management'
|
||||||
|
apply plugin: "com.google.cloud.tools.jib"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
@ -37,8 +40,11 @@ allprojects {
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
set('springCloudVersion', "2020.0.4")
|
set('springCloudVersion', "2020.0.4")
|
||||||
|
set("BASE_IMAGE_REGISTRY_URL", "192.168.0.10:10001")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply from: "${project.rootDir}/jib.gradle"
|
||||||
|
|
||||||
dependencyManagement {
|
dependencyManagement {
|
||||||
imports {
|
imports {
|
||||||
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
|
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
|
||||||
|
|
|
@ -4,3 +4,7 @@ distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
org.gradle.caching=true
|
||||||
|
org.gradle.parallel=true
|
||||||
|
org.gradle.parallel.threads=4
|
||||||
|
org.gradle.daemon=true
|
|
@ -0,0 +1,28 @@
|
||||||
|
jib.setAllowInsecureRegistries(true)
|
||||||
|
|
||||||
|
jib {
|
||||||
|
from {
|
||||||
|
image = "eclipse-temurin:17-jdk"
|
||||||
|
platforms {
|
||||||
|
platform {
|
||||||
|
architecture = "amd64"
|
||||||
|
os = "linux"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
image = "${BASE_IMAGE_REGISTRY_URL}/${project.name}"
|
||||||
|
tags = ["latest"]
|
||||||
|
}
|
||||||
|
container {
|
||||||
|
// entrypoint = ["INHERIT"]
|
||||||
|
creationTime = "USE_CURRENT_TIMESTAMP"
|
||||||
|
environment = [
|
||||||
|
"TZ": "Asia/Seoul",
|
||||||
|
]
|
||||||
|
jvmFlags = [
|
||||||
|
"--add-opens=java.base/java.time=ALL-UNNAMED"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -24,7 +24,7 @@ public class H2ConsoleConfiguration {
|
||||||
@EventListener(ContextRefreshedEvent.class)
|
@EventListener(ContextRefreshedEvent.class)
|
||||||
public void start() throws SQLException {
|
public void start() throws SQLException {
|
||||||
log.info("starting h2 console");
|
log.info("starting h2 console");
|
||||||
this.webServer = Server.createWebServer("-webPort", port, "-tcpAllowOthers").start();
|
this.webServer = Server.createWebServer("-webPort", port, "-tcpAllowOthers", "-webAllowOthers").start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventListener(ContextClosedEvent.class)
|
@EventListener(ContextClosedEvent.class)
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.myoa.engineering.crawl.shopping.configuration.web;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.converter.HttpMessageConverter;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebConfiguration implements WebMvcConfigurer {
|
||||||
|
/*
|
||||||
|
@Override
|
||||||
|
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
|
||||||
|
WebMvcConfigurer.super.configureMessageConverters(converters);
|
||||||
|
addJsonFormUrlEncodedConverter(converters);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addJsonFormUrlEncodedConverter(List<HttpMessageConverter<?>> converters) {
|
||||||
|
JsonFormUrlEncodedConverter<?> converter = new JsonFormUrlEncodedConverter<>();
|
||||||
|
MediaType mediaType = new MediaType(MediaType.APPLICATION_FORM_URLENCODED, StandardCharsets.UTF_8);
|
||||||
|
converter.setSupportedMediaTypes(List.of(mediaType));
|
||||||
|
converters.add(converter);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package com.myoa.engineering.crawl.shopping.controller;
|
||||||
|
|
||||||
|
import com.myoa.engineering.crawl.shopping.dto.slack.v2.SlackEventSubscriptionDTO;
|
||||||
|
import com.myoa.engineering.crawl.shopping.dto.slack.v2.SlackSlashCommandDTO;
|
||||||
|
import com.myoa.engineering.crawl.shopping.service.slack.RegisterCommandHandler;
|
||||||
|
import com.myoa.engineering.crawl.shopping.service.slack.ShoppingCommandHandler;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/slack")
|
||||||
|
public class SlackEventSubscriptionAPIController {
|
||||||
|
|
||||||
|
private final ShoppingCommandHandler shoppingCommandHandler;
|
||||||
|
private final RegisterCommandHandler registerCommandHandler;
|
||||||
|
|
||||||
|
public SlackEventSubscriptionAPIController(ShoppingCommandHandler shoppingCommandHandler,
|
||||||
|
RegisterCommandHandler registerCommandHandler) {
|
||||||
|
this.shoppingCommandHandler = shoppingCommandHandler;
|
||||||
|
this.registerCommandHandler = registerCommandHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = {"/subscriptions"})
|
||||||
|
private ResponseEntity<String> slackEventSubscription(@RequestBody SlackEventSubscriptionDTO requestDTO) {
|
||||||
|
log.info("requestDTO: {}", requestDTO);
|
||||||
|
return ResponseEntity.ok(requestDTO.getChallenge());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = {"/commands/help"}, consumes = {"application/x-www-form-urlencoded"})
|
||||||
|
private ResponseEntity<String> handleCommandHelp(SlackSlashCommandDTO requestDTO) {
|
||||||
|
log.info("requestDTO: {}", requestDTO);
|
||||||
|
return ResponseEntity.ok("""
|
||||||
|
/쇼핑 목록
|
||||||
|
/쇼핑 키워드 추가 (쇼핑몰명) (키워드명)
|
||||||
|
/쇼핑 키워드 삭제 (쇼핑몰명) (키워드명)
|
||||||
|
/쇼핑 키워드 목록
|
||||||
|
/등록 (사용자명)
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = {"/commands/shopping"}, consumes = {"application/x-www-form-urlencoded"})
|
||||||
|
private ResponseEntity<String> handleAddSubscription(SlackSlashCommandDTO requestDTO) {
|
||||||
|
log.info("requestDTO: {}", requestDTO);
|
||||||
|
|
||||||
|
List<String> results = shoppingCommandHandler.handle(requestDTO);
|
||||||
|
|
||||||
|
return ResponseEntity.ok(String.join("\n", results));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = {"/commands/register"}, consumes = {"application/x-www-form-urlencoded"})
|
||||||
|
private ResponseEntity<String> handleRegisterUser(SlackSlashCommandDTO requestDTO) {
|
||||||
|
log.info("requestDTO: {}", requestDTO);
|
||||||
|
|
||||||
|
List<String> results = registerCommandHandler.handle(requestDTO);
|
||||||
|
|
||||||
|
return ResponseEntity.ok(String.join("\n", results));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,22 +1,36 @@
|
||||||
package com.myoa.engineering.crawl.shopping.controller;
|
package com.myoa.engineering.crawl.shopping.controller;
|
||||||
|
|
||||||
import com.myoa.engineering.crawl.shopping.crawlhandler.PpomppuCrawlDomesticHandler;
|
import com.myoa.engineering.crawl.shopping.crawlhandler.PpomppuCrawlDomesticHandler;
|
||||||
|
import com.slack.api.methods.MethodsClient;
|
||||||
|
import com.slack.api.methods.SlackApiException;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/exploit")
|
@RequestMapping("/api/v1/exploit")
|
||||||
public class TestAPIController {
|
public class TestAPIController {
|
||||||
|
|
||||||
private final PpomppuCrawlDomesticHandler ppomppuCrawlDomesticHandler;
|
private final PpomppuCrawlDomesticHandler ppomppuCrawlDomesticHandler;
|
||||||
|
private final MethodsClient methodsClient;
|
||||||
|
|
||||||
public TestAPIController(PpomppuCrawlDomesticHandler ppomppuCrawlDomesticHandler) {
|
public TestAPIController(PpomppuCrawlDomesticHandler ppomppuCrawlDomesticHandler,
|
||||||
|
MethodsClient methodsClient) {
|
||||||
this.ppomppuCrawlDomesticHandler = ppomppuCrawlDomesticHandler;
|
this.ppomppuCrawlDomesticHandler = ppomppuCrawlDomesticHandler;
|
||||||
|
this.methodsClient = methodsClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/triggers")
|
@GetMapping("/triggers")
|
||||||
public void triggerExploit() {
|
public void triggerExploit() {
|
||||||
ppomppuCrawlDomesticHandler.handle();
|
ppomppuCrawlDomesticHandler.handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/test-message")
|
||||||
|
public void testMessage() throws SlackApiException, IOException {
|
||||||
|
methodsClient.chatPostMessage(req -> req
|
||||||
|
.channel("notify_shopping")
|
||||||
|
.text("Hello, World!"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.myoa.engineering.crawl.shopping.dto.feed.v1;
|
||||||
|
|
||||||
|
import com.myoa.engineering.crawl.shopping.support.dto.constant.CrawlTarget;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class SubscribedKeywordDTO {
|
||||||
|
|
||||||
|
private String userId;
|
||||||
|
private CrawlTarget crawlTarget;
|
||||||
|
private String keyword;
|
||||||
|
|
||||||
|
|
||||||
|
public String toMessage() {
|
||||||
|
return crawlTarget.getAlias() + " | " + keyword;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.myoa.engineering.crawl.shopping.dto.slack.v2;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ToString
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class SlackEventSubscriptionDTO {
|
||||||
|
|
||||||
|
private String token;
|
||||||
|
private String challenge;
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@JsonProperty("team_id")
|
||||||
|
private String teamId;
|
||||||
|
|
||||||
|
@JsonProperty("api_app_id")
|
||||||
|
private String apiAppId;
|
||||||
|
|
||||||
|
private Map<String, Object> event;
|
||||||
|
|
||||||
|
@JsonProperty("event_id")
|
||||||
|
private String eventId;
|
||||||
|
|
||||||
|
@JsonProperty("event_time")
|
||||||
|
private long eventTime;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.myoa.engineering.crawl.shopping.dto.slack.v2;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@ToString
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class SlackSlashCommandDTO {
|
||||||
|
|
||||||
|
private String token;
|
||||||
|
private String command;
|
||||||
|
private String text;
|
||||||
|
private String response_url;
|
||||||
|
private String trigger_id;
|
||||||
|
private String user_id;
|
||||||
|
private String user_name;
|
||||||
|
private String team_id;
|
||||||
|
private String api_app_id;
|
||||||
|
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ import com.myoa.engineering.crawl.shopping.domain.model.v2.SubscribedKeywordAggr
|
||||||
import com.myoa.engineering.crawl.shopping.event.ArticleUpsertEvent;
|
import com.myoa.engineering.crawl.shopping.event.ArticleUpsertEvent;
|
||||||
import com.myoa.engineering.crawl.shopping.service.AppUserQueryService;
|
import com.myoa.engineering.crawl.shopping.service.AppUserQueryService;
|
||||||
import com.myoa.engineering.crawl.shopping.service.SubscribedKeywordCacheService;
|
import com.myoa.engineering.crawl.shopping.service.SubscribedKeywordCacheService;
|
||||||
import com.myoa.engineering.crawl.shopping.service.UserNotifyService;
|
import com.myoa.engineering.crawl.shopping.service.slack.UserNotifyService;
|
||||||
import com.myoa.engineering.crawl.shopping.support.dto.constant.CrawlTarget;
|
import com.myoa.engineering.crawl.shopping.support.dto.constant.CrawlTarget;
|
||||||
import org.springframework.context.event.EventListener;
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
@ -44,7 +44,7 @@ public class ArticleUpsertEventListener {
|
||||||
.filter(AppUserModel::getEnabled)
|
.filter(AppUserModel::getEnabled)
|
||||||
.map(user -> {
|
.map(user -> {
|
||||||
List<ArticleModel> filteredArticles = handleAhoCorasick(articleMap)
|
List<ArticleModel> filteredArticles = handleAhoCorasick(articleMap)
|
||||||
.apply(subscribedKeywordCacheService.getSubscribedKeywordsCached(user.getName()));
|
.apply(subscribedKeywordCacheService.getSubscribedKeywordsCached(user.getSlackId()));
|
||||||
return UserNotifyModel.of(user.getSlackId(), filteredArticles);
|
return UserNotifyModel.of(user.getSlackId(), filteredArticles);
|
||||||
})
|
})
|
||||||
.forEach(this::notifyMessage);
|
.forEach(this::notifyMessage);
|
||||||
|
|
|
@ -4,6 +4,9 @@ import com.myoa.engineering.crawl.shopping.domain.entity.v2.AppUser;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface AppUserRepository extends JpaRepository<AppUser, Long> {
|
public interface AppUserRepository extends JpaRepository<AppUser, Long> {
|
||||||
|
Optional<AppUser> findBySlackId(String userId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface SubscribedKeywordRepository extends JpaRepository<SubscribedKeyword, Long> {
|
public interface SubscribedKeywordRepository extends JpaRepository<SubscribedKeyword, Long> {
|
||||||
|
@ -20,4 +21,6 @@ public interface SubscribedKeywordRepository extends JpaRepository<SubscribedKey
|
||||||
List<SubscribedKeyword> findByUserIdAndCrawlTarget(String userId, CrawlTarget crawlTarget);
|
List<SubscribedKeyword> findByUserIdAndCrawlTarget(String userId, CrawlTarget crawlTarget);
|
||||||
|
|
||||||
List<SubscribedKeyword> findByUserId(String userId);
|
List<SubscribedKeyword> findByUserId(String userId);
|
||||||
|
|
||||||
|
Optional<SubscribedKeyword> findByUserIdAndCrawlTargetAndKeyword(String userId, CrawlTarget crawlTarget, String keyword);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.myoa.engineering.crawl.shopping.service;
|
||||||
|
|
||||||
|
import com.myoa.engineering.crawl.shopping.domain.entity.v2.AppUser;
|
||||||
|
import com.myoa.engineering.crawl.shopping.infra.repository.v2.AppUserRepository;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class AppUserCommandService {
|
||||||
|
private final AppUserRepository appUserRepository;
|
||||||
|
|
||||||
|
public AppUserCommandService(AppUserRepository appUserRepository) {
|
||||||
|
this.appUserRepository = appUserRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void register(String slackId, String userName) {
|
||||||
|
appUserRepository.findBySlackId(slackId)
|
||||||
|
.ifPresent(user -> {
|
||||||
|
throw new IllegalArgumentException("이미 등록된 사용자입니다.");
|
||||||
|
});
|
||||||
|
|
||||||
|
AppUser appUser = AppUser.builder()
|
||||||
|
.enabled(true)
|
||||||
|
.slackId(slackId)
|
||||||
|
.name(userName)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
appUserRepository.save(appUser);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ package com.myoa.engineering.crawl.shopping.service;
|
||||||
import com.myoa.engineering.crawl.shopping.domain.model.v2.AppUserModel;
|
import com.myoa.engineering.crawl.shopping.domain.model.v2.AppUserModel;
|
||||||
import com.myoa.engineering.crawl.shopping.infra.repository.v2.AppUserRepository;
|
import com.myoa.engineering.crawl.shopping.infra.repository.v2.AppUserRepository;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -15,6 +16,7 @@ public class AppUserQueryService {
|
||||||
this.appUserRepository = appUserRepository;
|
this.appUserRepository = appUserRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
public List<AppUserModel> findAll() {
|
public List<AppUserModel> findAll() {
|
||||||
return appUserRepository.findAll()
|
return appUserRepository.findAll()
|
||||||
.stream()
|
.stream()
|
||||||
|
@ -22,4 +24,11 @@ public class AppUserQueryService {
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public AppUserModel findByUserId(String userId) {
|
||||||
|
return appUserRepository.findBySlackId(userId)
|
||||||
|
.map(AppUserModel::from)
|
||||||
|
.orElseThrow();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,15 +27,15 @@ public class SubscribedKeywordCacheService {
|
||||||
return SubscribedKeywordAggregatedModel.of(userId, crawlTarget, keywords);
|
return SubscribedKeywordAggregatedModel.of(userId, crawlTarget, keywords);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Cacheable(cacheNames = "subscribe.keywords", key = "#userId")
|
@Cacheable(cacheNames = "subscribe.keywords", key = "#slackId")
|
||||||
public Map<CrawlTarget, SubscribedKeywordAggregatedModel> getSubscribedKeywordsCached(String userId) {
|
public Map<CrawlTarget, SubscribedKeywordAggregatedModel> getSubscribedKeywordsCached(String slackId) {
|
||||||
System.out.println("getSubscribedKeywordsCached");
|
System.out.println("getSubscribedKeywordsCached");
|
||||||
return subscribedKeywordQueryService.findByUser(userId)
|
return subscribedKeywordQueryService.findByUser(slackId)
|
||||||
.stream()
|
.stream()
|
||||||
.collect(Collectors.groupingBy(SubscribedKeyword::getCrawlTarget,
|
.collect(Collectors.groupingBy(SubscribedKeyword::getCrawlTarget,
|
||||||
Collectors.mapping(SubscribedKeyword::getKeyword, Collectors.toList())))
|
Collectors.mapping(SubscribedKeyword::getKeyword, Collectors.toList())))
|
||||||
.entrySet().stream()
|
.entrySet().stream()
|
||||||
.collect(Collectors.toMap(Map.Entry::getKey, e -> SubscribedKeywordAggregatedModel.of(userId, e.getKey(), e.getValue())));
|
.collect(Collectors.toMap(Map.Entry::getKey, e -> SubscribedKeywordAggregatedModel.of(slackId, e.getKey(), e.getValue())));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
package com.myoa.engineering.crawl.shopping.service;
|
||||||
|
|
||||||
|
import com.myoa.engineering.crawl.shopping.domain.entity.v2.SubscribedKeyword;
|
||||||
|
import com.myoa.engineering.crawl.shopping.dto.feed.v1.SubscribedKeywordDTO;
|
||||||
|
import com.myoa.engineering.crawl.shopping.infra.repository.v2.SubscribedKeywordRepository;
|
||||||
|
import com.myoa.engineering.crawl.shopping.support.dto.constant.CrawlTarget;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class SubscribedKeywordCommandService {
|
||||||
|
|
||||||
|
private final SubscribedKeywordRepository subscribedKeywordRepository;
|
||||||
|
|
||||||
|
public SubscribedKeywordCommandService(SubscribedKeywordRepository subscribedKeywordRepository) {
|
||||||
|
this.subscribedKeywordRepository = subscribedKeywordRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void add(SubscribedKeyword subscribedKeyword) {
|
||||||
|
subscribedKeywordRepository.save(subscribedKeyword);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void delete(String userId, CrawlTarget crawlTarget, String keyword) {
|
||||||
|
SubscribedKeyword subscribedKeyword = subscribedKeywordRepository.findByUserIdAndCrawlTargetAndKeyword(userId, crawlTarget, keyword)
|
||||||
|
.orElseThrow(() -> new IllegalArgumentException("Not found keyword: " + keyword));
|
||||||
|
|
||||||
|
subscribedKeywordRepository.delete(subscribedKeyword);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public List<SubscribedKeywordDTO> list(String userId) {
|
||||||
|
return subscribedKeywordRepository.findByUserId(userId)
|
||||||
|
.stream()
|
||||||
|
.map(e -> SubscribedKeywordDTO.builder()
|
||||||
|
.keyword(e.getKeyword())
|
||||||
|
.userId(e.getUserId())
|
||||||
|
.crawlTarget(e.getCrawlTarget())
|
||||||
|
.build())
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,34 +0,0 @@
|
||||||
package com.myoa.engineering.crawl.shopping.service;
|
|
||||||
|
|
||||||
import com.myoa.engineering.crawl.shopping.configuration.slack.properties.SlackSecretProperties;
|
|
||||||
import com.myoa.engineering.crawl.shopping.dto.slack.v1.SlackMessageDTO;
|
|
||||||
import com.myoa.engineering.crawl.shopping.infra.client.slack.SlackAPIClient;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class UserNotifyService {
|
|
||||||
|
|
||||||
private static final String SLACK_PROPERTIES_UNIT_NAME = "shopping-crawler";
|
|
||||||
// private static final String NOTIFY_CHANNEL_ID = "notify_shopping";
|
|
||||||
// private static final String NOTIFY_ICON_EMOJI = ":monge_big:";
|
|
||||||
// private static final String NOTIFY_BOT_NAME = "몽이 탈호구봇";
|
|
||||||
|
|
||||||
private final SlackAPIClient slackAPIClient;
|
|
||||||
private final SlackSecretProperties.SlackSecretPropertiesUnit slackSecretProperties;
|
|
||||||
|
|
||||||
public UserNotifyService(SlackAPIClient slackAPIClient,
|
|
||||||
SlackSecretProperties slackSecretProperties) {
|
|
||||||
this.slackAPIClient = slackAPIClient;
|
|
||||||
this.slackSecretProperties = slackSecretProperties.find(SLACK_PROPERTIES_UNIT_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void notify(String message) {
|
|
||||||
SlackMessageDTO slackMessageDTO = SlackMessageDTO.builder()
|
|
||||||
.channel(slackSecretProperties.getChannel())
|
|
||||||
.text(message)
|
|
||||||
.iconEmoji(slackSecretProperties.getIconEmoji())
|
|
||||||
.username(slackSecretProperties.getUsername())
|
|
||||||
.build();
|
|
||||||
slackAPIClient.sendMessage(slackMessageDTO, slackSecretProperties.getToken());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.myoa.engineering.crawl.shopping.service.slack;
|
||||||
|
|
||||||
|
import com.myoa.engineering.crawl.shopping.dto.slack.v2.SlackSlashCommandDTO;
|
||||||
|
import com.myoa.engineering.crawl.shopping.service.AppUserCommandService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class RegisterCommandHandler implements SlackCommandHandler {
|
||||||
|
|
||||||
|
private final AppUserCommandService appUserCommandService;
|
||||||
|
|
||||||
|
public RegisterCommandHandler(AppUserCommandService appUserCommandService) {
|
||||||
|
this.appUserCommandService = appUserCommandService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> handle(SlackSlashCommandDTO requestDTO) {
|
||||||
|
if (!requestDTO.getCommand().equals("/등록")) {
|
||||||
|
throw new IllegalArgumentException("Invalid command: " + requestDTO.getCommand());
|
||||||
|
}
|
||||||
|
|
||||||
|
final String userName = requestDTO.getText();
|
||||||
|
|
||||||
|
try {
|
||||||
|
appUserCommandService.register(requestDTO.getUser_id(), userName);
|
||||||
|
return List.of("등록 완료");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return List.of(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package com.myoa.engineering.crawl.shopping.service.slack;
|
||||||
|
|
||||||
|
import com.myoa.engineering.crawl.shopping.dto.slack.v2.SlackSlashCommandDTO;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ShoppingCommandHandler implements SlackCommandHandler {
|
||||||
|
|
||||||
|
private final List<ShoppingCommandProcessor> processors;
|
||||||
|
|
||||||
|
public ShoppingCommandHandler(List<ShoppingCommandProcessor> processors) {
|
||||||
|
this.processors = processors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> handle(SlackSlashCommandDTO requestDTO) {
|
||||||
|
String[] commands = requestDTO.getText().split("\\s+", 2);
|
||||||
|
|
||||||
|
if (!requestDTO.getCommand().equals("/쇼핑")) {
|
||||||
|
throw new IllegalArgumentException("Invalid command: " + requestDTO.getCommand());
|
||||||
|
}
|
||||||
|
|
||||||
|
final String action = commands[0];
|
||||||
|
|
||||||
|
return processors.stream()
|
||||||
|
.filter(processor -> processor.isAssignable(action))
|
||||||
|
.map(processor -> processor.process(requestDTO))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.myoa.engineering.crawl.shopping.service.slack;
|
||||||
|
|
||||||
|
import com.myoa.engineering.crawl.shopping.dto.slack.v2.SlackSlashCommandDTO;
|
||||||
|
|
||||||
|
public interface ShoppingCommandProcessor {
|
||||||
|
|
||||||
|
boolean isAssignable(String menuContext);
|
||||||
|
|
||||||
|
String process(SlackSlashCommandDTO requestDTO);
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package com.myoa.engineering.crawl.shopping.service.slack;
|
||||||
|
|
||||||
|
public interface SlackCommandHandler {
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.myoa.engineering.crawl.shopping.service.slack;
|
||||||
|
|
||||||
|
import com.myoa.engineering.crawl.shopping.configuration.slack.properties.SlackSecretProperties;
|
||||||
|
import com.slack.api.methods.MethodsClient;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class UserNotifyService {
|
||||||
|
|
||||||
|
private static final String SLACK_PROPERTIES_UNIT_NAME = "shopping-crawler";
|
||||||
|
|
||||||
|
private final SlackSecretProperties.SlackSecretPropertiesUnit slackSecretProperties;
|
||||||
|
private final MethodsClient methodsClient;
|
||||||
|
|
||||||
|
public UserNotifyService(SlackSecretProperties slackSecretProperties,
|
||||||
|
MethodsClient methodsClient) {
|
||||||
|
this.slackSecretProperties = slackSecretProperties.find(SLACK_PROPERTIES_UNIT_NAME);
|
||||||
|
this.methodsClient = methodsClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notify(String message) {
|
||||||
|
try {
|
||||||
|
methodsClient.chatPostMessage(req -> req
|
||||||
|
.channel(slackSecretProperties.getChannel())
|
||||||
|
.username(slackSecretProperties.getUsername())
|
||||||
|
.text(message));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Failed. message: {}", message, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
package com.myoa.engineering.crawl.shopping.service.slack.shopping;
|
||||||
|
|
||||||
|
import com.myoa.engineering.crawl.shopping.domain.entity.v2.SubscribedKeyword;
|
||||||
|
import com.myoa.engineering.crawl.shopping.dto.feed.v1.SubscribedKeywordDTO;
|
||||||
|
import com.myoa.engineering.crawl.shopping.dto.slack.v2.SlackSlashCommandDTO;
|
||||||
|
import com.myoa.engineering.crawl.shopping.service.SubscribedKeywordCommandService;
|
||||||
|
import com.myoa.engineering.crawl.shopping.service.slack.ShoppingCommandProcessor;
|
||||||
|
import com.myoa.engineering.crawl.shopping.support.dto.constant.CrawlTarget;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class KeywordShoppingCommandProcessor implements ShoppingCommandProcessor {
|
||||||
|
|
||||||
|
private final SubscribedKeywordCommandService subscribedKeywordCommandService;
|
||||||
|
|
||||||
|
public KeywordShoppingCommandProcessor(SubscribedKeywordCommandService subscribedKeywordCommandService) {
|
||||||
|
this.subscribedKeywordCommandService = subscribedKeywordCommandService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAssignable(String menuContext) {
|
||||||
|
return menuContext.equals("키워드");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String process(SlackSlashCommandDTO requestDTO) {
|
||||||
|
// "키워드 추가 (쇼핑몰명) (키워드명)"
|
||||||
|
final String[] splited = requestDTO.getText().split("\\s+", 4);
|
||||||
|
|
||||||
|
final String action = splited[1];
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case "추가" -> {
|
||||||
|
final CrawlTarget crawlTarget = CrawlTarget.fromAlias(splited[2]);
|
||||||
|
final String keyword = splited[3];
|
||||||
|
SubscribedKeyword subscribedKeyword =
|
||||||
|
SubscribedKeyword.builder()
|
||||||
|
.crawlTarget(crawlTarget)
|
||||||
|
.userId(requestDTO.getUser_id())
|
||||||
|
.keyword(keyword)
|
||||||
|
.build();
|
||||||
|
subscribedKeywordCommandService.add(subscribedKeyword);
|
||||||
|
return "keyword: [" + keyword + "] 추가완료";
|
||||||
|
}
|
||||||
|
case "삭제" -> {
|
||||||
|
final CrawlTarget crawlTarget = CrawlTarget.fromAlias(splited[2]);
|
||||||
|
final String keyword = splited[3];
|
||||||
|
subscribedKeywordCommandService.delete(requestDTO.getUser_id(), crawlTarget, keyword);
|
||||||
|
return "keyword: [" + keyword + "] 삭제완료";
|
||||||
|
}
|
||||||
|
case "목록" -> {
|
||||||
|
List<SubscribedKeywordDTO> keywords = subscribedKeywordCommandService.list(requestDTO.getUser_id());
|
||||||
|
if (keywords.isEmpty()) {
|
||||||
|
return "등록된 키워드가 없습니다.";
|
||||||
|
}
|
||||||
|
return keywords.stream().map(SubscribedKeywordDTO::toMessage)
|
||||||
|
.collect(Collectors.joining("\n"));
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
return "지원하지 않는 명령어입니다.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.myoa.engineering.crawl.shopping.service.slack.shopping;
|
||||||
|
|
||||||
|
import com.myoa.engineering.crawl.shopping.dto.slack.v2.SlackSlashCommandDTO;
|
||||||
|
import com.myoa.engineering.crawl.shopping.service.slack.ShoppingCommandProcessor;
|
||||||
|
import com.myoa.engineering.crawl.shopping.support.dto.constant.CrawlTarget;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class ListShoppingCommandProcessor implements ShoppingCommandProcessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAssignable(String menuContext) {
|
||||||
|
return menuContext.equals("목록");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String process(SlackSlashCommandDTO requestDTO) {
|
||||||
|
return Stream.of(CrawlTarget.values())
|
||||||
|
.map(e -> e.getAlias() + " | " + e.isAvailable())
|
||||||
|
.collect(Collectors.joining("\n"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +0,0 @@
|
||||||
spring:
|
|
||||||
config:
|
|
||||||
activate:
|
|
||||||
on-profile: development
|
|
||||||
import:
|
|
||||||
- "configserver:http://192.168.0.100:11080"
|
|
||||||
|
|
||||||
|
|
||||||
server:
|
|
||||||
port: 20081
|
|
||||||
|
|
||||||
# import: optional:configserver:http://localhost:11080 # can be start up even config server was not found.
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
spring:
|
||||||
|
config:
|
||||||
|
activate:
|
||||||
|
on-profile: prod
|
||||||
|
import:
|
||||||
|
- classpath:/datasource/prod.yml
|
||||||
|
- classpath:/slack/prod.yml
|
||||||
|
devtools:
|
||||||
|
livereload:
|
||||||
|
enabled: false
|
||||||
|
restart:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
server:
|
||||||
|
port: 20080
|
||||||
|
|
||||||
|
# import: optional:configserver:http://localhost:11080 # can be start up even config server was not found.
|
||||||
|
|
||||||
|
feign:
|
||||||
|
client:
|
||||||
|
config:
|
||||||
|
default:
|
||||||
|
loggerLevel: FULL
|
|
@ -1,6 +0,0 @@
|
||||||
spring:
|
|
||||||
config:
|
|
||||||
activate:
|
|
||||||
on-profile: production
|
|
||||||
import:
|
|
||||||
- "configserver:http://ppn-config-server:20080"
|
|
|
@ -7,8 +7,7 @@ spring:
|
||||||
active: ${SPRING_ACTIVE_PROFILE:local}
|
active: ${SPRING_ACTIVE_PROFILE:local}
|
||||||
group:
|
group:
|
||||||
local: "local,datasource-local,webclient-local"
|
local: "local,datasource-local,webclient-local"
|
||||||
development: "development,datasource-development,webclient-development"
|
prod: "prod"
|
||||||
production: "production,datasource-production,webclient-production"
|
|
||||||
freemarker:
|
freemarker:
|
||||||
enabled: false
|
enabled: false
|
||||||
cloud:
|
cloud:
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
<configuration>
|
<configuration>
|
||||||
<springProperty name="DEFAULT_LEVEL_CONFIG" source="log.defaultLevel" />
|
<springProperty name="DEFAULT_LEVEL_CONFIG" source="log.defaultLevel" />
|
||||||
<springProfile name="local">
|
<springProfile name="local">
|
||||||
<include resource="logback/logback-development.xml" />
|
<include resource="logback/logback-dev.xml" />
|
||||||
<logger name="org.apache.kafka" level="INFO" />
|
<logger name="org.apache.kafka" level="INFO" />
|
||||||
</springProfile>
|
</springProfile>
|
||||||
<springProfile name="development">
|
<springProfile name="dev">
|
||||||
<include resource="logback/logback-development.xml" />
|
<include resource="logback/logback-dev.xml" />
|
||||||
<logger name="org.apache.kafka" level="INFO" />
|
<logger name="org.apache.kafka" level="INFO" />
|
||||||
</springProfile>
|
</springProfile>
|
||||||
<springProfile name="production">
|
<springProfile name="prod">
|
||||||
<include resource="logback/logback-production.xml" />
|
<include resource="logback/logback-prod.xml" />
|
||||||
</springProfile>
|
</springProfile>
|
||||||
</configuration>
|
</configuration>
|
|
@ -3,15 +3,12 @@
|
||||||
<!-- =========== property BETA ========= -->
|
<!-- =========== property BETA ========= -->
|
||||||
<property name="DEFAULT_LEVEL" value="${DEFAULT_LEVEL_CONFIG:-INFO}"/>
|
<property name="DEFAULT_LEVEL" value="${DEFAULT_LEVEL_CONFIG:-INFO}"/>
|
||||||
<!--file-->
|
<!--file-->
|
||||||
<property name="DIRECTORY" value="/home1/www/logs/supervisor"/>
|
|
||||||
<property name="IMMEDIATE_FLUSH" value="true"/>
|
<property name="IMMEDIATE_FLUSH" value="true"/>
|
||||||
<!--nelo2-->
|
<!--nelo2-->
|
||||||
<property name="NELO2_LEVEL" value="WARN"/>
|
<property name="NELO2_LEVEL" value="WARN"/>
|
||||||
<!-- =========== include appender =========== -->
|
<!-- =========== include appender =========== -->
|
||||||
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
|
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
|
||||||
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
|
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
|
||||||
<include resource="logback/component/logback-nelo2.xml"/>
|
|
||||||
<include resource="logback/component/logback-datachain.xml"/>
|
|
||||||
<!-- =========== root logger ============== -->
|
<!-- =========== root logger ============== -->
|
||||||
<root level="${DEFAULT_LEVEL}">
|
<root level="${DEFAULT_LEVEL}">
|
||||||
<appender-ref ref="CONSOLE"/>
|
<appender-ref ref="CONSOLE"/>
|
|
@ -3,15 +3,12 @@
|
||||||
<!-- =========== property RELEASE ========= -->
|
<!-- =========== property RELEASE ========= -->
|
||||||
<property name="DEFAULT_LEVEL" value="${DEFAULT_LEVEL_CONFIG:-INFO}"/>
|
<property name="DEFAULT_LEVEL" value="${DEFAULT_LEVEL_CONFIG:-INFO}"/>
|
||||||
<!--file-->
|
<!--file-->
|
||||||
<property name="DIRECTORY" value="/home1/www/logs/supervisor"/>
|
|
||||||
<property name="IMMEDIATE_FLUSH" value="true"/>
|
<property name="IMMEDIATE_FLUSH" value="true"/>
|
||||||
<!--nelo2-->
|
<!--nelo2-->
|
||||||
<property name="NELO2_LEVEL" value="WARN"/>
|
<property name="NELO2_LEVEL" value="WARN"/>
|
||||||
<!-- =========== include appender =========== -->
|
<!-- =========== include appender =========== -->
|
||||||
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
|
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
|
||||||
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
|
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
|
||||||
<include resource="logback/component/logback-nelo2.xml"/>
|
|
||||||
<include resource="logback/component/logback-datachain.xml"/>
|
|
||||||
<!-- =========== root logger ============== -->
|
<!-- =========== root logger ============== -->
|
||||||
<root level="${DEFAULT_LEVEL}">
|
<root level="${DEFAULT_LEVEL}">
|
||||||
<appender-ref ref="CONSOLE"/>
|
<appender-ref ref="CONSOLE"/>
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.myoa.engineering.crawl.shopping.controller;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class SlackEventSubscriptionAPIControllerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void test_handleAddSubscription_1() {
|
||||||
|
// given
|
||||||
|
String sut = "/쇼핑 키워드 추가 키워드1";
|
||||||
|
|
||||||
|
// when
|
||||||
|
String actual = sut.replaceFirst("/.+? ", "");
|
||||||
|
|
||||||
|
// then
|
||||||
|
Assertions.assertEquals("키워드 추가 키워드1", actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void test_handleAddSubscription_2() {
|
||||||
|
// given
|
||||||
|
String sut = "키워드 추가 키워드 1입니 다";
|
||||||
|
|
||||||
|
// when
|
||||||
|
String[] actual = sut.split("\\s+", 2);
|
||||||
|
|
||||||
|
// then
|
||||||
|
Assertions.assertEquals(2, actual.length);
|
||||||
|
Assertions.assertEquals("키워드", actual[0]);
|
||||||
|
Assertions.assertEquals("추가 키워드 1입니 다", actual[1]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,8 +6,20 @@ import lombok.Getter;
|
||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum CrawlTarget {
|
public enum CrawlTarget {
|
||||||
PPOMPPU_DOMESTIC,
|
PPOMPPU_DOMESTIC("뽐뿌국내", true),
|
||||||
PPOMPPU_OVERSEA,
|
PPOMPPU_OVERSEA("뽐뿌해외", false),
|
||||||
FMKOREA,
|
FMKOREA("펨코", false),
|
||||||
;
|
;
|
||||||
|
|
||||||
|
private final String alias;
|
||||||
|
private final boolean available;
|
||||||
|
|
||||||
|
public static CrawlTarget fromAlias(String alias) {
|
||||||
|
for (CrawlTarget crawlTarget : values()) {
|
||||||
|
if (crawlTarget.getAlias().equals(alias)) {
|
||||||
|
return crawlTarget;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Not found alias: " + alias);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue