Skip to content
This repository has been archived by the owner on Dec 11, 2018. It is now read-only.

Add support for links and discard feature #32

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions out/test/resources/com/scmspain/controller/tweets.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
DELETE FROM tweet_link;
DELETE FROM tweet;

INSERT INTO tweet(id, publisher, tweet, discarded, pre2015migrationstatus)
VALUES (1, 'Author1', 'This is a short tweet', false, 0);

INSERT INTO tweet(id, publisher, tweet, discarded, pre2015migrationstatus)
VALUES (2, 'Author2', 'This is a short tweet', false, 0);

INSERT INTO tweet(id, publisher, tweet, discarded, pre2015migrationstatus)
VALUES (3, 'Author1', 'Another tweet from author 1', false, 99);

INSERT INTO tweet(id, publisher, tweet, discarded, pre2015migrationstatus)
VALUES (4, 'Author1', 'A discarded tweet', true, 0);
1 change: 0 additions & 1 deletion src/main/java/com/scmspain/MsFcTechTestApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.scmspain.configuration.TweetConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

Expand Down
15 changes: 15 additions & 0 deletions src/main/java/com/scmspain/builders/TweetBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.scmspain.builders;

import com.scmspain.entities.Tweet;

public interface TweetBuilder {

/**
* Given a plaint text tweet, extracts the links
* @param publisher publisher of the tweet
* @param text tweet
* @return new tweet object
*/
Tweet buildTweet(String publisher, String text);

}
76 changes: 76 additions & 0 deletions src/main/java/com/scmspain/builders/TweetWithLinksBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.scmspain.builders;

import com.scmspain.entities.Tweet;
import com.scmspain.entities.TweetLink;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class TweetWithLinksBuilder implements TweetBuilder {

// A link is any set of non-whitespace consecutive characters starting with http:// or https:// and finishing with a space.
private static final Pattern PATTERN_HREF = Pattern.compile("(?:http|https)://\\S+ ");

@Override
public Tweet buildTweet(String publisher, String text) {
Tweet tweet = new Tweet();
tweet.setPublisher(publisher);

LinkExtractor extractor = getLinkedTweet(text);
tweet.setTweet(extractor.getShortText());
tweet.setLinks(toTweetLinks(tweet, extractor.getLinks()));

return tweet;
}

private LinkExtractor getLinkedTweet(String text) {
return new LinkExtractor(text);
}

private List<TweetLink> toTweetLinks(Tweet tweet, List<String> links) {
return links.stream()
.map(link -> toTweetLink(tweet, link))
.collect(Collectors.toList());
}

private TweetLink toTweetLink(Tweet tweet, String link) {
TweetLink tweetLink = new TweetLink();
tweetLink.setHref(link);
tweetLink.setTweet(tweet);
return tweetLink;
}

static class LinkExtractor {

private final String text;
private String shortText;
private List<String> links;

LinkExtractor(String text) {
this.text = text;
extractLinks();
}

private void extractLinks() {
shortText = PATTERN_HREF.splitAsStream(text).collect(Collectors.joining(""));

Matcher matcher = PATTERN_HREF.matcher(text);
links = new ArrayList<>();
while (matcher.find()) {
links.add(matcher.group().trim());
}
}

String getShortText() {
return shortText;
}

List<String> getLinks() {
return links;
}

}
}
17 changes: 12 additions & 5 deletions src/main/java/com/scmspain/configuration/TweetConfiguration.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
package com.scmspain.configuration;

import com.scmspain.controller.TweetController;
import com.scmspain.repository.TweetRepository;
import com.scmspain.builders.TweetBuilder;
import com.scmspain.builders.TweetWithLinksBuilder;
import com.scmspain.services.TweetService;
import com.scmspain.services.TweetServiceImpl;
import org.springframework.boot.actuate.metrics.writer.MetricWriter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.persistence.EntityManager;

