Commit 144b7f02 authored by Matija Obreza's avatar Matija Obreza
Browse files

Editing articles

parent aed26153
...@@ -93,6 +93,8 @@ public interface ContentService { ...@@ -93,6 +93,8 @@ public interface ContentService {
Article createGlobalArticle(String slug, Locale locale, String title, String body); Article createGlobalArticle(String slug, Locale locale, String title, String body);
Article updateGlobalArticle(String slug, Locale locale, String title, String body);
ActivityPost getActivityPost(long id); ActivityPost getActivityPost(long id);
ActivityPost updateActivityPost(long id, String title, String body); ActivityPost updateActivityPost(long id, String title, String body);
......
...@@ -178,6 +178,28 @@ public class ContentServiceImpl implements ContentService { ...@@ -178,6 +178,28 @@ public class ContentServiceImpl implements ContentService {
articleRepository.save(article); articleRepository.save(article);
return article; return article;
} }
@Override
@Transactional(readOnly = false)
@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
@CacheEvict(value = "contentcache", allEntries = true)
public Article updateGlobalArticle(String slug, Locale locale, String title, String body) {
Article article = getGlobalArticle(slug, locale, false);
if (article == null) {
throw new RuntimeException("Article does not exist");
}
article.setClassPk(ensureClassPK(Article.class));
article.setLang(locale.getLanguage());
article.setSlug(slug);
article.setTitle(htmlSanitizer.sanitize(title));
article.setBody(htmlSanitizer.sanitize(body));
article.setPostDate(Calendar.getInstance());
articleRepository.save(article);
return article;
}
/** /**
* Creates or updates an article * Creates or updates an article
......
...@@ -16,6 +16,11 @@ ...@@ -16,6 +16,11 @@
package org.genesys2.server.servlet.controller; package org.genesys2.server.servlet.controller;
import java.io.IOException;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import org.genesys2.server.model.impl.Article; import org.genesys2.server.model.impl.Article;
import org.genesys2.server.service.ContentService; import org.genesys2.server.service.ContentService;
import org.genesys2.spring.RequestAttributeLocaleResolver; import org.genesys2.spring.RequestAttributeLocaleResolver;
...@@ -25,181 +30,221 @@ import org.json.simple.JSONObject; ...@@ -25,181 +30,221 @@ import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser; import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException; import org.json.simple.parser.ParseException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import java.io.IOException; import org.springframework.web.bind.annotation.RequestMethod;
import java.util.Locale; import org.springframework.web.bind.annotation.RequestParam;
import java.util.Map;
import java.util.TreeMap;
@Controller @Controller
@RequestMapping("/content") @RequestMapping("/content")
public class ArticleController extends BaseController { public class ArticleController extends BaseController {
@Autowired @Autowired
private ContentService contentService; private ContentService contentService;
@Autowired @Autowired
private TransifexService transifexService; private TransifexService transifexService;
@Autowired @Autowired
private RequestAttributeLocaleResolver localeResolver; private RequestAttributeLocaleResolver localeResolver;
@RequestMapping(value = "/postToTransifex/{slug}", method = RequestMethod.GET) @RequestMapping(value = "/transifex", params = { "post" }, method = RequestMethod.POST)
@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')") @PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
public String postTotransifex(@PathVariable("slug") String slug, Model model) { public String postTotransifex(@RequestParam("slug") String slug, Model model) {
Article article = contentService.getGlobalArticle(slug, getLocale()); Article article = contentService.getGlobalArticle(slug, getLocale());
try { String resourceName = "article-" + slug;
transifexService.createXhtmlResource("article-" + slug, article.getTitle(), article.getBody()); try {
} catch (IOException e) { if (transifexService.resourceExists(resourceName)) {
model.addAttribute("responseFromTransifex", "fail"); transifexService.updateXhtmlResource(resourceName, article.getTitle(), article.getBody());
model.addAttribute("article", article); } else {
e.printStackTrace(); transifexService.createXhtmlResource(resourceName, article.getTitle(), article.getBody());
} }
model.addAttribute("responseFromTransifex", "resource added"); } catch (IOException e) {
model.addAttribute("article", article); model.addAttribute("responseFromTransifex", "article.transifex-failed");
return "/content/article-edit"; model.addAttribute("article", article);
} e.printStackTrace();
}
@RequestMapping(value = "/deleteFromTransifex", method = RequestMethod.POST) model.addAttribute("responseFromTransifex", "article.transifex-resource-updated");
@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')") model.addAttribute("article", article);
public String deleteFromtransifex(@RequestParam("articleSlug") String slug, Model model) { return "/content/article-edit";
Article article = contentService.getGlobalArticle(slug, getLocale()); }
if (transifexService.deleteResource("article-" + slug)) {
model.addAttribute("result", "deleted"); @RequestMapping(value = "/transifex", params = { "remove" }, method = RequestMethod.POST)
model.addAttribute("article", article); @PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
} else { public String deleteFromtransifex(@RequestParam("slug") String slug, Model model) {
model.addAttribute("result", "fail"); Article article = contentService.getGlobalArticle(slug, getLocale());
model.addAttribute("article", article); if (transifexService.deleteResource("article-" + slug)) {
} model.addAttribute("responseFromTransifex", "article.transifex-resource-removed");
return "/content/article-edit"; model.addAttribute("article", article);
} } else {
model.addAttribute("responseFromTransifex", "article.transifex-failed");
@RequestMapping(value = "/translate/{slug}/{lang}", method = RequestMethod.GET) model.addAttribute("article", article);
@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')") }
public String fetchFromtransifex(@PathVariable("slug") String slug, @PathVariable String lang, Model model) { return "/content/article-edit";
}
Article article = contentService.getGlobalArticle(slug, getLocale());
@RequestMapping(value = "/translate/{slug}/{language}", method = RequestMethod.GET)
JSONObject jsonObject; @PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
JSONParser jsonParser = new JSONParser(); public String fetchFromtransifex(@PathVariable("slug") String slug, @PathVariable("language") String language, Model model) {
String translatedResource = transifexService.getTranslatedResource("article-" + slug, new Locale(lang));
String content; Locale locale = new Locale(language);
String title = null;
String body = null; Article article = contentService.getGlobalArticle(slug, locale, false);
try { JSONObject jsonObject;
jsonObject = (JSONObject) jsonParser.parse(translatedResource); JSONParser jsonParser = new JSONParser();
content = (String) jsonObject.get("content"); String translatedResource = transifexService.getTranslatedResource("article-" + slug, locale);
title = content.split("<title>")[1].split("</title>")[0]; String content;
body = content.split("<body>")[1].split("</body>")[0]; String title = null;
} catch (ParseException e) { String body = null;
e.printStackTrace();
} try {
jsonObject = (JSONObject) jsonParser.parse(translatedResource);
article.setTitle(title); content = (String) jsonObject.get("content");
article.setBody(body); title = content.split("<title>")[1].split("</title>")[0];
article.setLang(lang); body = content.split("<body>")[1].split("</body>")[0];
} catch (ParseException e) {
model.addAttribute("article", article); e.printStackTrace();
return "/content/article-edit"; }
}
if (article == null) {
@RequestMapping article = new Article();
@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')") article.setSlug(slug);
public String list(ModelMap model, @RequestParam(value = "page", defaultValue = "1") int page, }
@RequestParam(value = "language", defaultValue = "") String lang) {
if (!lang.isEmpty()) { article.setTitle(title);
model.addAttribute("pagedData", contentService.listArticlesByLang(lang, new PageRequest(page - 1, 50, new Sort("slug")))); article.setBody(body);
} else { article.setLang(language);
model.addAttribute("pagedData", contentService.listArticles(new PageRequest(page - 1, 50, new Sort("slug"))));
} model.addAttribute("article", article);
return "/content/article-edit";
//todo full name of locales }
Map<String, String> locales = new TreeMap<>();
@RequestMapping
for (String language : localeResolver.getSupportedLocales()) { @PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
locales.put(new Locale(language).getDisplayName(), language); public String list(ModelMap model, @RequestParam(value = "page", defaultValue = "1") int page,
} @RequestParam(value = "language", defaultValue = "") String lang) {
if (!lang.isEmpty()) {
model.addAttribute("languages", locales); model.addAttribute("pagedData", contentService.listArticlesByLang(lang, new PageRequest(page - 1, 50, new Sort("slug"))));
} else {
return "/content/index"; model.addAttribute("pagedData", contentService.listArticles(new PageRequest(page - 1, 50, new Sort("slug"))));
} }
@RequestMapping("{url:.+}") // todo full name of locales
public String view(ModelMap model, @PathVariable(value = "url") String slug) { Map<String, String> locales = new TreeMap<>();
_logger.debug("Viewing article " + slug);
for (String language : localeResolver.getSupportedLocales()) {
final Article article = contentService.getGlobalArticle(slug, getLocale()); locales.put(new Locale(language).getDisplayName(), language);
if (article == null) { }
if (hasRole("ADMINISTRATOR")) {
return "redirect:/content/" + slug + "/edit"; model.addAttribute("languages", locales);
}
throw new ResourceNotFoundException(); return "/content/index";
} }
model.addAttribute("title", article.getTitle());
model.addAttribute("article", article); @RequestMapping("{url:.+}")
public String view(ModelMap model, @PathVariable(value = "url") String slug) {
return "/content/article"; _logger.debug("Viewing article " + slug);
}
final Article article = contentService.getGlobalArticle(slug, getLocale());
@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')") if (article == null) {
@RequestMapping("{url}/edit/{language}") if (hasRole("ADMINISTRATOR")) {
public String edit(ModelMap model, @PathVariable(value = "url") String slug, return "redirect:/content/" + slug + "/edit";
@PathVariable("language") String language) { }
_logger.debug("Editing article " + slug); throw new ResourceNotFoundException();
}
Article article = contentService.getArticleBySlugAndLang(slug, language); model.addAttribute("title", article.getTitle());
if (article == null) { model.addAttribute("article", article);
article = new Article();
article.setSlug(slug); return "/content/article";
article.setLang(getLocale().getLanguage()); }
}
model.addAttribute("article", article); /**
* Edit article in current language
return "/content/article-edit"; *
} * @param model
* @param slug
@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')") * @return
@RequestMapping(value = "/save-article", method = {RequestMethod.POST}) */
public String createNewGlobalArticle(ModelMap model, @RequestParam("slug") String slug, @RequestParam("title") String title, @PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
@RequestParam("body") String body) { @RequestMapping("{url}/edit")
public String edit(ModelMap model, @PathVariable(value = "url") String slug) {
contentService.createGlobalArticle(slug, getLocale(), title, body); _logger.debug("Editing article " + slug);
return "redirect:/content/" + slug + "/edit/" + LocaleContextHolder.getLocale().getLanguage();
return "redirect:/content/" + slug; }
}
/**
@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')") * Edit article in another language
@RequestMapping(value = "/save-article", params = {"id"}, method = {RequestMethod.POST}) *
public String saveExistingGlobalArticle(ModelMap model, @RequestParam("id") long id, @RequestParam("slug") String slug, * @param model
@RequestParam("title") String title, @RequestParam("body") String body) { * @param slug
* @param language
contentService.updateArticle(id, slug, title, body); * @return
*/
return "redirect:/content/" + slug; @PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
} @RequestMapping("{url}/edit/{language}")
public String edit(ModelMap model, @PathVariable(value = "url") String slug, @PathVariable("language") String language) {
@RequestMapping(value = "/blurp/update-blurp", method = {RequestMethod.POST}) _logger.debug("Editing article " + slug);
public String updateBlurp(ModelMap model, @RequestParam("id") long id, @RequestParam(required = false, value = "title") String title,
@RequestParam("body") String body) { Article article = contentService.getArticleBySlugAndLang(slug, language);
if (article == null) {
contentService.updateArticle(id, null, title, body); article = new Article();
article.setSlug(slug);
return "redirect:/"; article.setLang(language);
} }
model.addAttribute("article", article);
@RequestMapping(value = "/blurp/create-blurp", method = {RequestMethod.POST})
public String createBlurp(ModelMap model, @RequestParam("clazz") String clazz, @RequestParam("entityId") long entityId, return "/content/article-edit";
@RequestParam(required = false, value = "title") String title, @RequestParam("body") String body) throws ClassNotFoundException { }
contentService.updateArticle(Class.forName(clazz), entityId, "blurp", title, body, getLocale()); @PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
return "redirect:/"; @RequestMapping(value = "/save-article/{language}", method = { RequestMethod.POST })
} public String createNewGlobalArticle(ModelMap model, @RequestParam("slug") String slug, @PathVariable("language") String language,
@RequestParam("title") String title, @RequestParam("body") String body) {
contentService.createGlobalArticle(slug, new Locale(language), title, body);
return redirectAfterSave(slug, language);
}
private String redirectAfterSave(String slug, String language) {
if (LocaleContextHolder.getLocale().getLanguage().equals(language)) {
return "redirect:/content/" + slug;
} else {
return "redirect:/content/?language=" + language;
}
}
@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
@RequestMapping(value = "/save-article/{language}", params = { "id" }, method = { RequestMethod.POST })
public String saveExistingGlobalArticle(ModelMap model, @PathVariable("language") String language, @RequestParam("id") long id,
@RequestParam("slug") String slug, @RequestParam("title") String title, @RequestParam("body") String body) {
Article article = contentService.updateArticle(id, slug, title, body);
return redirectAfterSave(slug, article.getLang());
}
@RequestMapping(value = "/blurp/update-blurp", method = { RequestMethod.POST })
public String updateBlurp(ModelMap model, @RequestParam("id") long id, @RequestParam(required = false, value = "title") String title,
@RequestParam("body") String body) {
contentService.updateArticle(id, null, title, body);
return "redirect:/";
}
@RequestMapping(value = "/blurp/create-blurp", method = { RequestMethod.POST })
public String createBlurp(ModelMap model, @RequestParam("clazz") String clazz, @RequestParam("entityId") long entityId,
@RequestParam(required = false, value = "title") String title, @RequestParam("body") String body) throws ClassNotFoundException {
contentService.updateArticle(Class.forName(clazz), entityId, "blurp", title, body, getLocale());
return "redirect:/";
}
} }
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package org.genesys2.server.servlet.controller.transifex; package org.genesys2.server.servlet.controller.transifex;
import org.genesys2.server.aspect.AsAdmin;
import org.genesys2.server.model.impl.Article; import org.genesys2.server.model.impl.Article;
import org.genesys2.server.service.ContentService; import org.genesys2.server.service.ContentService;
import org.genesys2.server.servlet.controller.BaseController; import org.genesys2.server.servlet.controller.BaseController;
...@@ -54,12 +55,9 @@ public class TransifexAPIController extends BaseController { ...@@ -54,12 +55,9 @@ public class TransifexAPIController extends BaseController {
private Object transifexHookKey; private Object transifexHookKey;
/** /**
* Use "magic" SHA1 hash value just for some security purposes * Note: the hook key value should be set in preferences
*
* Note: the very same value should be in Transifex preferences
*
* @see classpath:spring/spring-security.xml
*/ */
@AsAdmin
@RequestMapping(value = "/hook/{hookKey:.+}", method = RequestMethod.POST) @RequestMapping(value = "/hook/{hookKey:.+}", method = RequestMethod.POST)
public @ResponseBody public @ResponseBody
String webHookHandle(@PathVariable("hookKey") String hookKey, @RequestParam(value = "project") String projectSlug, String webHookHandle(@PathVariable("hookKey") String hookKey, @RequestParam(value = "project") String projectSlug,
...@@ -92,22 +90,30 @@ public class TransifexAPIController extends BaseController { ...@@ -92,22 +90,30 @@ public class TransifexAPIController extends BaseController {
_logger.info("Fetching updated translation for article " + slug + " lang=" + lang); _logger.info("Fetching updated translation for article " + slug + " lang=" + lang);
Locale locale = new Locale(lang); Locale locale = new Locale(lang);
_logger.warn("Locale: " + locale);
String resourceBody = transifexService.getTranslatedResource("article-".concat(slug), locale); String resourceBody = transifexService.getTranslatedResource("article-".concat(slug), locale);
String title = resourceBody.split("<title>")[1].split("</title>")[0]; String title = resourceBody.split("<title>")[1].split("</title>")[0];
_logger.warn("Title: " + title);
String body = resourceBody.split("<body>")[1].split("</body>")[0]; String body = resourceBody.split("<body>")[1].split("</body>")[0];
_logger.warn("Body: " + body);
// Extract article from database we need (correct locale + do not use // Extract article from database we need (correct locale + do not use
// default (EN) language) // default (EN) language)
Article article = contentService.getGlobalArticle(slug, locale, false); Article article = contentService.getGlobalArticle(slug, locale, false);
if (article == null) {
// No article for selected locale // TODO Enable when tested
article = contentService.createGlobalArticle(slug, locale, title, body); // if (article == null) {
} else { // // No article for selected locale
// Update article for locale // article = contentService.createGlobalArticle(slug, locale, title,
article = contentService.updateArticle(article.getId(), article.getSlug(), title, body); // body);
} // } else {
// // Update article for locale
// article = contentService.updateGlobalArticle(slug, locale, title,
// body);
// }
_logger.info("Updated translation for article " + slug + " lang=" + lang); _logger.info("Updated translation for article " + slug + " lang=" + lang);
return article; return article;
......
...@@ -402,6 +402,11 @@ article.edit-article=Editing article ...@@ -402,6 +402,11 @@ article.edit-article=Editing article
article.slug=Article slug (URL) article.slug=Article slug (URL)
article.title=Article title article.title=Article title
article.body=Article body article.body=Article body
article.post-to-transifex=Post to Transifex
article.remove-from-transifex=Remove from Transifex
article.transifex-resource-updated=The resource was successfully updated on Transifex.
article.transifex-resource-removed=The resource was successfully removed from Transifex.
article.transifex-failed=An error occured while exchanging data with Transifex
activitypost=Activity post activitypost=Activity post
activitypost.add-new-post=Add new post activitypost.add-new-post=Add new post
......
...@@ -14,21 +14,17 @@ ...@@ -14,21 +14,17 @@
<c:if test="${article.lang eq 'en'}"> <c:if test="${article.lang eq 'en'}">
<div class="form-group"> <div class="form-group">
<div> ${responseFromTransifex}</div> <c:if test="${responseFromTransifex ne null}">
<a href="<c:url value="/content/postToTransifex/${article.slug}"/>" class="btn btn-default">Post to <div class="alert alert-warning"><spring:message code="${responseFromTransifex}" /></div>
Transifex</a> </c:if>
</div>
<div class="form-group"> <form method="post" action="<c:url value="/content/transifex"/>">
<div> ${result}</div> <input id="articleSlug" type="hidden" name="slug" value="${article.slug}"/>
<div> <input type="submit" name="post" class="btn btn-default" value="<spring:message code="article.post-to-transifex" />" />
<c:url var="deleteFromTransifex" value="/content/deleteFromTransifex"/> <input type="submit" name="remove" class="btn btn-default" value="<spring:message code="article.remove-from-transifex" />" />
<form method="post" action="${deleteFromTransifex}"> <!-- CSRF protection -->
<input id="articleSlug" type="hidden" name="articleSlug" value="${article.slug}"/> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<input type="submit" value="Delete from Transifex" class="btn btn-default"/> </form>
<!-- CSRF protection -->