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

Editing articles

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