@Configuration
public class TweetConfiguration {
@Bean
public TweetService getTweetService(EntityManager entityManager, MetricWriter metricWriter) {
return new TweetService(entityManager, metricWriter);
public TweetService getTweetService(TweetRepository tweetRepository, MetricWriter metricWriter) {
return new TweetServiceImpl(getTweetBuilder(), tweetRepository, metricWriter);
}

@Bean
public TweetBuilder getTweetBuilder() {
return new TweetWithLinksBuilder();
}

@Bean
public TweetController getTweetConfiguration(TweetService tweetService) {
public TweetController getTweetController(TweetService tweetService) {
return new TweetController(tweetService);
}
}
16 changes: 15 additions & 1 deletion src/main/java/com/scmspain/controller/TweetController.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.scmspain.controller;

import com.scmspain.controller.command.DiscardTweetCommand;
import com.scmspain.controller.command.PublishTweetCommand;
import com.scmspain.entities.Tweet;
import com.scmspain.services.TweetService;
Expand All @@ -9,10 +10,12 @@

import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.OK;

@RestController
public class TweetController {
private TweetService tweetService;

private final TweetService tweetService;

public TweetController(TweetService tweetService) {
this.tweetService = tweetService;
Expand All @@ -29,6 +32,17 @@ public void publishTweet(@RequestBody PublishTweetCommand publishTweetCommand) {
this.tweetService.publishTweet(publishTweetCommand.getPublisher(), publishTweetCommand.getTweet());
}

@PostMapping("/discarded")
@ResponseStatus(OK)
public void discardTweet(@RequestBody DiscardTweetCommand discardTweetCommand) {
this.tweetService.discardTweet(discardTweetCommand.getTweet());
}

@GetMapping("/discarded")
public List<Tweet> listDiscardedTweets() {
return this.tweetService.listDiscardedTweets();
}

@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(BAD_REQUEST)
@ResponseBody
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.scmspain.controller.command;

import javax.validation.constraints.NotNull;

public class DiscardTweetCommand {

@NotNull
private Long tweet;

public Long getTweet() {
return tweet;
}

public void setTweet(Long tweet) {
this.tweet = tweet;
}
}
44 changes: 38 additions & 6 deletions src/main/java/com/scmspain/entities/Tweet.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,40 @@
package com.scmspain.entities;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;

import javax.persistence.*;
import java.util.List;

@Entity
public class Tweet {

public static final int MAX_TWEET_LENGTH = 140;

@Id
@GeneratedValue
private Long id;

@Column(nullable = false)
private String publisher;
@Column(nullable = false, length = 140)

@Column(nullable = false, length = MAX_TWEET_LENGTH)
private String tweet;
@Column (nullable=true)

@Column(name="pre2015migrationstatus")
private Long pre2015MigrationStatus = 0L;

@OneToMany(targetEntity=TweetLink.class, cascade=CascadeType.ALL, mappedBy="tweet")
@Column
@JsonBackReference
private List<TweetLink> links;

@Column(nullable = false)
@JsonIgnore
private Boolean discarded;

public Tweet() {
discarded = false;
}

public Long getId() {
Expand Down Expand Up @@ -52,4 +69,19 @@ public void setPre2015MigrationStatus(Long pre2015MigrationStatus) {
this.pre2015MigrationStatus = pre2015MigrationStatus;
}

public void setLinks(List<TweetLink> links) {
this.links = links;
}

public List<TweetLink> getLinks() {
return links;
}

public void setDiscarded(boolean discarded) {
this.discarded = discarded;
}

public boolean getDiscarded() {
return discarded;
}
}
33 changes: 33 additions & 0 deletions src/main/java/com/scmspain/entities/TweetLink.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.scmspain.entities;

import com.fasterxml.jackson.annotation.JsonManagedReference;

import javax.persistence.*;

@Entity
public class TweetLink {

@GeneratedValue
@Id
private Long id;

@Column(nullable = false)
private String href;

@ManyToOne
@JoinColumn(name = "tweet_id", nullable = false)
@JsonManagedReference
private Tweet tweet;

public String getHref() {
return href;
}

public void setHref(String href) {
this.href = href;
}

public void setTweet(Tweet tweet) {
this.tweet = tweet;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.scmspain.exceptions;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(value= HttpStatus.NOT_FOUND, reason="Entity not found")
public class EntityNotFoundException extends RuntimeException {
}
16 changes: 16 additions & 0 deletions src/main/java/com/scmspain/repository/TweetRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.scmspain.repository;

import com.scmspain.entities.Tweet;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

public interface TweetRepository extends JpaRepository<Tweet, Long> {

@Query("SELECT t FROM Tweet AS t WHERE pre2015MigrationStatus<>99 AND discarded = false ORDER BY id DESC")
List<Tweet> findAllSortedByIdDesc();

@Query("SELECT t FROM Tweet AS t WHERE pre2015MigrationStatus<>99 AND discarded = true ORDER BY id DESC")
List<Tweet> findAllDiscardedSortedByIdDesc();
}
Loading