Merge pull request #153 from Doha2012/master
add schedule post to reddit
This commit is contained in:
commit
cc759f1cf9
|
@ -23,6 +23,9 @@ import org.springframework.util.MultiValueMap;
|
|||
|
||||
public class MyAuthorizationCodeAccessTokenProvider extends AuthorizationCodeAccessTokenProvider implements Serializable {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 3822611002661972274L;
|
||||
|
||||
private StateKeyGenerator stateKeyGenerator = new DefaultStateKeyGenerator();
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
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.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"));
|
||||
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
|
||||
return hibernateProperties;
|
||||
}
|
||||
|
||||
}
|
|
@ -13,7 +13,7 @@ public class ServletInitializer extends AbstractDispatcherServletInitializer {
|
|||
@Override
|
||||
protected WebApplicationContext createServletApplicationContext() {
|
||||
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
|
||||
context.register(WebConfig.class);
|
||||
context.register(PersistenceJPAConfig.class, WebConfig.class);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,12 +2,15 @@ package org.baeldung.config;
|
|||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.baeldung.web.schedule.ScheduledTasks;
|
||||
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.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;
|
||||
|
@ -27,7 +30,9 @@ import org.springframework.web.servlet.view.InternalResourceViewResolver;
|
|||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@ComponentScan(basePackages = { "org.baeldung.web" })
|
||||
@EnableScheduling
|
||||
@EnableAsync
|
||||
@ComponentScan({ "org.baeldung.web" })
|
||||
public class WebConfig extends WebMvcConfigurerAdapter {
|
||||
|
||||
@Bean
|
||||
|
@ -48,6 +53,25 @@ public class WebConfig extends WebMvcConfigurerAdapter {
|
|||
configurer.enable();
|
||||
}
|
||||
|
||||
// @Bean
|
||||
// public RedditController redditController(OAuth2RestTemplate redditRestTemplate) {
|
||||
// RedditController controller = new RedditController();
|
||||
// controller.setRedditRestTemplate(redditRestTemplate);
|
||||
// return controller;
|
||||
// }
|
||||
//
|
||||
// @Bean
|
||||
// public RestExceptionHandler restExceptionHandler() {
|
||||
// return new RestExceptionHandler();
|
||||
// }
|
||||
//
|
||||
@Bean
|
||||
public ScheduledTasks scheduledTasks(OAuth2ProtectedResourceDetails reddit) {
|
||||
ScheduledTasks s = new ScheduledTasks();
|
||||
s.setRedditRestTemplate(new OAuth2RestTemplate(reddit));
|
||||
return s;
|
||||
}
|
||||
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
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> {
|
||||
|
||||
public List<Post> findBySubmissionDateBefore(Date date);
|
||||
|
||||
public List<Post> findByUser(User user);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
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> {
|
||||
public User findByUsername(String username);
|
||||
|
||||
public User findByAccessToken(String token);
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package org.baeldung.persistence.model;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
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;
|
||||
|
||||
private String title;
|
||||
|
||||
private String subreddit;
|
||||
|
||||
private String url;
|
||||
|
||||
private Date submissionDate;
|
||||
|
||||
private boolean isSent;
|
||||
|
||||
private String submissionResponse;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "user_id")
|
||||
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 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package org.baeldung.persistence.model;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
@Entity
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private String username;
|
||||
|
||||
private String accessToken;
|
||||
|
||||
private String refreshToken;
|
||||
|
||||
private Date tokenExpiration;
|
||||
|
||||
@OneToMany(mappedBy = "user")
|
||||
private List<Post> posts;
|
||||
|
||||
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(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public void setAccessToken(String accessToken) {
|
||||
this.accessToken = accessToken;
|
||||
}
|
||||
|
||||
public String getRefreshToken() {
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
public void setRefreshToken(String refreshToken) {
|
||||
this.refreshToken = refreshToken;
|
||||
}
|
||||
|
||||
public Date getTokenExpiration() {
|
||||
return tokenExpiration;
|
||||
}
|
||||
|
||||
public void setTokenExpiration(Date tokenExpiration) {
|
||||
this.tokenExpiration = tokenExpiration;
|
||||
}
|
||||
|
||||
public List<Post> getPosts() {
|
||||
return posts;
|
||||
}
|
||||
|
||||
public void setPosts(List<Post> posts) {
|
||||
this.posts = posts;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,15 +1,21 @@
|
|||
package org.baeldung.web;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
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.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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;
|
||||
|
@ -17,37 +23,43 @@ import org.springframework.util.MultiValueMap;
|
|||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
@Controller
|
||||
public class RedditController {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
|
||||
|
||||
@Autowired
|
||||
private OAuth2RestTemplate redditRestTemplate;
|
||||
|
||||
// API
|
||||
@Autowired
|
||||
private UserRepository userReopsitory;
|
||||
|
||||
@Autowired
|
||||
private PostRepository postReopsitory;
|
||||
|
||||
@RequestMapping("/info")
|
||||
public final String getInfo(Model model) {
|
||||
final JsonNode node = redditRestTemplate.getForObject("https://oauth.reddit.com/api/v1/me", JsonNode.class);
|
||||
final String name = node.get("name").asText();
|
||||
JsonNode node = redditRestTemplate.getForObject("https://oauth.reddit.com/api/v1/me", JsonNode.class);
|
||||
String name = node.get("name").asText();
|
||||
addUser(name, redditRestTemplate.getAccessToken());
|
||||
model.addAttribute("info", name);
|
||||
return "reddit";
|
||||
}
|
||||
|
||||
@RequestMapping("/submit")
|
||||
public final String submit(Model model, @RequestParam Map<String, String> formParams) {
|
||||
final MultiValueMap<String, String> param = new LinkedMultiValueMap<String, String>();
|
||||
MultiValueMap<String, String> param = new LinkedMultiValueMap<String, String>();
|
||||
param.add("api_type", "json");
|
||||
param.add("kind", "link");
|
||||
param.add("resubmit", "true");
|
||||
param.add("sendreplies", "false");
|
||||
param.add("then", "comments");
|
||||
for (final Map.Entry<String, String> entry : formParams.entrySet()) {
|
||||
|
||||
for (Map.Entry<String, String> entry : formParams.entrySet()) {
|
||||
param.add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
|
@ -60,44 +72,73 @@ public class RedditController {
|
|||
}
|
||||
|
||||
@RequestMapping("/post")
|
||||
public final String showSubmissionForm(final Model model) {
|
||||
final String needsCaptchaResult = needsCaptcha();
|
||||
public final String showSubmissionForm(Model model) {
|
||||
String needsCaptchaResult = needsCaptcha();
|
||||
if (needsCaptchaResult.equalsIgnoreCase("true")) {
|
||||
final String iden = getNewCaptcha();
|
||||
String iden = getNewCaptcha();
|
||||
model.addAttribute("iden", iden);
|
||||
}
|
||||
return "submissionForm";
|
||||
}
|
||||
|
||||
// === private
|
||||
@RequestMapping("/postSchedule")
|
||||
public final String showSchedulePostForm(Model model) {
|
||||
String needsCaptchaResult = needsCaptcha();
|
||||
if (needsCaptchaResult.equalsIgnoreCase("true")) {
|
||||
model.addAttribute("msg", "Sorry, You do not have enought karma");
|
||||
return "submissionResponse";
|
||||
}
|
||||
return "schedulePostForm";
|
||||
}
|
||||
|
||||
final List<String> getSubreddit() throws JsonProcessingException, IOException {
|
||||
final String result = redditRestTemplate.getForObject("https://oauth.reddit.com/subreddits/popular?limit=50", String.class);
|
||||
final JsonNode node = new ObjectMapper().readTree(result).get("data").get("children");
|
||||
final List<String> subreddits = new ArrayList<String>();
|
||||
for (JsonNode child : node) {
|
||||
subreddits.add(child.get("data").get("display_name").asText());
|
||||
@RequestMapping("/schedule")
|
||||
public final String schedule(Model model, @RequestParam Map<String, String> formParams) throws ParseException {
|
||||
logger.info("User scheduling Post with these parameters: " + formParams.entrySet());
|
||||
User user = userReopsitory.findByAccessToken(redditRestTemplate.getAccessToken().getValue());
|
||||
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.setSubmissionDate(dateFormat.parse(formParams.get("date")));
|
||||
if (post.getSubmissionDate().before(new Date())) {
|
||||
model.addAttribute("msg", "Invalid date");
|
||||
return "submissionResponse";
|
||||
}
|
||||
return subreddits;
|
||||
postReopsitory.save(post);
|
||||
List<Post> posts = postReopsitory.findByUser(user);
|
||||
model.addAttribute("posts", posts);
|
||||
return "postListView";
|
||||
}
|
||||
|
||||
@RequestMapping("/posts")
|
||||
public final String getScheduledPosts(Model model) {
|
||||
User user = userReopsitory.findByAccessToken(redditRestTemplate.getAccessToken().getValue());
|
||||
List<Post> posts = postReopsitory.findByUser(user);
|
||||
model.addAttribute("posts", posts);
|
||||
return "postListView";
|
||||
}
|
||||
|
||||
// === private
|
||||
|
||||
private final String needsCaptcha() {
|
||||
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>();
|
||||
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("\"");
|
||||
String result = redditRestTemplate.postForObject("https://oauth.reddit.com/api/new_captcha", param, String.class, param);
|
||||
String[] split = result.split("\"");
|
||||
return split[split.length - 2];
|
||||
}
|
||||
|
||||
private final String parseResponse(final JsonNode node) {
|
||||
private final String parseResponse(JsonNode node) {
|
||||
String result = "";
|
||||
final JsonNode errorNode = node.get("json").get("errors").get(0);
|
||||
JsonNode errorNode = node.get("json").get("errors").get(0);
|
||||
if (errorNode != null) {
|
||||
for (JsonNode child : errorNode) {
|
||||
result = result + child.toString().replaceAll("\"|null", "") + "<br>";
|
||||
|
@ -111,4 +152,16 @@ public class RedditController {
|
|||
}
|
||||
}
|
||||
|
||||
private final void addUser(String name, OAuth2AccessToken token) {
|
||||
User user = userReopsitory.findByUsername(name);
|
||||
if (user == null) {
|
||||
user = new User();
|
||||
user.setUsername(name);
|
||||
user.setAccessToken(token.getValue());
|
||||
user.setRefreshToken(token.getRefreshToken().getValue());
|
||||
user.setTokenExpiration(token.getExpiration());
|
||||
userReopsitory.save(user);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep
|
|||
|
||||
@ControllerAdvice
|
||||
public class RestExceptionHandler extends ResponseEntityExceptionHandler implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -3861125729653781371L;
|
||||
|
||||
public RestExceptionHandler() {
|
||||
|
@ -36,5 +37,4 @@ public class RestExceptionHandler extends ResponseEntityExceptionHandler impleme
|
|||
String response = "Error Occurred : " + ex.getMessage();
|
||||
return handleExceptionInternal(ex, response, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR, request);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package org.baeldung.web.schedule;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.baeldung.persistence.dao.PostRepository;
|
||||
import org.baeldung.persistence.model.Post;
|
||||
import org.baeldung.persistence.model.User;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
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.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
@EnableScheduling
|
||||
public class ScheduledTasks {
|
||||
|
||||
private OAuth2RestTemplate redditRestTemplate;
|
||||
|
||||
@Autowired
|
||||
private PostRepository postReopsitory;
|
||||
|
||||
@Scheduled(fixedRate = 5 * 60 * 1000)
|
||||
public void reportCurrentTime() throws JsonProcessingException, IOException, ParseException {
|
||||
List<Post> posts = postReopsitory.findBySubmissionDateBefore(new Date());
|
||||
System.out.println(posts.size());
|
||||
for (Post post : posts) {
|
||||
if (post.isSent())
|
||||
continue;
|
||||
User user = post.getUser();
|
||||
DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(user.getAccessToken());
|
||||
token.setRefreshToken(new DefaultOAuth2RefreshToken((user.getRefreshToken())));
|
||||
token.setExpiration(user.getTokenExpiration());
|
||||
redditRestTemplate.getOAuth2ClientContext().setAccessToken(token);
|
||||
//
|
||||
UsernamePasswordAuthenticationToken userAuthToken = new UsernamePasswordAuthenticationToken(user.getUsername(), token.getValue(), Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")));
|
||||
SecurityContextHolder.getContext().setAuthentication(userAuthToken);
|
||||
//
|
||||
|
||||
MultiValueMap<String, String> param = new LinkedMultiValueMap<String, String>();
|
||||
param.add("api_type", "json");
|
||||
param.add("kind", "link");
|
||||
param.add("resubmit", "true");
|
||||
param.add("sendreplies", "false");
|
||||
param.add("then", "comments");
|
||||
param.add("title", post.getTitle());
|
||||
param.add("sr", post.getSubreddit());
|
||||
param.add("url", post.getUrl());
|
||||
|
||||
JsonNode node = redditRestTemplate.postForObject("https://oauth.reddit.com/api/submit", param, JsonNode.class);
|
||||
JsonNode errorNode = node.get("json").get("errors").get(0);
|
||||
if (errorNode == null) {
|
||||
post.setSent(true);
|
||||
postReopsitory.save(post);
|
||||
} else {
|
||||
post.setSubmissionResponse(errorNode.toString());
|
||||
postReopsitory.save(post);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setRedditRestTemplate(OAuth2RestTemplate redditRestTemplate) {
|
||||
this.redditRestTemplate = redditRestTemplate;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
################### 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
|
|
@ -0,0 +1,54 @@
|
|||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
|
||||
<title>Spring Security OAuth</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-inverse">
|
||||
<div class="container-fluid">
|
||||
<!-- Brand and toggle get grouped for better mobile display -->
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="info">Spring Security OAuth</a>
|
||||
</div>
|
||||
|
||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="active"><a href="#">My Scheduled Posts</a></li>
|
||||
<li><a href="post">Submit Post</a></li>
|
||||
<li><a href="postSchedule">Schedule Post</a></li>
|
||||
</ul>
|
||||
|
||||
</div><!-- /.navbar-collapse -->
|
||||
</div><!-- /.container-fluid -->
|
||||
</nav>
|
||||
<div class="container">
|
||||
<h1>My Scheduled Posts</h1>
|
||||
<table class="table table-bordered">
|
||||
<c:forEach var="post" items="${posts}" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Post title</th>
|
||||
<th>Submission Date</th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr <c:if test="${post.isSent()}"> class="success"</c:if>>
|
||||
<td><c:out value="${post.getTitle()}"/></td>
|
||||
<td><c:out value="${post.getSubmissionDate()}"/></td>
|
||||
<td><c:out value="${post.getSubmissionResponse()}"/></td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -7,12 +7,34 @@
|
|||
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-inverse">
|
||||
<div class="container-fluid">
|
||||
<!-- Brand and toggle get grouped for better mobile display -->
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="#">Spring Security OAuth</a>
|
||||
</div>
|
||||
|
||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="posts">My Scheduled Posts</a></li>
|
||||
<li><a href="post">Submit Post</a></li>
|
||||
<li><a href="postSchedule">Schedule Post</a></li>
|
||||
</ul>
|
||||
|
||||
</div><!-- /.navbar-collapse -->
|
||||
</div><!-- /.container-fluid -->
|
||||
</nav>
|
||||
<div class="container">
|
||||
<c:choose>
|
||||
<c:when test="${info != null}">
|
||||
<h1>Your Reddit Info</h1>
|
||||
<b>Your reddit username is </b>${info}
|
||||
<br><br><br>
|
||||
<h1>Welcome, <small>${info}</small></h1>
|
||||
<a href="post" class="btn btn-primary">Submit to Reddit</a>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
|
||||
<title>Spring Security OAuth</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="<c:url value="/resources/datetime-picker.css" />">
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
|
||||
<script src="<c:url value="/resources/datetime-picker.js" />"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-inverse">
|
||||
<div class="container-fluid">
|
||||
<!-- Brand and toggle get grouped for better mobile display -->
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="#">Spring Security OAuth</a>
|
||||
</div>
|
||||
|
||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="posts">My Scheduled Posts</a></li>
|
||||
<li><a href="post">Submit Post</a></li>
|
||||
<li class="active"><a href="#">Schedule Post</a></li>
|
||||
</ul>
|
||||
|
||||
</div><!-- /.navbar-collapse -->
|
||||
</div><!-- /.container-fluid -->
|
||||
</nav>
|
||||
<div class="container">
|
||||
<h1>Schedule Post</h1>
|
||||
<form action="schedule" method="post">
|
||||
<div class="row">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3">Title</label>
|
||||
<span class="col-sm-9"><input name="title" placeholder="title" class="form-control" /></span>
|
||||
</div>
|
||||
<br><br>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3">Url</label>
|
||||
<span class="col-sm-9"><input name="url" placeholder="url" class="form-control" /></span>
|
||||
</div>
|
||||
<br><br>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3">Subreddit</label>
|
||||
<span class="col-sm-9"><input name="sr" placeholder="Subreddit" class="form-control" /></span>
|
||||
</div>
|
||||
<br><br>
|
||||
|
||||
<label class="col-sm-3">Submission Date</label>
|
||||
<span class="col-sm-9"><input type="text" name="date" class="form-control"></span>
|
||||
<script type="text/javascript">
|
||||
$(function(){
|
||||
$('*[name=date]').appendDtpicker({"inline": true});
|
||||
});
|
||||
</script>
|
||||
|
||||
<br><br>
|
||||
<button type="submit" class="btn btn-primary">Post</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -7,6 +7,30 @@
|
|||
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-inverse">
|
||||
<div class="container-fluid">
|
||||
<!-- Brand and toggle get grouped for better mobile display -->
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="#">Spring Security OAuth</a>
|
||||
</div>
|
||||
|
||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="posts">My Scheduled Posts</a></li>
|
||||
<li class="active"><a href="#">Submit Post</a></li>
|
||||
<li><a href="postSchedule">Schedule Post</a></li>
|
||||
</ul>
|
||||
|
||||
</div><!-- /.navbar-collapse -->
|
||||
</div><!-- /.container-fluid -->
|
||||
</nav>
|
||||
<div class="container">
|
||||
<h1>Submit to Reddit</h1>
|
||||
<form action="submit" method="post">
|
||||
|
|
|
@ -7,9 +7,32 @@
|
|||
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-inverse">
|
||||
<div class="container-fluid">
|
||||
<!-- Brand and toggle get grouped for better mobile display -->
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="#">Spring Security OAuth</a>
|
||||
</div>
|
||||
|
||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="posts">My Scheduled Posts</a></li>
|
||||
<li><a href="post">Submit Post</a></li>
|
||||
<li><a href="postSchedule">Schedule Post</a></li>
|
||||
</ul>
|
||||
|
||||
</div><!-- /.navbar-collapse -->
|
||||
</div><!-- /.container-fluid -->
|
||||
</nav>
|
||||
<div class="container">
|
||||
<h1>${msg}</h1>
|
||||
<a href="post" class="btn btn-primary">Submit another link to Reddit</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,332 @@
|
|||
/**
|
||||
* Style-sheet for dtpicker
|
||||
* https://github.com/mugifly/jquery-simple-datetimepicker
|
||||
*/
|
||||
|
||||
.datepicker {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
font: 15px/1.5 "Helvetica Neue", mplus-2c, Helvetica, Arial, "Hiragino Kaku Gothic Pro", Meiryo, sans-serif;
|
||||
font-weight: 300;
|
||||
border: 1px solid #dfdfdf;
|
||||
border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
box-shadow: 0.5px 0.5px 0px #c8c8c8;
|
||||
-webkit-box-shadow: 0.5px 0.5px 3px #eeeeee;
|
||||
-moz-box-shadow: 0.5px 0.5px 3px #eeeeee;
|
||||
}
|
||||
|
||||
/*
|
||||
* datepicker_header
|
||||
*/
|
||||
|
||||
.datepicker > .datepicker_header{
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
background-color: #eeeeee;
|
||||
color: #3f3f3f;
|
||||
text-align: center;
|
||||
font-size: 9pt;
|
||||
font-weight: bold;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_header > a {
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
cursor: pointer;
|
||||
color: #3b7796;
|
||||
padding: 3px 16px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_header > a:hover {
|
||||
color: #303030;
|
||||
background-color: #c8c8c8;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_header > a:active {
|
||||
color: #ffffff;
|
||||
background-color: #808080;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_header > span {
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_header > .icon-home {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
vertical-align: middle;
|
||||
padding: 8px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_header > .icon-close {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
vertical-align: middle;
|
||||
padding: 8px;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
.datepicker > .datepicker_header > .icon-home > div {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAQCAYAAAB3AH1ZAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAAepJREFUSEudk71Kw2AUhnVxVnCyN1EcCjXUujmKF1AoRRCcNU4OIg5dtXF36tAb6B107qjg0iC4STt0EdTnTU8+v5rGNh54aM7Pe/J+abLmR3AZ7QeXD0+WZkI9zViaiXq9vg+5evU0Y+ksgjCqsrgPA2jBOzQs91FNPc0o70vLQtGHAbTgHRqW+6imnmaUS1PVqWL4SgijJr8juHK1H1Qb2Uxai1kivowmjODKq6Wopp5m0losA95Noh43ONXi+XpCPOsx49W9ZaIHp+CbSlFNPc24+i8DxfGX/YeZgTDqQrsgXc9AF9oFkcY9gQN7J3MjuOhs2WUS0ngGluqZmdNLs7IBTltmZsrvsZUKGaBfhik4vTSw3EBwfrdBfwhvwcX9tpVXNkBvA4bwBk4vDSw2UD27WbdLnf42mQmjIysl8ZeBWq3m9PRubWZOL43qGQOccpf8lc9tj5tWuP7g+tHaLqSR1pY7Pde78Ap7UIEPyOip5RgIOzvkzzCGF4gxtWltF9LAIgM78AxjeAF9/xk9tfy/gBuWOLVMfPIUDq08F3kGFOQlkIlPWKiXBvJfQl6+EjdvWJqJvwwoqMlErl4aabVowmmvbWEBEs2EJeLaFhZBmone8hMtAj2JIkykZYmQifRprAqa+sk3UgBXF8VWaxMAAAAASUVORK5CYII=);
|
||||
}
|
||||
.datepicker > .datepicker_header > .icon-close> div {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAQCAYAAAB3AH1ZAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAAfhJREFUSEvNVEtKA0EUHHBhsvZ7D0HF4PRMnERxI+hCQ4xuBE/g5yLRA+il/CCIXkDElRGt6qkZO91j1JUW1KJf1XvVn2Gif4XGUX986aRf0zIANXq0DBBv7Iwvb+192U+NHi2H0Tg+O2ycnN2DV+CcyiVQW5B2T6/KJUxr7dAkySN4bVbaiyqXMM1s3mr0wKtyDgytgQ/gu/gKbkumvgsOpJH0lieNN3s1O9iYd/EN657kyJikZ2uFDi97JDOgX8fAWyeg2MQO6IeT8Pbrao+Wtw/qJklvywBnE5ZuOAkve9SeA0PnQT+Ia7/2BoZXnK0uBkH5Oqxl4RNZYHAH9ANdMnxP9gA42X5FoMuhp6kEAnjlDPpVeIERm0B4+m0/N9AFq26Bta5sX0JvPvDCycFPTs+PbtQTUOvIHgAhu+DoJ4BH9mFgcAzyy3cDee3+c9ATq60ErjfDcP/kDPQ3hJtIM7XlwMAJ8FoBBe2bi/4m6J1QO34yrWlc740XxDffr/wm6EWP2u0GJsEnDS/DJVPvge7T0DspmT+aGQx+cUKGPriKTcCbzEhGwOn5GAZegM/gHdiSVAK1VBo9F+yRFJn2+hgGXtrBSXpn0mbQb5orbavl4ZfskZRDm5gGp1QKQM16nPACdhNpczZur3+ezAM1eoLwv0MUfQBkquZISGUUwgAAAABJRU5ErkJggg==);
|
||||
}
|
||||
.datepicker > .datepicker_header > a:hover > div, .datepicker > .datepicker_header > a:hover > div {
|
||||
background-position: -16px 0px;
|
||||
}
|
||||
|
||||
/*
|
||||
* datepicker_inner_container
|
||||
*/
|
||||
|
||||
.datepicker > .datepicker_inner_container {
|
||||
margin: -2px 0px -2px 0px;
|
||||
background-color: #d2d2d2;
|
||||
border: 1px solid #c8c8c8;
|
||||
border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
|
||||
box-shadow: 0.5px 0px 3px #c8c8c8;
|
||||
-webkit-box-shadow: 0.5px 0px 3px #c8c8c8;
|
||||
-moz-box-shadow: 0.5px 0px 3px #c8c8c8;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/*
|
||||
* datepicker_inner_container > datepicker_calendar
|
||||
*/
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_calendar {
|
||||
float: left;
|
||||
width: 18.3em;
|
||||
|
||||
margin-top: -0.5px;
|
||||
margin-left: -1px;
|
||||
margin-bottom: -2px;
|
||||
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #c8c8c8;
|
||||
|
||||
border-top:none;
|
||||
border-top-left-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
-webkit-border-top-left-radius: 3px;
|
||||
-webkit-border-bottom-left-radius: 3px;
|
||||
-moz-border-radius-topleft: 3px;
|
||||
-moz-border-radius-bottomleft: 3px;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_calendar > table {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/*
|
||||
* datepicker_inner_container > datepicker_calendar > datepicker_table > tbody > tr > th (WDay-cell)
|
||||
*/
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > th {
|
||||
color: #646464;
|
||||
width: 18px;
|
||||
font-size: small;
|
||||
font-weight: normal;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
/*
|
||||
* datepicker_inner_container > datepicker_calendar > datepicker_table > tbody > tr > td (Day-cell)
|
||||
*/
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td {
|
||||
color: #000000;
|
||||
font-size: small;
|
||||
text-align:center;
|
||||
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
cursor: pointer;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td.today {
|
||||
border-bottom: #bfbfbf solid 2px;
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td.wday_sat {
|
||||
color: #0044aa;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td.wday_sun {
|
||||
color: #e13b00;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td.day_another_month {
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td.day_in_past {
|
||||
cursor: default;
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td.day_in_unallowed {
|
||||
cursor: default;
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td.out_of_range {
|
||||
cursor: default;
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td.active {
|
||||
color: #ffffff;
|
||||
background-color: #808080;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_calendar > .datepicker_table > tbody > tr > td.hover {
|
||||
color: #000000;
|
||||
background-color: #c8c8c8;
|
||||
}
|
||||
|
||||
/*
|
||||
* datepicker_inner_container > datepicker_timelist
|
||||
*/
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_timelist {
|
||||
float: left;
|
||||
|
||||
margin-top: -0.5px;
|
||||
padding: 5px 0px;
|
||||
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
|
||||
background-color: #ffffff;
|
||||
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
-webkit-border-top-right-radius: 3px;
|
||||
-webkit-border-bottom-right-radius: 3px;
|
||||
-moz-border-radius-topright: 3px;
|
||||
-moz-border-radius-bottomright: 3px;
|
||||
text-align: right;
|
||||
width: 4.9em;
|
||||
}
|
||||
|
||||
/*
|
||||
.datepicker > .datepicker_inner_container > .datepicker_timelist::after {
|
||||
content: ".";
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
*/
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_timelist::-webkit-scrollbar {
|
||||
overflow: hidden;
|
||||
width: 6px;
|
||||
background: #fafafa;
|
||||
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
-webkit-border-top-right-radius: 3px;
|
||||
-webkit-border-bottom-right-radius: 3px;
|
||||
-moz-border-radius-topright: 3px;
|
||||
-moz-border-radius-bottomright: 3px;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_timelist::-webkit-scrollbar:horizontal {
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_timelist::-webkit-scrollbar-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_timelist::-webkit-scrollbar-piece {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_timelist::-webkit-scrollbar-piece:start {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_timelist::-webkit-scrollbar-thumb {
|
||||
background: #aaaaaa;
|
||||
border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_timelist::-webkit-scrollbar-corner {
|
||||
background: #333;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_timelist > div.timelist_item {
|
||||
padding-top: 5px;
|
||||
padding-bottom:5px;
|
||||
padding-left: 7px;
|
||||
padding-right: 7px;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 2px;
|
||||
font-size: small;
|
||||
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_timelist > div.timelist_item.time_in_past {
|
||||
cursor: default;
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_timelist > div.timelist_item.out_of_range {
|
||||
cursor: default;
|
||||
color: #cccccc;
|
||||
}
|
||||
.datepicker > .datepicker_inner_container > .datepicker_timelist > div.timelist_item.active {
|
||||
color: #ffffff;
|
||||
background-color: #808080;
|
||||
}
|
||||
|
||||
.datepicker > .datepicker_inner_container > .datepicker_timelist > div.timelist_item.hover {
|
||||
color: #000000;
|
||||
background-color: #c8c8c8;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue