Compare commits
	
		
			No commits in common. "08737664f462dd8f51390659bf4237b92157ebf7" and "4738b930dfce4db904ae09c2a13bfb067443a480" have entirely different histories.
		
	
	
		
			08737664f4
			...
			4738b930df
		
	
		|  | @ -36,7 +36,4 @@ out/ | ||||||
| ### VS Code ### | ### VS Code ### | ||||||
| .vscode/ | .vscode/ | ||||||
| 
 | 
 | ||||||
| temppassword.yml | temppassword.yml | ||||||
| data.sql |  | ||||||
| **/src/main/resources/slack |  | ||||||
| **/src/main/resources/datasource |  | ||||||
|  | @ -1,6 +1,5 @@ | ||||||
| #Sun Apr 28 23:47:38 KST 2024 |  | ||||||
| distributionBase=GRADLE_USER_HOME | distributionBase=GRADLE_USER_HOME | ||||||
| distributionPath=wrapper/dists | distributionPath=wrapper/dists | ||||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip | ||||||
| zipStoreBase=GRADLE_USER_HOME | zipStoreBase=GRADLE_USER_HOME | ||||||
| zipStorePath=wrapper/dists | zipStorePath=wrapper/dists | ||||||
|  |  | ||||||
|  | @ -0,0 +1,30 @@ | ||||||
|  | 
 | ||||||
