Merge pull request #210 from Doha2012/master
move oauth module to reddit app
This commit is contained in:
@@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry including="**/*.java" kind="src" path="src/main/resources"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry including="**/*.java" kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
@@ -1,48 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>spring-security-oauth</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.common.project.facet.core.builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.springframework.ide.eclipse.core.springbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.validation.validationbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
|
||||
<nature>org.springframework.ide.eclipse.core.springnature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
|
||||
<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
|
||||
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beansProjectDescription>
|
||||
<version>1</version>
|
||||
<pluginVersion><![CDATA[3.6.3.201411271034-RELEASE]]></pluginVersion>
|
||||
<configSuffixes>
|
||||
<configSuffix><![CDATA[xml]]></configSuffix>
|
||||
</configSuffixes>
|
||||
<enableImports><![CDATA[true]]></enableImports>
|
||||
<configs>
|
||||
</configs>
|
||||
<autoconfigs>
|
||||
</autoconfigs>
|
||||
<configSets>
|
||||
</configSets>
|
||||
</beansProjectDescription>
|
||||
@@ -1 +0,0 @@
|
||||
web: java $JAVA_OPTS -jar target/dependency/webapp-runner.jar --port $PORT target/*.war
|
||||
File diff suppressed because it is too large
Load Diff
-114
@@ -1,114 +0,0 @@
|
||||
package org.baeldung.config;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.oauth2.client.filter.state.DefaultStateKeyGenerator;
|
||||
import org.springframework.security.oauth2.client.filter.state.StateKeyGenerator;
|
||||
import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
|
||||
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
|
||||
import org.springframework.security.oauth2.client.resource.UserApprovalRequiredException;
|
||||
import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException;
|
||||
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
|
||||
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
|
||||
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.common.exceptions.InvalidRequestException;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
public class MyAuthorizationCodeAccessTokenProvider extends AuthorizationCodeAccessTokenProvider implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 3822611002661972274L;
|
||||
|
||||
private final StateKeyGenerator stateKeyGenerator = new DefaultStateKeyGenerator();
|
||||
|
||||
@Override
|
||||
public OAuth2AccessToken obtainAccessToken(OAuth2ProtectedResourceDetails details, AccessTokenRequest request) throws UserRedirectRequiredException, UserApprovalRequiredException, AccessDeniedException, OAuth2AccessDeniedException {
|
||||
final AuthorizationCodeResourceDetails resource = (AuthorizationCodeResourceDetails) details;
|
||||
|
||||
if (request.getAuthorizationCode() == null) {
|
||||
if (request.getStateKey() == null) {
|
||||
throw getRedirectForAuthorization(resource, request);
|
||||
}
|
||||
obtainAuthorizationCode(resource, request);
|
||||
}
|
||||
return retrieveToken(request, resource, getParametersForTokenRequest(resource, request), getHeadersForTokenRequest(request));
|
||||
}
|
||||
|
||||
private HttpHeaders getHeadersForTokenRequest(AccessTokenRequest request) {
|
||||
final HttpHeaders headers = new HttpHeaders();
|
||||
return headers;
|
||||
}
|
||||
|
||||
private MultiValueMap<String, String> getParametersForTokenRequest(AuthorizationCodeResourceDetails resource, AccessTokenRequest request) {
|
||||
final MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
|
||||
form.set("grant_type", "authorization_code");
|
||||
form.set("code", request.getAuthorizationCode());
|
||||
|
||||
final Object preservedState = request.getPreservedState();
|
||||
if (request.getStateKey() != null) {
|
||||
if (preservedState == null) {
|
||||
throw new InvalidRequestException("Possible CSRF detected - state parameter was present but no state could be found");
|
||||
}
|
||||
}
|
||||
|
||||
String redirectUri = null;
|
||||
if (preservedState instanceof String) {
|
||||
redirectUri = String.valueOf(preservedState);
|
||||
} else {
|
||||
redirectUri = resource.getRedirectUri(request);
|
||||
}
|
||||
|
||||
if ((redirectUri != null) && !"NONE".equals(redirectUri)) {
|
||||
form.set("redirect_uri", redirectUri);
|
||||
}
|
||||
|
||||
return form;
|
||||
}
|
||||
|
||||
private UserRedirectRequiredException getRedirectForAuthorization(AuthorizationCodeResourceDetails resource, AccessTokenRequest request) {
|
||||
final TreeMap<String, String> requestParameters = new TreeMap<String, String>();
|
||||
requestParameters.put("response_type", "code");
|
||||
requestParameters.put("client_id", resource.getClientId());
|
||||
requestParameters.put("duration", "permanent");
|
||||
|
||||
final String redirectUri = resource.getRedirectUri(request);
|
||||
if (redirectUri != null) {
|
||||
requestParameters.put("redirect_uri", redirectUri);
|
||||
}
|
||||
|
||||
if (resource.isScoped()) {
|
||||
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
final List<String> scope = resource.getScope();
|
||||
|
||||
if (scope != null) {
|
||||
final Iterator<String> scopeIt = scope.iterator();
|
||||
while (scopeIt.hasNext()) {
|
||||
builder.append(scopeIt.next());
|
||||
if (scopeIt.hasNext()) {
|
||||
builder.append(',');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
requestParameters.put("scope", builder.toString());
|
||||
}
|
||||
|
||||
final UserRedirectRequiredException redirectException = new UserRedirectRequiredException(resource.getUserAuthorizationUri(), requestParameters);
|
||||
|
||||
final String stateKey = stateKeyGenerator.generateKey(resource);
|
||||
redirectException.setStateKey(stateKey);
|
||||
request.setStateKey(stateKey);
|
||||
redirectException.setStateToPreserve(redirectUri);
|
||||
request.setPreservedState(redirectUri);
|
||||
|
||||
return redirectException;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package org.baeldung.config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
@PropertySource({ "classpath:persistence-${envTarget:dev}.properties" })
|
||||
@ComponentScan({ "org.baeldung.persistence" })
|
||||
@EnableJpaRepositories(basePackages = "org.baeldung.persistence.dao")
|
||||
public class PersistenceJPAConfig {
|
||||
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
public PersistenceJPAConfig() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
|
||||
em.setDataSource(dataSource());
|
||||
em.setPackagesToScan(new String[] { "org.baeldung.persistence.model" });
|
||||
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
|
||||
em.setJpaVendorAdapter(vendorAdapter);
|
||||
em.setJpaProperties(additionalProperties());
|
||||
return em;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
|
||||
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
|
||||
dataSource.setUrl(env.getProperty("jdbc.url"));
|
||||
dataSource.setUsername(env.getProperty("jdbc.user"));
|
||||
dataSource.setPassword(env.getProperty("jdbc.pass"));
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JpaTransactionManager transactionManager() {
|
||||
final JpaTransactionManager transactionManager = new JpaTransactionManager();
|
||||
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
|
||||
return transactionManager;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
|
||||
return new PersistenceExceptionTranslationPostProcessor();
|
||||
}
|
||||
|
||||
final Properties additionalProperties() {
|
||||
final Properties hibernateProperties = new Properties();
|
||||
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto", "create-drop"));
|
||||
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
|
||||
return hibernateProperties;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package org.baeldung.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.inMemoryAuthentication();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web.ignoring().antMatchers("/resources/**");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.anonymous().disable()
|
||||
.csrf().disable()
|
||||
.authorizeRequests()
|
||||
.antMatchers("/home.html","/post","/postSchedule","/posts").hasRole("USER")
|
||||
.and()
|
||||
.httpBasic().authenticationEntryPoint(oauth2AuthenticationEntryPoint())
|
||||
.and()
|
||||
.logout()
|
||||
.deleteCookies("JSESSIONID")
|
||||
.logoutUrl("/logout")
|
||||
.logoutSuccessUrl("/");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private LoginUrlAuthenticationEntryPoint oauth2AuthenticationEntryPoint() {
|
||||
return new LoginUrlAuthenticationEntryPoint("/login");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package org.baeldung.config;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.filter.DelegatingFilterProxy;
|
||||
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
|
||||
|
||||
public class ServletInitializer extends AbstractDispatcherServletInitializer {
|
||||
|
||||
@Override
|
||||
protected WebApplicationContext createServletApplicationContext() {
|
||||
final AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
|
||||
context.register(PersistenceJPAConfig.class, WebConfig.class, SecurityConfig.class, ThymeleafConfig.class);
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getServletMappings() {
|
||||
return new String[] { "/" };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WebApplicationContext createRootApplicationContext() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartup(ServletContext servletContext) throws ServletException {
|
||||
super.onStartup(servletContext);
|
||||
servletContext.addListener(new SessionListener());
|
||||
registerProxyFilter(servletContext, "oauth2ClientContextFilter");
|
||||
registerProxyFilter(servletContext, "springSecurityFilterChain");
|
||||
}
|
||||
|
||||
private void registerProxyFilter(ServletContext servletContext, String name) {
|
||||
final DelegatingFilterProxy filter = new DelegatingFilterProxy(name);
|
||||
filter.setContextAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher");
|
||||
servletContext.addFilter(name, filter).addMappingForUrlPatterns(null, false, "/*");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package org.baeldung.config;
|
||||
|
||||
import javax.servlet.http.HttpSessionEvent;
|
||||
import javax.servlet.http.HttpSessionListener;
|
||||
|
||||
import org.baeldung.reddit.util.MyFeatures;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SessionListener implements HttpSessionListener {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@Override
|
||||
public void sessionCreated(HttpSessionEvent event) {
|
||||
logger.info("==== Session is created ====");
|
||||
event.getSession().setMaxInactiveInterval(60 * 60);
|
||||
event.getSession().setAttribute("PREDICTION_FEATURE", MyFeatures.PREDICTION_FEATURE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionDestroyed(HttpSessionEvent event) {
|
||||
logger.info("==== Session is destroyed ====");
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package org.baeldung.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.ViewResolver;
|
||||
import org.thymeleaf.extras.springsecurity3.dialect.SpringSecurityDialect;
|
||||
import org.thymeleaf.spring4.SpringTemplateEngine;
|
||||
import org.thymeleaf.spring4.view.ThymeleafViewResolver;
|
||||
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
|
||||
import org.thymeleaf.templateresolver.TemplateResolver;
|
||||
|
||||
@Configuration
|
||||
public class ThymeleafConfig {
|
||||
@Bean
|
||||
public TemplateResolver templateResolver() {
|
||||
final ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
|
||||
templateResolver.setPrefix("/WEB-INF/jsp/");
|
||||
templateResolver.setSuffix(".jsp");
|
||||
|
||||
return templateResolver;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SpringTemplateEngine templateEngine() {
|
||||
final SpringTemplateEngine templateEngine = new SpringTemplateEngine();
|
||||
templateEngine.setTemplateResolver(templateResolver());
|
||||
templateEngine.addDialect(new SpringSecurityDialect());
|
||||
return templateEngine;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ViewResolver viewResolver() {
|
||||
final ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
|
||||
viewResolver.setTemplateEngine(templateEngine());
|
||||
viewResolver.setOrder(1);
|
||||
|
||||
return viewResolver;
|
||||
}
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
package org.baeldung.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.baeldung.persistence.dao.PostRepository;
|
||||
import org.baeldung.reddit.classifier.RedditClassifier;
|
||||
import org.baeldung.reddit.util.MyFeatures;
|
||||
import org.baeldung.reddit.util.UserAgentInterceptor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.security.oauth2.client.OAuth2ClientContext;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
|
||||
import org.springframework.security.oauth2.client.token.AccessTokenProvider;
|
||||
import org.springframework.security.oauth2.client.token.AccessTokenProviderChain;
|
||||
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsAccessTokenProvider;
|
||||
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
|
||||
import org.springframework.security.oauth2.client.token.grant.implicit.ImplicitAccessTokenProvider;
|
||||
import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordAccessTokenProvider;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
|
||||
import org.springframework.web.servlet.ViewResolver;
|
||||
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
import org.springframework.web.servlet.view.InternalResourceViewResolver;
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@EnableScheduling
|
||||
@EnableAsync
|
||||
@ComponentScan({ "org.baeldung.web" })
|
||||
public class WebConfig extends WebMvcConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
@Bean
|
||||
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
|
||||
return new PropertySourcesPlaceholderConfigurer();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ViewResolver viewResolver() {
|
||||
final InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
|
||||
viewResolver.setPrefix("/WEB-INF/jsp/");
|
||||
viewResolver.setSuffix(".jsp");
|
||||
return viewResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
|
||||
configurer.enable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addViewControllers(final ViewControllerRegistry registry) {
|
||||
super.addViewControllers(registry);
|
||||
registry.addViewController("/home.html");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OAuth2RestTemplate schedulerRedditTemplate(OAuth2ProtectedResourceDetails reddit) {
|
||||
final List<ClientHttpRequestInterceptor> list = new ArrayList<ClientHttpRequestInterceptor>();
|
||||
list.add(new UserAgentInterceptor());
|
||||
final OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(reddit);
|
||||
restTemplate.setInterceptors(list);
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RedditClassifier redditClassifier() throws IOException {
|
||||
final RedditClassifier redditClassifier = new RedditClassifier();
|
||||
if (MyFeatures.PREDICTION_FEATURE.isActive()) {
|
||||
final Resource file = new ClassPathResource("data.csv");
|
||||
redditClassifier.trainClassifier(file.getFile().getAbsolutePath());
|
||||
}
|
||||
return redditClassifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableOAuth2Client
|
||||
@PropertySource("classpath:reddit.properties")
|
||||
protected static class ResourceConfiguration {
|
||||
|
||||
@Value("${accessTokenUri}")
|
||||
private String accessTokenUri;
|
||||
|
||||
@Value("${userAuthorizationUri}")
|
||||
private String userAuthorizationUri;
|
||||
|
||||
@Value("${clientID}")
|
||||
private String clientID;
|
||||
|
||||
@Value("${clientSecret}")
|
||||
private String clientSecret;
|
||||
|
||||
@Autowired
|
||||
private PostRepository repo;
|
||||
|
||||
@Bean
|
||||
public OAuth2ProtectedResourceDetails reddit() {
|
||||
final AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
|
||||
details.setId("reddit");
|
||||
details.setClientId(clientID);
|
||||
details.setClientSecret(clientSecret);
|
||||
details.setAccessTokenUri(accessTokenUri);
|
||||
details.setUserAuthorizationUri(userAuthorizationUri);
|
||||
details.setTokenName("oauth_token");
|
||||
details.setScope(Arrays.asList("identity", "read", "submit", "edit"));
|
||||
details.setGrantType("authorization_code");
|
||||
details.setPreEstablishedRedirectUri("http://localhost:8080/spring-security-oauth/login");
|
||||
details.setUseCurrentUri(false);
|
||||
return details;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OAuth2RestTemplate redditRestTemplate(OAuth2ClientContext clientContext) {
|
||||
final OAuth2RestTemplate template = new OAuth2RestTemplate(reddit(), clientContext);
|
||||
final List<ClientHttpRequestInterceptor> list = new ArrayList<ClientHttpRequestInterceptor>();
|
||||
list.add(new UserAgentInterceptor());
|
||||
template.setInterceptors(list);
|
||||
final AccessTokenProviderChain accessTokenProvider = new AccessTokenProviderChain(Arrays.<AccessTokenProvider> asList(new MyAuthorizationCodeAccessTokenProvider(), new ImplicitAccessTokenProvider(), new ResourceOwnerPasswordAccessTokenProvider(),
|
||||
new ClientCredentialsAccessTokenProvider()));
|
||||
template.setAccessTokenProvider(accessTokenProvider);
|
||||
return template;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void startupCheck() {
|
||||
if (StringUtils.isBlank(accessTokenUri) || StringUtils.isBlank(userAuthorizationUri) || StringUtils.isBlank(clientID) || StringUtils.isBlank(clientSecret)) {
|
||||
throw new RuntimeException("Incomplete reddit properties");
|
||||
}
|
||||
repo.findAll();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package org.baeldung.persistence.dao;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.baeldung.persistence.model.Post;
|
||||
import org.baeldung.persistence.model.User;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface PostRepository extends JpaRepository<Post, Long> {
|
||||
|
||||
List<Post> findBySubmissionDateBeforeAndIsSent(Date date, boolean isSent);
|
||||
|
||||
List<Post> findByUser(User user);
|
||||
|
||||
List<Post> findByRedditIDNotNullAndNoOfAttemptsGreaterThan(int attempts);
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package org.baeldung.persistence.dao;
|
||||
|
||||
import org.baeldung.persistence.model.User;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
|
||||
User findByUsername(String username);
|
||||
|
||||
User findByAccessToken(String token);
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
package org.baeldung.persistence.model;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
@Entity
|
||||
public class Post {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String title;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String subreddit;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String url;
|
||||
|
||||
private boolean sendReplies;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Date submissionDate;
|
||||
|
||||
private boolean isSent;
|
||||
|
||||
private String submissionResponse;
|
||||
|
||||
private String redditID;
|
||||
|
||||
private int noOfAttempts;
|
||||
|
||||
private int timeInterval;
|
||||
|
||||
private int minScoreRequired;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "user_id", nullable = false)
|
||||
private User user;
|
||||
|
||||
public Post() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getSubreddit() {
|
||||
return subreddit;
|
||||
}
|
||||
|
||||
public void setSubreddit(String subreddit) {
|
||||
this.subreddit = subreddit;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public boolean isSendReplies() {
|
||||
return sendReplies;
|
||||
}
|
||||
|
||||
public void setSendReplies(boolean sendReplies) {
|
||||
this.sendReplies = sendReplies;
|
||||
}
|
||||
|
||||
public Date getSubmissionDate() {
|
||||
return submissionDate;
|
||||
}
|
||||
|
||||
public void setSubmissionDate(Date submissionDate) {
|
||||
this.submissionDate = submissionDate;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public boolean isSent() {
|
||||
return isSent;
|
||||
}
|
||||
|
||||
public void setSent(boolean isSent) {
|
||||
this.isSent = isSent;
|
||||
}
|
||||
|
||||
public String getSubmissionResponse() {
|
||||
return submissionResponse;
|
||||
}
|
||||
|
||||
public void setSubmissionResponse(String submissionResponse) {
|
||||
this.submissionResponse = submissionResponse;
|
||||
}
|
||||
|
||||
public String getRedditID() {
|
||||
return redditID;
|
||||
}
|
||||
|
||||
public void setRedditID(String redditID) {
|
||||
this.redditID = redditID;
|
||||
}
|
||||
|
||||
public int getNoOfAttempts() {
|
||||
return noOfAttempts;
|
||||
}
|
||||
|
||||
public void setNoOfAttempts(int noOfAttempts) {
|
||||
this.noOfAttempts = noOfAttempts;
|
||||
}
|
||||
|
||||
public int getTimeInterval() {
|
||||
return timeInterval;
|
||||
}
|
||||
|
||||
public void setTimeInterval(int timeInterval) {
|
||||
this.timeInterval = timeInterval;
|
||||
}
|
||||
|
||||
public int getMinScoreRequired() {
|
||||
return minScoreRequired;
|
||||
}
|
||||
|
||||
public void setMinScoreRequired(int minScoreRequired) {
|
||||
this.minScoreRequired = minScoreRequired;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Post [title=" + title + ", subreddit=" + subreddit + ", url=" + url + ", submissionDate=" + submissionDate + ", user=" + user + "]";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
package org.baeldung.persistence.model;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "APP_USER")
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String username;
|
||||
|
||||
private String accessToken;
|
||||
|
||||
private String refreshToken;
|
||||
|
||||
private Date tokenExpiration;
|
||||
|
||||
private boolean needCaptcha;
|
||||
|
||||
public User() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(final String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public void setAccessToken(final String accessToken) {
|
||||
this.accessToken = accessToken;
|
||||
}
|
||||
|
||||
public String getRefreshToken() {
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
public void setRefreshToken(final String refreshToken) {
|
||||
this.refreshToken = refreshToken;
|
||||
}
|
||||
|
||||
public Date getTokenExpiration() {
|
||||
return tokenExpiration;
|
||||
}
|
||||
|
||||
public void setTokenExpiration(final Date tokenExpiration) {
|
||||
this.tokenExpiration = tokenExpiration;
|
||||
}
|
||||
|
||||
public boolean isCaptchaNeeded() {
|
||||
return needCaptcha;
|
||||
}
|
||||
|
||||
public void setNeedCaptcha(final boolean needCaptcha) {
|
||||
this.needCaptcha = needCaptcha;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = (prime * result) + ((username == null) ? 0 : username.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final User user = (User) obj;
|
||||
if (!username.equals(user.username)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User [username=" + username + "]";
|
||||
}
|
||||
|
||||
}
|
||||
-145
@@ -1,145 +0,0 @@
|
||||
package org.baeldung.persistence.service;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.baeldung.persistence.dao.PostRepository;
|
||||
import org.baeldung.persistence.model.Post;
|
||||
import org.baeldung.persistence.model.User;
|
||||
import org.baeldung.reddit.util.RedditApiConstants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
@Service
|
||||
public class RedditService {
|
||||
|
||||
@Autowired
|
||||
@Qualifier("schedulerRedditTemplate")
|
||||
private OAuth2RestTemplate redditRestTemplate;
|
||||
|
||||
@Autowired
|
||||
private PostRepository postReopsitory;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
public void submitPost(final Post post) {
|
||||
try {
|
||||
submitPostInternal(post);
|
||||
} catch (final Exception e) {
|
||||
logger.error("Error occurred while submitting post " + post.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public int getPostScore(String redditId) {
|
||||
final JsonNode node = redditRestTemplate.getForObject("https://oauth.reddit.com/api/info?id=t3_" + redditId, JsonNode.class);
|
||||
logger.info(node.toString());
|
||||
final int score = node.get("data").get("children").get(0).get("data").get("score").asInt();
|
||||
logger.info("post score = " + score);
|
||||
return score;
|
||||
}
|
||||
|
||||
public void deletePost(String redditId) {
|
||||
final MultiValueMap<String, String> param = new LinkedMultiValueMap<String, String>();
|
||||
param.add("id", "t3_" + redditId);
|
||||
final JsonNode node = redditRestTemplate.postForObject("https://oauth.reddit.com/api/del.json", param, JsonNode.class);
|
||||
logger.info(node.toString());
|
||||
}
|
||||
|
||||
public void checkAndReSubmit(Post post) {
|
||||
try {
|
||||
checkAndReSubmitInternal(post);
|
||||
} catch (final Exception e) {
|
||||
logger.error("Error occurred while check post " + post.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// === private methods
|
||||
|
||||
private void submitPostInternal(final Post post) {
|
||||
final User user = post.getUser();
|
||||
final DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(user.getAccessToken());
|
||||
token.setRefreshToken(new DefaultOAuth2RefreshToken((user.getRefreshToken())));
|
||||
token.setExpiration(user.getTokenExpiration());
|
||||
redditRestTemplate.getOAuth2ClientContext().setAccessToken(token);
|
||||
//
|
||||
final UsernamePasswordAuthenticationToken userAuthToken = new UsernamePasswordAuthenticationToken(user.getUsername(), token.getValue(), Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")));
|
||||
SecurityContextHolder.getContext().setAuthentication(userAuthToken);
|
||||
//
|
||||
final MultiValueMap<String, String> param = new LinkedMultiValueMap<String, String>();
|
||||
param.add(RedditApiConstants.TITLE, post.getTitle());
|
||||
param.add(RedditApiConstants.SR, post.getSubreddit());
|
||||
param.add(RedditApiConstants.URL, post.getUrl());
|
||||
param.add(RedditApiConstants.API_TYPE, "json");
|
||||
param.add(RedditApiConstants.KIND, "link");
|
||||
param.add(RedditApiConstants.RESUBMIT, "true");
|
||||
param.add(RedditApiConstants.THEN, "comments");
|
||||
if (post.isSendReplies()) {
|
||||
param.add(RedditApiConstants.SENDREPLIES, "true");
|
||||
}
|
||||
|
||||
logger.info("Submit link with these parameters: " + param.entrySet());
|
||||
final JsonNode node = redditRestTemplate.postForObject("https://oauth.reddit.com/api/submit", param, JsonNode.class);
|
||||
parseResponse(node, post);
|
||||
}
|
||||
|
||||
private void parseResponse(JsonNode node, Post post) {
|
||||
final JsonNode errorNode = node.get("json").get("errors").get(0);
|
||||
if (errorNode == null) {
|
||||
post.setSent(true);
|
||||
post.setSubmissionResponse("Successfully sent");
|
||||
post.setRedditID(node.get("json").get("data").get("id").asText());
|
||||
post.setNoOfAttempts(post.getNoOfAttempts() - 1);
|
||||
postReopsitory.save(post);
|
||||
logger.info("Successfully sent " + post.toString());
|
||||
} else {
|
||||
post.setSubmissionResponse(errorNode.toString());
|
||||
postReopsitory.save(post);
|
||||
logger.info("Error occurred: " + errorNode.toString() + "while submitting post " + post.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void checkAndReSubmitInternal(Post post) {
|
||||
if (didIntervalPassed(post.getSubmissionDate(), post.getTimeInterval())) {
|
||||
final int score = getPostScore(post.getRedditID());
|
||||
if (score < post.getMinScoreRequired()) {
|
||||
deletePost(post.getRedditID());
|
||||
resetPost(post);
|
||||
} else {
|
||||
post.setNoOfAttempts(0);
|
||||
postReopsitory.save(post);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean didIntervalPassed(Date submissonDate, int postInterval) {
|
||||
final long currentTime = new Date().getTime();
|
||||
final long interval = currentTime - submissonDate.getTime();
|
||||
final long intervalInMinutes = TimeUnit.MINUTES.convert(interval, TimeUnit.MILLISECONDS);
|
||||
return intervalInMinutes > postInterval;
|
||||
}
|
||||
|
||||
private void resetPost(Post post) {
|
||||
long time = new Date().getTime();
|
||||
time += TimeUnit.MILLISECONDS.convert(post.getTimeInterval(), TimeUnit.MINUTES);
|
||||
post.setRedditID(null);
|
||||
post.setSubmissionDate(new Date(time));
|
||||
post.setSent(false);
|
||||
post.setSubmissionResponse("Not sent yet");
|
||||
postReopsitory.save(post);
|
||||
}
|
||||
|
||||
}
|
||||
-168
@@ -1,168 +0,0 @@
|
||||
package org.baeldung.reddit.classifier;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.apache.mahout.classifier.sgd.AdaptiveLogisticRegression;
|
||||
import org.apache.mahout.classifier.sgd.CrossFoldLearner;
|
||||
import org.apache.mahout.classifier.sgd.L2;
|
||||
import org.apache.mahout.math.NamedVector;
|
||||
import org.apache.mahout.math.RandomAccessSparseVector;
|
||||
import org.apache.mahout.math.Vector;
|
||||
import org.apache.mahout.vectorizer.encoders.AdaptiveWordValueEncoder;
|
||||
import org.apache.mahout.vectorizer.encoders.FeatureVectorEncoder;
|
||||
import org.apache.mahout.vectorizer.encoders.StaticWordValueEncoder;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.io.Files;
|
||||
|
||||
public class RedditClassifier {
|
||||
public static int GOOD = 0;
|
||||
public static int BAD = 1;
|
||||
|
||||
private final int[] trainCount = { 0, 0 };
|
||||
private final int[] evalCount = { 0, 0 };
|
||||
private final int[] correctCount = { 0, 0 };
|
||||
|
||||
private final AdaptiveLogisticRegression classifier;
|
||||
private final FeatureVectorEncoder titleEncoder;
|
||||
private final FeatureVectorEncoder domainEncoder;
|
||||
private final int noOfFeatures;
|
||||
private final int minScore;
|
||||
private CrossFoldLearner learner;
|
||||
private double accuracy;
|
||||
|
||||
public RedditClassifier() {
|
||||
this(150, 1000, 7);
|
||||
}
|
||||
|
||||
public RedditClassifier(final int poolSize, final int noOfFeatures, int minScore) {
|
||||
this.minScore = minScore;
|
||||
this.noOfFeatures = noOfFeatures;
|
||||
classifier = new AdaptiveLogisticRegression(2, noOfFeatures, new L2());
|
||||
classifier.setPoolSize(poolSize);
|
||||
titleEncoder = new AdaptiveWordValueEncoder("title");
|
||||
titleEncoder.setProbes(1);
|
||||
domainEncoder = new StaticWordValueEncoder("domain");
|
||||
domainEncoder.setProbes(1);
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
public void trainClassifier(final String fileName) throws IOException {
|
||||
final List<NamedVector> vectors = extractVectors(readDataFile(fileName));
|
||||
final int size = vectors.size();
|
||||
final int noOfTraining = (int) (size * 0.8);
|
||||
final List<NamedVector> trainingData = vectors.subList(0, noOfTraining);
|
||||
final List<NamedVector> testData = vectors.subList(noOfTraining, size);
|
||||
int category;
|
||||
for (final NamedVector vector : trainingData) {
|
||||
category = (vector.getName() == "GOOD") ? GOOD : BAD;
|
||||
classifier.train(category, vector);
|
||||
trainCount[category]++;
|
||||
}
|
||||
System.out.println("Training count ========= Good = " + trainCount[0] + " ___ Bad = " + trainCount[1]);
|
||||
System.out.println("----------------------------------------------------------------- \n");
|
||||
evaluateClassifier(testData);
|
||||
}
|
||||
|
||||
public Vector convertPost(final String title, final String domain, final int hour) {
|
||||
final Vector vector = new RandomAccessSparseVector(noOfFeatures);
|
||||
final List<String> words = Splitter.onPattern("\\W").omitEmptyStrings().splitToList(title);
|
||||
vector.set(0, hour);
|
||||
vector.set(1, words.size());
|
||||
domainEncoder.addToVector(domain, vector);
|
||||
for (final String word : words) {
|
||||
titleEncoder.addToVector(word, vector);
|
||||
}
|
||||
return vector;
|
||||
}
|
||||
|
||||
public int classify(final Vector features) {
|
||||
if (learner == null) {
|
||||
learner = classifier.getBest().getPayload().getLearner();
|
||||
}
|
||||
return learner.classifyFull(features).maxValueIndex();
|
||||
}
|
||||
|
||||
public double getAccuracy() {
|
||||
return accuracy;
|
||||
}
|
||||
|
||||
// ==== Private methods
|
||||
|
||||
private void evaluateClassifier(final List<NamedVector> vectors) throws IOException {
|
||||
int category, result;
|
||||
int correct = 0;
|
||||
int wrong = 0;
|
||||
for (final NamedVector vector : vectors) {
|
||||
category = (vector.getName() == "GOOD") ? GOOD : BAD;
|
||||
result = classify(vector);
|
||||
|
||||
evalCount[category]++;
|
||||
if (category == result) {
|
||||
correct++;
|
||||
correctCount[result]++;
|
||||
} else {
|
||||
wrong++;
|
||||
}
|
||||
}
|
||||
System.out.println("Eval count =================== Good = " + evalCount[0] + " ----- Bad = " + evalCount[1] + "\n");
|
||||
System.out.println("Overall Evaluation ============= Correct prediction = " + correct + " ----- Wrong prediction = " + wrong);
|
||||
System.out.println("Correctly Evaluated =========== Correct Good = " + correctCount[0] + " ----- Correct Bad = " + correctCount[1]);
|
||||
System.out.println("Correctly Evaluated (%) ======== Good accuracy = " + (correctCount[0] / (evalCount[0] + 0.0)) + " ----- Bad accuracy = " + (correctCount[1] / (evalCount[1] + 0.0)));
|
||||
this.accuracy = correct / (wrong + correct + 0.0);
|
||||
}
|
||||
|
||||
private List<String> readDataFile(final String fileName) throws IOException {
|
||||
List<String> lines = Files.readLines(new File(fileName), Charset.forName("utf-8"));
|
||||
if ((lines == null) || (lines.size() == 0)) {
|
||||
new RedditDataCollector().collectData();
|
||||
lines = Files.readLines(new File(fileName), Charset.forName("utf-8"));
|
||||
}
|
||||
lines.remove(0);
|
||||
return lines;
|
||||
}
|
||||
|
||||
private List<NamedVector> extractVectors(final List<String> lines) {
|
||||
final List<NamedVector> vectors = new ArrayList<NamedVector>(lines.size());
|
||||
for (final String line : lines) {
|
||||
vectors.add(extractVector(line));
|
||||
}
|
||||
return vectors;
|
||||
}
|
||||
|
||||
private NamedVector extractVector(final String line) {
|
||||
final String[] items = line.split(",");
|
||||
final String numberOfVotes = items[0];
|
||||
final String time = items[1];
|
||||
final String numberOfWordInTitle = items[2];
|
||||
final String title = items[3];
|
||||
final String theRootDomain = items[4];
|
||||
|
||||
final RandomAccessSparseVector internalVector = new RandomAccessSparseVector(noOfFeatures);
|
||||
|
||||
final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
|
||||
cal.setTimeInMillis(Long.parseLong(time) * 1000);
|
||||
internalVector.set(0, cal.get(Calendar.HOUR_OF_DAY)); // hour of day
|
||||
|
||||
internalVector.set(1, Integer.parseInt(numberOfWordInTitle)); // number of words in the title
|
||||
|
||||
domainEncoder.addToVector(theRootDomain, internalVector);
|
||||
final List<String> words = Splitter.on(' ').splitToList(title);
|
||||
words.stream().filter(word -> word.length() > 2).forEach(word -> titleEncoder.addToVector(word, internalVector));
|
||||
|
||||
final String category = extractCategory(Integer.parseInt(numberOfVotes));
|
||||
return new NamedVector(internalVector, category);
|
||||
}
|
||||
|
||||
private String extractCategory(final int score) {
|
||||
return (score < minScore) ? "BAD" : "GOOD";
|
||||
}
|
||||
|
||||
}
|
||||
-88
@@ -1,88 +0,0 @@
|
||||
package org.baeldung.reddit.classifier;
|
||||
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.baeldung.reddit.util.UserAgentInterceptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
public class RedditDataCollector {
|
||||
public static final String DATA_FILE = "src/main/resources/data.csv";
|
||||
public static final int DATA_SIZE = 20000;
|
||||
public static final int LIMIT = 100;
|
||||
public static final Long YEAR = 31536000L;
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private Long timestamp;
|
||||
private final RestTemplate restTemplate;
|
||||
private final String subreddit;
|
||||
|
||||
public RedditDataCollector() {
|
||||
this("java");
|
||||
}
|
||||
|
||||
public RedditDataCollector(String subreddit) {
|
||||
restTemplate = new RestTemplate();
|
||||
final List<ClientHttpRequestInterceptor> list = new ArrayList<ClientHttpRequestInterceptor>();
|
||||
list.add(new UserAgentInterceptor());
|
||||
restTemplate.setInterceptors(list);
|
||||
this.subreddit = subreddit;
|
||||
}
|
||||
|
||||
public void collectData() throws IOException {
|
||||
final int noOfRounds = DATA_SIZE / LIMIT;
|
||||
timestamp = System.currentTimeMillis() / 1000;
|
||||
final FileWriter writer = new FileWriter(DATA_FILE);
|
||||
writer.write("Score, Timestamp in utc, Number of wrods in title, Title, Domain \n");
|
||||
for (int i = 0; i < noOfRounds; i++) {
|
||||
getPosts(writer);
|
||||
System.out.println(i);
|
||||
}
|
||||
writer.close();
|
||||
}
|
||||
|
||||
// ==== Private
|
||||
|
||||
private void getPosts(FileWriter writer) {
|
||||
final String fullUrl = "http://www.reddit.com/r/" + subreddit + "/search.json?sort=new&q=timestamp:" + (timestamp - YEAR) + ".." + timestamp + "&restrict_sr=on&syntax=cloudsearch&limit=" + LIMIT;
|
||||
try {
|
||||
final JsonNode node = restTemplate.getForObject(fullUrl, JsonNode.class);
|
||||
parseNode(node, writer);
|
||||
Thread.sleep(3000);
|
||||
} catch (final Exception e) {
|
||||
logger.error("server error", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void parseNode(JsonNode node, FileWriter writer) throws IOException {
|
||||
String line;
|
||||
List<String> words;
|
||||
int score;
|
||||
for (final JsonNode child : node.get("data").get("children")) {
|
||||
score = child.get("data").get("score").asInt();
|
||||
words = Splitter.onPattern("\\W").omitEmptyStrings().splitToList(child.get("data").get("title").asText());
|
||||
timestamp = child.get("data").get("created_utc").asLong();
|
||||
|
||||
line = score + ",";
|
||||
line += timestamp + ",";
|
||||
line += words.size() + "," + Joiner.on(' ').join(words) + ",";
|
||||
line += child.get("data").get("domain").asText() + "\n";
|
||||
writer.write(line);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
final RedditDataCollector collector = new RedditDataCollector();
|
||||
collector.collectData();
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package org.baeldung.reddit.util;
|
||||
|
||||
public enum MyFeatures {
|
||||
|
||||
PREDICTION_FEATURE(false);
|
||||
|
||||
private boolean active;
|
||||
|
||||
private MyFeatures(boolean active) {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return this.active;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package org.baeldung.reddit.util;
|
||||
|
||||
/**
|
||||
* Specified by Reddit API at http://www.reddit.com/dev/api#POST_api_submit
|
||||
*/
|
||||
public final class RedditApiConstants {
|
||||
public static final String API_TYPE = "api_type";
|
||||
public static final String URL = "url";
|
||||
public static final String SR = "sr";
|
||||
public static final String TITLE = "title";
|
||||
public static final String THEN = "then";
|
||||
public static final String SENDREPLIES = "sendreplies";
|
||||
public static final String RESUBMIT = "resubmit";
|
||||
public static final String KIND = "kind";
|
||||
|
||||
private RedditApiConstants() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
package org.baeldung.reddit.util;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
|
||||
public class UserAgentInterceptor implements ClientHttpRequestInterceptor {
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
|
||||
|
||||
final HttpHeaders headers = request.getHeaders();
|
||||
headers.add("User-Agent", "Schedule with Reddit");
|
||||
return execution.execute(request, body);
|
||||
}
|
||||
}
|
||||
@@ -1,275 +0,0 @@
|
||||
package org.baeldung.web;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.baeldung.persistence.dao.PostRepository;
|
||||
import org.baeldung.persistence.dao.UserRepository;
|
||||
import org.baeldung.persistence.model.Post;
|
||||
import org.baeldung.persistence.model.User;
|
||||
import org.baeldung.reddit.classifier.RedditClassifier;
|
||||
import org.baeldung.reddit.util.RedditApiConstants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
@Controller
|
||||
public class RedditController {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
|
||||
private final SimpleDateFormat dfHour = new SimpleDateFormat("HH");
|
||||
|
||||
@Autowired
|
||||
@Qualifier("redditRestTemplate")
|
||||
private OAuth2RestTemplate redditRestTemplate;
|
||||
|
||||
@Autowired
|
||||
private UserRepository userReopsitory;
|
||||
|
||||
@Autowired
|
||||
private PostRepository postReopsitory;
|
||||
|
||||
@Autowired
|
||||
private RedditClassifier redditClassifier;
|
||||
|
||||
@RequestMapping("/login")
|
||||
public final String redditLogin() {
|
||||
final JsonNode node = redditRestTemplate.getForObject("https://oauth.reddit.com/api/v1/me", JsonNode.class);
|
||||
loadAuthentication(node.get("name").asText(), redditRestTemplate.getAccessToken());
|
||||
return "redirect:home.html";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/submit", method = RequestMethod.POST)
|
||||
public final String submit(final Model model, @RequestParam final Map<String, String> formParams) {
|
||||
final MultiValueMap<String, String> param1 = constructParams(formParams);
|
||||
|
||||
logger.info("Submitting Link with these parameters: " + param1);
|
||||
final JsonNode node = redditRestTemplate.postForObject("https://oauth.reddit.com/api/submit", param1, JsonNode.class);
|
||||
logger.info("Submitted Link - Full Response from Reddit: " + node.toString());
|
||||
final String responseMsg = parseResponse(node);
|
||||
model.addAttribute("msg", responseMsg);
|
||||
return "submissionResponse";
|
||||
}
|
||||
|
||||
@RequestMapping("/post")
|
||||
public final String showSubmissionForm(final Model model) {
|
||||
final boolean isCaptchaNeeded = getCurrentUser().isCaptchaNeeded();
|
||||
if (isCaptchaNeeded) {
|
||||
final String iden = getNewCaptcha();
|
||||
model.addAttribute("iden", iden);
|
||||
}
|
||||
return "submissionForm";
|
||||
}
|
||||
|
||||
@RequestMapping("/postSchedule")
|
||||
public final String showSchedulePostForm(final Model model) {
|
||||
final boolean isCaptchaNeeded = getCurrentUser().isCaptchaNeeded();
|
||||
if (isCaptchaNeeded) {
|
||||
model.addAttribute("msg", "Sorry, You do not have enought karma");
|
||||
return "submissionResponse";
|
||||
}
|
||||
return "schedulePostForm";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/schedule", method = RequestMethod.POST)
|
||||
public final String schedule(final Model model, @RequestParam final Map<String, String> formParams) throws ParseException {
|
||||
logger.info("User scheduling Post with these parameters: " + formParams.entrySet());
|
||||
final User user = getCurrentUser();
|
||||
final Post post = new Post();
|
||||
post.setUser(user);
|
||||
post.setSent(false);
|
||||
post.setTitle(formParams.get("title"));
|
||||
post.setSubreddit(formParams.get("sr"));
|
||||
post.setUrl(formParams.get("url"));
|
||||
post.setNoOfAttempts(Integer.parseInt(formParams.get("attempt")));
|
||||
post.setTimeInterval(Integer.parseInt(formParams.get("interval")));
|
||||
post.setMinScoreRequired(Integer.parseInt(formParams.get("score")));
|
||||
|
||||
if (formParams.containsKey("sendreplies")) {
|
||||
post.setSendReplies(true);
|
||||
}
|
||||
post.setSubmissionDate(dateFormat.parse(formParams.get("date")));
|
||||
post.setSubmissionResponse("Not sent yet");
|
||||
if (post.getSubmissionDate().before(new Date())) {
|
||||
model.addAttribute("msg", "Invalid date");
|
||||
return "submissionResponse";
|
||||
}
|
||||
postReopsitory.save(post);
|
||||
final List<Post> posts = postReopsitory.findByUser(user);
|
||||
model.addAttribute("posts", posts);
|
||||
return "postListView";
|
||||
}
|
||||
|
||||
@RequestMapping("/posts")
|
||||
public final String getScheduledPosts(final Model model) {
|
||||
final User user = getCurrentUser();
|
||||
final List<Post> posts = postReopsitory.findByUser(user);
|
||||
model.addAttribute("posts", posts);
|
||||
return "postListView";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/predicatePostResponse", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public final String predicatePostResponse(@RequestParam(value = "title") final String title, @RequestParam(value = "domain") final String domain) {
|
||||
final int hour = Integer.parseInt(dfHour.format(new Date()));
|
||||
final int result = redditClassifier.classify(redditClassifier.convertPost(title, domain, hour));
|
||||
return (result == RedditClassifier.GOOD) ? "{Good Response}" : "{Bad response}";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/checkIfAlreadySubmitted", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public String checkIfAlreadySubmitted(@RequestParam("url") final String url, @RequestParam("sr") final String sr) {
|
||||
logger.info("check if already submitted");
|
||||
final JsonNode node = redditRestTemplate.getForObject("https://oauth.reddit.com/r/" + sr + "/search?q=url:" + url + "&restrict_sr=on", JsonNode.class);
|
||||
logger.info(node.toString());
|
||||
return node.get("data").get("children").toString();
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/subredditAutoComplete")
|
||||
@ResponseBody
|
||||
public String subredditAutoComplete(@RequestParam("term") final String term) {
|
||||
final MultiValueMap<String, String> param = new LinkedMultiValueMap<String, String>();
|
||||
param.add("query", term);
|
||||
final JsonNode node = redditRestTemplate.postForObject("https://oauth.reddit.com//api/search_reddit_names", param, JsonNode.class);
|
||||
return node.get("names").toString();
|
||||
}
|
||||
|
||||
// === post actions
|
||||
|
||||
@RequestMapping(value = "/deletePost/{id}", method = RequestMethod.DELETE)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public void deletePost(@PathVariable("id") final Long id) {
|
||||
postReopsitory.delete(id);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/editPost/{id}", method = RequestMethod.GET)
|
||||
public String showEditPostForm(final Model model, @PathVariable Long id) {
|
||||
final Post post = postReopsitory.findOne(id);
|
||||
model.addAttribute("post", post);
|
||||
model.addAttribute("dateValue", dateFormat.format(post.getSubmissionDate()));
|
||||
return "editPostForm";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/updatePost/{id}", method = RequestMethod.POST)
|
||||
public String updatePost(Model model, @PathVariable("id") final Long id, @RequestParam final Map<String, String> formParams) throws ParseException {
|
||||
final Post post = postReopsitory.findOne(id);
|
||||
post.setTitle(formParams.get("title"));
|
||||
post.setSubreddit(formParams.get("sr"));
|
||||
post.setUrl(formParams.get("url"));
|
||||
|
||||
post.setNoOfAttempts(Integer.parseInt(formParams.get("attempt")));
|
||||
post.setTimeInterval(Integer.parseInt(formParams.get("interval")));
|
||||
post.setMinScoreRequired(Integer.parseInt(formParams.get("score")));
|
||||
|
||||
if (formParams.containsKey("sendreplies")) {
|
||||
post.setSendReplies(true);
|
||||
} else {
|
||||
post.setSendReplies(false);
|
||||
}
|
||||
post.setSubmissionDate(dateFormat.parse(formParams.get("date")));
|
||||
if (post.getSubmissionDate().before(new Date())) {
|
||||
model.addAttribute("msg", "Invalid date");
|
||||
return "submissionResponse";
|
||||
}
|
||||
postReopsitory.save(post);
|
||||
return "redirect:/posts";
|
||||
}
|
||||
|
||||
// === private
|
||||
|
||||
private User getCurrentUser() {
|
||||
return (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
}
|
||||
|
||||
private final MultiValueMap<String, String> constructParams(final Map<String, String> formParams) {
|
||||
final MultiValueMap<String, String> param = new LinkedMultiValueMap<String, String>();
|
||||
param.add(RedditApiConstants.API_TYPE, "json");
|
||||
param.add(RedditApiConstants.KIND, "link");
|
||||
param.add(RedditApiConstants.RESUBMIT, "true");
|
||||
param.add(RedditApiConstants.THEN, "comments");
|
||||
for (final Map.Entry<String, String> entry : formParams.entrySet()) {
|
||||
param.add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return param;
|
||||
}
|
||||
|
||||
private final String needsCaptcha() {
|
||||
final String result = redditRestTemplate.getForObject("https://oauth.reddit.com/api/needs_captcha.json", String.class);
|
||||
return result;
|
||||
}
|
||||
|
||||
private final String getNewCaptcha() {
|
||||
final Map<String, String> param = new HashMap<String, String>();
|
||||
param.put("api_type", "json");
|
||||
|
||||
final String result = redditRestTemplate.postForObject("https://oauth.reddit.com/api/new_captcha", param, String.class, param);
|
||||
final String[] split = result.split("\"");
|
||||
return split[split.length - 2];
|
||||
}
|
||||
|
||||
private final String parseResponse(final JsonNode node) {
|
||||
String result = "";
|
||||
final JsonNode errorNode = node.get("json").get("errors").get(0);
|
||||
if (errorNode != null) {
|
||||
for (final JsonNode child : errorNode) {
|
||||
result = result + child.toString().replaceAll("\"|null", "") + "<br>";
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
if ((node.get("json").get("data") != null) && (node.get("json").get("data").get("url") != null)) {
|
||||
return "Post submitted successfully " + node.get("json").get("data").get("url").asText();
|
||||
} else {
|
||||
return "Error Occurred";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadAuthentication(final String name, final OAuth2AccessToken token) {
|
||||
User user = userReopsitory.findByUsername(name);
|
||||
if (user == null) {
|
||||
user = new User();
|
||||
user.setUsername(name);
|
||||
}
|
||||
|
||||
if (needsCaptcha().equalsIgnoreCase("true")) {
|
||||
user.setNeedCaptcha(true);
|
||||
} else {
|
||||
user.setNeedCaptcha(false);
|
||||
}
|
||||
|
||||
user.setAccessToken(token.getValue());
|
||||
user.setRefreshToken(token.getRefreshToken().getValue());
|
||||
user.setTokenExpiration(token.getExpiration());
|
||||
userReopsitory.save(user);
|
||||
|
||||
final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user, token.getValue(), Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")));
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package org.baeldung.web;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
|
||||
import org.springframework.security.oauth2.client.resource.UserApprovalRequiredException;
|
||||
import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||
|
||||
@ControllerAdvice
|
||||
public class RestExceptionHandler extends ResponseEntityExceptionHandler implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -3861125729653781371L;
|
||||
|
||||
public RestExceptionHandler() {
|
||||
super();
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
// 4xx
|
||||
|
||||
@ExceptionHandler({ OAuth2AccessDeniedException.class })
|
||||
public ModelAndView handleOAuth2AccessDeniedException(final OAuth2AccessDeniedException ex, final WebRequest request) {
|
||||
logger.error("403 Status Code", ex);
|
||||
final String response = "Error Occurred - Forbidden: " + ex.getMessage();
|
||||
final ModelAndView model = new ModelAndView("submissionResponse");
|
||||
model.addObject("msg", response);
|
||||
return model;
|
||||
// return handleExceptionInternal(ex, response, new HttpHeaders(), HttpStatus.FORBIDDEN, request);
|
||||
}
|
||||
|
||||
@ExceptionHandler({ HttpClientErrorException.class })
|
||||
public ModelAndView handleHttpClientErrorException(final HttpClientErrorException ex, final WebRequest request) {
|
||||
logger.error("400 Status Code", ex);
|
||||
final String response = "Error Occurred - To Many Requests: " + ex.getMessage();
|
||||
final ModelAndView model = new ModelAndView("submissionResponse");
|
||||
model.addObject("msg", response);
|
||||
return model;
|
||||
// return handleExceptionInternal(ex, response, new HttpHeaders(), HttpStatus.TOO_MANY_REQUESTS, request);
|
||||
}
|
||||
|
||||
// HttpClientErrorException
|
||||
// 500
|
||||
|
||||
@ExceptionHandler({ UserApprovalRequiredException.class, UserRedirectRequiredException.class })
|
||||
public ResponseEntity<Object> handleRedirect(final RuntimeException ex, final WebRequest request) {
|
||||
logger.info(ex.getLocalizedMessage());
|
||||
throw ex;
|
||||
}
|
||||
|
||||
@ExceptionHandler({ Exception.class })
|
||||
public ModelAndView handleInternal(final RuntimeException ex, final WebRequest request, final HttpServletResponse response) {
|
||||
logger.info(response.getHeader("x-ratelimit-remaining"));
|
||||
logger.error("500 Status Code", ex);
|
||||
final String message = "Error Occurred: " + ex.getLocalizedMessage();
|
||||
final ModelAndView model = new ModelAndView("submissionResponse");
|
||||
model.addObject("msg", message);
|
||||
return model;
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package org.baeldung.web.schedule;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.baeldung.persistence.dao.PostRepository;
|
||||
import org.baeldung.persistence.model.Post;
|
||||
import org.baeldung.persistence.service.RedditService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class RedditScheduler {
|
||||
|
||||
@Autowired
|
||||
private RedditService service;
|
||||
|
||||
@Autowired
|
||||
private PostRepository postReopsitory;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@Scheduled(fixedRate = 1 * 60 * 1000)
|
||||
public void schedulePosts() {
|
||||
final List<Post> posts = postReopsitory.findBySubmissionDateBeforeAndIsSent(new Date(), false);
|
||||
logger.info(posts.size() + " Posts in the queue.");
|
||||
for (final Post post : posts) {
|
||||
service.submitPost(post);
|
||||
}
|
||||
}
|
||||
|
||||
@Scheduled(fixedRate = 3 * 60 * 1000)
|
||||
public void checkAndReSubmitPosts() {
|
||||
final List<Post> submitted = postReopsitory.findByRedditIDNotNullAndNoOfAttemptsGreaterThan(0);
|
||||
logger.info(submitted.size() + " Posts to check their score");
|
||||
for (final Post post : submitted) {
|
||||
service.checkAndReSubmit(post);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
persistence.properties
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,20 +0,0 @@
|
||||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>web - %date [%thread] %-5level %logger{36} - %message%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="org.springframework" level="WARN" />
|
||||
<logger name="org.springframework.transaction" level="WARN" />
|
||||
|
||||
<!-- in order to debug some marshalling issues, this needs to be TRACE -->
|
||||
<logger name="org.springframework.web.servlet.mvc" level="WARN" />
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
@@ -1,10 +0,0 @@
|
||||
################### DataSource Configuration ##########################
|
||||
jdbc.driverClassName=com.mysql.jdbc.Driver
|
||||
jdbc.url=jdbc:mysql://localhost:3306/oauth_reddit?createDatabaseIfNotExist=true
|
||||
jdbc.user=tutorialuser
|
||||
jdbc.pass=tutorialmy5ql
|
||||
init-db=false
|
||||
################### Hibernate Configuration ##########################
|
||||
hibernate.dialect=org.hibernate.dialect.MySQLDialect
|
||||
hibernate.show_sql=false
|
||||
hibernate.hbm2ddl.auto=update
|
||||
@@ -1,10 +0,0 @@
|
||||
################### DataSource Configuration ##########################
|
||||
jdbc.driverClassName=com.mysql.jdbc.Driver
|
||||
jdbc.url=jdbc:mysql://localhost:3306/oauth_reddit?createDatabaseIfNotExist=true
|
||||
jdbc.user=tutorialuser
|
||||
jdbc.pass=tutorialmy5ql
|
||||
init-db=false
|
||||
################### Hibernate Configuration ##########################
|
||||
hibernate.dialect=org.hibernate.dialect.MySQLDialect
|
||||
hibernate.show_sql=false
|
||||
hibernate.hbm2ddl.auto=create-drop
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user