package org.pegadi.webapp.control;
import com.google.common.base.Function;
import no.dusken.common.model.Person;
import org.apache.commons.lang.StringUtils;
import org.pegadi.articlesearch.StatusTerm;
import org.pegadi.model.Article;
import org.pegadi.server.ArticleServer;
import org.pegadi.sqlsearch.SearchTerm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;
import javax.xml.transform.TransformerException;
import javax.xml.xpath.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.google.common.collect.Lists.transform;
import static org.apache.commons.lang.StringUtils.isBlank;
@Controller
@RequestMapping("/articles")
public class ExportPublishedArticles {
private final Logger log = LoggerFactory.getLogger(getClass());
@Autowired
private ArticleServer articleServer;
@Value("${exportarticles.apikey:}")
private String apikey;
@RequestMapping("/list")
public @ResponseBody List<Map<String, Object>> getArticles(HttpServletRequest request, @RequestParam(required = false, defaultValue = "50") Integer count, @RequestParam(required = false, defaultValue = "0") Integer offset) throws XPathExpressionException {
checkAuthentication(request);
StatusTerm searchTerm = new StatusTerm(6);
searchTerm.setOrderBy("lastSaved desc");
return getArticleList(searchTerm, count, offset);
}
@RequestMapping("/{articleId}")
public @ResponseBody Map<String, Object> getArticleBody(HttpServletRequest request, @PathVariable Integer articleId) throws TransformerException, XPathExpressionException {
checkAuthentication(request);
HashMap<String, Object> articleMap = new HashMap<String, Object>();
Article article = articleServer.getArticleByID(articleId);
boolean b = article.parseText();
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
String title = xpath.compile("//fullArtikkel/text/tittel").evaluate(article.getDocument(), XPathConstants.STRING).toString();
String description = xpath.compile("//fullArtikkel/text/ingress").evaluate(article.getDocument(), XPathConstants.STRING).toString();
articleMap.put("title", title);
articleMap.put("description", description);
NodeList nodes = (NodeList) xpath.compile("//fullArtikkel/text/*/text()").evaluate(article.getDocument(), XPathConstants.NODESET);
StringBuilder bodyBuilder = new StringBuilder();
for (int i = 0; i < nodes.getLength(); i++) {
Node item = nodes.item(i);
String nodeName = item.getParentNode().getNodeName();
String nodeValue = item.getNodeValue();
appendIfMellomtittel(nodeName, nodeValue, bodyBuilder);
appendIfBrodtekst(nodeName, nodeValue, bodyBuilder);
}
articleMap.put("body", bodyBuilder.toString());
addAuthorUsernames(article, articleMap);
return articleMap;
}
private List<Map<String, Object>> getArticleList(SearchTerm limitClauseToSearchTerm, Integer count, Integer offset) throws XPathExpressionException {
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
final XPathExpression expression = xpath.compile("//fullArtikkel/text/tittel/text()");
List<Article> articles = doGetArticles(limitClauseToSearchTerm, count, offset);
return transform(articles, new Function<Article, Map<String, Object>>() {
@Override
public Map<String, Object> apply(@Nullable Article article) {
HashMap<String, Object> articleMap = new HashMap<String, Object>();
articleMap.put("title", article.getName());
try {
if (article.parseText()) {
String title = expression.evaluate(article.getDocument(), XPathConstants.STRING).toString();
articleMap.put("printtitle", title);
}
} catch (XPathExpressionException e) { log.error("XPath error", e);}
addAuthorUsernames(article, articleMap);
articleMap.put("id", String.valueOf(article.getId()));
articleMap.put("charactercount", String.valueOf(article.getCurrentNumberOfCharacters()));
articleMap.put("description", article.getDescription());
return articleMap;
}
});
}
private void addAuthorUsernames(Article article, Map<String, Object> articleMap) {
List<Person> journalistsForArticle = articleServer.getCoJournalistsForArticle(article.getId());
journalistsForArticle.add(article.getJournalist());
List<String> transform = transform(journalistsForArticle, new Function<Person, String>() {
@Override
public String apply(@Nullable Person input) {
if(input != null){
return input.getUsername();
}else {
return null;
}
}
});
articleMap.put("authors", transform);
}
private void appendIfBrodtekst(String nodeName, String nodeValue, StringBuilder bodyBuilder) {
if(nodeName.equals("brodtekst")){
bodyBuilder.append("<p>");
bodyBuilder.append(nodeValue);
bodyBuilder.append("</p>");
}
}
private void appendIfMellomtittel(String nodeName, String nodeValue, StringBuilder bodyBuilder) {
if(nodeName.equals("mellomtittel")){
bodyBuilder.append("<h2>");
bodyBuilder.append(nodeValue);
bodyBuilder.append("</h2>");
}
}
private List<Article> doGetArticles(SearchTerm searchTerm, Integer count, Integer offset) {
return articleServer.getArticlesBySearchTerm(searchTerm, count, offset);
}
private void checkAuthentication(HttpServletRequest request) {
String apikeyParam = request.getParameter("apikey");
if(isBlank(apikeyParam) || !apikey.equals(apikeyParam)){
log.warn("Client with IP {} tries to access {} with key {}",
new Object[]{StringUtils.defaultIfEmpty(request.getHeader("X-Forwarded-For"), request.getRemoteAddr()),
request.getRequestURI()});
throw new AccessDeniedException("Service requires https and a valid apikey.");
}
}
@ExceptionHandler(AccessDeniedException.class)
public ResponseEntity<String> handleAccessDeniedException(AccessDeniedException exception){
return new ResponseEntity<String>(exception.getMessage(), HttpStatus.UNAUTHORIZED);
}
}