ArticleController.java
/*
* Copyright 2024 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.genesys.server.api.v2.impl;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.genesys.blocks.auditlog.service.ClassPKService;
import org.genesys.server.api.ApiBaseController;
import org.genesys.server.api.v2.FilteredCRUDController;
import org.genesys.server.api.v2.TranslatedCRUDController;
import org.genesys.server.api.v2.facade.ArticleApiService;
import org.genesys.server.api.v2.facade.ArticleLangApiService;
import org.genesys.server.api.v2.mapper.MapstructMapper;
import org.genesys.server.api.v2.model.impl.ArticleDTO;
import org.genesys.server.api.v2.model.impl.ArticleLangDTO;
import org.genesys.server.api.v2.model.impl.ClassPKInfo;
import org.genesys.server.api.v2.model.impl.RepositoryFileDTO;
import org.genesys.server.api.v2.model.impl.TranslatedArticleDTO;
import org.genesys.server.exception.NotFoundElement;
import org.genesys.server.model.impl.Article;
import org.genesys.server.model.impl.ArticleLang;
import org.genesys.server.service.filter.ArticleFilter;
import org.genesys.server.service.filter.ArticleLangFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
@RestController("articleApi2")
@RequestMapping(ArticleController.CONTROLLER_URL)
@Tag(name = "Article")
public class ArticleController extends TranslatedCRUDController<ArticleDTO, TranslatedArticleDTO,
ArticleLangDTO, Article, ArticleLang, ArticleApiService, ArticleFilter> {
/** The Constant CONTROLLER_URL. */
public static final String CONTROLLER_URL = ApiBaseController.APIv2_BASE + "/article";
@Autowired
private ClassPKService classPKService;
@Autowired
private MapstructMapper mapstructMapper;
@RestController("articleLangApi2")
@RequestMapping(ArticleController.ArticleLangController.API_URL)
@PreAuthorize("isAuthenticated()")
@Tag(name = "Article")
public static class ArticleLangController extends FilteredCRUDController<ArticleLangDTO, ArticleLang, ArticleLangApiService, ArticleLangFilter> {
/** The Constant API_URL. */
public static final String API_URL = ArticleController.CONTROLLER_URL + "/lang";
}
// @Autowired(required = false)
// private TransifexService transifexService;
//
// @Autowired
// private ObjectMapper mapper;
//
// @Resource
// private Set<String> supportedLocales;
//
// private static final String defaultLanguage = "en";
/**
* Gets the article
*
* @param slug the slug
* @param className the className of article
* @param targetId the targetId
* @param language the language
* @return the article
*/
@RequestMapping(value = "/{slug:.+}/{clazz}/{targetId:\\d+}/{language}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE })
public TranslatedArticleDTO getArticle(@PathVariable(value = "clazz") final String className, @PathVariable("targetId") final long targetId,
@PathVariable(value = "slug") final String slug, @PathVariable(value = "language") final String language) throws ClassNotFoundException {
final TranslatedArticleDTO article = translatedApiService.getArticle(Class.forName(className), targetId, slug, new Locale(language));
if (article == null) {
throw new NotFoundElement("Article not found.");
}
return article;
}
/**
* Gets the article
*
* @param slug the slug
* @param language the language
* @return the article
*/
@RequestMapping(value = "/{slug:.+}/{language}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE })
public TranslatedArticleDTO getArticleBySlugAndLang(@PathVariable(value = "slug") final String slug, @PathVariable(value = "language") final String language) {
final TranslatedArticleDTO article = translatedApiService.getArticleBySlugAndLang(slug, language);
if (article == null) {
throw new NotFoundElement("Article not found.");
}
return article;
}
/**
* Gets the global article
*
* @param slug the slug
* @param language the language
* @return the global article
*/
@RequestMapping(value = "/global-article/{slug:.+}/{language}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE })
public TranslatedArticleDTO getGlobalArticle(@PathVariable(value = "slug") final String slug, @PathVariable(value = "language") final String language) {
final TranslatedArticleDTO article = translatedApiService.getGlobalArticle(slug, new Locale(language));
if (article == null) {
throw new NotFoundElement("Article not found.");
}
return article;
}
/**
* Delete articles.
*
* @param entities the list of IDs and versions of articles
* @return list of operation responses
*/
@PostMapping(value = "/delete-articles", produces = { MediaType.APPLICATION_JSON_VALUE })
public List<OpResponse<Boolean>> deleteArticles(@RequestBody final List<IDandVersion> entities) {
return entities.stream().map(entity -> {
try {
translatedApiService.deleteArticle(entity.id, entity.version);
return new OpResponse<>(true);
} catch (Throwable e) {
LOG.info("Error deleting article by id={}: {}", entity.id, e.getMessage());
return new OpResponse<Boolean>(e, false);
}
}).collect(Collectors.toList());
}
/**
* Uploads a file to Article folder
*
* @param id the id of Article
* @param file the file to upload
* @return persisted file
* @throws Exception
*/
@PostMapping(value = "/{id:\\d+}/upload", produces = { MediaType.APPLICATION_JSON_VALUE })
public RepositoryFileDTO uploadArticleFile(@PathVariable("id") final long id, @RequestPart(name = "file") final MultipartFile file)
throws Exception {
return translatedApiService.uploadArticleFile(translatedApiService.get(id), file);
}
@GetMapping(value = "/classPK/{className}", produces = { MediaType.APPLICATION_JSON_VALUE })
public ClassPKInfo getClassPK(@PathVariable("className") final String className) throws Exception {
return mapstructMapper.mapInfo(classPKService.getClassPk(Class.forName(className)));
}
// @PostMapping(value = "/transifex")
// @PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
// public TranslatedArticleDTO postToTransifex(@RequestParam("slug") String slug,
// @RequestParam(value = "targetId", required = false) Long targetId, @RequestParam("classPkShortName") String classPkShortName) throws IOException {
// if (transifexService == null) {
// throw new NotFoundElement("translationService not enabled");
// }
//
// TranslatedArticleDTO article;
// String resourceName;
// if (targetId != null) {
// article = translatedApiService.getArticleBySlugLangTargetIdClassPk(slug, LocaleContextHolder.getLocale().toLanguageTag(), targetId, classPkShortName);
// resourceName = "article-" + slug + "-" + classPkShortName + "-" + targetId;
// } else {
// article = translatedApiService.getGlobalArticle(slug, LocaleContextHolder.getLocale(), true);
// resourceName = "article-" + slug;
// }
//
// String title;
// String summary;
// String body;
// var translation = article.getTranslation();
// title = translation != null ? translation.getTitle() : article.getEntity().getOriginalTitle();
// summary = translation != null ? translation.getSummary() : article.getEntity().getSummary();
// body = translation != null ? translation.getBody() : article.getEntity().getBody();
//
// String messageBody = String.format("<div class=\"summary\">%s</div><div class=\"body\">%s</div>", summary, body);
//
// if (transifexService.resourceExists(resourceName)) {
// transifexService.updateXhtmlResource(resourceName, title, messageBody);
// } else {
// transifexService.createXhtmlResource(resourceName, title, messageBody);
// }
//
// return article;
// }
// @DeleteMapping(value = "/transifex")
// @PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
// public Boolean deleteFromTransifex(@RequestParam("slug") String slug,
// @RequestParam(value = "targetId", required = false) Long targetId, @RequestParam("classPkShortName") String classPkShortName) throws TransifexException {
// if (transifexService == null) {
// throw new NotFoundElement("translationService not enabled");
// }
//
// String resourceName;
// if (targetId != null) {
// resourceName = "article-" + slug + "-" + classPkShortName + "-" + targetId;
// } else {
// resourceName = "article-" + slug;
// }
//
// return transifexService.deleteResource(resourceName);
// }
// /**
// * Fetch all from Transifex and store
// *
// * @param slug - article slug
// * @return map with results of fetching
// * @throws Exception
// */
// @PostMapping(value = "/transifex/fetchAll")
// @PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
// public Map<String, String> fetchAllFromTransifex(@RequestParam("slug") String slug, @RequestParam(value = "targetId", required = false) Long targetId,
// @RequestParam(value = "classPkShortName", required = false) String classPkShortName, @RequestParam(name = "template", defaultValue = "false") Boolean template) throws Exception {
// if (transifexService == null) {
// throw new NotFoundElement("translationService not enabled");
// }
//
// String resourceName;
// if (targetId != null) {
// resourceName = "article-" + slug + "-" + classPkShortName + "-" + targetId;
// } else {
// resourceName = "article-" + slug;
// }
//
// Map<String, String> responses = new HashMap<>(20);
//
// for (String lang : supportedLocales) {
// if (defaultLanguage.equalsIgnoreCase(lang)) {
// continue;
// }
//
// Locale locale = Locale.forLanguageTag(lang);
// LOG.info("Fetching article {} translation for {}", resourceName, locale);
//
// String translatedResource;
// try {
// translatedResource = transifexService.getTranslatedResource(resourceName, locale, TransifexService.TranslationMode.ONLYTRANSLATED);
// } catch (TransifexException e) {
// LOG.warn(e.getMessage(), e);
// if (e.getCause() != null) {
// responses.put(lang, e.getLocalizedMessage() + ": " + e.getCause().getLocalizedMessage());
// } else {
// responses.put(lang, e.getLocalizedMessage());
// }
// // throw new Exception(e.getMessage(), e);
// continue;
// }
//
// String title;
// String body;
// String summary = null;
//
// try {
// JsonNode jsonObject = mapper.readTree(translatedResource);
// String content = jsonObject.get("content").asText();
//
// Document doc = Jsoup.parse(content);
// title = doc.title();
// if (content.contains("class=\"summary")) {
// // 1st <div class="summary">...
// summary = doc.body().child(0).html();
// // 2nd <div class="body">...
// body = doc.body().child(1).html();
// } else {
// // Old fashioned body-only approach
// body = doc.body().html();
// }
//
// if (targetId != null && StringUtils.isNotBlank(classPkShortName)) {
// ClassPK classPk = translatedApiService.getClassPk(classPkShortName);
// translatedApiService.updateArticle(Class.forName(classPk.getClassname()), targetId, slug, title, summary, body, new Locale(lang));
// responses.put(lang, "article.translations-updated");
// } else if (targetId == null && StringUtils.isBlank(classPkShortName)) {
// translatedApiService.updateGlobalArticle(slug, locale, title, summary, body);
// responses.put(lang, "article.translations-updated");
// } else {
// responses.put(lang, "Error updating local content");
// }
// } catch (IOException e) {
// LOG.warn(e.getMessage(), e);
// responses.put(lang, e.getMessage());
// }
// }
//
// return responses;
// }
}