...
 
Commits (5)
......@@ -6,11 +6,9 @@ COPY . .
RUN ./gradlew --no-daemon build
FROM openjdk:8-jre
#ENV PORT 4567
#EXPOSE 4567
COPY --from=BUILD /usr/src/app/build/libs /opt/target
COPY application.yml /opt/target
COPY application-production.yml /opt/target
WORKDIR /opt/target
CMD ["/bin/bash", "-c", "find -type f -name 'socializer-*.jar' | xargs java -jar"]
CMD ["/bin/bash", "-c", "find -type f -name 'socializer-*.jar' | xargs java -Dspring.profiles.active=production -Xmx128m -jar"]
......@@ -34,13 +34,9 @@ repositories {
dependencies {
compileOnly "org.springframework.boot:spring-boot-configuration-processor"
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-social-twitter:1.1.0.RELEASE'
runtimeOnly 'org.springframework.boot:spring-boot-starter-actuator'
runtimeOnly 'org.postgresql:postgresql'
testRuntimeOnly 'com.h2database:h2'
implementation('org.springframework.boot:spring-boot-starter-social-twitter:1.1.0.RELEASE') {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
}
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.projectreactor:reactor-test'
......
......@@ -2,24 +2,3 @@ version: '3'
services:
socializer:
build: .
depends_on:
- db
environment:
- BOT_DB_URL=jdbc:postgresql://db:5432/crawler
- BOT_DB_USERNAME=crawler
- BOT_DB_PASSWORD=crawler
- BOT_DB_TYPE=postgresql
- BOT_DB_DDL=update
db:
image: "postgres:11.1"
ports:
- "5432:5432"
volumes:
- pg-data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=socializer
- POSTGRES_PASSWORD=socializer
- POSTGRES_DB=socializer
volumes:
pg-data:
......@@ -44,6 +44,7 @@ public class TwitterDAO {
.id(tweet.getId())
.handle(handle)
.createdAt(tweet.getCreatedAt())
.body(tweet.getText())
.build()
)
.findFirst();
......
package org.alcibiade.socializer.dao;
import org.alcibiade.socializer.properties.AccountProperties;
import org.alcibiade.socializer.properties.SocializerProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.social.twitter.api.Twitter;
import org.springframework.social.twitter.api.impl.TwitterTemplate;
import org.springframework.stereotype.Component;
@Component
public class TwitterFactory {
private final SocializerProperties socializerProperties;
@Autowired
public TwitterFactory(SocializerProperties socializerProperties) {
this.socializerProperties = socializerProperties;
}
public Twitter createTwitterInstance(AccountProperties accountProperties) {
Twitter twitter = new TwitterTemplate(
accountProperties.getApiKey(), accountProperties.getApiSecretKey(),
accountProperties.getAccessToken(), accountProperties.getAccessTokenSecret()
socializerProperties.getTwitter().getApiKey(),
socializerProperties.getTwitter().getApiSecretKey(),
accountProperties.getAccessToken(),
accountProperties.getAccessTokenSecret()
);
return twitter;
......
......@@ -7,8 +7,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.transaction.Transactional;
@Slf4j
@Component
public class RetweetJob {
......@@ -24,7 +22,6 @@ public class RetweetJob {
}
@Scheduled(initialDelay = 5_000L, fixedRate = 300_000L)
@Transactional
public void retweet() {
log.info("Processing retweets...");
socializerProperties.getTwitter().getAccounts().entrySet().stream()
......
......@@ -6,10 +6,6 @@ import javax.validation.constraints.NotBlank;
@Data
public class AccountProperties {
@NotBlank
private String apiKey;
@NotBlank
private String apiSecretKey;
@NotBlank
private String accessToken;
@NotBlank
......
......@@ -7,7 +7,8 @@ import java.util.List;
@Data
public class RetweetProperties {
private List<String> filters;
@NotEmpty
private List<String> users;
private List<String> keywords;
}
......@@ -2,11 +2,18 @@ package org.alcibiade.socializer.properties;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import java.util.Map;
@Data
public class TwitterProperties {
@NotBlank
private String apiKey;
@NotBlank
private String apiSecretKey;
@NotEmpty
private Map<String, AccountProperties> accounts;
......
......@@ -25,43 +25,57 @@ public class TwitterService {
public void retweet(String accountName, AccountProperties accountProperties) {
RetweetProperties retweetProperties = accountProperties.getRetweet();
log.info("Re-tweeting for account {}", accountName);
try {
twitterDAO.open(accountProperties);
Optional<Date> lastRT = twitterDAO.getLastRetweetTime();
log.info("Last retweet of {} is {}", accountName, lastRT);
log.info("Last retweet by {} is at {}", accountName, lastRT);
for (String handle : retweetProperties.getUsers()) {
Optional<TweetEntity> tweet = twitterDAO.getMostRecentMessage(handle);
log.info("Considering re-tweeting {} with last tweet {}", handle, tweet);
log.info("Considering re-tweeting {}", handle);
Optional<TweetEntity> optionalTweet = twitterDAO.getMostRecentMessage(handle);
if (!optionalTweet.isPresent()) {
log.info("No tweet found");
continue;
}
TweetEntity tweet = optionalTweet.get();
if (!filterAccepts(tweet, retweetProperties.getFilters())) {
List<String> keywords = retweetProperties.getKeywords();
if (!filterAccepts(tweet, keywords)) {
log.info("Tweet does not match keywords {}", keywords);
continue;
}
if (accept(lastRT, tweet)) {
log.info("Re-tweeting tweet from {} created at {}", handle, tweet.get().getCreatedAt());
twitterDAO.reTeweet(tweet.get().getId());
if (!acceptableDates(lastRT, tweet)) {
log.info("Tweet is older than my last message.");
continue;
}
log.info("Re-tweeting tweet from {} created at {}", handle, tweet.getCreatedAt());
twitterDAO.reTeweet(tweet.getId());
}
} finally {
twitterDAO.close();
}
}
private boolean filterAccepts(Optional<TweetEntity> tweet, List<String> filters) {
if (!tweet.isPresent()) {
return false;
}
if (filters == null) {
private boolean filterAccepts(TweetEntity tweet, List<String> keywords) {
if (keywords == null) {
return true;
}
for (String term : filters) {
if (tweet.get().getBody().toLowerCase().contains(term)) {
String body = tweet.getBody().toLowerCase();
for (String term : keywords) {
term = term.toLowerCase();
if (body.contains(term)) {
return true;
}
}
......@@ -69,15 +83,11 @@ public class TwitterService {
return false;
}
private boolean accept(Optional<Date> lastRT, Optional<TweetEntity> tweet) {
if (tweet.isPresent()) {
if (lastRT.isPresent()) {
return lastRT.get().before(tweet.get().getCreatedAt());
} else {
return true;
}
private boolean acceptableDates(Optional<Date> lastRT, TweetEntity tweet) {
if (lastRT.isPresent()) {
return lastRT.get().before(tweet.getCreatedAt());
} else {
return false;
return true;
}
}
}
spring:
datasource:
url: jdbc:postgresql://localhost:5432/socializer
username: socializer
password: socializer
jpa:
show-sql: false
hibernate:
ddl-auto: update
logging:
level:
org.hibernate.engine.jdbc.env.internal.LobCreatorBuilderImpl: ERROR
org.alcibiade: DEBUG
......@@ -25,7 +25,7 @@ public class SocializerApplicationTests {
AccountProperties account1 = properties.getTwitter().getAccounts().get("account1");
Assertions.assertThat(account1.getAccessTokenSecret()).isEqualTo("dddddddddddddddddddddddddddddddddd");
Assertions.assertThat(account1.getRetweet().getFilters()).containsExactly("filterterm");
Assertions.assertThat(account1.getRetweet().getKeywords()).containsExactly("filterterm");
Assertions.assertThat(account1.getRetweet().getUsers()).containsExactly("retweeteduser1", "retweeteduser2");
AccountProperties account2 = properties.getTwitter().getAccounts().get("account2");
......@@ -36,7 +36,7 @@ public class SocializerApplicationTests {
AccountProperties account3 = properties.getTwitter().getAccounts().get("account3");
Assertions.assertThat(account3.getAccessTokenSecret()).isEqualTo("hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh");
Assertions.assertThat(account3.getRetweet().getFilters()).isNull();
Assertions.assertThat(account3.getRetweet().getKeywords()).isNull();
Assertions.assertThat(account3.getRetweet().getUsers()).isNotEmpty();
}
......
spring:
datasource:
url: jdbc:h2:mem:testdb
username: sa
password:
driver-class-name: org.h2.Driver
socializer:
twitter:
apiKey: 'aaaaaaaaaaaaaaaaaaaa'
apiSecretKey: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'
accounts:
account1:
apiKey: 'aaaaaaaaaaaaaaaaaaaa'
apiSecretKey: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'
accessToken: 'ccccccccccccc-cccccccccccccccccc'
accessTokenSecret: 'dddddddddddddddddddddddddddddddddd'
retweet:
filters:
keywords:
- filterterm
users:
- retweeteduser1
- retweeteduser2
account2:
apiKey: 'aaaaaaaaaaaaaaaaaaaa'
apiSecretKey: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'
accessToken: 'eeeeeeeeeeeee-eeeeeeeeeeeeeeeeee'
accessTokenSecret: 'ffffffffffffffffffffffffffffffffff'
account3:
apiKey: 'aaaaaaaaaaaaaaaaaaaa'
apiSecretKey: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'
accessToken: 'ggggggggggggg-gggggggggggggggggg'
accessTokenSecret: 'hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh'
......