|  | dependencies { | ||||||
|  |     developmentOnly 'org.springframework.boot:spring-boot-devtools' | ||||||
|  |     runtimeOnly 'com.h2database:h2' | ||||||
|  |     runtimeOnly 'mysql:mysql-connector-java' | ||||||
|  |     compileOnly 'org.projectlombok:lombok' | ||||||
|  | 
 | ||||||
|  |     implementation project(':support') | ||||||
|  |     // https://projectreactor.io/docs/core/release/reference/#debug-activate | ||||||
|  |     implementation 'org.springframework.boot:spring-boot-starter-webflux' | ||||||
|  |     implementation 'org.springframework.boot:spring-boot-starter-data-jpa' | ||||||
|  |     implementation 'org.springframework.boot:spring-boot-starter-jdbc' | ||||||
|  |     implementation 'org.springframework.cloud:spring-cloud-starter-config' | ||||||
|  |     implementation 'org.springframework.boot:spring-boot-starter-actuator' | ||||||
|  |     implementation 'com.rometools:rome:1.16.0' | ||||||
|  |     implementation 'org.jsoup:jsoup:1.14.2' | ||||||
|  |     implementation 'com.h2database:h2:1.4.200' | ||||||
|  | 
 | ||||||
|  |     annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' | ||||||
|  |     annotationProcessor 'org.projectlombok:lombok' | ||||||
|  | 
 | ||||||
|  |     testImplementation 'org.springframework.boot:spring-boot-starter-test' | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | test { | ||||||
|  |     useJUnitPlatform() | ||||||
|  |     testLogging { | ||||||
|  |         events "passed", "skipped", "failed" | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,23 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.processor; | ||||||
|  | 
 | ||||||
|  | import org.springframework.boot.SpringApplication; | ||||||
|  | import org.springframework.boot.autoconfigure.SpringBootApplication; | ||||||
|  | import org.springframework.context.annotation.Import; | ||||||
|  | 
 | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.support.webclient.PpomppuNotifierWebClientConfiguration; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * ProcessorApplication | ||||||
|  |  * @author Shin Woo-jin (woo-jin.shin@linecorp.com) | ||||||
|  |  * @since 2021-08-20 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | @Import({ PpomppuNotifierWebClientConfiguration.class }) | ||||||
|  | @SpringBootApplication | ||||||
|  | public class ProcessorApplication { | ||||||
|  | 
 | ||||||
|  |     public static void main(String[] args) { | ||||||
|  |         SpringApplication.run(ProcessorApplication.class, args); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.configuration.datasource; | package com.myoa.engineering.crawl.ppomppu.processor.configuration; | ||||||
| 
 | 
 | ||||||
|  | import java.sql.SQLException; | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
| import org.h2.tools.Server; | import org.h2.tools.Server; | ||||||
| import org.springframework.beans.factory.annotation.Value; | import org.springframework.beans.factory.annotation.Value; | ||||||
|  | @ -9,8 +10,6 @@ import org.springframework.context.event.ContextClosedEvent; | ||||||
| import org.springframework.context.event.ContextRefreshedEvent; | import org.springframework.context.event.ContextRefreshedEvent; | ||||||
| import org.springframework.context.event.EventListener; | import org.springframework.context.event.EventListener; | ||||||
| 
 | 
 | ||||||
| import java.sql.SQLException; |  | ||||||
| 
 |  | ||||||
| @Slf4j | @Slf4j | ||||||
| @Profile({"datasource-local", "datasource-development"}) | @Profile({"datasource-local", "datasource-development"}) | ||||||
| @Configuration | @Configuration | ||||||
|  | @ -1,58 +1,54 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.configuration.datasource; | package com.myoa.engineering.crawl.ppomppu.processor.configuration; | ||||||
| 
 | 
 | ||||||
| import com.myoa.engineering.crawl.shopping.configuration.datasource.properties.DatasourceProperties; | import com.myoa.engineering.crawl.ppomppu.processor.configuration.properties.DatasourceProperties; | ||||||
| import com.myoa.engineering.crawl.shopping.configuration.datasource.properties.HibernateProperties; | import com.myoa.engineering.crawl.ppomppu.processor.configuration.properties.DatasourceProperties.DataSourcePropertiesUnit; | ||||||
| import com.myoa.engineering.crawl.shopping.configuration.datasource.properties.HikariProperties; | import com.myoa.engineering.crawl.ppomppu.processor.configuration.properties.HibernateProperties; | ||||||
| import com.myoa.engineering.crawl.shopping.domain.entity.BaseScanDomain; | import com.myoa.engineering.crawl.ppomppu.processor.configuration.properties.HikariProperties; | ||||||
| import com.myoa.engineering.crawl.shopping.infra.repository.BaseScanRepository; | import com.myoa.engineering.crawl.ppomppu.processor.domain.BaseScanDomain; | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.processor.infrastructure.repository.BaseScanRepository; | ||||||
| import com.zaxxer.hikari.HikariConfig; | import com.zaxxer.hikari.HikariConfig; | ||||||
| import com.zaxxer.hikari.HikariDataSource; | import com.zaxxer.hikari.HikariDataSource; | ||||||
| import jakarta.persistence.EntityManagerFactory; | import java.util.Enumeration; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.Properties; | ||||||
|  | import javax.persistence.EntityManagerFactory; | ||||||
|  | import javax.sql.DataSource; | ||||||
| import lombok.NonNull; | import lombok.NonNull; | ||||||
| import org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy; |  | ||||||
| import org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl; |  | ||||||
| import org.hibernate.cfg.AvailableSettings; | import org.hibernate.cfg.AvailableSettings; | ||||||
| import org.springframework.beans.factory.annotation.Qualifier; | import org.springframework.beans.factory.annotation.Qualifier; | ||||||
| import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; | import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; | ||||||
| import org.springframework.context.annotation.Bean; | import org.springframework.context.annotation.Bean; | ||||||
| import org.springframework.context.annotation.Configuration; | import org.springframework.context.annotation.Configuration; | ||||||
| import org.springframework.data.jpa.repository.config.EnableJpaAuditing; |  | ||||||
| import org.springframework.data.jpa.repository.config.EnableJpaRepositories; | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; | ||||||
| import org.springframework.orm.jpa.JpaTransactionManager; | import org.springframework.orm.jpa.JpaTransactionManager; | ||||||
| import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; | import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; | ||||||
| import org.springframework.transaction.PlatformTransactionManager; | import org.springframework.transaction.PlatformTransactionManager; | ||||||
| 
 | 
 | ||||||
| import javax.sql.DataSource; |  | ||||||
| import java.util.Enumeration; |  | ||||||
| import java.util.HashMap; |  | ||||||
| import java.util.Map; |  | ||||||
| import java.util.Properties; |  | ||||||
| 
 |  | ||||||
| @Configuration | @Configuration | ||||||
| @EnableJpaAuditing |  | ||||||
| @EnableJpaRepositories(basePackageClasses = BaseScanRepository.class, | @EnableJpaRepositories(basePackageClasses = BaseScanRepository.class, | ||||||
|         entityManagerFactoryRef = "shoppingCrawlerEntityManagerFactory", |     entityManagerFactoryRef = "ppomppuNotifierProcessorEntityManagerFactory", | ||||||
|         transactionManagerRef = "shoppingCrawlerTransactionManager" |     transactionManagerRef = "ppomppuNotifierProcessorTransactionManager" | ||||||
| ) | ) | ||||||
| public class ShoppingCrawlerDatasourceConfiguration { | public class PpomppuDatasourceConfiguration { | ||||||
| 
 | 
 | ||||||
|     private static final String DATA_SOURCE_UNIT_NAME = "crawler-shopping"; |     private static final String DATA_SOURCE_UNIT_NAME = "ppn_mysql"; | ||||||
| 
 | 
 | ||||||
|     private final DatasourceProperties dataSourceProeprties; |     private final DatasourceProperties dataSourceProeprties; | ||||||
|     private final HikariProperties hikariProperties; |     private final HikariProperties hikariProperties; | ||||||
|     private final HibernateProperties hibernateProperties; |     private final HibernateProperties hibernateProperties; | ||||||
| 
 | 
 | ||||||
|     public ShoppingCrawlerDatasourceConfiguration(DatasourceProperties dataSourceProeprties, |     public PpomppuDatasourceConfiguration(DatasourceProperties dataSourceProeprties, | ||||||
|                                                   HikariProperties hikariProperties, |                                           HikariProperties hikariProperties, | ||||||
|                                                   HibernateProperties hibernateProperties) { |                                           HibernateProperties hibernateProperties) { | ||||||
|         this.dataSourceProeprties = dataSourceProeprties; |         this.dataSourceProeprties = dataSourceProeprties; | ||||||
|         this.hikariProperties = hikariProperties; |         this.hikariProperties = hikariProperties; | ||||||
|         this.hibernateProperties = hibernateProperties; |         this.hibernateProperties = hibernateProperties; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Bean(name = "shoppingCrawlerDataSource") |     @Bean(name = "ppomppuNotifierProcessorDataSource") | ||||||
|     public DataSource dataSource() { |     public DataSource dataSource() { | ||||||
|         DatasourceProperties.DataSourcePropertiesUnit dataSourcePropertiesUnit = dataSourceProeprties.find(DATA_SOURCE_UNIT_NAME); |         DataSourcePropertiesUnit dataSourcePropertiesUnit = dataSourceProeprties.find(DATA_SOURCE_UNIT_NAME); | ||||||
| 
 | 
 | ||||||
|         final HikariConfig hikariConfig = new HikariConfig(); |         final HikariConfig hikariConfig = new HikariConfig(); | ||||||
|         hikariConfig.setJdbcUrl(dataSourcePropertiesUnit.toCompletedJdbcUrl()); |         hikariConfig.setJdbcUrl(dataSourcePropertiesUnit.toCompletedJdbcUrl()); | ||||||
|  | @ -73,19 +69,19 @@ public class ShoppingCrawlerDatasourceConfiguration { | ||||||
|         return dataSource; |         return dataSource; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Bean("shoppingCrawlerEntityManagerFactory") |     @Bean("ppomppuNotifierProcessorEntityManagerFactory") | ||||||
|     public LocalContainerEntityManagerFactoryBean entityManagerFactory( |     public LocalContainerEntityManagerFactoryBean entityManagerFactory( | ||||||
|             EntityManagerFactoryBuilder builder, |         EntityManagerFactoryBuilder builder, | ||||||
|             @Qualifier("shoppingCrawlerDataSource") DataSource dataSource) { |         @Qualifier("ppomppuNotifierProcessorDataSource") DataSource dataSource) { | ||||||
|         return builder.dataSource(dataSource) |         return builder.dataSource(dataSource) | ||||||
|                       .packages(BaseScanDomain.class) |                       .packages(BaseScanDomain.class) | ||||||
|                       .properties(getPropsMap(DATA_SOURCE_UNIT_NAME)) |                       .properties(getPropsMap(DATA_SOURCE_UNIT_NAME)) | ||||||
|                       .build(); |                       .build(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Bean("shoppingCrawlerTransactionManager") |     @Bean("ppomppuNotifierProcessorTransactionManager") | ||||||
|     public PlatformTransactionManager transactionManager( |     public PlatformTransactionManager transactionManager( | ||||||
|             @Qualifier("shoppingCrawlerEntityManagerFactory") EntityManagerFactory entityManagerFactory) { |         @Qualifier("ppomppuNotifierProcessorEntityManagerFactory") EntityManagerFactory entityManagerFactory) { | ||||||
|         return new JpaTransactionManager(entityManagerFactory); |         return new JpaTransactionManager(entityManagerFactory); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -95,17 +91,20 @@ public class ShoppingCrawlerDatasourceConfiguration { | ||||||
|         properties.put(AvailableSettings.FORMAT_SQL, hibernateProperties.getFormatSql()); |         properties.put(AvailableSettings.FORMAT_SQL, hibernateProperties.getFormatSql()); | ||||||
|         properties.put(AvailableSettings.SHOW_SQL, hibernateProperties.getShowSql()); |         properties.put(AvailableSettings.SHOW_SQL, hibernateProperties.getShowSql()); | ||||||
|         properties.put(AvailableSettings.HBM2DDL_AUTO, hibernateProperties.getHbm2ddlAuto()); |         properties.put(AvailableSettings.HBM2DDL_AUTO, hibernateProperties.getHbm2ddlAuto()); | ||||||
|         properties.put(AvailableSettings.CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT, hibernateProperties.getDisableAutoCommit()); |         properties.put(AvailableSettings.CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT, | ||||||
|         properties.put(AvailableSettings.IMPLICIT_NAMING_STRATEGY, ImplicitNamingStrategyJpaCompliantImpl.class.getName()); |                        hibernateProperties.getDisableAutoCommit()); | ||||||
|         properties.put(AvailableSettings.PHYSICAL_NAMING_STRATEGY, CamelCaseToUnderscoresNamingStrategy.class.getName()); |         properties.put(AvailableSettings.IMPLICIT_NAMING_STRATEGY, | ||||||
|  |                        "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy"); | ||||||
|  |         properties.put(AvailableSettings.PHYSICAL_NAMING_STRATEGY, | ||||||
|  |                        "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy"); | ||||||
|         properties.put(AvailableSettings.GENERATE_STATISTICS, "false"); |         properties.put(AvailableSettings.GENERATE_STATISTICS, "false"); | ||||||
| //        properties.put(AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS, "true"); |         properties.put(AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS, "true"); | ||||||
| //        properties.put(AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS_SKIP_COLUMN_DEFINITIONS, "true"); |         properties.put(AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS_SKIP_COLUMN_DEFINITIONS, "true"); | ||||||
|         properties.put(AvailableSettings.STATEMENT_BATCH_SIZE, "20"); |         properties.put(AvailableSettings.STATEMENT_BATCH_SIZE, "20"); | ||||||
|         properties.put(AvailableSettings.ORDER_INSERTS, "true"); |         properties.put(AvailableSettings.ORDER_INSERTS, "true"); | ||||||
|         properties.put(AvailableSettings.ORDER_UPDATES, "true"); |         properties.put(AvailableSettings.ORDER_UPDATES, "true"); | ||||||
|         properties.put(AvailableSettings.BATCH_VERSIONED_DATA, "true"); |         properties.put(AvailableSettings.BATCH_VERSIONED_DATA, "true"); | ||||||
| //        properties.put(AvailableSettings.JPA_ID_GENERATOR_GLOBAL_SCOPE_COMPLIANCE, "false"); |         properties.put(AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "false"); | ||||||
|         return properties; |         return properties; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -1,26 +1,29 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.configuration.datasource.properties; | package com.myoa.engineering.crawl.ppomppu.processor.configuration.properties; | ||||||
| 
 | 
 | ||||||
| import com.myoa.engineering.crawl.shopping.support.util.ObjectUtil; | import com.myoa.engineering.crawl.ppomppu.support.util.ObjectUtil; | ||||||
| import lombok.Data; | import java.util.List; | ||||||
|  | 
 | ||||||
|  | import lombok.Getter; | ||||||
|  | import lombok.Setter; | ||||||
| import org.springframework.boot.context.properties.ConfigurationProperties; | import org.springframework.boot.context.properties.ConfigurationProperties; | ||||||
| import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||||
| 
 | 
 | ||||||
| import java.util.List; |  | ||||||
| 
 |  | ||||||
| @Component | @Component | ||||||
| @Data | @Setter | ||||||
| @ConfigurationProperties(prefix = "datasource") | @Getter | ||||||
|  | @ConfigurationProperties(prefix = "infra.database") | ||||||
| public class DatasourceProperties { | public class DatasourceProperties { | ||||||
| 
 | 
 | ||||||
|     private List<DataSourcePropertiesUnit> units; |     private List<DataSourcePropertiesUnit> units; | ||||||
| 
 | 
 | ||||||
|     @Data |     @Getter | ||||||
|  |     @Setter | ||||||
|     public static class DataSourcePropertiesUnit { |     public static class DataSourcePropertiesUnit { | ||||||
| 
 | 
 | ||||||
|         private String unitName; |         private String unitName; | ||||||
|         private String schemaName; |         private String schemaName; | ||||||
|         private String connectionParameters; |         private String connectionParameters; | ||||||
|         private String dbConnectionUrl; |         private String datasourceUrl; | ||||||
|         private Boolean isSimpleConnectionUrl; |         private Boolean isSimpleConnectionUrl; | ||||||
|         private String username; |         private String username; | ||||||
|         private String password; |         private String password; | ||||||
|  | @ -28,9 +31,9 @@ public class DatasourceProperties { | ||||||
| 
 | 
 | ||||||
|         public String toCompletedJdbcUrl() { |         public String toCompletedJdbcUrl() { | ||||||
|             if (ObjectUtil.isEmpty(isSimpleConnectionUrl) || isSimpleConnectionUrl == false) { |             if (ObjectUtil.isEmpty(isSimpleConnectionUrl) || isSimpleConnectionUrl == false) { | ||||||
|                 return String.format("%s/%s?%s", dbConnectionUrl, schemaName, connectionParameters); |                 return String.format("%s/%s?%s", datasourceUrl, schemaName, connectionParameters); | ||||||
|             } |             } | ||||||
|             return dbConnectionUrl; |             return datasourceUrl; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -39,7 +42,7 @@ public class DatasourceProperties { | ||||||
|                     .filter(e -> e.getUnitName().equals(unitName)) |                     .filter(e -> e.getUnitName().equals(unitName)) | ||||||
|                     .findFirst() |                     .findFirst() | ||||||
|                     .orElseThrow( |                     .orElseThrow( | ||||||
|                             () -> new IllegalArgumentException(this.getClass().getName() + ": unitName Not found. " + unitName)); |                         () -> new IllegalArgumentException(this.getClass().getName() + ": unitName Not found. " + unitName)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | @ -1,11 +1,13 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.configuration.datasource.properties; | package com.myoa.engineering.crawl.ppomppu.processor.configuration.properties; | ||||||
| 
 |  | ||||||
| import lombok.Getter; |  | ||||||
| import lombok.Setter; |  | ||||||
| import org.springframework.boot.context.properties.ConfigurationProperties; |  | ||||||
| import org.springframework.stereotype.Component; |  | ||||||
| 
 | 
 | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import lombok.Getter; | ||||||
|  | import lombok.Setter; | ||||||
|  | 
 | ||||||
|  | import org.hibernate.dialect.MySQL8Dialect; | ||||||
|  | import org.hibernate.dialect.MySQLDialect; | ||||||
|  | import org.springframework.boot.context.properties.ConfigurationProperties; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
| 
 | 
 | ||||||
| @Component | @Component | ||||||
| @Setter | @Setter | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.configuration.datasource.properties; | package com.myoa.engineering.crawl.ppomppu.processor.configuration.properties; | ||||||
| 
 | 
 | ||||||
| import lombok.Getter; | import lombok.Getter; | ||||||
| import lombok.Setter; | import lombok.Setter; | ||||||
|  | @ -1,18 +1,17 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.domain.entity; | package com.myoa.engineering.crawl.ppomppu.processor.domain; | ||||||
| 
 |  | ||||||
| import lombok.Getter; |  | ||||||
| import org.springframework.data.annotation.CreatedDate; |  | ||||||
| import org.springframework.data.annotation.LastModifiedDate; |  | ||||||
| 
 |  | ||||||
| import jakarta.persistence.*; |  | ||||||
| import org.springframework.data.jpa.domain.support.AuditingEntityListener; |  | ||||||
| 
 | 
 | ||||||
| import java.io.Serializable; | import java.io.Serializable; | ||||||
| import java.time.Instant; | import java.time.Instant; | ||||||
|  | import javax.persistence.Column; | ||||||
|  | import org.springframework.data.annotation.CreatedDate; | ||||||
|  | import org.springframework.data.annotation.LastModifiedDate; | ||||||
| 
 | 
 | ||||||
| @Getter | /** | ||||||
| @MappedSuperclass |  * Auditable | ||||||
| @EntityListeners(AuditingEntityListener.class) |  * | ||||||
|  |  * @author Shin Woo-jin (woozu.shin@kakaoent.com) | ||||||
|  |  * @since 2021-09-08 | ||||||
|  |  */ | ||||||
| public abstract class Auditable implements Serializable { | public abstract class Auditable implements Serializable { | ||||||
|     private static final long serialVersionUID = -7105030870015828551L; |     private static final long serialVersionUID = -7105030870015828551L; | ||||||
| 
 | 
 | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.domain.entity; | package com.myoa.engineering.crawl.ppomppu.processor.domain; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * BaseScanDomain |  * BaseScanDomain | ||||||
|  | @ -1,14 +1,19 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.domain.entity.v1; | package com.myoa.engineering.crawl.ppomppu.processor.domain; | ||||||
| 
 | 
 | ||||||
| import com.myoa.engineering.crawl.shopping.domain.entity.Auditable; | import com.myoa.engineering.crawl.ppomppu.support.dto.code.PpomppuBoardName; | ||||||
| import com.myoa.engineering.crawl.shopping.support.dto.constant.PpomppuBoardName; | import java.time.Instant; | ||||||
| import jakarta.persistence.*; | import javax.persistence.Column; | ||||||
|  | import javax.persistence.Entity; | ||||||
|  | import javax.persistence.EnumType; | ||||||
|  | import javax.persistence.Enumerated; | ||||||
|  | import javax.persistence.GeneratedValue; | ||||||
|  | import javax.persistence.GenerationType; | ||||||
|  | import javax.persistence.Id; | ||||||
|  | import javax.persistence.Table; | ||||||
| import lombok.Builder; | import lombok.Builder; | ||||||
| import lombok.Getter; | import lombok.Getter; | ||||||
| import lombok.NoArgsConstructor; | import lombok.NoArgsConstructor; | ||||||
| 
 | 
 | ||||||
| import java.time.Instant; |  | ||||||
| 
 |  | ||||||
| @Getter | @Getter | ||||||
| @NoArgsConstructor | @NoArgsConstructor | ||||||
| @Entity | @Entity | ||||||
|  | @ -1,12 +1,15 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.domain.entity.v1; | package com.myoa.engineering.crawl.ppomppu.processor.domain; | ||||||
| 
 | 
 | ||||||
| import com.myoa.engineering.crawl.shopping.domain.entity.Auditable; | import java.time.Instant; | ||||||
|  | import javax.persistence.Column; | ||||||
|  | import javax.persistence.Entity; | ||||||
|  | import javax.persistence.GeneratedValue; | ||||||
|  | import javax.persistence.GenerationType; | ||||||
|  | import javax.persistence.Id; | ||||||
|  | import javax.persistence.Table; | ||||||
| import lombok.Getter; | import lombok.Getter; | ||||||
| import lombok.NoArgsConstructor; | import lombok.NoArgsConstructor; | ||||||
| 
 | 
 | ||||||
| import jakarta.persistence.*; |  | ||||||
| import java.time.Instant; |  | ||||||
| 
 |  | ||||||
| @Getter | @Getter | ||||||
| @NoArgsConstructor | @NoArgsConstructor | ||||||
| @Entity | @Entity | ||||||
|  | @ -0,0 +1,32 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.processor.domain; | ||||||
|  | 
 | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.support.dto.code.PpomppuBoardName; | ||||||
|  | import javax.persistence.Column; | ||||||
|  | import javax.persistence.Entity; | ||||||
|  | import javax.persistence.EnumType; | ||||||
|  | import javax.persistence.Enumerated; | ||||||
|  | import javax.persistence.GeneratedValue; | ||||||
|  | import javax.persistence.GenerationType; | ||||||
|  | import javax.persistence.Id; | ||||||
|  | import javax.persistence.Table; | ||||||
|  | import lombok.Getter; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | 
 | ||||||
|  | @Getter | ||||||
|  | @NoArgsConstructor | ||||||
|  | @Entity | ||||||
|  | @Table(name = "subscribed_board") | ||||||
|  | public class SubscribedBoard extends Auditable { | ||||||
|  | 
 | ||||||
|  |     @Id | ||||||
|  |     @GeneratedValue(strategy = GenerationType.IDENTITY) | ||||||
|  |     private Long id; | ||||||
|  | 
 | ||||||
|  |     @Column | ||||||
|  |     private Long userId; | ||||||
|  | 
 | ||||||
|  |     @Column | ||||||
|  |     @Enumerated(EnumType.STRING) | ||||||
|  |     private PpomppuBoardName boardName; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -1,17 +1,20 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.domain.entity.v1; | package com.myoa.engineering.crawl.ppomppu.processor.domain; | ||||||
| 
 | 
 | ||||||
| import com.myoa.engineering.crawl.shopping.domain.entity.Auditable; | import java.time.Instant; | ||||||
|  | import javax.persistence.Column; | ||||||
|  | import javax.persistence.Entity; | ||||||
|  | import javax.persistence.GeneratedValue; | ||||||
|  | import javax.persistence.GenerationType; | ||||||
|  | import javax.persistence.Id; | ||||||
|  | import javax.persistence.Table; | ||||||
| import lombok.Getter; | import lombok.Getter; | ||||||
| import lombok.NoArgsConstructor; | import lombok.NoArgsConstructor; | ||||||
| 
 | 
 | ||||||
| import jakarta.persistence.*; |  | ||||||
| import java.time.Instant; |  | ||||||
| 
 |  | ||||||
| @Getter | @Getter | ||||||
| @NoArgsConstructor | @NoArgsConstructor | ||||||
| @Entity | @Entity | ||||||
| @Table(name = "subscribed_user") | @Table(name = "subscribed_user") | ||||||
| public class SubscribedUser extends Auditable { | public class SubscribedUser extends Auditable{ | ||||||
| 
 | 
 | ||||||
|     @Id |     @Id | ||||||
|     @GeneratedValue(strategy = GenerationType.IDENTITY) |     @GeneratedValue(strategy = GenerationType.IDENTITY) | ||||||
|  | @ -1,13 +1,12 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.dto; | package com.myoa.engineering.crawl.ppomppu.processor.dto; | ||||||
| 
 | 
 | ||||||
| import com.myoa.engineering.crawl.shopping.support.dto.constant.PpomppuBoardName; | import com.myoa.engineering.crawl.ppomppu.support.dto.code.PpomppuBoardName; | ||||||
|  | import java.io.Serializable; | ||||||
|  | import java.time.Instant; | ||||||
| import lombok.Builder; | import lombok.Builder; | ||||||
| import lombok.Getter; | import lombok.Getter; | ||||||
| import lombok.NoArgsConstructor; | import lombok.NoArgsConstructor; | ||||||
| 
 | 
 | ||||||
| import java.io.Serializable; |  | ||||||
| import java.time.Instant; |  | ||||||
| 
 |  | ||||||
| /** | /** | ||||||
|  * FeedParsedResult |  * FeedParsedResult | ||||||
|  * |  * | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.dto.constant; | package com.myoa.engineering.crawl.ppomppu.processor.dto.constant; | ||||||
| 
 | 
 | ||||||
| import lombok.AllArgsConstructor; | import lombok.AllArgsConstructor; | ||||||
| import lombok.Getter; | import lombok.Getter; | ||||||
|  | @ -1,7 +1,16 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.infra.client.ppomppu; | package com.myoa.engineering.crawl.ppomppu.processor.infrastructure.client; | ||||||
| 
 | 
 | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.support.webclient.factory.WebClientFilterFactory; | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.support.webclient.factory.WebFluxExchangeStragiesFactory; | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.support.dto.code.PpomppuBoardName; | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
|  | import org.springframework.core.ParameterizedTypeReference; | ||||||
| import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||||
|  | import org.springframework.web.reactive.function.client.WebClient; | ||||||
|  | import org.springframework.web.reactive.function.client.WebClientRequestException; | ||||||
|  | import reactor.core.publisher.Mono; | ||||||
|  | import reactor.core.scheduler.Schedulers; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * PpomppuBoardFeedRetriever |  * PpomppuBoardFeedRetriever | ||||||
|  | @ -11,11 +20,11 @@ import org.springframework.stereotype.Component; | ||||||
|  */ |  */ | ||||||
| @Slf4j | @Slf4j | ||||||
| @Component | @Component | ||||||
| public class PpomppuBoardClient { | public class PpomppuBoardFeedRetriever { | ||||||
| /* | 
 | ||||||
|     private final WebClient webClient; |     private final WebClient webClient; | ||||||
| 
 | 
 | ||||||
|     public PpomppuBoardClient(WebClient.Builder webClientBuilder) { |     public PpomppuBoardFeedRetriever(WebClient.Builder webClientBuilder) { | ||||||
|         this.webClient = webClientBuilder.baseUrl(PpomppuBoardName.PPOMPPU_URL) |         this.webClient = webClientBuilder.baseUrl(PpomppuBoardName.PPOMPPU_URL) | ||||||
|                                          .exchangeStrategies(WebFluxExchangeStragiesFactory.ofTextHtml()) |                                          .exchangeStrategies(WebFluxExchangeStragiesFactory.ofTextHtml()) | ||||||
|                                          .filter(WebClientFilterFactory.logRequest()) |                                          .filter(WebClientFilterFactory.logRequest()) | ||||||
|  | @ -34,5 +43,5 @@ public class PpomppuBoardClient { | ||||||
|                         }); |                         }); | ||||||
|                         // .doOnNext(e -> log.info("[getHtml] {}", e)); |                         // .doOnNext(e -> log.info("[getHtml] {}", e)); | ||||||
|     } |     } | ||||||
| */ | 
 | ||||||
| } | } | ||||||
|  | @ -0,0 +1,4 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.processor.infrastructure.repository; | ||||||
|  | 
 | ||||||
|  | public interface BaseScanRepository { | ||||||
|  | } | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.infra.repository.v1; | package com.myoa.engineering.crawl.ppomppu.processor.infrastructure.repository; | ||||||
| 
 | 
 | ||||||
| import com.myoa.engineering.crawl.shopping.domain.entity.v1.PpomppuArticle; | import com.myoa.engineering.crawl.ppomppu.processor.domain.PpomppuArticle; | ||||||
| import org.springframework.data.jpa.repository.JpaRepository; | import org.springframework.data.jpa.repository.JpaRepository; | ||||||
| import org.springframework.stereotype.Repository; | import org.springframework.stereotype.Repository; | ||||||
| 
 | 
 | ||||||
|  | @ -1,12 +1,11 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.infra.repository.v1; | package com.myoa.engineering.crawl.ppomppu.processor.infrastructure.repository; | ||||||
| 
 | 
 | ||||||
| import com.myoa.engineering.crawl.shopping.domain.entity.v1.PpomppuBoardFeedStatus; | import com.myoa.engineering.crawl.ppomppu.processor.domain.PpomppuBoardFeedStatus; | ||||||
| import com.myoa.engineering.crawl.shopping.support.dto.constant.PpomppuBoardName; | import com.myoa.engineering.crawl.ppomppu.support.dto.code.PpomppuBoardName; | ||||||
|  | import java.util.Optional; | ||||||
| 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 PpomppuBoardFeedStatusRepository extends JpaRepository<PpomppuBoardFeedStatus, Long> { | public interface PpomppuBoardFeedStatusRepository extends JpaRepository<PpomppuBoardFeedStatus, Long> { | ||||||
| 
 | 
 | ||||||
|  | @ -1,18 +1,20 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.service; | package com.myoa.engineering.crawl.ppomppu.processor.service; | ||||||
| 
 |  | ||||||
| import com.myoa.engineering.crawl.shopping.domain.entity.v1.PpomppuArticle; |  | ||||||
| import com.myoa.engineering.crawl.shopping.domain.entity.v1.PpomppuBoardFeedStatus; |  | ||||||
| import com.myoa.engineering.crawl.shopping.infra.repository.v1.PpomppuArticleRepository; |  | ||||||
| import com.myoa.engineering.crawl.shopping.infra.repository.v1.PpomppuBoardFeedStatusRepository; |  | ||||||
| import com.myoa.engineering.crawl.shopping.support.dto.constant.PpomppuBoardName; |  | ||||||
| import lombok.extern.slf4j.Slf4j; |  | ||||||
| import org.springframework.stereotype.Service; |  | ||||||
| import org.springframework.transaction.annotation.Transactional; |  | ||||||
| 
 | 
 | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Optional; | import java.util.Optional; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
| 
 | 
 | ||||||
|  | import org.springframework.stereotype.Service; | ||||||
|  | import org.springframework.transaction.annotation.Transactional; | ||||||
|  | 
 | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.processor.domain.PpomppuArticle; | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.processor.domain.PpomppuBoardFeedStatus; | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.processor.infrastructure.repository.PpomppuArticleRepository; | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.processor.infrastructure.repository.PpomppuBoardFeedStatusRepository; | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.support.dto.code.PpomppuBoardName; | ||||||
|  | 
 | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
| @Slf4j | @Slf4j | ||||||
| @Service | @Service | ||||||
| public class PpomppuArticleService { | public class PpomppuArticleService { | ||||||
|  | @ -3,7 +3,7 @@ | ||||||
|  * LINE Corporation PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. |  * LINE Corporation PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| package com.myoa.engineering.crawl.shopping.util; | package com.myoa.engineering.crawl.ppomppu.processor.util; | ||||||
| 
 | 
 | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
|  | @ -14,9 +14,9 @@ import java.util.Collection; | ||||||
|  * @author Shin Woo-jin (lp12254@linecorp.com) |  * @author Shin Woo-jin (lp12254@linecorp.com) | ||||||
|  * @since 2019-10-28 |  * @since 2019-10-28 | ||||||
|  */ |  */ | ||||||
| public final class ObjectUtils { | public final class ObjectUtil { | ||||||
| 
 | 
 | ||||||
|     private ObjectUtils() { |     private ObjectUtil() { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | @ -58,7 +58,7 @@ public final class ObjectUtils { | ||||||
|      * @return Is there objects array has null? |      * @return Is there objects array has null? | ||||||
|      */ |      */ | ||||||
|     public static boolean hasNullObject(Object... args) { |     public static boolean hasNullObject(Object... args) { | ||||||
|         return Arrays.stream(args).anyMatch(ObjectUtils::isNullObject); |         return Arrays.stream(args).anyMatch(ObjectUtil::isNullObject); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | @ -72,7 +72,7 @@ public final class ObjectUtils { | ||||||
|      * @return Is there objects array has null? |      * @return Is there objects array has null? | ||||||
|      */ |      */ | ||||||
|     public static boolean hasAllObject(Object... args) { |     public static boolean hasAllObject(Object... args) { | ||||||
|         return Arrays.stream(args).noneMatch(ObjectUtils::isNullObject); |         return Arrays.stream(args).noneMatch(ObjectUtil::isNullObject); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | @ -86,7 +86,7 @@ public final class ObjectUtils { | ||||||
|      * @return Is there null all of given objects? |      * @return Is there null all of given objects? | ||||||
|      */ |      */ | ||||||
|     public static boolean hasAllNullObjects(final Object... args) { |     public static boolean hasAllNullObjects(final Object... args) { | ||||||
|         return Arrays.stream(args).allMatch(ObjectUtils::isNullObject); |         return Arrays.stream(args).allMatch(ObjectUtil::isNullObject); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | @ -0,0 +1,11 @@ | ||||||
|  | spring: | ||||||
|  |   config: | ||||||
|  |     activate: | ||||||
|  |       on-profile: local | ||||||
|  |     import: | ||||||
|  |       - "configserver:http://localhost:20085" | ||||||
|  | 
 | ||||||
|  | server: | ||||||
|  |   port: 20081 | ||||||
|  | 
 | ||||||
|  |     # import: optional:configserver:http://localhost:11080 # can be start up even config server was not found. | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| spring: | spring: | ||||||
|   application: |   application: | ||||||
|     name: crawler-shopping |     name: ppn-processor | ||||||
|   main: |   main: | ||||||
|     allow-bean-definition-overriding: true |     allow-bean-definition-overriding: true | ||||||
|   profiles: |   profiles: | ||||||
|  | @ -11,9 +11,6 @@ spring: | ||||||
|       production: "production,datasource-production,webclient-production" |       production: "production,datasource-production,webclient-production" | ||||||
|   freemarker: |   freemarker: | ||||||
|     enabled: false |     enabled: false | ||||||
|   cloud: |  | ||||||
|     config: |  | ||||||
|       enabled: false |  | ||||||
| 
 | 
 | ||||||
| server: | server: | ||||||
|   port: 20080 |   port: 20080 | ||||||
|  | @ -0,0 +1,26 @@ | ||||||
|  | dependencies { | ||||||
|  |     developmentOnly 'org.springframework.boot:spring-boot-devtools' | ||||||
|  |     runtimeOnly 'com.h2database:h2' | ||||||
|  |     runtimeOnly 'mysql:mysql-connector-java' | ||||||
|  |     compileOnly 'org.projectlombok:lombok' | ||||||
|  | 
 | ||||||
|  |     implementation project(':support') | ||||||
|  |     // https://projectreactor.io/docs/core/release/reference/#debug-activate | ||||||
|  |     implementation 'org.springframework.boot:spring-boot-starter-webflux' | ||||||
|  |     implementation 'org.springframework.boot:spring-boot-configuration-processor' | ||||||
|  |     implementation 'org.springframework.cloud:spring-cloud-starter-config' | ||||||
|  |     implementation 'org.springframework.boot:spring-boot-starter-actuator' | ||||||
|  |     implementation 'org.telegram:telegrambots:5.3.0' | ||||||
|  | 
 | ||||||
|  |     annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' | ||||||
|  |     annotationProcessor 'org.projectlombok:lombok' | ||||||
|  | 
 | ||||||
|  |     testImplementation 'org.springframework.boot:spring-boot-starter-test' | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | test { | ||||||
|  |     useJUnitPlatform() | ||||||
|  |     testLogging { | ||||||
|  |         events "passed", "skipped", "failed" | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,25 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.receiver; | ||||||
|  | 
 | ||||||
|  | import org.springframework.boot.SpringApplication; | ||||||
|  | import org.springframework.boot.autoconfigure.SpringBootApplication; | ||||||
|  | import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||||||
|  | import org.springframework.context.annotation.Import; | ||||||
|  | 
 | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.receiver.configuration.properties.TelegramBotProperties; | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.support.webclient.PpomppuNotifierWebClientConfiguration; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * ReceiverApplication | ||||||
|  |  * @author Shin Woo-jin (woo-jin.shin@linecorp.com) | ||||||
|  |  * @since 2021-08-20 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | @Import({ PpomppuNotifierWebClientConfiguration.class}) | ||||||
|  | @SpringBootApplication | ||||||
|  | // @EnableConfigurationProperties({ TelegramBotProperties.class }) | ||||||
|  | public class ReceiverApplication { | ||||||
|  | 
 | ||||||
|  |     public static void main(String[] args) { | ||||||
|  |         SpringApplication.run(ReceiverApplication.class, args); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,39 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.receiver.configuration; | ||||||
|  | 
 | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | import org.springframework.context.annotation.Bean; | ||||||
|  | import org.springframework.context.annotation.Configuration; | ||||||
|  | import org.telegram.telegrambots.meta.TelegramBotsApi; | ||||||
|  | import org.telegram.telegrambots.meta.exceptions.TelegramApiException; | ||||||
|  | import org.telegram.telegrambots.updatesreceivers.DefaultBotSession; | ||||||
|  | 
 | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.receiver.configuration.properties.TelegramBotProperties; | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.receiver.configuration.properties.TelegramBotProperties.TelegramBotPropertiesUnit; | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.receiver.dispatch.MessageDispatcher; | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.receiver.handler.message.MessageHandler; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * TelegramBotConfiguration | ||||||
|  |  * @author Shin Woo-jin (woo-jin.shin@linecorp.com) | ||||||
|  |  * @since 2021-08-21 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | @Configuration | ||||||
|  | public class TelegramBotConfiguration { | ||||||
|  | 
 | ||||||
|  |     private static final String BOT_PROPERTIES_UNIT_NAME = "ppomppu_notify_bot"; | ||||||
|  |     @Bean | ||||||
|  |     public TelegramBotsApi telegramBotsApi(MessageDispatcher messageDispatcher) throws TelegramApiException { | ||||||
|  |         TelegramBotsApi api = new TelegramBotsApi(DefaultBotSession.class); | ||||||
|  |         api.registerBot(messageDispatcher); | ||||||
|  |         return api; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Bean | ||||||
|  |     public MessageDispatcher messageDispatcher(List<MessageHandler> messageHandlers, | ||||||
|  |                                                TelegramBotProperties telegramBotProperties) { | ||||||
|  |         TelegramBotPropertiesUnit propertiesUnit = telegramBotProperties.find(BOT_PROPERTIES_UNIT_NAME); | ||||||
|  |         return new MessageDispatcher(messageHandlers, propertiesUnit.getName(), propertiesUnit.getToken()); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,44 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.receiver.configuration.properties; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | import org.springframework.boot.context.properties.ConfigurationProperties; | ||||||
|  | import org.springframework.boot.context.properties.ConstructorBinding; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | 
 | ||||||
|  | import lombok.AllArgsConstructor; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.Getter; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | import lombok.Setter; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * TelegramBotProperties | ||||||
|  |  * @author Shin Woo-jin (woo-jin.shin@linecorp.com) | ||||||
|  |  * @since 2021-09-05 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | @Component | ||||||
|  | @Setter | ||||||
|  | @Getter | ||||||
|  | @ConfigurationProperties(prefix = "infra.telegram.bot") | ||||||
|  | public class TelegramBotProperties { | ||||||
|  | 
 | ||||||
|  |     private List<TelegramBotPropertiesUnit> units = new ArrayList<>(); | ||||||
|  | 
 | ||||||
|  |     @Data | ||||||
|  |     public static class TelegramBotPropertiesUnit { | ||||||
|  |         private String unitName; | ||||||
|  |         private String name; | ||||||
|  |         private String token; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public TelegramBotPropertiesUnit find(String unitName) { | ||||||
|  |         return units.stream() | ||||||
|  |                     .filter(e -> e.getUnitName().equals(unitName)) | ||||||
|  |                     .findFirst() | ||||||
|  |                     .orElseThrow( | ||||||
|  |                         () -> new IllegalArgumentException(this.getClass().getName() + ": unitName Not found. " + unitName)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,33 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.receiver.controller.v1; | ||||||
|  | 
 | ||||||
|  | import org.springframework.web.bind.annotation.PathVariable; | ||||||
|  | import org.springframework.web.bind.annotation.PostMapping; | ||||||
|  | import org.springframework.web.bind.annotation.RequestMapping; | ||||||
|  | import org.springframework.web.bind.annotation.RestController; | ||||||
|  | 
 | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.receiver.service.ProcessorAPIService; | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.support.dto.code.PpomppuBoardName; | ||||||
|  | 
 | ||||||
|  | import reactor.core.publisher.Mono; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * EventAPIController | ||||||
|  |  * @author Shin Woo-jin (woo-jin.shin@linecorp.com) | ||||||
|  |  * @since 2021-09-05 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | @RestController | ||||||
|  | @RequestMapping("/api/v1/") | ||||||
|  | public class EventAPIController { | ||||||
|  | 
 | ||||||
|  |     private final ProcessorAPIService processorAPIService; | ||||||
|  | 
 | ||||||
|  |     public EventAPIController(ProcessorAPIService processorAPIService) { | ||||||
|  |         this.processorAPIService = processorAPIService; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @PostMapping("/exploit/parsePpomppuRSS/{boardName}") | ||||||
|  |     public Mono<String> parsePpomppuRSS(@PathVariable("boardName") PpomppuBoardName boardName) { | ||||||
|  |         return processorAPIService.emitParseEvent(boardName); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,50 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.receiver.dispatch; | ||||||
|  | 
 | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | import org.telegram.telegrambots.bots.TelegramLongPollingBot; | ||||||
|  | import org.telegram.telegrambots.meta.api.objects.Message; | ||||||
|  | import org.telegram.telegrambots.meta.api.objects.Update; | ||||||
|  | 
 | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.receiver.handler.message.MessageHandler; | ||||||
|  | 
 | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
|  | @Slf4j | ||||||
|  | public class MessageDispatcher extends TelegramLongPollingBot { | ||||||
|  | 
 | ||||||
|  |     private final List<MessageHandler> messageHandlers; | ||||||
|  |     private final String botName; | ||||||
|  |     private final String botToken; | ||||||
|  | 
 | ||||||
|  |     public MessageDispatcher(List<MessageHandler> messageHandlers, String botName, String botToken) { | ||||||
|  |         this.messageHandlers = messageHandlers; | ||||||
|  |         this.botName = botName; | ||||||
|  |         this.botToken = botToken; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String getBotToken() { | ||||||
|  |         return botToken; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void onUpdateReceived(Update update) { | ||||||
|  | 
 | ||||||
|  |         Message message = update.getMessage(); | ||||||
|  |         MessageHandler handler = getMessageHandler(message); | ||||||
|  |         handler.handle(message); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private MessageHandler getMessageHandler(Message message) { | ||||||
|  |         return messageHandlers.stream() | ||||||
|  |                               .filter(e -> e.isApplicable(message)) | ||||||
|  |                               .findFirst() | ||||||
|  |                               .orElseThrow(() -> new IllegalArgumentException("Can not found applicable handler")); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String getBotUsername() { | ||||||
|  |         return botName; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,25 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.receiver.dto; | ||||||
|  | 
 | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.support.dto.code.PpomppuBoardName; | ||||||
|  | import java.io.Serializable; | ||||||
|  | import java.time.Instant; | ||||||
|  | import lombok.Getter; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * FeedParsedResult | ||||||
|  |  * | ||||||
|  |  * @author Shin Woo-jin (woozu.shin@kakaoent.com) | ||||||
|  |  * @since 2021-09-08 | ||||||
|  |  */ | ||||||
|  | @Getter | ||||||
|  | @NoArgsConstructor | ||||||
|  | public class FeedParsedResult implements Serializable { | ||||||
|  | 
 | ||||||
|  |     private static final long serialVersionUID = -3771310078623481348L; | ||||||
|  | 
 | ||||||
|  |     private PpomppuBoardName boardName; | ||||||
|  |     private Instant requestedAt; | ||||||
|  |     private Instant processedAt; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,19 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.receiver.dto.constant; | ||||||
|  | 
 | ||||||
|  | import lombok.AllArgsConstructor; | ||||||
|  | import lombok.Getter; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * WebClientPropertiesUnitName | ||||||
|  |  * @author Shin Woo-jin (woo-jin.shin@linecorp.com) | ||||||
|  |  * @since 2021-11-18 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | @Getter | ||||||
|  | @AllArgsConstructor | ||||||
|  | public enum WebClientPropertiesUnitName { | ||||||
|  |     PPOMPPU_NOTIFIER_PROCESSOR_API("ppn-processor-api"), | ||||||
|  |     ; | ||||||
|  | 
 | ||||||
|  |     private String unitName; | ||||||
|  | } | ||||||
|  | @ -0,0 +1,21 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.receiver.handler.message; | ||||||
|  | 
 | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.support.util.ObjectUtil; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | import org.telegram.telegrambots.meta.api.objects.Message; | ||||||
|  | 
 | ||||||
|  | @Slf4j | ||||||
|  | @Component | ||||||
|  | public class HelloWorldMessageHandler implements MessageHandler { | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean isApplicable(Message message) { | ||||||
|  |         return ObjectUtil.isEmpty(message); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void handle(Message message) { | ||||||
|  |         // skip empty event message. | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,12 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.receiver.handler.message; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * ImageHandler | ||||||
|  |  * @author Shin Woo-jin (woo-jin.shin@linecorp.com) | ||||||
|  |  * @since 2021-08-21 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | public interface ImageMessageHandler extends MessageHandler { | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,17 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.receiver.handler.message; | ||||||
|  | 
 | ||||||
|  | import org.telegram.telegrambots.meta.api.objects.Message; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * MessageHandler | ||||||
|  |  * @author Shin Woo-jin (woo-jin.shin@linecorp.com) | ||||||
|  |  * @since 2021-08-21 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | public interface MessageHandler { | ||||||
|  | 
 | ||||||
|  |     boolean isApplicable(Message message); | ||||||
|  | 
 | ||||||
|  |     void handle(Message message); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,18 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.receiver.handler.message; | ||||||
|  | 
 | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.support.util.ObjectUtil; | ||||||
|  | import org.telegram.telegrambots.meta.api.objects.Message; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * TextMessageHandler | ||||||
|  |  * | ||||||
|  |  * @author Shin Woo-jin (woo-jin.shin@linecorp.com) | ||||||
|  |  * @since 2021-08-21 | ||||||
|  |  */ | ||||||
|  | public interface TextMessageHandler extends MessageHandler { | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     default boolean isApplicable(Message message) { | ||||||
|  |         return ObjectUtil.isNotEmpty(message) && message.isUserMessage() && message.hasText(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,48 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.receiver.handler.message.text; | ||||||
|  | 
 | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | import org.telegram.telegrambots.meta.api.objects.Message; | ||||||
|  | 
 | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.receiver.handler.message.TextMessageHandler; | ||||||
|  | 
 | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * CommandHandler | ||||||
|  |  * @author Shin Woo-jin (woo-jin.shin@linecorp.com) | ||||||
|  |  * @since 2021-08-21 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | @Slf4j | ||||||
|  | @Component | ||||||
|  | public class CommandHandler implements TextMessageHandler { | ||||||
|  | 
 | ||||||
|  |     private final List<TextCommandProcessor> processors; | ||||||
|  | 
 | ||||||
|  |     public CommandHandler(List<TextCommandProcessor> processors) { | ||||||
|  |         this.processors = processors; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean isApplicable(Message message) { | ||||||
|  |         return TextMessageHandler.super.isApplicable(message) | ||||||
|  |                && message.isCommand(); // && message.getText().startsWith("/"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void handle(Message message) { | ||||||
|  |         log.info("CommandHandler : {}", message.getText()); | ||||||
|  |         TextCommandCode commandCode = TextCommandCode.find(message.getText()); | ||||||
|  |         TextCommandProcessor applicableProcessor = getApplicableProcessor(commandCode); | ||||||
|  |         applicableProcessor.process(message); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private TextCommandProcessor getApplicableProcessor(TextCommandCode commandCode) { | ||||||
|  |         return processors.stream() | ||||||
|  |                          .filter(e -> e.isApplicable(commandCode)) | ||||||
|  |                          .findFirst() | ||||||
|  |                          .orElseThrow(() -> new IllegalArgumentException("Can not found")); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,30 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.receiver.handler.message.text; | ||||||
|  | 
 | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | import org.telegram.telegrambots.meta.api.objects.Message; | ||||||
|  | 
 | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.receiver.handler.message.TextMessageHandler; | ||||||
|  | 
 | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * NormalTextHandler | ||||||
|  |  * @author Shin Woo-jin (woo-jin.shin@linecorp.com) | ||||||
|  |  * @since 2021-08-21 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | @Slf4j | ||||||
|  | @Component | ||||||
|  | public class CommonTextHandler implements TextMessageHandler { | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean isApplicable(Message message) { | ||||||
|  |         return TextMessageHandler.super.isApplicable(message) && message.isCommand() == false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void handle(Message message) { | ||||||
|  |         log.info("CommonTextHandler : {}", message.getText()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,24 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.receiver.handler.message.text; | ||||||
|  | 
 | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | import org.telegram.telegrambots.meta.api.objects.Message; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * EmptyTextCommandProcessor | ||||||
|  |  * @author Shin Woo-jin (woo-jin.shin@linecorp.com) | ||||||
|  |  * @since 2021-09-05 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | @Component | ||||||
|  | public class EmptyTextCommandProcessor implements TextCommandProcessor { | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean isApplicable(TextCommandCode commandCode) { | ||||||
|  |         return commandCode == TextCommandCode.EMPTY; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void process(Message message) { | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,27 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.receiver.handler.message.text; | ||||||
|  | 
 | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | import org.telegram.telegrambots.meta.api.objects.Message; | ||||||
|  | 
 | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * StartCommandProcessor | ||||||
|  |  * @author Shin Woo-jin (woo-jin.shin@linecorp.com) | ||||||
|  |  * @since 2021-09-05 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | @Slf4j | ||||||
|  | @Component | ||||||
|  | public class StartTextCommandProcessor implements TextCommandProcessor { | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean isApplicable(TextCommandCode commandCode) { | ||||||
|  |         return TextCommandCode.START == commandCode; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void process(Message message) { | ||||||
|  |         log.info("[process] user: {}, command: {}", message.getChatId(), message.getText()); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,33 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.receiver.handler.message.text; | ||||||
|  | 
 | ||||||
|  | import java.util.Arrays; | ||||||
|  | 
 | ||||||
|  | import lombok.Getter; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * CommandTextCode | ||||||
|  |  * @author Shin Woo-jin (woo-jin.shin@linecorp.com) | ||||||
|  |  * @since 2021-09-05 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | @Getter | ||||||
|  | @NoArgsConstructor | ||||||
|  | public enum TextCommandCode { | ||||||
|  |     EMPTY(null), | ||||||
|  |     START("/start"), | ||||||
|  |     ; | ||||||
|  |     private String value; | ||||||
|  | 
 | ||||||
|  |     TextCommandCode(String value) { | ||||||
|  |         this.value = value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static TextCommandCode find(String value) { | ||||||
|  |         return Arrays.stream(TextCommandCode.values()) | ||||||
|  |                      .filter(e -> e != EMPTY) | ||||||
|  |                      .filter(e -> value.startsWith(e.getValue())) | ||||||
|  |                      .findFirst() | ||||||
|  |                      .orElse(TextCommandCode.EMPTY); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,17 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.receiver.handler.message.text; | ||||||
|  | 
 | ||||||
|  | import org.telegram.telegrambots.meta.api.objects.Message; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * TextCommandProcessor | ||||||
|  |  * @author Shin Woo-jin (woo-jin.shin@linecorp.com) | ||||||
|  |  * @since 2021-09-05 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | public interface TextCommandProcessor { | ||||||
|  | 
 | ||||||
|  |     boolean isApplicable(TextCommandCode commandCode); | ||||||
|  | 
 | ||||||
|  |     void process(Message message); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,44 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.receiver.infrastructure.client; | ||||||
|  | 
 | ||||||
|  | import org.springframework.core.ParameterizedTypeReference; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | import org.springframework.web.reactive.function.client.WebClient; | ||||||
|  | import org.springframework.web.reactive.function.client.WebClientRequestException; | ||||||
|  | 
 | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.receiver.dto.constant.WebClientPropertiesUnitName; | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.support.dto.code.PpomppuBoardName; | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.support.webclient.factory.WebClientFilterFactory; | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.support.webclient.properties.WebClientProperties; | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.support.webclient.properties.WebClientProperties.WebClientPropertiesUnit; | ||||||
|  | 
 | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import reactor.core.publisher.Mono; | ||||||
|  | import reactor.core.scheduler.Schedulers; | ||||||
|  | 
 | ||||||
|  | @Slf4j | ||||||
|  | @Component | ||||||
|  | public class ProcessorAPIWebClient { | ||||||
|  | 
 | ||||||
|  |     private final WebClient webClient; | ||||||
|  | 
 | ||||||
|  |     public ProcessorAPIWebClient(WebClientProperties webClientProperties) { | ||||||
|  |         WebClientPropertiesUnit webClientPropertiesUnit = | ||||||
|  |             webClientProperties.find(WebClientPropertiesUnitName.PPOMPPU_NOTIFIER_PROCESSOR_API.getUnitName()); | ||||||
|  |         this.webClient = WebClient.builder() | ||||||
|  |                                   .baseUrl(webClientPropertiesUnit.getBaseUrl()) | ||||||
|  |                                   .filter(WebClientFilterFactory.logRequest()) | ||||||
|  |                                   .filter(WebClientFilterFactory.logResponse()) | ||||||
|  |                                   .build(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Mono<String> emitParseEvent(PpomppuBoardName boardName) { | ||||||
|  |         return webClient.post() | ||||||
|  |                         .uri("/api/v1/crawl/boards/{boardName}", boardName) | ||||||
|  |                         .exchangeToMono(e -> e.bodyToMono(new ParameterizedTypeReference<String>() {})) | ||||||
|  |                         .publishOn(Schedulers.boundedElastic()) | ||||||
|  |                         .onErrorResume(WebClientRequestException.class, t -> { | ||||||
|  |                             log.info("Exception occured, ignoring. : {}", t.getClass().getSimpleName()); | ||||||
|  |                             return Mono.empty(); | ||||||
|  |                         }); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,30 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.receiver.service; | ||||||
|  | 
 | ||||||
|  | import org.springframework.stereotype.Service; | ||||||
|  | 
 | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.receiver.infrastructure.client.ProcessorAPIWebClient; | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.support.dto.code.PpomppuBoardName; | ||||||
|  | 
 | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import reactor.core.publisher.Mono; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * ProcessorAPIService | ||||||
|  |  * @author Shin Woo-jin (woo-jin.shin@linecorp.com) | ||||||
|  |  * @since 2021-09-05 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | @Slf4j | ||||||
|  | @Service | ||||||
|  | public class ProcessorAPIService { | ||||||
|  | 
 | ||||||
|  |     private final ProcessorAPIWebClient processorAPIWebClient; | ||||||
|  | 
 | ||||||
|  |     public ProcessorAPIService(ProcessorAPIWebClient processorAPIWebClient) { | ||||||
|  |         this.processorAPIWebClient = processorAPIWebClient; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Mono<String> emitParseEvent(PpomppuBoardName boardName) { | ||||||
|  |         return processorAPIWebClient.emitParseEvent(boardName); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,6 @@ | ||||||
|  | spring: | ||||||
|  |   config: | ||||||
|  |     activate: | ||||||
|  |       on-profile: development | ||||||
|  |     import: | ||||||
|  |       - "configserver:http://192.168.0.100:11080" | ||||||
|  | @ -0,0 +1,6 @@ | ||||||
|  | spring: | ||||||
|  |   config: | ||||||
|  |     activate: | ||||||
|  |       on-profile: local | ||||||
|  |     import: | ||||||
|  |       - "configserver:http://localhost:20085" | ||||||
|  | @ -0,0 +1,15 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <configuration> | ||||||
|  |   <springProperty name="DEFAULT_LEVEL_CONFIG" source="log.defaultLevel" /> | ||||||
|  |   <springProfile name="local"> | ||||||
|  |     <include resource="logback/logback-development.xml" /> | ||||||
|  |     <logger name="org.apache.kafka" level="INFO" /> | ||||||
|  |   </springProfile> | ||||||
|  |   <springProfile name="development"> | ||||||
|  |     <include resource="logback/logback-development.xml" /> | ||||||
|  |     <logger name="org.apache.kafka" level="INFO" /> | ||||||
|  |   </springProfile> | ||||||
|  |   <springProfile name="production"> | ||||||
|  |     <include resource="logback/logback-production.xml" /> | ||||||
|  |   </springProfile> | ||||||
|  | </configuration> | ||||||
|  | @ -0,0 +1,23 @@ | ||||||
|  | <included> | ||||||
|  |   <property name="FILE_LOG_PATTERN" | ||||||
|  |             value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{45}:%L - %msg%n" /> | ||||||
|  |   <property name="LOG_FILE_BASE" value="lcp-benefit-benefit-api" /> | ||||||
|  |   <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||||||
|  |     <file>${DIRECTORY}/${LOG_FILE_BASE}_log</file> | ||||||
|  |     <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | ||||||
|  |       <fileNamePattern>${DIRECTORY}/${LOG_FILE_BASE}_log.%d{yyyyMMdd}.%i</fileNamePattern> | ||||||
|  |       <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> | ||||||
|  |         <maxFileSize>1000MB</maxFileSize> | ||||||
|  |       </timeBasedFileNamingAndTriggeringPolicy> | ||||||
|  |       <maxHistory>60</maxHistory> | ||||||
|  |     </rollingPolicy> | ||||||
|  |     <encoder> | ||||||
|  |       <pattern>${FILE_LOG_PATTERN}</pattern> | ||||||
|  |       <immediateFlush>${IMMEDIATE_FLUSH}</immediateFlush> | ||||||
|  |     </encoder> | ||||||
|  |   </appender> | ||||||
|  |   <appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender"> | ||||||
|  |     <queueSize>1024</queueSize> | ||||||
|  |     <appender-ref ref="FILE" /> | ||||||
|  |   </appender> | ||||||
|  | </included> | ||||||
|  | @ -0,0 +1,19 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <included> | ||||||
|  |   <!-- =========== property BETA ========= --> | ||||||
|  |   <property name="DEFAULT_LEVEL" value="${DEFAULT_LEVEL_CONFIG:-INFO}"/> | ||||||
|  |   <!--file--> | ||||||
|  |   <property name="DIRECTORY" value="/home1/www/logs/supervisor"/> | ||||||
|  |   <property name="IMMEDIATE_FLUSH" value="true"/> | ||||||
|  |   <!--nelo2--> | ||||||
|  |   <property name="NELO2_LEVEL" value="WARN"/> | ||||||
|  |   <!-- =========== include appender =========== --> | ||||||
|  |   <include resource="org/springframework/boot/logging/logback/defaults.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 level="${DEFAULT_LEVEL}"> | ||||||
|  |     <appender-ref ref="CONSOLE"/> | ||||||
|  |   </root> | ||||||
|  | </included> | ||||||
|  | @ -0,0 +1,19 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <included> | ||||||
|  |   <!-- =========== property RELEASE ========= --> | ||||||
|  |   <property name="DEFAULT_LEVEL" value="${DEFAULT_LEVEL_CONFIG:-INFO}"/> | ||||||
|  |   <!--file--> | ||||||
|  |   <property name="DIRECTORY" value="/home1/www/logs/supervisor"/> | ||||||
|  |   <property name="IMMEDIATE_FLUSH" value="true"/> | ||||||
|  |   <!--nelo2--> | ||||||
|  |   <property name="NELO2_LEVEL" value="WARN"/> | ||||||
|  |   <!-- =========== include appender =========== --> | ||||||
|  |   <include resource="org/springframework/boot/logging/logback/defaults.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 level="${DEFAULT_LEVEL}"> | ||||||
|  |     <appender-ref ref="CONSOLE"/> | ||||||
|  |   </root> | ||||||
|  | </included> | ||||||
|  | @ -0,0 +1,23 @@ | ||||||
|  | dependencies { | ||||||
|  |     developmentOnly 'org.springframework.boot:spring-boot-devtools' | ||||||
|  |     runtimeOnly 'mysql:mysql-connector-java' | ||||||
|  |     compileOnly 'org.projectlombok:lombok' | ||||||
|  | 
 | ||||||
|  |     implementation project(':support') | ||||||
|  |     // https://projectreactor.io/docs/core/release/reference/#debug-activate | ||||||
|  |     implementation 'org.springframework.boot:spring-boot-starter-webflux' | ||||||
|  |     implementation 'org.springframework.boot:spring-boot-starter-actuator' | ||||||
|  |     implementation 'org.springframework.cloud:spring-cloud-starter-config' | ||||||
|  | 
 | ||||||
|  |     annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' | ||||||
|  |     annotationProcessor 'org.projectlombok:lombok' | ||||||
|  | 
 | ||||||
|  |     testImplementation 'org.springframework.boot:spring-boot-starter-test' | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | test { | ||||||
|  |     useJUnitPlatform() | ||||||
|  |     testLogging { | ||||||
|  |         events "passed", "skipped", "failed" | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,22 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.sender; | ||||||
|  | 
 | ||||||
|  | import org.springframework.boot.SpringApplication; | ||||||
|  | import org.springframework.boot.autoconfigure.SpringBootApplication; | ||||||
|  | import org.springframework.context.annotation.Import; | ||||||
|  | 
 | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.support.webclient.PpomppuNotifierWebClientConfiguration; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * SenderApplication | ||||||
|  |  * @author Shin Woo-jin (woo-jin.shin@linecorp.com) | ||||||
|  |  * @since 2021-08-20 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | @Import({ PpomppuNotifierWebClientConfiguration.class }) | ||||||
|  | @SpringBootApplication | ||||||
|  | public class SenderApplication { | ||||||
|  | 
 | ||||||
|  |     public static void main(String[] args) { | ||||||
|  |         SpringApplication.run(SenderApplication.class, args); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.configuration.slack.properties; | package com.myoa.engineering.crawl.ppomppu.sender.configuration.properties; | ||||||
| 
 | 
 | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
|  | @ -7,16 +7,18 @@ import lombok.Setter; | ||||||
| import org.springframework.boot.context.properties.ConfigurationProperties; | import org.springframework.boot.context.properties.ConfigurationProperties; | ||||||
| import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||||
| 
 | 
 | ||||||
| @Data | @Getter | ||||||
|  | @Setter | ||||||
| @Component | @Component | ||||||
| @ConfigurationProperties(prefix = "slack.bot") | @ConfigurationProperties("infra.slack.bot") | ||||||
| public class SlackSecretProperties { | public class SlackSecretProperties { | ||||||
| 
 | 
 | ||||||
|     private List<SlackSecretPropertiesUnit> units; |     private List<SlackSecretPropertiesUnit> units; | ||||||
| 
 | 
 | ||||||
|     @Data |     @Data | ||||||
|     public static class SlackSecretPropertiesUnit { |     public static class SlackSecretPropertiesUnit { | ||||||
|         private String botUnitName; | 
 | ||||||
|  |         private String botName; | ||||||
|         private String username; |         private String username; | ||||||
|         private String iconEmoji; |         private String iconEmoji; | ||||||
|         private String channel; |         private String channel; | ||||||
|  | @ -25,7 +27,7 @@ public class SlackSecretProperties { | ||||||
| 
 | 
 | ||||||
|     public SlackSecretPropertiesUnit find(String botUnitName) { |     public SlackSecretPropertiesUnit find(String botUnitName) { | ||||||
|         return units.stream() |         return units.stream() | ||||||
|                     .filter(e -> e.getBotUnitName().equals(botUnitName)) |                     .filter(e -> e.getBotName().equals(botUnitName)) | ||||||
|                     .findFirst() |                     .findFirst() | ||||||
|                     .orElseThrow(() -> new IllegalArgumentException("not found bot unit name : " + botUnitName)); |                     .orElseThrow(() -> new IllegalArgumentException("not found bot unit name : " + botUnitName)); | ||||||
|     } |     } | ||||||
|  | @ -0,0 +1,33 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.sender.controller; | ||||||
|  | 
 | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.sender.infrastructure.client.MongeShoppingBotSlackMessageSender; | ||||||
|  | import org.springframework.web.bind.annotation.GetMapping; | ||||||
|  | import org.springframework.web.bind.annotation.RequestMapping; | ||||||
|  | import org.springframework.web.bind.annotation.RestController; | ||||||
|  | 
 | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import reactor.core.publisher.Mono; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * TestAPIController | ||||||
|  |  * | ||||||
|  |  * @author Shin Woo-jin (woo-jin.shin@linecorp.com) | ||||||
|  |  * @since 2021-11-15 | ||||||
|  |  */ | ||||||
|  | @Slf4j | ||||||
|  | @RestController | ||||||
|  | @RequestMapping("/api/v1") | ||||||
|  | public class TestAPIController { | ||||||
|  | 
 | ||||||
|  |     private final MongeShoppingBotSlackMessageSender sender; | ||||||
|  | 
 | ||||||
|  |     public TestAPIController(MongeShoppingBotSlackMessageSender sender) { | ||||||
|  |         this.sender = sender; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GetMapping("/test") | ||||||
|  |     public Mono<String> test() { | ||||||
|  |         log.info("received!!!"); | ||||||
|  |         return sender.sendMessage(sender.ofMessage("testtesttest!!!")); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.dto.slack; | package com.myoa.engineering.crawl.ppomppu.sender.dto; | ||||||
| 
 | 
 | ||||||
| import java.io.Serializable; | import java.io.Serializable; | ||||||
| 
 | 
 | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.dto.slack; | package com.myoa.engineering.crawl.ppomppu.sender.dto; | ||||||
| 
 | 
 | ||||||
| import java.util.List; | import java.util.List; | ||||||
| 
 | 
 | ||||||
|  | @ -0,0 +1,17 @@ | ||||||
|  | package com.myoa.engineering.crawl.ppomppu.sender.infrastructure.client; | ||||||
|  | 
 | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.sender.dto.MessageDTO; | ||||||
|  | 
 | ||||||
|  | import reactor.core.publisher.Mono; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * MessageSender | ||||||
|  |  * @author Shin Woo-jin (woo-jin.shin@linecorp.com) | ||||||
|  |  * @since 2021-11-14 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | public interface MessageSender<T extends MessageDTO> { | ||||||
|  | 
 | ||||||
|  |     Mono<String> sendMessage(T message); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -1,6 +1,17 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.infra.client.slack; | package com.myoa.engineering.crawl.ppomppu.sender.infrastructure.client; | ||||||
|  | 
 | ||||||
|  | import org.springframework.http.HttpHeaders; | ||||||
|  | import org.springframework.http.MediaType; | ||||||
|  | import org.springframework.web.reactive.function.client.WebClient; | ||||||
|  | import org.springframework.web.reactive.function.client.WebClientRequestException; | ||||||
|  | 
 | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.sender.dto.SlackMessageDTO; | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.support.webclient.factory.WebClientFilterFactory; | ||||||
|  | import com.myoa.engineering.crawl.ppomppu.support.webclient.factory.WebFluxExchangeStragiesFactory; | ||||||
| 
 | 
 | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import reactor.core.publisher.Mono; | ||||||
|  | import reactor.core.scheduler.Schedulers; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * SlackMessageSender |  * SlackMessageSender | ||||||
|  | @ -9,9 +20,8 @@ import lombok.extern.slf4j.Slf4j; | ||||||
|  * @since 2021-09-08 |  * @since 2021-09-08 | ||||||
|  */ |  */ | ||||||
| @Slf4j | @Slf4j | ||||||
| public class SlackMessageSender { /* implements MessageSender<SlackMessageDTO> {*/ | public class SlackMessageSender implements MessageSender<SlackMessageDTO> { | ||||||
| 
 | 
 | ||||||
| /* |  | ||||||
|     private static final String SLACK_API_URL = "https://slack.com/api"; |     private static final String SLACK_API_URL = "https://slack.com/api"; | ||||||
| 
 | 
 | ||||||
|     private final WebClient webClient; |     private final WebClient webClient; | ||||||
|  | @ -42,6 +52,4 @@ public class SlackMessageSender { /* implements MessageSender<SlackMessageDTO> { | ||||||
|                         .doOnNext(e -> log.info("[sendMessage] {}", e)); |                         .doOnNext(e -> log.info("[sendMessage] {}", e)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  | @ -0,0 +1,10 @@ | ||||||
|  | spring: | ||||||
|  |   config: | ||||||
|  |     activate: | ||||||
|  |       on-profile: development | ||||||
|  |     import: | ||||||
|  |       - "configserver:http://192.168.0.100:11080" | ||||||
|  |     # import: optional:configserver:http://localhost:11080 # can be start up even config server was not found. | ||||||
|  | 
 | ||||||
|  | server: | ||||||
|  |   port: 20082 | ||||||
|  | @ -3,16 +3,8 @@ spring: | ||||||
|     activate: |     activate: | ||||||
|       on-profile: local |       on-profile: local | ||||||
|     import: |     import: | ||||||
|       - classpath:/datasource/local.yml |       - "configserver:http://localhost:20085" | ||||||
|       - classpath:/slack/local.yml |  | ||||||
| 
 |  | ||||||
| server: |  | ||||||
|   port: 20080 |  | ||||||
| 
 |  | ||||||
|     # import: optional:configserver:http://localhost:11080 # can be start up even config server was not found. |     # import: optional:configserver:http://localhost:11080 # can be start up even config server was not found. | ||||||
| 
 | 
 | ||||||
| feign: | server: | ||||||
|   client: |   port: 20082 | ||||||
|     config: |  | ||||||
|       default: |  | ||||||
|         loggerLevel: FULL |  | ||||||
|  | @ -0,0 +1,6 @@ | ||||||
|  | spring: | ||||||
|  |   config: | ||||||
|  |     activate: | ||||||
|  |       on-profile: production | ||||||
|  |     import: | ||||||
|  |       - "configserver:http://ppn-config-server:20080" | ||||||
|  | @ -0,0 +1,15 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <configuration> | ||||||
|  |   <springProfile name="local"> | ||||||
|  |     <include resource="logback/logback-development.xml" /> | ||||||
|  |     <logger name="org.apache.kafka" level="INFO" /> | ||||||
|  |   </springProfile> | ||||||
|  |   <springProperty name="DEFAULT_LEVEL_CONFIG" source="log.defaultLevel" /> | ||||||
|  |   <springProfile name="development"> | ||||||
|  |     <include resource="logback/logback-development.xml" /> | ||||||
|  |     <logger name="org.apache.kafka" level="INFO" /> | ||||||
|  |   </springProfile> | ||||||
|  |   <springProfile name="production"> | ||||||
|  |     <include resource="logback/logback-production.xml" /> | ||||||
|  |   </springProfile> | ||||||
|  | </configuration> | ||||||
|  | @ -0,0 +1,23 @@ | ||||||
|  | <included> | ||||||
|  |   <property name="FILE_LOG_PATTERN" | ||||||
|  |             value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{45}:%L - %msg%n" /> | ||||||
|  |   <property name="LOG_FILE_BASE" value="lcp-benefit-benefit-api" /> | ||||||
|  |   <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||||||
|  |     <file>${DIRECTORY}/${LOG_FILE_BASE}_log</file> | ||||||
|  |     <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | ||||||
|  |       <fileNamePattern>${DIRECTORY}/${LOG_FILE_BASE}_log.%d{yyyyMMdd}.%i</fileNamePattern> | ||||||
|  |       <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> | ||||||
|  |         <maxFileSize>1000MB</maxFileSize> | ||||||
|  |       </timeBasedFileNamingAndTriggeringPolicy> | ||||||
|  |       <maxHistory>60</maxHistory> | ||||||
|  |     </rollingPolicy> | ||||||
|  |     <encoder> | ||||||
|  |       <pattern>${FILE_LOG_PATTERN}</pattern> | ||||||
|  |       <immediateFlush>${IMMEDIATE_FLUSH}</immediateFlush> | ||||||
|  |     </encoder> | ||||||
|  |   </appender> | ||||||
|  |   <appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender"> | ||||||
|  |     <queueSize>1024</queueSize> | ||||||
|  |     <appender-ref ref="FILE" /> | ||||||
|  |   </appender> | ||||||
|  | </included> | ||||||
|  | @ -0,0 +1,19 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <included> | ||||||
|  |   <!-- =========== property BETA ========= --> | ||||||
|  |   <property name="DEFAULT_LEVEL" value="${DEFAULT_LEVEL_CONFIG:-INFO}"/> | ||||||
|  |   <!--file--> | ||||||
|  |   <property name="DIRECTORY" value="/home1/www/logs/supervisor"/> | ||||||
|  |   <property name="IMMEDIATE_FLUSH" value="true"/> | ||||||
|  |   <!--nelo2--> | ||||||
|  |   <property name="NELO2_LEVEL" value="WARN"/> | ||||||
|  |   <!-- =========== include appender =========== --> | ||||||
|  |   <include resource="org/springframework/boot/logging/logback/defaults.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 level="${DEFAULT_LEVEL}"> | ||||||
|  |     <appender-ref ref="CONSOLE"/> | ||||||
|  |   </root> | ||||||
|  | </included> | ||||||
|  | @ -0,0 +1,19 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <included> | ||||||
|  |   <!-- =========== property RELEASE ========= --> | ||||||
|  |   <property name="DEFAULT_LEVEL" value="${DEFAULT_LEVEL_CONFIG:-INFO}"/> | ||||||
|  |   <!--file--> | ||||||
|  |   <property name="DIRECTORY" value="/home1/www/logs/supervisor"/> | ||||||
|  |   <property name="IMMEDIATE_FLUSH" value="true"/> | ||||||
|  |   <!--nelo2--> | ||||||
|  |   <property name="NELO2_LEVEL" value="WARN"/> | ||||||
|  |   <!-- =========== include appender =========== --> | ||||||
|  |   <include resource="org/springframework/boot/logging/logback/defaults.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 level="${DEFAULT_LEVEL}"> | ||||||
|  |     <appender-ref ref="CONSOLE"/> | ||||||
|  |   </root> | ||||||
|  | </included> | ||||||
|  | @ -1,14 +1,14 @@ | ||||||
| rootProject.name = 'PpomppuNotifier' | rootProject.name = 'PpomppuNotifier' | ||||||
| 
 | 
 | ||||||
| //include 'reader' | include 'receiver' | ||||||
| //project(':reader').projectDir = "$rootDir/reader" as File | project(':receiver').projectDir = "$rootDir/receiver" as File | ||||||
| //include 'processor' | 
 | ||||||
| //project(':processor').projectDir = "$rootDir/processor" as File | include 'processor' | ||||||
| //include 'writer' | project(':processor').projectDir = "$rootDir/processor" as File | ||||||
| //project(':writer').projectDir = "$rootDir/writer" as File | 
 | ||||||
|  | include 'sender' | ||||||
|  | project(':sender').projectDir = "$rootDir/sender" as File | ||||||
| 
 | 
 | ||||||
| include 'shopping-crawler' |  | ||||||
| project(':shopping-crawler').projectDir = "$rootDir/shopping-crawler" as File |  | ||||||
| 
 | 
 | ||||||
| include 'support' | include 'support' | ||||||
| project(':support').projectDir = "$rootDir/support" as File | project(':support').projectDir = "$rootDir/support" as File | ||||||
|  |  | ||||||
										
											Binary file not shown.
										
									
								
							|  | @ -1,42 +0,0 @@ | ||||||
| dependencies { |  | ||||||
|     developmentOnly 'org.springframework.boot:spring-boot-devtools' |  | ||||||
|     runtimeOnly 'com.h2database:h2' |  | ||||||
|     runtimeOnly 'com.mysql:mysql-connector-j' |  | ||||||
|     compileOnly 'org.projectlombok:lombok' |  | ||||||
| 
 |  | ||||||
|     implementation project(':support') |  | ||||||
|     // https://projectreactor.io/docs/core/release/reference/#debug-activate |  | ||||||
|     implementation("org.springframework.boot:spring-boot-starter-web") { |  | ||||||
|         exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat" |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     implementation("org.springframework.boot:spring-boot-starter-undertow") { |  | ||||||
|         exclude group: "io.undertow", module: "undertow-websockets-jsr" |  | ||||||
|     } |  | ||||||
|     implementation 'org.springframework.boot:spring-boot-starter-data-jpa' |  | ||||||
|     implementation 'org.springframework.boot:spring-boot-configuration-processor' |  | ||||||
|     implementation 'org.springframework.cloud:spring-cloud-starter-config' |  | ||||||
|     implementation 'org.springframework.boot:spring-boot-starter-actuator' |  | ||||||
|     implementation 'com.rometools:rome:2.1.0' |  | ||||||
|     implementation 'org.jsoup:jsoup:1.17.2' |  | ||||||
|     implementation 'com.h2database:h2:2.2.224' |  | ||||||
|     implementation "org.springframework.cloud:spring-cloud-starter-openfeign" |  | ||||||
|     implementation "io.github.openfeign:feign-hc5" |  | ||||||
|     implementation 'org.ahocorasick:ahocorasick:0.6.3' |  | ||||||
| 
 |  | ||||||
|     annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' |  | ||||||
|     annotationProcessor 'org.projectlombok:lombok' |  | ||||||
| 
 |  | ||||||
|     testImplementation 'org.springframework.boot:spring-boot-starter-test' |  | ||||||
|     testImplementation('org.assertj:assertj-core:3.25.3') |  | ||||||
|     testImplementation("org.jeasy:easy-random-core:5.0.0") |  | ||||||
|     testCompileOnly 'org.projectlombok:lombok' |  | ||||||
|     testAnnotationProcessor('org.projectlombok:lombok') |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| test { |  | ||||||
|     useJUnitPlatform() |  | ||||||
|     testLogging { |  | ||||||
|         events "passed", "skipped", "failed" |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,19 +0,0 @@ | ||||||
| package com.myoa.engineering.crawl.shopping; |  | ||||||
| 
 |  | ||||||
| import org.springframework.boot.SpringApplication; |  | ||||||
| import org.springframework.boot.autoconfigure.SpringBootApplication; |  | ||||||
| import org.springframework.boot.context.properties.EnableConfigurationProperties; |  | ||||||
| import org.springframework.cloud.openfeign.EnableFeignClients; |  | ||||||
| import org.springframework.scheduling.annotation.EnableScheduling; |  | ||||||
| 
 |  | ||||||
| @EnableScheduling |  | ||||||
| @EnableFeignClients |  | ||||||
| @EnableConfigurationProperties |  | ||||||
| @SpringBootApplication |  | ||||||
| public class ShoppingCrawlerApplication { |  | ||||||
| 
 |  | ||||||
|     public static void main(String[] args) { |  | ||||||
|         SpringApplication.run(ShoppingCrawlerApplication.class, args); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
|  | @ -1,30 +0,0 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.configuration; |  | ||||||
| 
 |  | ||||||
| import feign.Logger; |  | ||||||
| import feign.RequestInterceptor; |  | ||||||
| import feign.codec.ErrorDecoder; |  | ||||||
| import lombok.extern.slf4j.Slf4j; |  | ||||||
| import org.springframework.context.annotation.Bean; |  | ||||||
| import org.springframework.context.annotation.Configuration; |  | ||||||
| import org.springframework.http.HttpHeaders; |  | ||||||
| import org.springframework.http.MediaType; |  | ||||||
| 
 |  | ||||||
| @Slf4j |  | ||||||
| @Configuration |  | ||||||
| public class FeignDefaultConfig { |  | ||||||
| 
 |  | ||||||
|     @Bean |  | ||||||
|     Logger.Level feignLoggerLevel() { |  | ||||||
|         return Logger.Level.FULL; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     public static final String MIME_TYPE = |  | ||||||
|             MediaType.APPLICATION_JSON_VALUE + ";charset=utf-8"; |  | ||||||
| 
 |  | ||||||
|     @Bean |  | ||||||
|     public RequestInterceptor requestInterceptor() { |  | ||||||
|         return requestTemplate -> requestTemplate.header(HttpHeaders.CONTENT_TYPE, MIME_TYPE); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
|  | @ -1,22 +0,0 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.controller; |  | ||||||
| 
 |  | ||||||
| import com.myoa.engineering.crawl.shopping.crawlhandler.PpomppuCrawlDomesticHandler; |  | ||||||
| import org.springframework.web.bind.annotation.GetMapping; |  | ||||||
| import org.springframework.web.bind.annotation.RequestMapping; |  | ||||||
| import org.springframework.web.bind.annotation.RestController; |  | ||||||
| 
 |  | ||||||
| @RestController |  | ||||||
| @RequestMapping("/api/v1/exploit") |  | ||||||
| public class TestAPIController { |  | ||||||
| 
 |  | ||||||
|     private final PpomppuCrawlDomesticHandler ppomppuCrawlDomesticHandler; |  | ||||||
| 
 |  | ||||||
|     public TestAPIController(PpomppuCrawlDomesticHandler ppomppuCrawlDomesticHandler) { |  | ||||||
|         this.ppomppuCrawlDomesticHandler = ppomppuCrawlDomesticHandler; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @GetMapping("/triggers") |  | ||||||
|     public void triggerExploit() { |  | ||||||
|         ppomppuCrawlDomesticHandler.handle(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,10 +0,0 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.crawlhandler; |  | ||||||
| 
 |  | ||||||
| import com.myoa.engineering.crawl.shopping.support.dto.constant.CrawlTarget; |  | ||||||
| 
 |  | ||||||
| public interface CrawlHandler { |  | ||||||
| 
 |  | ||||||
|     CrawlTarget getCrawlTarget(); |  | ||||||
| 
 |  | ||||||
|     void handle(); |  | ||||||
| } |  | ||||||
|  | @ -1,18 +0,0 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.crawlhandler; |  | ||||||
| 
 |  | ||||||
| import com.myoa.engineering.crawl.shopping.support.dto.constant.CrawlTarget; |  | ||||||
| import lombok.extern.slf4j.Slf4j; |  | ||||||
| import org.springframework.stereotype.Component; |  | ||||||
| 
 |  | ||||||
| @Slf4j |  | ||||||
| @Component |  | ||||||
| public class FmkoreaCrawlHandler implements CrawlHandler { |  | ||||||
|     @Override |  | ||||||
|     public CrawlTarget getCrawlTarget() { |  | ||||||
|         return CrawlTarget.FMKOREA; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public void handle() { |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,58 +0,0 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.crawlhandler; |  | ||||||
| 
 |  | ||||||
| import com.myoa.engineering.crawl.shopping.crawlhandler.parser.PpomppuArticleParserV2; |  | ||||||
| import com.myoa.engineering.crawl.shopping.domain.entity.v2.Article; |  | ||||||
| import com.myoa.engineering.crawl.shopping.infra.client.ppomppu.PpomppuBoardClientV2; |  | ||||||
| import com.myoa.engineering.crawl.shopping.service.ArticleCommandService; |  | ||||||
| import com.myoa.engineering.crawl.shopping.support.dto.constant.CrawlTarget; |  | ||||||
| import org.springframework.stereotype.Component; |  | ||||||
| 
 |  | ||||||
| import java.util.HashMap; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Map; |  | ||||||
| import java.util.stream.Stream; |  | ||||||
| 
 |  | ||||||
| @Component |  | ||||||
| public class PpomppuCrawlDomesticHandler implements CrawlHandler { |  | ||||||
| 
 |  | ||||||
|     private final PpomppuBoardClientV2 ppomppuBoardClient; |  | ||||||
|     private final PpomppuArticleParserV2 ppomppuArticleParserV2; |  | ||||||
|     private final ArticleCommandService articleCommandService; |  | ||||||
| 
 |  | ||||||
|     public PpomppuCrawlDomesticHandler(PpomppuBoardClientV2 ppomppuBoardClient, |  | ||||||
|                                        PpomppuArticleParserV2 ppomppuArticleParserV2, |  | ||||||
|                                        ArticleCommandService articleCommandService) { |  | ||||||
|         this.ppomppuBoardClient = ppomppuBoardClient; |  | ||||||
|         this.ppomppuArticleParserV2 = ppomppuArticleParserV2; |  | ||||||
|         this.articleCommandService = articleCommandService; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public CrawlTarget getCrawlTarget() { |  | ||||||
|         return CrawlTarget.PPOMPPU_DOMESTIC; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public void handle() { |  | ||||||
| 
 |  | ||||||
|         String boardHtmlPage1 = ppomppuBoardClient.getBoardHtml("/zboard/zboard.php", generateRequestParams(1)); |  | ||||||
|         List<Article> parsedPage1 = ppomppuArticleParserV2.parse(boardHtmlPage1); |  | ||||||
| 
 |  | ||||||
|         String boardHtmlPage2 = ppomppuBoardClient.getBoardHtml("/zboard/zboard.php", generateRequestParams(2)); |  | ||||||
|         List<Article> parsedPage2 = ppomppuArticleParserV2.parse(boardHtmlPage2); |  | ||||||
| 
 |  | ||||||
|         List<Article> merged = Stream.of(parsedPage1, parsedPage2) |  | ||||||
|                                      .flatMap(List::stream) |  | ||||||
|                                      .map(e -> e.updateCrawlTarget(getCrawlTarget())) |  | ||||||
|                                      .toList(); |  | ||||||
| 
 |  | ||||||
|         articleCommandService.upsert(merged); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private Map<String, String> generateRequestParams(int pageId) { |  | ||||||
|         Map<String, String> params = new HashMap<>(); |  | ||||||
|         params.put("id", "ppomppu"); |  | ||||||
|         params.put("page", String.valueOf(pageId)); |  | ||||||
|         return params; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,115 +0,0 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.crawlhandler.parser; |  | ||||||
| 
 |  | ||||||
| import com.myoa.engineering.crawl.shopping.domain.entity.v2.Article; |  | ||||||
| import com.myoa.engineering.crawl.shopping.support.dto.constant.PpomppuBoardName; |  | ||||||
| import com.myoa.engineering.crawl.shopping.util.DateTimeUtils; |  | ||||||
| import com.myoa.engineering.crawl.shopping.util.NumberUtils; |  | ||||||
| import io.micrometer.core.instrument.util.StringUtils; |  | ||||||
| import lombok.extern.slf4j.Slf4j; |  | ||||||
| import org.jsoup.Jsoup; |  | ||||||
| import org.jsoup.nodes.Document; |  | ||||||
| import org.jsoup.nodes.Element; |  | ||||||
| import org.jsoup.select.Elements; |  | ||||||
| import org.springframework.stereotype.Component; |  | ||||||
| 
 |  | ||||||
| import java.time.ZoneId; |  | ||||||
| import java.time.ZonedDateTime; |  | ||||||
| import java.time.format.DateTimeFormatter; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.regex.Matcher; |  | ||||||
| import java.util.regex.Pattern; |  | ||||||
| 
 |  | ||||||
| @Slf4j |  | ||||||
| @Component |  | ||||||
| public final class PpomppuArticleParserV2 { |  | ||||||
| 
 |  | ||||||
|     private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yy.MM.dd HH:mm:ss") |  | ||||||
|                                                                                   .withZone(ZoneId.of("Asia/Seoul")); |  | ||||||
| 
 |  | ||||||
|     private PpomppuArticleParserV2() { |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public List<Article> parse(String html) { |  | ||||||
|         Elements trElements = converHtmlToTrElements(html); |  | ||||||
|         return trElements.stream() |  | ||||||
|                          .filter(this::isRealArticle) |  | ||||||
|                          .map(this::parse) |  | ||||||
|                          .toList(); |  | ||||||
| 
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private Elements converHtmlToTrElements(String data) { |  | ||||||
|         Document document = Jsoup.parse(data); |  | ||||||
|         Elements trList = document.getElementById("revolution_main_table").getElementsByTag("tr"); |  | ||||||
|         return trList; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private boolean isRealArticle(Element tr) { |  | ||||||
|         Elements tdList = tr.getElementsByTag("td"); |  | ||||||
|         if (tdList.size() != 6) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (!hasOnlyNumeric(tdList.get(0))) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private Pattern pattern_numeric = Pattern.compile("\\d+"); |  | ||||||
| 
 |  | ||||||
|     private boolean hasOnlyNumeric(Element td) { |  | ||||||
|         return pattern_numeric.matcher(td.text()).matches(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private Article parse(Element tr) { |  | ||||||
|         Elements tdList = tr.getElementsByTag("td"); |  | ||||||
|         Long articleId = Long.parseLong(tdList.get(0).text()); |  | ||||||
| 
 |  | ||||||
|         String title = tdList.get(2).text(); |  | ||||||
|         String articleUrl = parseArticleUrl(tdList.get(2).getElementsByTag("a").attr("href")); |  | ||||||
|         String boardName = parseBoardName(title); |  | ||||||
|         Integer recommended = parseRecommended(tdList.get(4)); |  | ||||||
|         Integer hit = NumberUtils.parseInt(tdList.get(5).text(), 0); |  | ||||||
|         ZonedDateTime registeredAt = DateTimeUtils.parse(tdList.get(3).text()); |  | ||||||
| 
 |  | ||||||
|         return Article.builder() |  | ||||||
|                       .articleId(articleId) |  | ||||||
|                       .title(title) |  | ||||||
|                       .boardName(boardName) |  | ||||||
|                       .articleUrl(articleUrl) |  | ||||||
|                       .recommended(recommended) |  | ||||||
|                       .hit(hit) |  | ||||||
|                       .registeredAt(registeredAt) |  | ||||||
|                       .build(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public Integer parseRecommended(Element td) { |  | ||||||
|         final String voteString = td.text(); |  | ||||||
|         if (StringUtils.isEmpty(voteString)) { |  | ||||||
|             return null; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         final int voteUp = Integer.parseInt(td.text().split(" - ")[0]); |  | ||||||
|         final int voteDown = Integer.parseInt(td.text().split(" - ")[1]); |  | ||||||
|         int recommended = voteUp - voteDown; |  | ||||||
|         return recommended; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static String parseArticleUrl(String data) { |  | ||||||
|         return PpomppuBoardName.ofViewPageUrl(data); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     Pattern patternBoardName = Pattern.compile("\\[(.+?)\\]"); |  | ||||||
| 
 |  | ||||||
|     public String parseBoardName(String fullTitle) { |  | ||||||
|         Matcher matcher = patternBoardName.matcher(fullTitle); |  | ||||||
|         String lastMatched = null; |  | ||||||
|         while (matcher.find()) { |  | ||||||
|             lastMatched = matcher.group(1); |  | ||||||
|         } |  | ||||||
|         return lastMatched; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
|  | @ -1,27 +0,0 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.domain.entity.v1; |  | ||||||
| 
 |  | ||||||
| import com.myoa.engineering.crawl.shopping.domain.entity.Auditable; |  | ||||||
| import com.myoa.engineering.crawl.shopping.support.dto.constant.PpomppuBoardName; |  | ||||||
| import lombok.Getter; |  | ||||||
| import lombok.NoArgsConstructor; |  | ||||||
| 
 |  | ||||||
| import jakarta.persistence.*; |  | ||||||
| 
 |  | ||||||
| @Getter |  | ||||||
| @NoArgsConstructor |  | ||||||
| @Entity |  | ||||||
| @Table(name = "subscribed_board") |  | ||||||
| public class SubscribedBoard extends Auditable { |  | ||||||
| 
 |  | ||||||
|     @Id |  | ||||||
|     @GeneratedValue(strategy = GenerationType.IDENTITY) |  | ||||||
|     private Long id; |  | ||||||
| 
 |  | ||||||
|     @Column |  | ||||||
|     private Long userId; |  | ||||||
| 
 |  | ||||||
|     @Column |  | ||||||
|     @Enumerated(EnumType.STRING) |  | ||||||
|     private PpomppuBoardName boardName; |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
|  | @ -1,29 +0,0 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.domain.entity.v2; |  | ||||||
| 
 |  | ||||||
| import com.myoa.engineering.crawl.shopping.domain.entity.Auditable; |  | ||||||
| import jakarta.persistence.*; |  | ||||||
| import lombok.AllArgsConstructor; |  | ||||||
| import lombok.Builder; |  | ||||||
| import lombok.Getter; |  | ||||||
| import lombok.NoArgsConstructor; |  | ||||||
| 
 |  | ||||||
| @Getter |  | ||||||
| @Builder |  | ||||||
| @NoArgsConstructor |  | ||||||
| @AllArgsConstructor |  | ||||||
| @Entity |  | ||||||
| @Table |  | ||||||
| public class AppUser extends Auditable { |  | ||||||
|     @Id |  | ||||||
|     @GeneratedValue(strategy = GenerationType.IDENTITY) |  | ||||||
|     private Long id; |  | ||||||
| 
 |  | ||||||
|     @Column |  | ||||||
|     private String name; |  | ||||||
| 
 |  | ||||||
|     @Column |  | ||||||
|     private String slackId; |  | ||||||
| 
 |  | ||||||
|     @Column |  | ||||||
|     private Boolean enabled; |  | ||||||
| } |  | ||||||
|  | @ -1,63 +0,0 @@ | ||||||
| package com.myoa.engineering.crawl.shopping.domain.entity.v2; |  | ||||||
| 
 |  | ||||||
| import com.myoa.engineering.crawl.shopping.domain.entity.Auditable; |  | ||||||
| import com.myoa.engineering.crawl.shopping.support.dto.constant.CrawlTarget; |  | ||||||
| import jakarta.persistence.*; |  | ||||||
| import lombok.AllArgsConstructor; |  | ||||||
| import lombok.Builder; |  | ||||||
| import lombok.Getter; |  | ||||||
| import lombok.NoArgsConstructor; |  | ||||||
| 
 |  | ||||||
| import java.time.ZonedDateTime; |  | ||||||
| 
 |  | ||||||
| @Getter |  | ||||||
| @Builder |  | ||||||
| @NoArgsConstructor |  | ||||||
| @AllArgsConstructor |  | ||||||
| @Entity |  | ||||||
| @Table |  | ||||||
| public class Article extends Auditable { |  | ||||||
| 
 |  | ||||||
|     @Id |  | ||||||
|     @GeneratedValue(strategy = GenerationType.IDENTITY) |  | ||||||
|     private Long id; |  | ||||||
| 
 |  | ||||||
|     @Column |  | ||||||
|     private Long articleId; |  | ||||||
| 
 |  | ||||||
|     @Column |  | ||||||
|     @Enumerated(EnumType.STRING) |  | ||||||
|     private CrawlTarget crawlTarget; |  | ||||||
| 
 |  | ||||||
|     @Column |  | ||||||
|     private String boardName; |  | ||||||
| 
 |  | ||||||
|     @Column |  | ||||||
|     private String articleUrl; |  | ||||||
| 
 |  | ||||||
|     @Column |  | ||||||
|     private String title; |  | ||||||
| 
 |  | ||||||
|     @Column |  | ||||||
|     private Integer hit; |  | ||||||
| 
 |  | ||||||
|     @Column |  | ||||||
|     private Integer recommended; |  | ||||||
| 
 |  | ||||||
|     @Column |  | ||||||
|     private ZonedDateTime registeredAt; |  | ||||||
| 
 |  | ||||||
|     public Article update(Article article) { |  | ||||||
|         this.boardName = article.getBoardName(); |  | ||||||
|         this.articleUrl = article.getArticleUrl(); |  | ||||||
|         this.title = article.getTitle(); |  | ||||||
|         this.hit = article.getHit(); |  | ||||||
|         this.recommended = article.getRecommended(); |  | ||||||
|         return this; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public Article updateCrawlTarget(CrawlTarget crawlTarget) { |  | ||||||
|         this.crawlTarget = crawlTarget; |  | ||||||
|         return this; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue