ContentServiceImpl.java

/*
 * Copyright 2019 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.service.impl;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.genesys.blocks.auditlog.service.ClassPKService;
import org.genesys.blocks.model.ClassPK;
import org.genesys.blocks.model.EntityId;
import org.genesys.filerepository.InvalidRepositoryFileDataException;
import org.genesys.filerepository.InvalidRepositoryPathException;
import org.genesys.filerepository.model.RepositoryFile;
import org.genesys.filerepository.service.RepositoryService;
import org.genesys.server.api.v1.mapper.APIv1Mapper;
import org.genesys.server.api.v1.model.ActivityPost;
import org.genesys.server.api.v1.model.Article;
import org.genesys.server.api.v1.model.Menu;
import org.genesys.server.api.v1.model.MenuItem;
import org.genesys.server.api.v1.model.RepositoryImage;
import org.genesys.server.api.v1.model.RepositoryImageInfo;
import org.genesys.server.component.security.AsAdminInvoker;
import org.genesys.server.component.security.SecurityUtils;
import org.genesys.server.exception.NotFoundElement;
import org.genesys.server.exception.SearchException;
import org.genesys.server.model.UserRole;
import org.genesys.server.model.impl.ArticleLang;
import org.genesys.server.persistence.MenuRepository;
import org.genesys.server.service.ActivityPostService;
import org.genesys.server.service.ArticleService;
import org.genesys.server.service.ArticleTranslationService;
import org.genesys.server.service.CRMException;
import org.genesys.server.service.ContentService;
import org.genesys.server.service.MenuItemService;
import org.genesys.server.service.filter.ActivityPostFilter;
import org.genesys.server.service.filter.ArticleFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;

@Service
@Validated
public class ContentServiceImpl implements ContentService {
	public static final Logger LOG = LoggerFactory.getLogger(ContentServiceImpl.class);

	@Autowired
	private ClassPKService classPkService;

	@Autowired
	private MenuRepository repoMenu;


	@Autowired
	private VelocityEngine velocityEngine;

	@Autowired
	protected RepositoryService repositoryService;

	/** The securityUtils. */
	@Autowired
	private SecurityUtils securityUtils;

	/** Execute code as admin */
	@Autowired
	protected AsAdminInvoker asAdminInvoker;

	@Autowired
	private ActivityPostService activityPostService;
	@Autowired
	private ArticleService articleService;
	@Autowired
	private APIv1Mapper mapper;

	@Autowired
	private ArticleTranslationService articleTranslationService;
	
	@Autowired
	private MenuItemService menuItemService;

	@Override
	public Locale getDefaultLocale() {
		return Locale.ENGLISH;
	}

	@Override
	@Transactional(readOnly = true)
	public List<ActivityPost> lastNews() {
		final PageRequest page = PageRequest.of(0, 6, Direction.DESC, "publishDate");
		List<ActivityPost> allNews = allNews(page).getContent();
		return allNews;
	}

	@Override
	@Transactional(readOnly = true)
	public Page<ActivityPost> allNews(Pageable page) {
		return activityPostService.allNews(page).map(mapper::map);
	}

	/**
	 * @throws SearchException 
	 * @deprecated use {@link #listArticles(ArticleFilter filter, Pageable pageable)}
	 */
	@Override
	@Deprecated
	@Transactional(readOnly = true)
	public Page<Article> listArticles(Pageable pageable) throws SearchException {
		return articleService.listFiltered(null, pageable).map(mapper::map);
	}

	@Override
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
	@Transactional(readOnly = true)
	public Page<Article> listArticles(final ArticleFilter filter, final Pageable pageable) throws SearchException {
		return articleService.listFiltered(filter, pageable).map(mapper::map);
	}

	/**
	 * @throws SearchException 
	 * @deprecated use {@link #listArticles(ArticleFilter filter, Pageable pageable)}
	 */
	@Override
	@Deprecated
	@Transactional(readOnly = true)
	public Page<Article> listArticlesByLang(String lang, Pageable pageable) throws SearchException {
		var filter = new ArticleFilter();
		filter.originalLanguageTag = Set.of(lang);
		return articleService.listFiltered(filter, pageable).map(mapper::map);
	}

	@Override
	@Transactional(readOnly = true)
	public Article getGlobalArticle(String slug, Locale locale, boolean useDefault) {
		return getArticle(Article.class, null, slug, locale, useDefault);
	}

	/**
	 * Get article, use default locale if required
	 */
	@Override
	@Transactional(readOnly = true)
	public Article getGlobalArticle(String slug, Locale locale) {
		return getGlobalArticle(slug, locale, true);
	}

	@Override
	@Transactional(readOnly = true)
	public Article getArticle(EntityId entity, String slug, Locale locale) {
		return getArticle(entity.getClass(), entity.getId(), slug, locale, true);
	}

	@Override
	@Transactional(readOnly = true)
	public Article getArticleBySlugAndLang(String slug, String lang) {
		// QArticle qArticle = QArticle.article;
		// var inst = Instant.now();
		// if (! (securityUtils.hasRole(UserRole.ADMINISTRATOR) || securityUtils.hasRole(UserRole.CONTENTMANAGER))) {
		// 	return articleRepository.findOne(qArticle.publishDate.before(inst)
		// 			.andAnyOf(qArticle.expirationDate.isNull(), qArticle.expirationDate.after(inst))
		// 			.and(qArticle.slug.eq(slug)).and(qArticle.lang.eq(lang))).orElse(null);
		// }
		// return articleRepository.findBySlugAndLang(slug, lang);
		return getArticle(Article.class, null, slug, Locale.forLanguageTag(lang), false);
	}

	@Override
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
	@Transactional(readOnly = true)
	public Article getArticleBySlugLangTargetIdClassPk(String slug, String lang, Long targetId, String classPKShortName) {
		// ClassPK classPK = classPkService.findByShortName(classPKShortName);
		// return articleRepository.findBySlugAndLangAndTargetIdAndClassPk(slug, lang, targetId, classPK);
		var article = articleService.getArticleBySlugLangTargetIdClassPk(slug, lang, targetId, classPKShortName);
		return mapper.map(article);
	}

	@Override
	@Transactional(readOnly = true)
	public Article getArticle(Class<?> clazz, Long targetId, String slug, Locale locale, boolean useDefault) {
		var article = articleService.getArticleBySlugLangTargetIdClassPk(slug, locale.toLanguageTag(), targetId, clazz.getSimpleName());
		return mapper.map(article);
	}

	@Override
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
	@Transactional
	public Article updateArticle(long id, String slug, String title, String summary, String body) throws NotFoundElement {

		var lang = LocaleContextHolder.getLocale().toLanguageTag();
		// return article;
		var article = articleService.get(id);
		if (Objects.equals(article.getOriginalLanguageTag(), lang)) {
			// Update Article
			article.setSlug(slug);
			article.setTitle(title);
			article.setSummary(summary);
			article.setBody(body);
			article = articleService.update(article);
		} else {
			// Update ArticleLang
			var articleLang = articleTranslationService.getLang(article, lang);
			if (articleLang == null) {
				articleLang = new ArticleLang(article, lang, title, summary, body);
			} else {
				articleLang.setTitle(title);
				articleLang.setSummary(summary);
				articleLang.setBody(body);
			}
			articleTranslationService.upsertLang(article, articleLang);
		}

		return mapper.map(articleService.loadTranslated(article.getId()));
	}

	@Override
	@Transactional
	public Article createArticle(Class<?> clazz, Long targetId, String slug, Locale locale, String title, String summary, String body, boolean isTemplate, Instant publishDate, Instant expirationDate) throws CRMException {
		var article = articleService.getArticle(clazz, targetId, slug, locale);

		if (article == null) {
			var art = new org.genesys.server.model.impl.Article();
			art.setClassPk(getClassPk(clazz));
			art.setTargetId(targetId);
			art.setSlug(slug);
			art.setOriginalLanguageTag(locale.toLanguageTag());
			art.setTemplate(isTemplate);
			art.setTitle(title);
			art.setSummary(summary);
			art.setBody(body);
			art.setPublishDate(publishDate);
			art.setExpirationDate(expirationDate);
			art = articleService.createFast(art);
			return mapper.map(articleService.loadTranslated(art.getId()));
		}

		if (Objects.equals(locale.toLanguageTag(), article.entity.getOriginalLanguageTag())) {
			// Not a translation!
			return mapper.map(article);
		} else {
			var translation = article.translation;
			if (translation == null) { // No such translation
				translation = new ArticleLang(article.entity, locale.toLanguageTag(), title, summary, body);
			// } else {
			// 	translation.setTitle(title);
			// 	translation.setSummary(summary);
			// 	translation.setBody(body);
				articleTranslationService.upsertLang(article.entity, translation);
			}
			return mapper.map(articleService.loadTranslated(article.entity.getId()));
		}
	}

	@Override
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
	@Transactional
	public Article updateGlobalArticle(String slug, Locale locale, String title, String summary, String body, Instant publishDate, Instant expirationDate) throws CRMException {

		var lang = locale.toLanguageTag();
		var article = articleService.getArticleBySlugAndLang(slug, lang);

		var translation = article.translation;
		if (Objects.equals(lang, article.entity.getOriginalLanguageTag())) {
			article.entity.setTitle(title);
			article.entity.setSummary(summary);
			article.entity.setBody(body);
			article.entity.setPublishDate(publishDate);
			article.entity.setExpirationDate(expirationDate);
			articleService.update(article.entity);
		} else {
			if (translation == null) { // No such translation
				translation = new ArticleLang(article.entity, lang, title, summary, body);
			} else {
				translation.setTitle(title);
				translation.setSummary(summary);
				translation.setBody(body);
			}
			articleTranslationService.upsertLang(article.entity, translation);
		}
		
		return mapper.map(articleService.loadTranslated(article.entity.getId()));
	}

	@Override
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
	@Transactional
	public Article updateGlobalArticle(String slug, Locale locale, String title, String summary, String body) throws CRMException {
		return updateGlobalArticle(slug, locale, title, summary, body, Instant.now(), null);
	}

	/**
	 * Creates or updates an article
	 * 
	 * @param entity
	 * @param body
	 * @param locale
	 * @return
	 * @throws CRMException
	 */
	@Override
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER') or hasPermission(#entity, 'ADMINISTRATION')")
	@Transactional
	public Article updateArticle(EntityId entity, String slug, String title, String summary, String body, Locale locale) throws CRMException {
		return updateArticle(entity.getClass(), entity.getId(), slug, title, summary, body, locale);
	}

	@Override
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
	@Transactional
	public Article updateArticle(Class<?> clazz, Long id, String slug, String title, String summary, String body, Locale locale) throws CRMException {
		
		var lang = locale.toLanguageTag();
		var article = articleService.getArticle(clazz, id, slug, locale);

		if (article == null) {
			throw new NotFoundElement("No such article");
		}

		var translation = article.translation;
		if (Objects.equals(lang, article.entity.getOriginalLanguageTag())) {
			article.entity.setTitle(title);
			article.entity.setSummary(summary);
			article.entity.setBody(body);
			articleService.update(article.entity);
		} else {
			if (translation == null) { // No such translation
				translation = new ArticleLang(article.entity, lang, title, summary, body);
			} else {
				translation.setTitle(title);
				translation.setSummary(summary);
				translation.setBody(body);
			}
			articleTranslationService.upsertLang(article.entity, translation);
		}

		return mapper.map(articleService.loadTranslated(article.entity.getId()));
	}

	@Override
	public ClassPK getClassPk(Class<?> clazz) {
		return classPkService.getClassPk(clazz);
	}

	@Override
	public ClassPK getClassPk(String shortName) {
		return classPkService.findByShortName(shortName);
	}

	@Override
	@Transactional(isolation = Isolation.READ_UNCOMMITTED)
	public synchronized ClassPK ensureClassPK(Class<?> clazz) {
		return classPkService.getClassPk(clazz);
	}

	// @Override
	// public Article getArticle(long id) {
	// 	return articleRepository.findById(id).orElseThrow(() -> { throw new NotFoundElement("Record not found by id=" + id); });
	// }

	@Override
	@Transactional(readOnly = true)
	public ActivityPost getActivityPost(long id) {
		var now = Instant.now();
		var post = activityPostService.loadTranslated(id);

		if (securityUtils.hasRole(UserRole.ADMINISTRATOR) || securityUtils.hasRole(UserRole.CONTENTMANAGER)) {
			return mapper.map(post);
		}

		if ((post.getEntity().getPublishDate() != null && post.getEntity().getPublishDate().isAfter(now))
		|| (post.getEntity().getExpirationDate() != null && post.getEntity().getExpirationDate().isBefore(now))) {
			throw new NotFoundElement("Record not found by id=" + id);
		}

		return mapper.map(post);
	}

	/**
	 * Create and persist a new {@link ActivityPost}
	 */
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
	@Override
	@Transactional
	public ActivityPost createActivityPost(String title, String summary, String body, Instant publishDate, Instant expirationDate, RepositoryImage coverImage) {
		// final ActivityPost newPost = new ActivityPost();
		// newPost.setPublishDate(publishDate);
		// newPost.setExpirationDate(expirationDate);
		// newPost.setCoverImage(coverImage);
		// return updatePostData(newPost, title, summary, body);
		var source = new org.genesys.server.model.impl.ActivityPost();
		source.setOriginalLanguageTag(getDefaultLocale().getLanguage());
		source.setTitle(title);
		source.setSummary(summary);
		source.setBody(body);
		source.setPublishDate(publishDate);
		source.setExpirationDate(expirationDate);
		source.setCoverImage(mapper.map(coverImage));
		source = activityPostService.createFast(source);
		return mapper.map(activityPostService.loadTranslated(source.getId()));
	}

	@Override
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
	@Transactional
	public ActivityPost updateActivityPost(long id, String title, String summary, String body) throws NotFoundElement {
		var translatedPost = activityPostService.loadTranslated(id);
		var post = translatedPost.entity;
		if (Objects.equals(getDefaultLocale().getLanguage(), post.getOriginalLanguageTag())) {
			post.setTitle(title);
			post.setSummary(summary);
			post.setBody(body);
			post = activityPostService.update(post);
			return mapper.map(activityPostService.loadTranslated(post.getId()));

		} else { // No update
			return mapper.map(translatedPost);
		}
	}

	@Override
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
	@Transactional
	public ActivityPost updateActivityPost(long id, String title, String summary, String body, Instant publishDate, Instant expirationDate, RepositoryImage coverImage) throws NotFoundElement {
		var translatedPost = activityPostService.loadTranslated(id);
		var post = translatedPost.entity;
		if (Objects.equals(getDefaultLocale().getLanguage(), post.getOriginalLanguageTag())) {
			post.setTitle(title);
			post.setSummary(summary);
			post.setBody(body);
			post.setPublishDate(publishDate);
			post.setExpirationDate(expirationDate);
			post.setCoverImage(mapper.map(coverImage));
			post = activityPostService.update(post);
			return mapper.map(activityPostService.loadTranslated(post.getId()));

		} else { // No update
			return mapper.map(translatedPost);
		}
	}
	
	@Override
	@Transactional(readOnly = true)
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
	public Page<ActivityPost> listActivityPosts(ActivityPostFilter filter, Pageable pageable) throws SearchException {
		return activityPostService.listFiltered(filter, pageable).map(mapper::map);
	}

	@Override
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
	@Transactional
	public void deleteActivityPost(ActivityPost activityPost) {
		activityPostService.remove(activityPostService.get(activityPost.getId()));
	}

	@Override
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
	@Transactional
	public void deleteArticle(final Long id, final Integer version) {
		articleService.deleteArticle(id, version);
	}

	@Override
	public String processTemplate(String templateStr, Map<String, Object> root) {
		final StringWriter swOut = new StringWriter();
		processTemplate(templateStr, root, swOut);
		if (LOG.isTraceEnabled()) {
			LOG.trace(swOut.toString());
		}
		return swOut.toString();
	}

	@Override
	public void processTemplate(String templateStr, Map<String, Object> root, Writer writer) {
		final VelocityContext context = new VelocityContext();
		for (final var entry : root.entrySet()) {
			context.put(entry.getKey(), entry.getValue());
		}
		context.put("esc", new org.apache.velocity.tools.generic.EscapeTool());

		/**
		 * Merge data and template
		 */
		velocityEngine.evaluate(context, writer, "log tag name", templateStr);
	}

	/**
	 * Load/get the CMS menu specified by the key
	 *
	 * @param key
	 * @return
	 */
	@Override
	@Transactional(readOnly = true)
	public Menu getMenu(String key) {
		var menu = repoMenu.findByKey(key);
		if (menu != null) {
			menu.getItems().size();
		}
		return mapper.map(menu);
	}

	/**
	 * Ensure the CMS menu item exists in the menu
	 *
	 * @return
	 */
	@Override
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
	@Transactional
	public MenuItem ensureMenuItem(String menuKey, String url, String text) {
		return this.ensureMenuItem(menuKey, new MenuItem(url, text));
	}

	/**
	 * Ensure the CMS menu item exists in the menu
	 * 
	 * @return
	 */
	@Override
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
	@Transactional
	public MenuItem ensureMenuItem(String menuKey, MenuItem source) {
		return mapper.map(menuItemService.ensureMenuItem(menuKey, mapper.map(source)));
	}

	@Override
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
	@Transactional
	public org.genesys.server.model.impl.MenuItem updateMenuItem(final long id, final MenuItem source) {
		return menuItemService.update(mapper.map(source), menuItemService.get(id));
	}

	@Override
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
	@Transactional
	public MenuItem deleteMenuItem(final long id) {
		return mapper.map(menuItemService.remove(menuItemService.get(id)));
	}

	@Override
	@Transactional(readOnly = true)
	public MenuItem getMenuItem(final long id) {
		return mapper.map(menuItemService.loadTranslated(id));
	}

	/**
	 * Update the CMS menu specified by key with the provided structure
	 * 
	 * @param key
	 * @param items
	 * @return
	 */
	@Override
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
	@Transactional
	public Menu updateMenu(String menuKey, List<MenuItem> items) {
		// Menu menu = repoMenu.findByKey(menuKey);

		// if (items.size() == 0) {
		// 	if (menu != null) {
		// 		LOG.info("Deleting CMS menu {}", menuKey);
		// 		// Should delete all menu items
		// 		repoMenu.delete(menu);
		// 	} else {
		// 		// NOOP
		// 		LOG.info("Unknown CMS menu {}", menuKey);
		// 	}
		// 	return null;
		// }

		// if (menu == null) {
		// 	// Create instance
		// 	menu = new Menu();
		// 	menu.setKey(menuKey);
		// }

		// // TODO Remove items missing from the List

		// // TODO Add items in the list missing from the menu

		// // TODO Persist.

		// return menu;
		throw new UnsupportedOperationException("Not implemented");
	}

	@Override
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER')")
	public void sanitizeAll() {
		LOG.info("Sanitizing articles");

		articleService.sanitizeAll();;
	}

	@Override
	@Transactional
	public Article createGlobalArticle(String slug, Locale locale, String title, String summary, String body, boolean isTemplate, Instant publishDate, Instant expirationDate) throws CRMException {
		var article = articleService.getArticleBySlugAndLang(slug, locale.toLanguageTag());
		if (article == null && !getDefaultLocale().getLanguage().equals(locale.toLanguageTag())) {
			throw new CRMException("Global articles must first be created in primary language=" + getDefaultLocale().getLanguage());
		}

		if (article != null && article.entity.getOriginalLanguageTag().equals(locale.toLanguageTag())) {
			throw new CRMException(String.format("Global article with slug='%s' and language='%s' already exists.", slug, locale.toLanguageTag()));
		}

		if (article == null) {
			var source = new org.genesys.server.model.impl.Article();
			source.setClassPk(ensureClassPK(Article.class));
			source.setTargetId(0L);
			source.setSlug(slug);
			source.setTitle(title);
			source.setSummary(summary);
			source.setBody(body);
			source.setTemplate(isTemplate);
			source.setPublishDate(publishDate);
			source.setExpirationDate(expirationDate);
			source.setOriginalLanguageTag(locale.toLanguageTag());
			// Create new
			source = articleService.createFast(source);
			return mapper.map(articleService.loadTranslated(source.getId()));
		} else {
			articleTranslationService.addLang(article.entity, new ArticleLang(article.entity, locale.toLanguageTag(), title, summary, body));
			return mapper.map(articleService.loadTranslated(article.entity.getId()));
		}
	}

	@Override
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER') or hasPermission(#article, 'ADMINISTRATION')")
	public RepositoryFile uploadArticleFile(long articleId, final MultipartFile file) throws IOException, InvalidRepositoryPathException, InvalidRepositoryFileDataException {
		if (file == null)
			throw new InvalidRepositoryPathException("Nothing to upload. File must be provided.");

		return articleService.uploadArticleFile(articleService.get(articleId), file);
	}

	@Override
	@PreAuthorize("hasRole('ADMINISTRATOR') or hasRole('CONTENTMANAGER') or hasPermission(#activityPost, 'ADMINISTRATION')")
	public RepositoryFile uploadActivityPostFile(long activityPostId, final MultipartFile file) throws IOException, InvalidRepositoryPathException, InvalidRepositoryFileDataException {
		if (file == null)
			throw new InvalidRepositoryPathException("Nothing to upload. File must be provided.");

		// Reload
		return activityPostService.uploadActivityPostFile(activityPostService.get(activityPostId), file);
	}

}