All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.wallride.service.PageService Maven / Gradle / Ivy

There is a newer version: 1.0.0.M18
Show newest version
/*
 * Copyright 2014 Tagbangers, Inc.
 *
 * 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.wallride.service;

import org.apache.commons.lang.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.MessageCodesResolver;
import org.wallride.autoconfigure.WallRideCacheConfiguration;
import org.wallride.autoconfigure.WallRideProperties;
import org.wallride.domain.*;
import org.wallride.exception.DuplicateCodeException;
import org.wallride.exception.EmptyCodeException;
import org.wallride.exception.ServiceException;
import org.wallride.model.*;
import org.wallride.repository.*;
import org.wallride.support.AuthorizedUser;
import org.wallride.support.CodeFormatter;
import org.wallride.web.controller.admin.article.CustomFieldValueEditForm;

import javax.annotation.Resource;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
@Transactional(rollbackFor = Exception.class)
public class PageService {

	@Resource
	private PostRepository postRepository;

	@Resource
	private PageRepository pageRepository;

	@Resource
	private TagRepository tagRepository;

	@Resource
	private MediaRepository mediaRepository;

	@Inject
	private MessageCodesResolver messageCodesResolver;

	@Inject
	private PlatformTransactionManager transactionManager;

	@Inject
	private WallRideProperties wallRideProperties;

	@PersistenceContext
	private EntityManager entityManager;

	private static Logger logger = LoggerFactory.getLogger(PageService.class);

	@CacheEvict(value = WallRideCacheConfiguration.PAGE_CACHE, allEntries = true)
	public Page createPage(PageCreateRequest request, Post.Status status, AuthorizedUser authorizedUser) {
		LocalDateTime now = LocalDateTime.now();

		String code = request.getCode();
		if (code == null) {
			try {
				code = new CodeFormatter().parse(request.getTitle(), LocaleContextHolder.getLocale());
			} catch (ParseException e) {
				throw new ServiceException(e);
			}
		}
		if (!StringUtils.hasText(code)) {
			if (!status.equals(Post.Status.DRAFT)) {
				throw new EmptyCodeException();
			}
		}

		if (!status.equals(Post.Status.DRAFT)) {
			Post duplicate = postRepository.findOneByCodeAndLanguage(code, request.getLanguage());
			if (duplicate != null) {
				throw new DuplicateCodeException(code);
			}
		}

		Page page = new Page();

		if (!status.equals(Post.Status.DRAFT)) {
			page.setCode(code);
			page.setDraftedCode(null);
		} else {
			page.setCode(null);
			page.setDraftedCode(code);
		}

		Page parent = (request.getParentId() != null) ? pageRepository.findOneByIdAndLanguage(request.getParentId(), request.getLanguage()) : null;
		int rgt = 0;
		if (parent == null) {
			rgt = pageRepository.findMaxRgt();
			rgt++;
		} else {
			rgt = parent.getRgt();
			pageRepository.unshiftRgt(rgt);
			pageRepository.unshiftLft(rgt);
		}

		page.setParent(parent);

		Media cover = null;
		if (request.getCoverId() != null) {
			cover = entityManager.getReference(Media.class, request.getCoverId());
		}
		page.setCover(cover);
		page.setTitle(request.getTitle());
		page.setBody(request.getBody());

		page.setAuthor(entityManager.getReference(User.class, authorizedUser.getId()));

		LocalDateTime date = request.getDate();
		if (Post.Status.PUBLISHED.equals(status)) {
			if (date == null) {
				date = now;
			} else if (date.isAfter(now)) {
				status = Post.Status.SCHEDULED;
			}
		}
		page.setDate(date);
		page.setStatus(status);
		page.setLanguage(request.getLanguage());

		page.getCategories().clear();
		SortedSet categories = new TreeSet<>();
		for (long categoryId : request.getCategoryIds()) {
			categories.add(entityManager.getReference(Category.class, categoryId));
		}
		page.setCategories(categories);

		page.getTags().clear();
		Set tagNames = StringUtils.commaDelimitedListToSet(request.getTags());
		if (!CollectionUtils.isEmpty(tagNames)) {
			for (String tagName : tagNames) {
				Tag tag = tagRepository.findOneForUpdateByNameAndLanguage(tagName, request.getLanguage());
				if (tag == null) {
					tag = new Tag();
					tag.setName(tagName);
					tag.setLanguage(request.getLanguage());
					page.setCreatedAt(now);
					page.setCreatedBy(authorizedUser.toString());
					page.setUpdatedAt(now);
					page.setUpdatedBy(authorizedUser.toString());
					tag = tagRepository.saveAndFlush(tag);
				}
				page.getTags().add(tag);
			}
		}

		page.getRelatedPosts().clear();
		Set relatedPosts = new HashSet<>();
		for (long relatedId : request.getRelatedPostIds()) {
			relatedPosts.add(entityManager.getReference(Post.class, relatedId));
		}
		page.setRelatedToPosts(relatedPosts);

		Seo seo = new Seo();
		seo.setTitle(request.getSeoTitle());
		seo.setDescription(request.getSeoDescription());
		seo.setKeywords(request.getSeoKeywords());
		page.setSeo(seo);

		page.setLft(rgt);
		page.setRgt(rgt + 1);

		List medias = new ArrayList<>();
		if (StringUtils.hasText(request.getBody())) {
//			Blog blog = blogService.getBlogById(Blog.DEFAULT_ID);
			String mediaUrlPrefix = wallRideProperties.getMediaUrlPrefix();
			Pattern mediaUrlPattern = Pattern.compile(String.format("%s([0-9a-zA-Z\\-]+)", mediaUrlPrefix));
			Matcher mediaUrlMatcher = mediaUrlPattern.matcher(request.getBody());
			while (mediaUrlMatcher.find()) {
				Media media = mediaRepository.findOneById(mediaUrlMatcher.group(1));
				medias.add(media);
			}
		}
		page.setMedias(medias);

		page.setCreatedAt(now);
		page.setCreatedBy(authorizedUser.toString());
		page.setUpdatedAt(now);
		page.setUpdatedBy(authorizedUser.toString());

		page.getCustomFieldValues().clear();
		if (!CollectionUtils.isEmpty(request.getCustomFieldValues())) {
			for (CustomFieldValueEditForm valueForm : request.getCustomFieldValues()) {
				CustomFieldValue value =  new CustomFieldValue();
				value.setCustomField(entityManager.getReference(CustomField.class, valueForm.getCustomFieldId()));
				value.setPost(page);
				if (valueForm.getFieldType().equals(CustomField.FieldType.CHECKBOX)) {
					if (!ArrayUtils.isEmpty(valueForm.getTextValues())) {
						value.setTextValue(String.join(",", valueForm.getTextValues()));
					} else {
						value.setTextValue(null);
					}
				} else {
					value.setTextValue(valueForm.getTextValue());
				}
				value.setStringValue(valueForm.getStringValue());
				value.setNumberValue(valueForm.getNumberValue());
				value.setDateValue(valueForm.getDateValue());
				value.setDatetimeValue(valueForm.getDatetimeValue());
				if (!value.isEmpty()) {
					page.getCustomFieldValues().add(value);
				}
			}
		}

		return pageRepository.save(page);
	}

	@CacheEvict(value = WallRideCacheConfiguration.PAGE_CACHE, allEntries = true)
	public Page savePageAsDraft(PageUpdateRequest request, AuthorizedUser authorizedUser) {
		postRepository.lock(request.getId());
		Page page = pageRepository.findOneByIdAndLanguage(request.getId(), request.getLanguage());
		if (!page.getStatus().equals(Post.Status.DRAFT)) {
			Page draft = pageRepository.findOne(PageSpecifications.draft(page));
			if (draft == null) {
				PageCreateRequest createRequest = new PageCreateRequest.Builder()
						.code(request.getCode())
						.coverId(request.getCoverId())
						.title(request.getTitle())
						.body(request.getBody())
						.authorId(request.getAuthorId())
						.date(request.getDate())
						.parentId(request.getParentId())
						.categoryIds(request.getCategoryIds())
						.tags(request.getTags())
						.seoTitle(request.getSeoTitle())
						.seoDescription(request.getSeoDescription())
						.seoKeywords(request.getSeoKeywords())
						.customFieldValues(new ArrayList<>(request.getCustomFieldValues()))
						.language(request.getLanguage())
						.build();
				draft = createPage(createRequest, Post.Status.DRAFT, authorizedUser);
				draft.setDrafted(page);
				return pageRepository.save(draft);
			} else {
				PageUpdateRequest updateRequest = new PageUpdateRequest.Builder()
						.id(draft.getId())
						.code(request.getCode())
						.coverId(request.getCoverId())
						.title(request.getTitle())
						.body(request.getBody())
						.authorId(request.getAuthorId())
						.date(request.getDate())
						.parentId(request.getParentId())
						.categoryIds(request.getCategoryIds())
						.tags(request.getTags())
						.seoTitle(request.getSeoTitle())
						.seoDescription(request.getSeoDescription())
						.seoKeywords(request.getSeoKeywords())
						.customFieldValues(request.getCustomFieldValues())
						.language(request.getLanguage())
						.build();
				return savePage(updateRequest, authorizedUser);
			}
		} else {
			return savePage(request, authorizedUser);
		}
	}

	@CacheEvict(value = WallRideCacheConfiguration.PAGE_CACHE, allEntries = true)
	public Page savePageAsPublished(PageUpdateRequest request, AuthorizedUser authorizedUser) {
		postRepository.lock(request.getId());
		Page page = pageRepository.findOneByIdAndLanguage(request.getId(), request.getLanguage());
		Page deleteTarget = getDraftById(page.getId());
		if (deleteTarget != null) {
			pageRepository.delete(deleteTarget);
		}
		page.setDrafted(null);
		page.setStatus(Post.Status.PUBLISHED);
		pageRepository.save(page);
		return savePage(request, authorizedUser);
	}

	@CacheEvict(value = WallRideCacheConfiguration.PAGE_CACHE, allEntries = true)
	public Page savePageAsUnpublished(PageUpdateRequest request, AuthorizedUser authorizedUser) {
		postRepository.lock(request.getId());
		Page page = pageRepository.findOneByIdAndLanguage(request.getId(), request.getLanguage());
		Page deleteTarget = getDraftById(page.getId());
		if (deleteTarget != null) {
			pageRepository.delete(deleteTarget);
		}
		page.setDrafted(null);
		page.setStatus(Post.Status.DRAFT);
		pageRepository.save(page);
		pageRepository.deleteByDrafted(page);
		return savePage(request, authorizedUser);
	}

	@CacheEvict(value = WallRideCacheConfiguration.PAGE_CACHE, allEntries = true)
	public Page savePage(PageUpdateRequest request, AuthorizedUser authorizedUser) {
		postRepository.lock(request.getId());
		Page page = pageRepository.findOneByIdAndLanguage(request.getId(), request.getLanguage());
		LocalDateTime now = LocalDateTime.now();

		String code = request.getCode();
		if (code == null) {
			try {
				code = new CodeFormatter().parse(request.getTitle(), LocaleContextHolder.getLocale());
			} catch (ParseException e) {
				throw new ServiceException(e);
			}
		}
		if (!StringUtils.hasText(code)) {
			if (!page.getStatus().equals(Post.Status.DRAFT)) {
				throw new EmptyCodeException();
			}
		}
		if (!page.getStatus().equals(Post.Status.DRAFT)) {
			Post duplicate = postRepository.findOneByCodeAndLanguage(code, request.getLanguage());
			if (duplicate != null && !duplicate.equals(page)) {
				throw new DuplicateCodeException(code);
			}
		}

		if (!page.getStatus().equals(Post.Status.DRAFT)) {
			page.setCode(code);
			page.setDraftedCode(null);
		} else {
			page.setCode(null);
			page.setDraftedCode(code);
		}

		Page parent = (request.getParentId() != null) ? entityManager.getReference(Page.class, request.getParentId()) : null;
		if (!(page.getParent() == null && parent == null) && !ObjectUtils.nullSafeEquals(page.getParent(), parent)) {
			pageRepository.shiftLftRgt(page.getLft(), page.getRgt());
			pageRepository.shiftRgt(page.getRgt());
			pageRepository.shiftLft(page.getRgt());

			int rgt = 0;
			if (parent == null) {
				rgt = pageRepository.findMaxRgt();
				rgt++;
			} else {
				rgt = parent.getRgt();
				pageRepository.unshiftRgt(rgt);
				pageRepository.unshiftLft(rgt);
			}
			page.setLft(rgt);
			page.setRgt(rgt + 1);
		}

		page.setParent(parent);

		Media cover = null;
		if (request.getCoverId() != null) {
			cover = entityManager.getReference(Media.class, request.getCoverId());
		}
		page.setCover(cover);
		page.setTitle(request.getTitle());
		page.setBody(request.getBody());

//		User author = null;
//		if (request.getAuthorId() != null) {
//			author = entityManager.getReference(User.class, request.getAuthorId());
//		}
//		page.setAuthor(author);

		LocalDateTime date = request.getDate();
		if (Post.Status.PUBLISHED.equals(page.getStatus())) {
			if (date == null) {
				date = now.truncatedTo(ChronoUnit.HOURS);
			} else if (date.isAfter(now)) {
				page.setStatus(Post.Status.SCHEDULED);
			}
		}
		page.setDate(date);
		page.setLanguage(request.getLanguage());

		page.getCategories().clear();
		SortedSet categories = new TreeSet<>();
		for (long categoryId : request.getCategoryIds()) {
			categories.add(entityManager.getReference(Category.class, categoryId));
		}
		page.setCategories(categories);

		page.getTags().clear();
		Set tagNames = StringUtils.commaDelimitedListToSet(request.getTags());
		if (!CollectionUtils.isEmpty(tagNames)) {
			for (String tagName : tagNames) {
				Tag tag = tagRepository.findOneForUpdateByNameAndLanguage(tagName, request.getLanguage());
				if (tag == null) {
					tag = new Tag();
					tag.setName(tagName);
					tag.setLanguage(request.getLanguage());
					page.setCreatedAt(now);
					page.setCreatedBy(authorizedUser.toString());
					page.setUpdatedAt(now);
					page.setUpdatedBy(authorizedUser.toString());
					tag = tagRepository.saveAndFlush(tag);
				}
				page.getTags().add(tag);
			}
		}

		page.getRelatedPosts().clear();
		Set relatedPosts = new HashSet<>();
		for (long relatedId : request.getRelatedPostIds()) {
			relatedPosts.add(entityManager.getReference(Post.class, relatedId));
		}
		page.setRelatedToPosts(relatedPosts);

		Seo seo = new Seo();
		seo.setTitle(request.getSeoTitle());
		seo.setDescription(request.getSeoDescription());
		seo.setKeywords(request.getSeoKeywords());
		page.setSeo(seo);

		List medias = new ArrayList<>();
		if (StringUtils.hasText(request.getBody())) {
//			Blog blog = blogService.getBlogById(Blog.DEFAULT_ID);
			String mediaUrlPrefix = wallRideProperties.getMediaUrlPrefix();
			Pattern mediaUrlPattern = Pattern.compile(String.format("%s([0-9a-zA-Z\\-]+)", mediaUrlPrefix));
			Matcher mediaUrlMatcher = mediaUrlPattern.matcher(request.getBody());
			while (mediaUrlMatcher.find()) {
				Media media = mediaRepository.findOneById(mediaUrlMatcher.group(1));
				medias.add(media);
			}
		}
		page.setMedias(medias);

		page.setUpdatedAt(now);
		page.setUpdatedBy(authorizedUser.toString());

		SortedSet fieldValues = new TreeSet<>();
		Map valueMap = new LinkedHashMap<>();
		for (CustomFieldValue value : page.getCustomFieldValues()) {
			valueMap.put(value.getCustomField(), value);
		}

		page.getCustomFieldValues().clear();
		if (!CollectionUtils.isEmpty(request.getCustomFieldValues())) {
			for (CustomFieldValueEditForm valueForm : request.getCustomFieldValues()) {
				CustomField customField = entityManager.getReference(CustomField.class, valueForm.getCustomFieldId());
				CustomFieldValue value = valueMap.get(customField);
				if (value == null) {
					value = new CustomFieldValue();
				}
				value.setCustomField(customField);
				value.setPost(page);
				if (valueForm.getFieldType().equals(CustomField.FieldType.CHECKBOX)) {
					if (!ArrayUtils.isEmpty(valueForm.getTextValues())) {
						value.setTextValue(String.join(",", valueForm.getTextValues()));
					} else {
						value.setTextValue(null);
					}
				} else {
					value.setTextValue(valueForm.getTextValue());
				}
				value.setStringValue(valueForm.getStringValue());
				value.setNumberValue(valueForm.getNumberValue());
				value.setDateValue(valueForm.getDateValue());
				value.setDatetimeValue(valueForm.getDatetimeValue());
				if (!value.isEmpty()) {
					fieldValues.add(value);
				}
			}
		}
		page.setCustomFieldValues(fieldValues);

		return pageRepository.save(page);
	}

	@CacheEvict(value = WallRideCacheConfiguration.PAGE_CACHE, allEntries = true)
	public void updatePageHierarchy(List> data, String language) {
		for (int i = 0; i < data.size(); i++) {
			Map map = data.get(i);
			if (map.get("item_id") != null) {
				postRepository.lock(Long.parseLong((String) map.get("item_id")));
				Page page = pageRepository.findOneByIdAndLanguage(Long.parseLong((String) map.get("item_id")), language);
				if (page != null) {
					Page parent = null;
					if (map.get("parent_id") != null) {
						parent = pageRepository.findOneByIdAndLanguage(Long.parseLong((String) map.get("parent_id")), language);
					}
					page.setParent(parent);
					page.setLft(((int) map.get("left")) - 1);
					page.setRgt(((int) map.get("right")) - 1);
//					page.setDepth((int) map.get("depth"));
//					page.setSort(i);
					pageRepository.save(page);
				}
			}
		}
	}

	@CacheEvict(value = WallRideCacheConfiguration.PAGE_CACHE, allEntries = true)
	public Page deletePage(PageDeleteRequest request, BindingResult result) throws BindException {
		postRepository.lock(request.getId());
		Page page = pageRepository.findOneByIdAndLanguage(request.getId(), request.getLanguage());
		Page parent = page.getParent();
		for (Page child : page.getChildren()) {
			child.setParent(parent);
			pageRepository.saveAndFlush(child);
		}
		page.getChildren().clear();
		pageRepository.saveAndFlush(page);
		pageRepository.delete(page);

		pageRepository.shiftLftRgt(page.getLft(), page.getRgt());
		pageRepository.shiftRgt(page.getRgt());
		pageRepository.shiftLft(page.getRgt());

		return page;
	}

	@CacheEvict(value = WallRideCacheConfiguration.PAGE_CACHE, allEntries = true)
	public Page deletePage(long id, String language) {
		postRepository.lock(id);
		Page page = pageRepository.findOneByIdAndLanguage(id, language);
		Page parent = page.getParent();
		for (Page child : page.getChildren()) {
			child.setParent(parent);
			pageRepository.saveAndFlush(child);
		}
		page.getChildren().clear();
		pageRepository.saveAndFlush(page);
		pageRepository.delete(page);

		pageRepository.shiftLftRgt(page.getLft(), page.getRgt());
		pageRepository.shiftRgt(page.getRgt());
		pageRepository.shiftLft(page.getRgt());

		return page;
	}

	@CacheEvict(value = WallRideCacheConfiguration.PAGE_CACHE, allEntries = true)
	@Transactional(propagation = Propagation.NOT_SUPPORTED)
	public List bulkDeletePage(PageBulkDeleteRequest bulkDeleteRequest, BindingResult result) {
		List pages = new ArrayList<>();
		for (long id : bulkDeleteRequest.getIds()) {
			final PageDeleteRequest deleteRequest = new PageDeleteRequest.Builder()
					.id(id)
					.language(bulkDeleteRequest.getLanguage())
					.build();

			final BeanPropertyBindingResult r = new BeanPropertyBindingResult(deleteRequest, "request");
			r.setMessageCodesResolver(messageCodesResolver);

			TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
			transactionTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW);
			Page page = null;
			try {
				page = transactionTemplate.execute(new TransactionCallback() {
					public Page doInTransaction(TransactionStatus status) {
						try {
							return deletePage(deleteRequest, r);
						} catch (BindException e) {
							throw new RuntimeException(e);
						}
					}
				});
				pages.add(page);
			} catch (Exception e) {
				logger.debug("Errors: {}", r);
				result.addAllErrors(r);
			}
		}
		return pages;
	}

	public List getPageIds(PageSearchRequest request) {
		return pageRepository.searchForId(request);
	}

	@Cacheable(value = WallRideCacheConfiguration.PAGE_CACHE)
	public org.springframework.data.domain.Page getPages(PageSearchRequest request) {
		return getPages(request, null);
	}

	@Cacheable(value = WallRideCacheConfiguration.PAGE_CACHE)
	public org.springframework.data.domain.Page getPages(PageSearchRequest request, Pageable pageable) {
		return pageRepository.search(request, pageable);
	}

	@Cacheable(value = WallRideCacheConfiguration.PAGE_CACHE)
	public List getPathPages(Page page) {
		return getPathPages(page, false);
	}

	@Cacheable(value = WallRideCacheConfiguration.PAGE_CACHE)
	public List getPathPages(Page page, boolean includeUnpublished) {
		return pageRepository.findAll(PageSpecifications.path(page, includeUnpublished));
	}

	public List getChildPages(Page page) {
		return getChildPages(page, false);
	}

	public List getChildPages(Page page, boolean includeUnpublished) {
		return pageRepository.findAll(PageSpecifications.children(page, includeUnpublished));
	}

	public List getSiblingPages(Page page) {
		return getSiblingPages(page, false);
	}

	public List getSiblingPages(Page page, boolean includeUnpublished) {
		return pageRepository.findAll(PageSpecifications.siblings(page, includeUnpublished));
	}

	public Page getPageById(long id) {
		return pageRepository.findOneById(id);
	}

	public Page getPageById(long id, String language) {
		return pageRepository.findOneByIdAndLanguage(id, language);
	}

	@Cacheable(value = WallRideCacheConfiguration.PAGE_CACHE)
	public Page getPageByCode(String code, String language) {
		return pageRepository.findOneByCodeAndLanguage(code, language);
	}

	public Page getDraftById(long id) {
		return pageRepository.findOne(PageSpecifications.draft(entityManager.getReference(Page.class, id)));
	}

	public long countPages(String language) {
		return pageRepository.count(language);
	}

	public long countPagesByStatus(Post.Status status, String language) {
		return pageRepository.countByStatus(status, language);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy