/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.knowledge.base.service.impl;
import com.liferay.asset.kernel.model.AssetEntry;
import com.liferay.asset.kernel.model.AssetLink;
import com.liferay.asset.kernel.model.AssetLinkConstants;
import com.liferay.expando.kernel.model.ExpandoBridge;
import com.liferay.knowledge.base.configuration.KBGroupServiceConfiguration;
import com.liferay.knowledge.base.constants.AdminActivityKeys;
import com.liferay.knowledge.base.constants.KBArticleConstants;
import com.liferay.knowledge.base.constants.KBConstants;
import com.liferay.knowledge.base.constants.KBFolderConstants;
import com.liferay.knowledge.base.exception.KBArticleContentException;
import com.liferay.knowledge.base.exception.KBArticleParentException;
import com.liferay.knowledge.base.exception.KBArticlePriorityException;
import com.liferay.knowledge.base.exception.KBArticleSourceURLException;
import com.liferay.knowledge.base.exception.KBArticleStatusException;
import com.liferay.knowledge.base.exception.KBArticleTitleException;
import com.liferay.knowledge.base.exception.KBArticleUrlTitleException;
import com.liferay.knowledge.base.exception.NoSuchArticleException;
import com.liferay.knowledge.base.internal.importer.KBArticleImporter;
import com.liferay.knowledge.base.internal.util.KBArticleLocalSiblingNavigationHelper;
import com.liferay.knowledge.base.model.KBArticle;
import com.liferay.knowledge.base.model.KBFolder;
import com.liferay.knowledge.base.service.base.KBArticleLocalServiceBaseImpl;
import com.liferay.knowledge.base.service.util.AdminSubscriptionSender;
import com.liferay.knowledge.base.service.util.AdminUtil;
import com.liferay.knowledge.base.service.util.KnowledgeBaseConstants;
import com.liferay.knowledge.base.util.KnowledgeBaseUtil;
import com.liferay.knowledge.base.util.comparator.KBArticlePriorityComparator;
import com.liferay.knowledge.base.util.comparator.KBArticleVersionComparator;
import com.liferay.portal.kernel.bean.BeanPropertiesUtil;
import com.liferay.portal.kernel.bean.BeanReference;
import com.liferay.portal.kernel.dao.orm.Conjunction;
import com.liferay.portal.kernel.dao.orm.Criterion;
import com.liferay.portal.kernel.dao.orm.Disjunction;
import com.liferay.portal.kernel.dao.orm.DynamicQuery;
import com.liferay.portal.kernel.dao.orm.DynamicQueryFactoryUtil;
import com.liferay.portal.kernel.dao.orm.Junction;
import com.liferay.portal.kernel.dao.orm.Property;
import com.liferay.portal.kernel.dao.orm.PropertyFactoryUtil;
import com.liferay.portal.kernel.dao.orm.QueryUtil;
import com.liferay.portal.kernel.dao.orm.RestrictionsFactoryUtil;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.json.JSONFactoryUtil;
import com.liferay.portal.kernel.json.JSONObject;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.Group;
import com.liferay.portal.kernel.model.ModelHintsUtil;
import com.liferay.portal.kernel.model.ResourceConstants;
import com.liferay.portal.kernel.model.SystemEventConstants;
import com.liferay.portal.kernel.model.User;
import com.liferay.portal.kernel.module.configuration.ConfigurationException;
import com.liferay.portal.kernel.module.configuration.ConfigurationProvider;
import com.liferay.portal.kernel.portletfilerepository.PortletFileRepository;
import com.liferay.portal.kernel.repository.model.FileEntry;
import com.liferay.portal.kernel.search.IndexWriterHelper;
import com.liferay.portal.kernel.search.Indexer;
import com.liferay.portal.kernel.search.IndexerRegistry;
import com.liferay.portal.kernel.service.ServiceContext;
import com.liferay.portal.kernel.systemevent.SystemEvent;
import com.liferay.portal.kernel.systemevent.SystemEventHierarchyEntryThreadLocal;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.CharPool;
import com.liferay.portal.kernel.util.ContentTypes;
import com.liferay.portal.kernel.util.ListUtil;
import com.liferay.portal.kernel.util.OrderByComparator;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.SubscriptionSender;
import com.liferay.portal.kernel.util.TempFileEntryUtil;
import com.liferay.portal.kernel.util.Time;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.workflow.WorkflowConstants;
import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
import com.liferay.portal.kernel.workflow.WorkflowThreadLocal;
import com.liferay.portal.spring.extender.service.ServiceReference;
import com.liferay.subscription.model.Subscription;
import com.liferay.subscription.service.SubscriptionLocalService;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Peter Shin
* @author Brian Wing Shun Chan
* @author Edward Han
*/
public class KBArticleLocalServiceImpl extends KBArticleLocalServiceBaseImpl {
@Override
public FileEntry addAttachment(
long userId, long resourcePrimKey, String fileName,
InputStream inputStream, String mimeType)
throws PortalException {
KBArticle kbArticle = kbArticleLocalService.getLatestKBArticle(
resourcePrimKey, WorkflowConstants.STATUS_ANY);
return portletFileRepository.addPortletFileEntry(
kbArticle.getGroupId(), userId, KBArticle.class.getName(),
kbArticle.getClassPK(), KBConstants.SERVICE_NAME,
kbArticle.getAttachmentsFolderId(), inputStream, fileName, mimeType,
false);
}
@Override
public KBArticle addKBArticle(
long userId, long parentResourceClassNameId,
long parentResourcePrimKey, String title, String urlTitle,
String content, String description, String sourceURL,
String[] sections, String[] selectedFileNames,
ServiceContext serviceContext)
throws PortalException {
// KB article
User user = userLocalService.getUser(userId);
long groupId = serviceContext.getScopeGroupId();
urlTitle = normalizeUrlTitle(urlTitle);
double priority = getPriority(groupId, parentResourcePrimKey);
Date now = new Date();
validate(title, content, sourceURL);
validateParent(parentResourceClassNameId, parentResourcePrimKey);
long kbFolderId = KnowledgeBaseUtil.getKBFolderId(
parentResourceClassNameId, parentResourcePrimKey);
urlTitle = StringUtil.toLowerCase(urlTitle);
validateUrlTitle(groupId, kbFolderId, urlTitle);
long kbArticleId = counterLocalService.increment();
long resourcePrimKey = counterLocalService.increment();
long rootResourcePrimKey = getRootResourcePrimKey(
resourcePrimKey, parentResourceClassNameId, parentResourcePrimKey);
KBArticle kbArticle = kbArticlePersistence.create(kbArticleId);
kbArticle.setUuid(serviceContext.getUuid());
kbArticle.setResourcePrimKey(resourcePrimKey);
kbArticle.setGroupId(groupId);
kbArticle.setCompanyId(user.getCompanyId());
kbArticle.setUserId(user.getUserId());
kbArticle.setUserName(user.getFullName());
kbArticle.setCreateDate(serviceContext.getCreateDate(now));
kbArticle.setModifiedDate(serviceContext.getModifiedDate(now));
kbArticle.setRootResourcePrimKey(rootResourcePrimKey);
kbArticle.setParentResourceClassNameId(parentResourceClassNameId);
kbArticle.setParentResourcePrimKey(parentResourcePrimKey);
kbArticle.setKbFolderId(kbFolderId);
kbArticle.setVersion(KBArticleConstants.DEFAULT_VERSION);
kbArticle.setTitle(title);
kbArticle.setUrlTitle(
getUniqueUrlTitle(
groupId, kbFolderId, kbArticleId, title, urlTitle));
kbArticle.setContent(content);
kbArticle.setDescription(description);
kbArticle.setPriority(priority);
kbArticle.setSections(
StringUtil.merge(AdminUtil.escapeSections(sections)));
kbArticle.setViewCount(0);
kbArticle.setLatest(true);
kbArticle.setMain(false);
kbArticle.setStatus(WorkflowConstants.STATUS_DRAFT);
kbArticle.setSourceURL(sourceURL);
kbArticle.setExpandoBridgeAttributes(serviceContext);
kbArticlePersistence.update(kbArticle);
// Resources
if (serviceContext.isAddGroupPermissions() ||
serviceContext.isAddGuestPermissions()) {
addKBArticleResources(
kbArticle, serviceContext.isAddGroupPermissions(),
serviceContext.isAddGuestPermissions());
}
else {
addKBArticleResources(
kbArticle, serviceContext.getGroupPermissions(),
serviceContext.getGuestPermissions());
}
// Asset
updateKBArticleAsset(
userId, kbArticle, serviceContext.getAssetCategoryIds(),
serviceContext.getAssetTagNames(),
serviceContext.getAssetLinkEntryIds());
// Attachments
addKBArticleAttachments(userId, kbArticle, selectedFileNames);
// Workflow
return WorkflowHandlerRegistryUtil.startWorkflowInstance(
user.getCompanyId(), groupId, userId, KBArticle.class.getName(),
resourcePrimKey, kbArticle, serviceContext,
Collections.<String, Serializable>emptyMap());
}
@Override
public void addKBArticleResources(
KBArticle kbArticle, boolean addGroupPermissions,
boolean addGuestPermissions)
throws PortalException {
resourceLocalService.addResources(
kbArticle.getCompanyId(), kbArticle.getGroupId(),
kbArticle.getUserId(), KBArticle.class.getName(),
kbArticle.getResourcePrimKey(), false, addGroupPermissions,
addGuestPermissions);
}
@Override
public void addKBArticleResources(
KBArticle kbArticle, String[] groupPermissions,
String[] guestPermissions)
throws PortalException {
resourceLocalService.addModelResources(
kbArticle.getCompanyId(), kbArticle.getGroupId(),
kbArticle.getUserId(), KBArticle.class.getName(),
kbArticle.getResourcePrimKey(), groupPermissions, guestPermissions);
}
@Override
public void addKBArticleResources(
long kbArticleId, boolean addGroupPermissions,
boolean addGuestPermissions)
throws PortalException {
KBArticle kbArticle = kbArticlePersistence.findByPrimaryKey(
kbArticleId);
addKBArticleResources(
kbArticle, addGroupPermissions, addGuestPermissions);
}
@Override
public void addKBArticleResources(
long kbArticleId, String[] groupPermissions,
String[] guestPermissions)
throws PortalException {
KBArticle kbArticle = kbArticlePersistence.findByPrimaryKey(
kbArticleId);
addKBArticleResources(kbArticle, groupPermissions, guestPermissions);
}
@Override
public int addKBArticlesMarkdown(
long userId, long groupId, long parentKbFolderId, String fileName,
boolean prioritizeByNumericalPrefix, InputStream inputStream,
ServiceContext serviceContext)
throws PortalException {
boolean workflowEnabled = WorkflowThreadLocal.isEnabled();
try {
WorkflowThreadLocal.setEnabled(false);
return kbArticleImporter.processZipFile(
userId, groupId, parentKbFolderId, prioritizeByNumericalPrefix,
inputStream, serviceContext);
}
finally {
WorkflowThreadLocal.setEnabled(workflowEnabled);
}
}
@Override
public void addTempAttachment(
long groupId, long userId, String fileName, String tempFolderName,
InputStream inputStream, String mimeType)
throws PortalException {
TempFileEntryUtil.addTempFileEntry(
groupId, userId, fileName, tempFolderName, inputStream, mimeType);
}
@Override
public void deleteGroupKBArticles(long groupId) throws PortalException {
// KB articles
deleteKBArticles(groupId, KBFolderConstants.DEFAULT_PARENT_FOLDER_ID);
// Subscriptions
Group group = groupLocalService.getGroup(groupId);
List<Subscription> subscriptions =
subscriptionLocalService.getSubscriptions(
group.getCompanyId(), KBArticle.class.getName(), groupId);
for (Subscription subscription : subscriptions) {
unsubscribeGroupKBArticles(subscription.getUserId(), groupId);
}
}
@Override
@SystemEvent(
action = SystemEventConstants.ACTION_SKIP,
type = SystemEventConstants.TYPE_DELETE
)
public KBArticle deleteKBArticle(KBArticle kbArticle)
throws PortalException {
// Child KB articles
deleteKBArticles(
kbArticle.getGroupId(), kbArticle.getResourcePrimKey());
// Resources
resourceLocalService.deleteResource(
kbArticle.getCompanyId(), KBArticle.class.getName(),
ResourceConstants.SCOPE_INDIVIDUAL, kbArticle.getResourcePrimKey());
// KB articles
kbArticlePersistence.removeByResourcePrimKey(
kbArticle.getResourcePrimKey());
// KB comments
kbCommentLocalService.deleteKBComments(
KBArticle.class.getName(), kbArticle.getResourcePrimKey());
// Asset
deleteAssets(kbArticle);
// Expando
expandoRowLocalService.deleteRows(kbArticle.getKbArticleId());
// Ratings
ratingsStatsLocalService.deleteStats(
KBArticle.class.getName(), kbArticle.getResourcePrimKey());
// Social
socialActivityLocalService.deleteActivities(
KBArticle.class.getName(), kbArticle.getResourcePrimKey());
// Indexer
Indexer<KBArticle> indexer = indexerRegistry.getIndexer(
KBArticle.class);
indexer.delete(kbArticle);
// Attachments
portletFileRepository.deletePortletFolder(
kbArticle.getAttachmentsFolderId());
// Subscriptions
deleteSubscriptions(kbArticle);
// Workflow
workflowInstanceLinkLocalService.deleteWorkflowInstanceLinks(
kbArticle.getCompanyId(), kbArticle.getGroupId(),
KBArticle.class.getName(), kbArticle.getResourcePrimKey());
return kbArticle;
}
@Override
public KBArticle deleteKBArticle(long resourcePrimKey)
throws PortalException {
KBArticle kbArticle = getLatestKBArticle(
resourcePrimKey, WorkflowConstants.STATUS_ANY);
return kbArticleLocalService.deleteKBArticle(kbArticle);
}
@Override
public void deleteKBArticles(long groupId, long parentResourcePrimKey)
throws PortalException {
List<KBArticle> childKBArticles = getKBArticles(
groupId, parentResourcePrimKey, WorkflowConstants.STATUS_ANY,
QueryUtil.ALL_POS, QueryUtil.ALL_POS, null);
for (KBArticle childKBArticle : childKBArticles) {
kbArticleLocalService.deleteKBArticle(childKBArticle);
}
}
@Override
public void deleteKBArticles(long[] resourcePrimKeys)
throws PortalException {
List<KBArticle> kbArticles = getKBArticles(
resourcePrimKeys, WorkflowConstants.STATUS_ANY, null);
for (KBArticle kbArticle : kbArticles) {
kbArticleLocalService.deleteKBArticle(kbArticle);
}
}
@Override
public void deleteTempAttachment(
long groupId, long userId, String fileName, String tempFolderName)
throws PortalException {
TempFileEntryUtil.deleteTempFileEntry(
groupId, userId, fileName, tempFolderName);
}
@Override
public KBArticle fetchFirstChildKBArticle(
long groupId, long parentResourcePrimKey) {
return kbArticlePersistence.fetchByG_P_L_First(
groupId, parentResourcePrimKey, true,
new KBArticlePriorityComparator(true));
}
@Override
public KBArticle fetchKBArticle(
long resourcePrimKey, long groupId, int version) {
return kbArticlePersistence.fetchByR_G_V(
resourcePrimKey, groupId, version);
}
@Override
public KBArticle fetchKBArticleByUrlTitle(
long groupId, long kbFolderId, String urlTitle) {
urlTitle = StringUtil.replaceFirst(
urlTitle, CharPool.SLASH, StringPool.BLANK);
KBArticle kbArticle = fetchLatestKBArticleByUrlTitle(
groupId, kbFolderId, urlTitle, WorkflowConstants.STATUS_APPROVED);
if (kbArticle == null) {
kbArticle = fetchLatestKBArticleByUrlTitle(
groupId, kbFolderId, urlTitle,
WorkflowConstants.STATUS_PENDING);
}
return kbArticle;
}
@Override
public KBArticle fetchKBArticleByUrlTitle(
long groupId, String kbFolderUrlTitle, String urlTitle)
throws PortalException {
urlTitle = StringUtil.replaceFirst(
urlTitle, CharPool.SLASH, StringPool.BLANK);
List<KBArticle> kbArticles = kbArticleFinder.findByUrlTitle(
groupId, kbFolderUrlTitle, urlTitle, _STATUSES, 0, 1);
if (kbArticles.isEmpty()) {
return null;
}
return kbArticles.get(0);
}
@Override
public KBArticle fetchLatestKBArticle(long resourcePrimKey, int status) {
if (status == WorkflowConstants.STATUS_ANY) {
return kbArticlePersistence.fetchByResourcePrimKey_First(
resourcePrimKey, new KBArticleVersionComparator());
}
return kbArticlePersistence.fetchByR_S_First(
resourcePrimKey, status, new KBArticleVersionComparator());
}
@Override
public KBArticle fetchLatestKBArticle(long resourcePrimKey, long groupId) {
return kbArticlePersistence.fetchByR_G_L_First(
resourcePrimKey, groupId, true, null);
}
@Override
public KBArticle fetchLatestKBArticleByUrlTitle(
long groupId, long kbFolderId, String urlTitle, int status) {
urlTitle = StringUtil.replaceFirst(
urlTitle, CharPool.SLASH, StringPool.BLANK);
List<KBArticle> kbArticles = null;
OrderByComparator<KBArticle> orderByComparator =
new KBArticleVersionComparator();
if (status == WorkflowConstants.STATUS_ANY) {
kbArticles = kbArticlePersistence.findByG_KBFI_UT(
groupId, kbFolderId, urlTitle, 0, 1, orderByComparator);
}
else {
kbArticles = kbArticlePersistence.findByG_KBFI_UT_ST(
groupId, kbFolderId, urlTitle, status, 0, 1, orderByComparator);
}
if (kbArticles.isEmpty()) {
return null;
}
return kbArticles.get(0);
}
@Override
public List<KBArticle> getAllDescendantKBArticles(
long resourcePrimKey, int status,
OrderByComparator<KBArticle> orderByComparator) {
return getAllDescendantKBArticles(
resourcePrimKey, status, orderByComparator, false);
}
@Override
public List<KBArticle> getCompanyKBArticles(
long companyId, int status, int start, int end,
OrderByComparator<KBArticle> orderByComparator) {
if (status == WorkflowConstants.STATUS_ANY) {
return kbArticlePersistence.findByC_L(
companyId, true, start, end, orderByComparator);
}
else if (status == WorkflowConstants.STATUS_APPROVED) {
return kbArticlePersistence.findByC_M(
companyId, true, start, end, orderByComparator);
}
return kbArticlePersistence.findByC_S(
companyId, status, start, end, orderByComparator);
}
@Override
public int getCompanyKBArticlesCount(long companyId, int status) {
if (status == WorkflowConstants.STATUS_ANY) {
return kbArticlePersistence.countByC_L(companyId, true);
}
else if (status == WorkflowConstants.STATUS_APPROVED) {
return kbArticlePersistence.countByC_M(companyId, true);
}
return kbArticlePersistence.countByC_S(companyId, status);
}
@Override
public List<KBArticle> getGroupKBArticles(
long groupId, int status, int start, int end,
OrderByComparator<KBArticle> orderByComparator) {
if (status == WorkflowConstants.STATUS_ANY) {
return kbArticlePersistence.findByG_L(
groupId, true, start, end, orderByComparator);
}
else if (status == WorkflowConstants.STATUS_APPROVED) {
return kbArticlePersistence.findByG_M(
groupId, true, start, end, orderByComparator);
}
return kbArticlePersistence.findByG_S(
groupId, status, start, end, orderByComparator);
}
@Override
public int getGroupKBArticlesCount(long groupId, int status) {
if (status == WorkflowConstants.STATUS_ANY) {
return kbArticlePersistence.countByG_L(groupId, true);
}
else if (status == WorkflowConstants.STATUS_APPROVED) {
return kbArticlePersistence.countByG_M(groupId, true);
}
return kbArticlePersistence.countByG_S(groupId, status);
}
@Override
public KBArticle getKBArticle(long resourcePrimKey, int version)
throws PortalException {
return kbArticlePersistence.findByR_V(resourcePrimKey, version);
}
@Override
public List<KBArticle> getKBArticleAndAllDescendantKBArticles(
long resourcePrimKey, int status,
OrderByComparator<KBArticle> orderByComparator) {
return getAllDescendantKBArticles(
resourcePrimKey, status, orderByComparator, true);
}
/**
* @deprecated As of 1.1.0, replaced by {@link
* #getKBArticleAndAllDescendantKBArticles(long, int,
* OrderByComparator)}
*/
@Deprecated
@Override
public List<KBArticle> getKBArticleAndAllDescendants(
long resourcePrimKey, int status,
OrderByComparator<KBArticle> orderByComparator) {
return getKBArticleAndAllDescendantKBArticles(
resourcePrimKey, status, orderByComparator);
}
@Override
public KBArticle getKBArticleByUrlTitle(
long groupId, long kbFolderId, String urlTitle)
throws PortalException {
urlTitle = StringUtil.replaceFirst(
urlTitle, CharPool.SLASH, StringPool.BLANK);
// Get the latest KB article that is approved, if none are approved, get
// the latest unapproved KB article
KBArticle kbArticle = fetchKBArticleByUrlTitle(
groupId, kbFolderId, urlTitle);
if (kbArticle == null) {
throw new NoSuchArticleException(
"No KBArticle exists with the key {groupId=" + groupId +
", kbFolderId=" + kbFolderId + ", urlTitle=" + urlTitle +
"}");
}
return kbArticle;
}
@Override
public KBArticle getKBArticleByUrlTitle(
long groupId, String kbFolderUrlTitle, String urlTitle)
throws PortalException {
urlTitle = StringUtil.replaceFirst(
urlTitle, CharPool.SLASH, StringPool.BLANK);
KBArticle kbArticle = fetchKBArticleByUrlTitle(
groupId, kbFolderUrlTitle, urlTitle);
if (kbArticle == null) {
throw new NoSuchArticleException(
"No KBArticle with the key {groupId=" + groupId +
", urlTitle=" + urlTitle + "} found in a folder with URL " +
"title " + kbFolderUrlTitle);
}
return kbArticle;
}
@Override
public List<KBArticle> getKBArticles(
long groupId, long parentResourcePrimKey, int status, int start,
int end, OrderByComparator<KBArticle> orderByComparator) {
if (status == WorkflowConstants.STATUS_ANY) {
return kbArticlePersistence.findByG_P_L(
groupId, parentResourcePrimKey, true, start, end,
orderByComparator);
}
else if (status == WorkflowConstants.STATUS_APPROVED) {
return kbArticlePersistence.findByG_P_M(
groupId, parentResourcePrimKey, true, start, end,
orderByComparator);
}
return kbArticlePersistence.findByG_P_S(
groupId, parentResourcePrimKey, status, start, end,
orderByComparator);
}
@Override
public List<KBArticle> getKBArticles(
long[] resourcePrimKeys, int status,
OrderByComparator<KBArticle> orderByComparator) {
List<KBArticle> kbArticles = new ArrayList<>();
Long[][] params = new Long[][] {ArrayUtil.toArray(resourcePrimKeys)};
while ((params = KnowledgeBaseUtil.getParams(params[0])) != null) {
List<KBArticle> curKBArticles = null;
if (status == WorkflowConstants.STATUS_ANY) {
curKBArticles = kbArticlePersistence.findByR_L(
ArrayUtil.toArray(params[1]), true);
}
else if (status == WorkflowConstants.STATUS_APPROVED) {
curKBArticles = kbArticlePersistence.findByR_M(
ArrayUtil.toArray(params[1]), true);
}
else {
curKBArticles = kbArticlePersistence.findByR_S(
ArrayUtil.toArray(params[1]), status);
}
kbArticles.addAll(curKBArticles);
}
if (orderByComparator != null) {
kbArticles = ListUtil.sort(kbArticles, orderByComparator);
}
else {
kbArticles = KnowledgeBaseUtil.sort(resourcePrimKeys, kbArticles);
}
return Collections.unmodifiableList(kbArticles);
}
@Override
public int getKBArticlesCount(
long groupId, long parentResourcePrimKey, int status) {
if (status == WorkflowConstants.STATUS_ANY) {
return kbArticlePersistence.countByG_P_L(
groupId, parentResourcePrimKey, true);
}
else if (status == WorkflowConstants.STATUS_APPROVED) {
return kbArticlePersistence.countByG_P_M(
groupId, parentResourcePrimKey, true);
}
return kbArticlePersistence.countByG_P_S(
groupId, parentResourcePrimKey, status);
}
@Override
public List<KBArticle> getKBArticleVersions(
long resourcePrimKey, int status, int start, int end,
OrderByComparator<KBArticle> orderByComparator) {
if (status == WorkflowConstants.STATUS_ANY) {
return kbArticlePersistence.findByResourcePrimKey(
resourcePrimKey, start, end, orderByComparator);
}
return kbArticlePersistence.findByR_S(
resourcePrimKey, status, start, end, orderByComparator);
}
@Override
public int getKBArticleVersionsCount(long resourcePrimKey, int status) {
if (status == WorkflowConstants.STATUS_ANY) {
return kbArticlePersistence.countByResourcePrimKey(resourcePrimKey);
}
return kbArticlePersistence.countByR_S(resourcePrimKey, status);
}
@Override
public List<KBArticle> getKBFolderKBArticles(
long groupId, long kbFolderId) {
return kbArticlePersistence.findByG_KBFI_L(groupId, kbFolderId, true);
}
@Override
public int getKBFolderKBArticlesCount(
long groupId, long kbFolderId, int status) {
return kbArticlePersistence.countByG_KBFI_S(
groupId, kbFolderId, status);
}
@Override
public KBArticle getLatestKBArticle(long resourcePrimKey, int status)
throws PortalException {
if (status == WorkflowConstants.STATUS_ANY) {
return kbArticlePersistence.findByResourcePrimKey_First(
resourcePrimKey, new KBArticleVersionComparator());
}
return kbArticlePersistence.findByR_S_First(
resourcePrimKey, status, new KBArticleVersionComparator());
}
@Override
public KBArticle getLatestKBArticleByUrlTitle(
long groupId, long kbFolderId, String urlTitle, int status)
throws PortalException {
urlTitle = StringUtil.replaceFirst(
urlTitle, CharPool.SLASH, StringPool.BLANK);
KBArticle latestKBArticle = fetchLatestKBArticleByUrlTitle(
groupId, kbFolderId, urlTitle, status);
if (latestKBArticle == null) {
throw new NoSuchArticleException(
"No KBArticle exists with the key {groupId=" + groupId +
", kbFolderId=" + kbFolderId + ", urlTitle=" + urlTitle +
", status=" + status + "}");
}
return latestKBArticle;
}
@Override
public KBArticle[] getPreviousAndNextKBArticles(long kbArticleId)
throws PortalException {
KBArticleLocalSiblingNavigationHelper
kbArticleLocalSiblingNavigationHelper =
new KBArticleLocalSiblingNavigationHelper(kbArticlePersistence);
return kbArticleLocalSiblingNavigationHelper.
getPreviousAndNextKBArticles(kbArticleId);
}
@Override
public List<KBArticle> getSectionsKBArticles(
long groupId, String[] sections, int status, int start, int end,
OrderByComparator<KBArticle> orderByComparator) {
String[] array = AdminUtil.escapeSections(sections);
for (int i = 0; i < array.length; i++) {
array[i] = StringUtil.quote(array[i], StringPool.PERCENT);
}
if (status == WorkflowConstants.STATUS_ANY) {
return kbArticlePersistence.findByG_S_L(
groupId, array, true, start, end, orderByComparator);
}
else if (status == WorkflowConstants.STATUS_APPROVED) {
return kbArticlePersistence.findByG_S_M(
groupId, array, true, start, end, orderByComparator);
}
return kbArticlePersistence.findByG_S_S(
groupId, array, status, start, end, orderByComparator);
}
@Override
public int getSectionsKBArticlesCount(
long groupId, String[] sections, int status) {
String[] array = AdminUtil.escapeSections(sections);
for (int i = 0; i < array.length; i++) {
array[i] = StringUtil.quote(array[i], StringPool.PERCENT);
}
if (status == WorkflowConstants.STATUS_ANY) {
return kbArticlePersistence.countByG_S_L(groupId, array, true);
}
else if (status == WorkflowConstants.STATUS_APPROVED) {
return kbArticlePersistence.countByG_S_M(groupId, array, true);
}
return kbArticlePersistence.countByG_S_S(groupId, array, status);
}
/**
* @deprecated As of 1.1.0, replaced by {@link #getKBArticles(long, long,
* int, int, int, OrderByComparator)}
*/
@Deprecated
@Override
public List<KBArticle> getSiblingKBArticles(
long groupId, long parentResourcePrimKey, int status, int start,
int end, OrderByComparator<KBArticle> orderByComparator) {
return getKBArticles(
groupId, parentResourcePrimKey, status, start, end,
orderByComparator);
}
/**
* @deprecated As of 1.1.0, replaced by {@link #getKBArticlesCount(long,
* long, int)}
*/
@Deprecated
@Override
public int getSiblingKBArticlesCount(
long groupId, long parentResourcePrimKey, int status) {
return getKBArticlesCount(groupId, parentResourcePrimKey, status);
}
@Override
public String[] getTempAttachmentNames(
long groupId, long userId, String tempFolderName)
throws PortalException {
return TempFileEntryUtil.getTempFileNames(
groupId, userId, tempFolderName);
}
@Override
public void moveKBArticle(
long userId, long resourcePrimKey, long parentResourceClassNameId,
long parentResourcePrimKey, double priority)
throws PortalException {
KBArticle kbArticle = getLatestKBArticle(
resourcePrimKey, WorkflowConstants.STATUS_ANY);
if (kbArticle.getResourcePrimKey() == parentResourcePrimKey) {
return;
}
validateParent(
kbArticle, parentResourceClassNameId, parentResourcePrimKey);
validateParentStatus(
parentResourceClassNameId, parentResourcePrimKey,
kbArticle.getStatus());
validate(priority);
updatePermissionFields(
resourcePrimKey, parentResourceClassNameId, parentResourcePrimKey);
long kbFolderClassNameId = classNameLocalService.getClassNameId(
KBFolderConstants.getClassName());
long kbFolderId = KBFolderConstants.DEFAULT_PARENT_FOLDER_ID;
if (parentResourceClassNameId == kbFolderClassNameId) {
kbFolderId = parentResourcePrimKey;
}
else {
KBArticle parentKBArticle = getLatestKBArticle(
parentResourcePrimKey, WorkflowConstants.STATUS_ANY);
kbFolderId = parentKBArticle.getKbFolderId();
}
List<KBArticle> kbArticles = getKBArticleVersions(
resourcePrimKey, WorkflowConstants.STATUS_ANY, QueryUtil.ALL_POS,
QueryUtil.ALL_POS, new KBArticleVersionComparator());
for (KBArticle curKBArticle : kbArticles) {
curKBArticle.setParentResourceClassNameId(
parentResourceClassNameId);
curKBArticle.setParentResourcePrimKey(parentResourcePrimKey);
curKBArticle.setKbFolderId(kbFolderId);
curKBArticle.setPriority(priority);
kbArticlePersistence.update(curKBArticle);
}
if (kbArticle.getKbFolderId() != kbFolderId) {
List<KBArticle> descendantKBArticles = getAllDescendantKBArticles(
resourcePrimKey, WorkflowConstants.STATUS_ANY, null);
for (KBArticle curKBArticle : descendantKBArticles) {
List<KBArticle> kbArticleVersions = getKBArticleVersions(
curKBArticle.getResourcePrimKey(),
WorkflowConstants.STATUS_ANY, QueryUtil.ALL_POS,
QueryUtil.ALL_POS, new KBArticleVersionComparator());
for (KBArticle kbArticleVersion : kbArticleVersions) {
kbArticleVersion.setKbFolderId(kbFolderId);
kbArticlePersistence.update(kbArticleVersion);
}
}
}
// Social
KBArticle latestKBArticle = getLatestKBArticle(
resourcePrimKey, WorkflowConstants.STATUS_ANY);
JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
extraDataJSONObject.put("title", latestKBArticle.getTitle());
if (latestKBArticle.isApproved() || !latestKBArticle.isFirstVersion()) {
socialActivityLocalService.addActivity(
userId, latestKBArticle.getGroupId(), KBArticle.class.getName(),
resourcePrimKey, AdminActivityKeys.MOVE_KB_ARTICLE,
extraDataJSONObject.toString(), 0);
}
}
@Override
public KBArticle revertKBArticle(
long userId, long resourcePrimKey, int version,
ServiceContext serviceContext)
throws PortalException {
KBArticle kbArticle = kbArticleLocalService.getKBArticle(
resourcePrimKey, version);
ExpandoBridge expandoBridge = kbArticle.getExpandoBridge();
serviceContext.setExpandoBridgeAttributes(
expandoBridge.getAttributes());
return updateKBArticle(
userId, resourcePrimKey, kbArticle.getTitle(),
kbArticle.getContent(), kbArticle.getDescription(),
kbArticle.getSourceURL(), StringUtil.split(kbArticle.getSections()),
null, null, serviceContext);
}
@Override
public List<KBArticle> search(
long groupId, String title, String content, int status, Date startDate,
Date endDate, boolean andOperator, int start, int end,
OrderByComparator<KBArticle> orderByComparator) {
DynamicQuery dynamicQuery = buildDynamicQuery(
groupId, title, content, status, startDate, endDate, andOperator);
return dynamicQuery(dynamicQuery, start, end, orderByComparator);
}
@Override
public void subscribeGroupKBArticles(long userId, long groupId)
throws PortalException {
subscriptionLocalService.addSubscription(
userId, groupId, KBArticle.class.getName(), groupId);
}
@Override
public void subscribeKBArticle(
long userId, long groupId, long resourcePrimKey)
throws PortalException {
subscriptionLocalService.addSubscription(
userId, groupId, KBArticle.class.getName(), resourcePrimKey);
}
@Override
public void unsubscribeGroupKBArticles(long userId, long groupId)
throws PortalException {
subscriptionLocalService.deleteSubscription(
userId, KBArticle.class.getName(), groupId);
}
@Override
public void unsubscribeKBArticle(long userId, long resourcePrimKey)
throws PortalException {
subscriptionLocalService.deleteSubscription(
userId, KBArticle.class.getName(), resourcePrimKey);
}
@Override
public KBArticle updateKBArticle(
long userId, long resourcePrimKey, String title, String content,
String description, String sourceURL, String[] sections,
String[] selectedFileNames, long[] removeFileEntryIds,
ServiceContext serviceContext)
throws PortalException {
// KB article
User user = userLocalService.getUser(userId);
validate(title, content, sourceURL);
KBArticle oldKBArticle = getLatestKBArticle(
resourcePrimKey, WorkflowConstants.STATUS_ANY);
int oldVersion = oldKBArticle.getVersion();
KBArticle kbArticle = null;
if (oldKBArticle.isApproved()) {
long kbArticleId = counterLocalService.increment();
kbArticle = kbArticlePersistence.create(kbArticleId);
kbArticle.setUuid(serviceContext.getUuid());
kbArticle.setResourcePrimKey(oldKBArticle.getResourcePrimKey());
kbArticle.setGroupId(oldKBArticle.getGroupId());
kbArticle.setCompanyId(user.getCompanyId());
kbArticle.setUserId(user.getUserId());
kbArticle.setUserName(user.getFullName());
kbArticle.setCreateDate(oldKBArticle.getCreateDate());
kbArticle.setRootResourcePrimKey(
oldKBArticle.getRootResourcePrimKey());
kbArticle.setParentResourceClassNameId(
oldKBArticle.getParentResourceClassNameId());
kbArticle.setParentResourcePrimKey(
oldKBArticle.getParentResourcePrimKey());
kbArticle.setKbFolderId(oldKBArticle.getKbFolderId());
kbArticle.setVersion(oldVersion + 1);
kbArticle.setUrlTitle(oldKBArticle.getUrlTitle());
kbArticle.setPriority(oldKBArticle.getPriority());
kbArticle.setViewCount(oldKBArticle.getViewCount());
}
else {
kbArticle = oldKBArticle;
}
if (oldKBArticle.isPending()) {
kbArticle.setStatus(WorkflowConstants.STATUS_PENDING);
}
else {
kbArticle.setStatus(WorkflowConstants.STATUS_DRAFT);
}
kbArticle.setModifiedDate(serviceContext.getModifiedDate(null));
kbArticle.setTitle(title);
kbArticle.setContent(content);
kbArticle.setDescription(description);
kbArticle.setSourceURL(sourceURL);
kbArticle.setSections(
StringUtil.merge(AdminUtil.escapeSections(sections)));
kbArticle.setLatest(true);
kbArticle.setMain(false);
kbArticle.setExpandoBridgeAttributes(serviceContext);
kbArticlePersistence.update(kbArticle);
if (oldKBArticle.isApproved()) {
oldKBArticle.setLatest(false);
kbArticlePersistence.update(oldKBArticle);
}
// Resources
if ((serviceContext.getGroupPermissions() != null) ||
(serviceContext.getGuestPermissions() != null)) {
updateKBArticleResources(
kbArticle, serviceContext.getGroupPermissions(),
serviceContext.getGuestPermissions());
}
// Asset
updateKBArticleAsset(
userId, kbArticle, serviceContext.getAssetCategoryIds(),
serviceContext.getAssetTagNames(),
serviceContext.getAssetLinkEntryIds());
// Attachments
addKBArticleAttachments(userId, kbArticle, selectedFileNames);
removeKBArticleAttachments(removeFileEntryIds);
// Workflow
WorkflowHandlerRegistryUtil.startWorkflowInstance(
user.getCompanyId(), kbArticle.getGroupId(), userId,
KBArticle.class.getName(), resourcePrimKey, kbArticle,
serviceContext);
return kbArticle;
}
@Override
public void updateKBArticleAsset(
long userId, KBArticle kbArticle, long[] assetCategoryIds,
String[] assetTagNames, long[] assetLinkEntryIds)
throws PortalException {
// TODO
long classTypeId = 0;
AssetEntry assetEntry = assetEntryLocalService.updateEntry(
userId, kbArticle.getGroupId(), kbArticle.getCreateDate(),
kbArticle.getModifiedDate(), KBArticle.class.getName(),
kbArticle.getClassPK(), kbArticle.getUuid(), classTypeId,
assetCategoryIds, assetTagNames, false, null, null, null,
ContentTypes.TEXT_HTML, kbArticle.getTitle(),
kbArticle.getDescription(), null, null, null, 0, 0, null, false);
assetLinkLocalService.updateLinks(
userId, assetEntry.getEntryId(), assetLinkEntryIds,
AssetLinkConstants.TYPE_RELATED);
}
@Override
public void updateKBArticleResources(
KBArticle kbArticle, String[] groupPermissions,
String[] guestPermissions)
throws PortalException {
resourceLocalService.updateResources(
kbArticle.getCompanyId(), kbArticle.getGroupId(),
KBArticle.class.getName(), kbArticle.getResourcePrimKey(),
groupPermissions, guestPermissions);
}
@Override
public void updateKBArticlesPriorities(
Map<Long, Double> resourcePrimKeyToPriorityMap)
throws PortalException {
for (double priority : resourcePrimKeyToPriorityMap.values()) {
validate(priority);
}
long[] resourcePrimKeys = StringUtil.split(
StringUtil.merge(resourcePrimKeyToPriorityMap.keySet()), 0L);
List<KBArticle> kbArticles = getKBArticles(
resourcePrimKeys, WorkflowConstants.STATUS_ANY, null);
for (KBArticle kbArticle : kbArticles) {
double priority = resourcePrimKeyToPriorityMap.get(
kbArticle.getResourcePrimKey());
updatePriority(kbArticle.getResourcePrimKey(), priority);
}
}
@Override
public void updatePriority(long resourcePrimKey, double priority) {
List<KBArticle> kbArticleVersions = getKBArticleVersions(
resourcePrimKey, WorkflowConstants.STATUS_ANY, QueryUtil.ALL_POS,
QueryUtil.ALL_POS, null);
for (KBArticle kbArticle : kbArticleVersions) {
kbArticle.setPriority(priority);
kbArticlePersistence.update(kbArticle);
}
}
@Override
public KBArticle updateStatus(
long userId, long resourcePrimKey, int status,
ServiceContext serviceContext)
throws PortalException {
// KB article
User user = userLocalService.getUser(userId);
boolean main = false;
Date now = new Date();
if (status == WorkflowConstants.STATUS_APPROVED) {
main = true;
}
KBArticle kbArticle = getLatestKBArticle(
resourcePrimKey, WorkflowConstants.STATUS_ANY);
validateParentStatus(
kbArticle.getParentResourceClassNameId(),
kbArticle.getParentResourcePrimKey(), status);
kbArticle.setModifiedDate(serviceContext.getModifiedDate(now));
kbArticle.setMain(main);
kbArticle.setStatus(status);
kbArticle.setStatusByUserId(user.getUserId());
kbArticle.setStatusByUserName(user.getFullName());
kbArticle.setStatusDate(serviceContext.getModifiedDate(now));
kbArticlePersistence.update(kbArticle);
if (status != WorkflowConstants.STATUS_APPROVED) {
return kbArticle;
}
if (!kbArticle.isFirstVersion()) {
KBArticle oldKBArticle = kbArticlePersistence.findByR_V(
resourcePrimKey, kbArticle.getVersion() - 1);
oldKBArticle.setMain(false);
kbArticlePersistence.update(oldKBArticle);
}
// Asset
AssetEntry assetEntry = assetEntryLocalService.getEntry(
KBArticle.class.getName(), kbArticle.getKbArticleId());
List<AssetLink> assetLinks = assetLinkLocalService.getDirectLinks(
assetEntry.getEntryId(), AssetLinkConstants.TYPE_RELATED);
long[] assetLinkEntryIds = StringUtil.split(
ListUtil.toString(assetLinks, AssetLink.ENTRY_ID2_ACCESSOR), 0L);
updateKBArticleAsset(
userId, kbArticle, assetEntry.getCategoryIds(),
assetEntry.getTagNames(), assetLinkEntryIds);
SystemEventHierarchyEntryThreadLocal.push(KBArticle.class);
try {
assetEntryLocalService.deleteEntry(
KBArticle.class.getName(), kbArticle.getKbArticleId());
}
finally {
SystemEventHierarchyEntryThreadLocal.pop(KBArticle.class);
}
assetEntryLocalService.updateVisible(
KBArticle.class.getName(), kbArticle.getResourcePrimKey(), true);
// Social
JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
extraDataJSONObject.put("title", kbArticle.getTitle());
if (!kbArticle.isFirstVersion()) {
socialActivityLocalService.addActivity(
userId, kbArticle.getGroupId(), KBArticle.class.getName(),
resourcePrimKey, AdminActivityKeys.UPDATE_KB_ARTICLE,
extraDataJSONObject.toString(), 0);
}
else {
socialActivityLocalService.addActivity(
userId, kbArticle.getGroupId(), KBArticle.class.getName(),
resourcePrimKey, AdminActivityKeys.ADD_KB_ARTICLE,
extraDataJSONObject.toString(), 0);
}
// Indexer
Indexer<KBArticle> indexer = indexerRegistry.getIndexer(
KBArticle.class);
indexer.reindex(kbArticle);
// Subscriptions
notifySubscribers(userId, kbArticle, serviceContext);
return kbArticle;
}
@Override
public void updateViewCount(
long userId, long resourcePrimKey, int viewCount)
throws PortalException {
KBArticle kbArticle = getLatestKBArticle(
resourcePrimKey, WorkflowConstants.STATUS_ANY);
kbArticle.setViewCount(viewCount);
kbArticlePersistence.update(kbArticle);
if (kbArticle.isApproved() || kbArticle.isFirstVersion()) {
return;
}
kbArticle = getLatestKBArticle(
resourcePrimKey, WorkflowConstants.STATUS_APPROVED);
kbArticle.setViewCount(viewCount);
kbArticlePersistence.update(kbArticle);
}
protected void addKBArticleAttachment(
long userId, long groupId, long resourcePrimKey,
String selectedFileName)
throws PortalException {
FileEntry tempFileEntry = TempFileEntryUtil.getTempFileEntry(
groupId, userId, selectedFileName,
KnowledgeBaseConstants.TEMP_FOLDER_NAME);
InputStream inputStream = tempFileEntry.getContentStream();
String mimeType = tempFileEntry.getMimeType();
addAttachment(
userId, resourcePrimKey, selectedFileName, inputStream, mimeType);
if (tempFileEntry != null) {
TempFileEntryUtil.deleteTempFileEntry(
tempFileEntry.getFileEntryId());
}
}
protected void addKBArticleAttachments(
long userId, KBArticle kbArticle, String[] selectedFileNames)
throws PortalException {
if (ArrayUtil.isEmpty(selectedFileNames)) {
return;
}
for (String selectedFileName : selectedFileNames) {
addKBArticleAttachment(
userId, kbArticle.getGroupId(), kbArticle.getResourcePrimKey(),
selectedFileName);
}
}
protected DynamicQuery buildDynamicQuery(
long groupId, String title, String content, int status, Date startDate,
Date endDate, boolean andOperator) {
Junction junction = null;
if (andOperator) {
junction = RestrictionsFactoryUtil.conjunction();
}
else {
junction = RestrictionsFactoryUtil.disjunction();
}
Map<String, String> terms = new HashMap<>();
if (Validator.isNotNull(title)) {
terms.put("title", title);
}
if (Validator.isNotNull(content)) {
terms.put("content", content);
}
for (Map.Entry<String, String> entry : terms.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
Disjunction disjunction = RestrictionsFactoryUtil.disjunction();
for (String keyword : KnowledgeBaseUtil.splitKeywords(value)) {
Criterion criterion = RestrictionsFactoryUtil.ilike(
key, StringUtil.quote(keyword, StringPool.PERCENT));
disjunction.add(criterion);
}
junction.add(disjunction);
}
if (status != WorkflowConstants.STATUS_ANY) {
Property property = PropertyFactoryUtil.forName("status");
junction.add(property.eq(status));
}
if ((endDate != null) && (startDate != null)) {
Disjunction disjunction = RestrictionsFactoryUtil.disjunction();
String[] propertyNames = {"createDate", "modifiedDate"};
for (String propertyName : propertyNames) {
Property property = PropertyFactoryUtil.forName(propertyName);
Conjunction conjunction = RestrictionsFactoryUtil.conjunction();
conjunction.add(property.gt(startDate));
conjunction.add(property.lt(endDate));
disjunction.add(conjunction);
}
junction.add(disjunction);
}
DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
KBArticle.class, getClassLoader());
if (status == WorkflowConstants.STATUS_ANY) {
Property property = PropertyFactoryUtil.forName("latest");
dynamicQuery.add(property.eq(Boolean.TRUE));
}
else if (status == WorkflowConstants.STATUS_APPROVED) {
Property property = PropertyFactoryUtil.forName("main");
dynamicQuery.add(property.eq(Boolean.TRUE));
}
if (groupId > 0) {
Property property = PropertyFactoryUtil.forName("groupId");
dynamicQuery.add(property.eq(groupId));
}
return dynamicQuery.add(junction);
}
protected void deleteAssets(KBArticle kbArticle) throws PortalException {
assetEntryLocalService.deleteEntry(
KBArticle.class.getName(), kbArticle.getClassPK());
if (!kbArticle.isApproved() && !kbArticle.isFirstVersion()) {
assetEntryLocalService.deleteEntry(
KBArticle.class.getName(), kbArticle.getResourcePrimKey());
}
}
protected void deleteSubscriptions(KBArticle kbArticle)
throws PortalException {
List<Subscription> subscriptions =
subscriptionLocalService.getSubscriptions(
kbArticle.getCompanyId(), KBArticle.class.getName(),
kbArticle.getResourcePrimKey());
for (Subscription subscription : subscriptions) {
unsubscribeKBArticle(
subscription.getUserId(), subscription.getClassPK());
}
}
protected void getAllDescendantKBArticles(
List<KBArticle> kbArticles, long resourcePrimKey, int status,
OrderByComparator<KBArticle> orderByComparator) {
List<KBArticle> curKBArticles = null;
if (status == WorkflowConstants.STATUS_ANY) {
curKBArticles = kbArticlePersistence.findByP_L(
resourcePrimKey, true, QueryUtil.ALL_POS, QueryUtil.ALL_POS,
orderByComparator);
}
else if (status == WorkflowConstants.STATUS_APPROVED) {
curKBArticles = kbArticlePersistence.findByP_M(
resourcePrimKey, true, QueryUtil.ALL_POS, QueryUtil.ALL_POS,
orderByComparator);
}
else {
curKBArticles = kbArticlePersistence.findByP_S(
resourcePrimKey, status, QueryUtil.ALL_POS, QueryUtil.ALL_POS,
orderByComparator);
}
for (KBArticle curKBArticle : curKBArticles) {
kbArticles.add(curKBArticle);
getAllDescendantKBArticles(
kbArticles, curKBArticle.getResourcePrimKey(), status,
orderByComparator);
}
}
protected List<KBArticle> getAllDescendantKBArticles(
long resourcePrimKey, int status,
OrderByComparator<KBArticle> orderByComparator,
boolean includeParentArticle) {
List<KBArticle> kbArticles = null;
if (includeParentArticle) {
kbArticles = getKBArticles(
new long[] {resourcePrimKey}, status, null);
kbArticles = ListUtil.copy(kbArticles);
}
else {
kbArticles = new ArrayList<>();
}
getAllDescendantKBArticles(
kbArticles, resourcePrimKey, status, orderByComparator);
return Collections.unmodifiableList(kbArticles);
}
protected Map<String, String> getEmailKBArticleDiffs(KBArticle kbArticle) {
Map<String, String> emailKBArticleDiffs = new HashMap<>();
for (String param : new String[] {"content", "title"}) {
String value = BeanPropertiesUtil.getString(kbArticle, param);
try {
value = AdminUtil.getKBArticleDiff(
kbArticle.getResourcePrimKey(), kbArticle.getVersion() - 1,
kbArticle.getVersion(), param);
}
catch (Exception e) {
_log.error(e, e);
}
emailKBArticleDiffs.put(param, value);
}
return emailKBArticleDiffs;
}
protected KBGroupServiceConfiguration getKBGroupServiceConfiguration(
long groupId)
throws ConfigurationException {
return configurationProvider.getGroupConfiguration(
KBGroupServiceConfiguration.class, groupId);
}
protected double getPriority(long groupId, long parentResourcePrimKey)
throws PortalException {
KBGroupServiceConfiguration kbGroupServiceConfiguration =
getKBGroupServiceConfiguration(groupId);
if (!kbGroupServiceConfiguration.articleIncrementPriorityEnabled()) {
return KBArticleConstants.DEFAULT_VERSION;
}
List<KBArticle> kbArticles = getKBArticles(
groupId, parentResourcePrimKey, WorkflowConstants.STATUS_ANY, 0, 1,
new KBArticlePriorityComparator());
if (kbArticles.isEmpty()) {
return KBArticleConstants.DEFAULT_PRIORITY;
}
KBArticle kbArticle = kbArticles.get(0);
return Math.floor(kbArticle.getPriority()) + 1;
}
protected long getRootResourcePrimKey(
long resourcePrimKey, long parentResourceClassNameId,
long parentResourcePrimKey)
throws PortalException {
if (parentResourcePrimKey ==
KBFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
return resourcePrimKey;
}
long classNameId = classNameLocalService.getClassNameId(
KBArticleConstants.getClassName());
if (parentResourceClassNameId == classNameId) {
KBArticle kbArticle = getLatestKBArticle(
parentResourcePrimKey, WorkflowConstants.STATUS_ANY);
return kbArticle.getRootResourcePrimKey();
}
return resourcePrimKey;
}
protected Date getTicketExpirationDate() {
return new Date(System.currentTimeMillis() + _TICKET_EXPIRATION);
}
protected String getUniqueUrlTitle(
long groupId, long kbFolderId, long kbArticleId, String title)
throws PortalException {
String urlTitle = KnowledgeBaseUtil.getUrlTitle(kbArticleId, title);
String uniqueUrlTitle = urlTitle;
if (kbFolderId == KBFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
int kbArticlesCount = kbArticlePersistence.countByG_KBFI_UT_ST(
groupId, kbFolderId, uniqueUrlTitle, _STATUSES);
for (int i = 1; kbArticlesCount > 0; i++) {
uniqueUrlTitle = getUniqueUrlTitle(urlTitle, i);
kbArticlesCount = kbArticlePersistence.countByG_KBFI_UT_ST(
groupId, kbFolderId, uniqueUrlTitle, _STATUSES);
}
return uniqueUrlTitle;
}
KBFolder kbFolder = kbFolderPersistence.findByPrimaryKey(kbFolderId);
int kbArticlesCount = kbArticleFinder.countByUrlTitle(
groupId, kbFolder.getUrlTitle(), uniqueUrlTitle, _STATUSES);
for (int i = 1; kbArticlesCount > 0; i++) {
uniqueUrlTitle = getUniqueUrlTitle(urlTitle, i);
kbArticlesCount = kbArticleFinder.countByUrlTitle(
groupId, kbFolder.getUrlTitle(), uniqueUrlTitle, _STATUSES);
}
return uniqueUrlTitle;
}
protected String getUniqueUrlTitle(
long groupId, long kbFolderId, long kbArticleId, String title,
String urlTitle)
throws PortalException {
if (Validator.isNull(urlTitle)) {
return getUniqueUrlTitle(groupId, kbFolderId, kbArticleId, title);
}
return urlTitle.substring(1);
}
protected String getUniqueUrlTitle(String urlTitle, int suffix) {
String uniqueUrlTitle = urlTitle + StringPool.DASH + suffix;
int maxLength = ModelHintsUtil.getMaxLength(
KBArticle.class.getName(), "urlTitle");
return StringUtil.shorten(
uniqueUrlTitle, maxLength, StringPool.DASH + suffix);
}
protected boolean isValidFileName(String name) {
if ((name == null) || name.contains(StringPool.BACK_SLASH) ||
name.contains(StringPool.SLASH)) {
return false;
}
return true;
}
protected String normalizeUrlTitle(String urlTitle) {
if (urlTitle == null) {
return null;
}
if (StringUtil.startsWith(urlTitle, CharPool.SLASH)) {
return urlTitle;
}
return StringPool.SLASH + urlTitle;
}
protected void notifySubscribers(
long userId, KBArticle kbArticle, ServiceContext serviceContext)
throws PortalException {
if (Validator.isNull(serviceContext.getLayoutFullURL())) {
return;
}
KBGroupServiceConfiguration kbGroupServiceConfiguration =
getKBGroupServiceConfiguration(kbArticle.getGroupId());
if (serviceContext.isCommandAdd() &&
!kbGroupServiceConfiguration.emailKBArticleAddedEnabled()) {
return;
}
if (serviceContext.isCommandUpdate() &&
!kbGroupServiceConfiguration.emailKBArticleUpdatedEnabled()) {
return;
}
String fromName = kbGroupServiceConfiguration.emailFromName();
String fromAddress = kbGroupServiceConfiguration.emailFromAddress();
String kbArticleContent = StringUtil.replace(
kbArticle.getContent(), new String[] {"href=\"/", "src=\"/"},
new String[] {
"href=\"" + serviceContext.getPortalURL() + "/",
"src=\"" + serviceContext.getPortalURL() + "/"
});
Map<String, String> kbArticleDiffs = getEmailKBArticleDiffs(kbArticle);
for (Map.Entry<String, String> entry : kbArticleDiffs.entrySet()) {
String value = StringUtil.replace(
entry.getValue(), new String[] {"href=\"/", "src=\"/"},
new String[] {
"href=\"" + serviceContext.getPortalURL() + "/",
"src=\"" + serviceContext.getPortalURL() + "/"
});
kbArticleDiffs.put(entry.getKey(), value);
}
String subject = null;
String body = null;
if (serviceContext.isCommandAdd()) {
subject = kbGroupServiceConfiguration.emailKBArticleAddedSubject();
body = kbGroupServiceConfiguration.emailKBArticleAddedBody();
}
else {
subject =
kbGroupServiceConfiguration.emailKBArticleUpdatedSubject();
body = kbGroupServiceConfiguration.emailKBArticleUpdatedBody();
}
SubscriptionSender subscriptionSender = new AdminSubscriptionSender(
kbArticle, serviceContext);
subscriptionSender.setBody(body);
subscriptionSender.setCompanyId(kbArticle.getCompanyId());
subscriptionSender.setContextAttribute(
"[$ARTICLE_CONTENT$]", kbArticleContent, false);
subscriptionSender.setContextAttribute(
"[$ARTICLE_CONTENT_DIFF$]", kbArticleDiffs.get("content"), false);
subscriptionSender.setContextAttribute(
"[$ARTICLE_TITLE$]", kbArticle.getTitle(), false);
subscriptionSender.setContextAttribute(
"[$ARTICLE_TITLE_DIFF$]", kbArticleDiffs.get("title"), false);
subscriptionSender.setContextCreatorUserPrefix("ARTICLE");
subscriptionSender.setCreatorUserId(kbArticle.getUserId());
subscriptionSender.setCurrentUserId(userId);
subscriptionSender.setFrom(fromAddress, fromName);
subscriptionSender.setHtmlFormat(true);
subscriptionSender.setMailId("kb_article", kbArticle.getKbArticleId());
subscriptionSender.setPortletId(serviceContext.getPortletId());
subscriptionSender.setReplyToAddress(fromAddress);
subscriptionSender.setScopeGroupId(kbArticle.getGroupId());
subscriptionSender.setSubject(subject);
subscriptionSender.addPersistedSubscribers(
KBArticle.class.getName(), kbArticle.getGroupId());
subscriptionSender.addPersistedSubscribers(
KBArticle.class.getName(), kbArticle.getResourcePrimKey());
while (!kbArticle.isRoot() &&
(kbArticle.getClassNameId() ==
kbArticle.getParentResourceClassNameId())) {
kbArticle = getLatestKBArticle(
kbArticle.getParentResourcePrimKey(),
WorkflowConstants.STATUS_APPROVED);
subscriptionSender.addPersistedSubscribers(
KBArticle.class.getName(), kbArticle.getResourcePrimKey());
}
subscriptionSender.flushNotificationsAsync();
}
protected void removeKBArticleAttachments(long[] removeFileEntryIds)
throws PortalException {
if (ArrayUtil.isEmpty(removeFileEntryIds)) {
return;
}
for (long removeFileEntryId : removeFileEntryIds) {
portletFileRepository.deletePortletFileEntry(removeFileEntryId);
}
}
protected void updatePermissionFields(
long resourcePrimKey, long parentResourceClassNameId,
long parentResourcePrimKey)
throws PortalException {
// See KBArticlePermission#contains
KBArticle kbArticle = getLatestKBArticle(
resourcePrimKey, WorkflowConstants.STATUS_ANY);
if (kbArticle.getParentResourcePrimKey() == parentResourcePrimKey) {
return;
}
long rootResourcePrimKey = getRootResourcePrimKey(
resourcePrimKey, parentResourceClassNameId, parentResourcePrimKey);
if (kbArticle.getRootResourcePrimKey() == rootResourcePrimKey) {
return;
}
// Sync database
List<KBArticle> kbArticles1 = getKBArticleAndAllDescendantKBArticles(
resourcePrimKey, WorkflowConstants.STATUS_ANY, null);
for (KBArticle kbArticle1 : kbArticles1) {
List<KBArticle> kbArticles2 = getKBArticleVersions(
kbArticle1.getResourcePrimKey(), WorkflowConstants.STATUS_ANY,
QueryUtil.ALL_POS, QueryUtil.ALL_POS, null);
for (KBArticle kbArticle2 : kbArticles2) {
kbArticle2.setRootResourcePrimKey(rootResourcePrimKey);
kbArticlePersistence.update(kbArticle2);
}
}
// Sync indexed permission fields
indexWriterHelper.updatePermissionFields(
KBArticle.class.getName(), String.valueOf(resourcePrimKey));
}
protected void validate(double priority) throws PortalException {
if (priority <= 0) {
throw new KBArticlePriorityException(
"Invalid priority " + priority);
}
}
protected void validate(String title, String content, String sourceURL)
throws PortalException {
if (Validator.isNull(title)) {
throw new KBArticleTitleException("Title is null");
}
if (Validator.isNull(content)) {
throw new KBArticleContentException("Content is null");
}
validateSourceURL(sourceURL);
}
protected void validateParent(
KBArticle kbArticle, long parentResourceClassNameId,
long parentResourcePrimKey)
throws PortalException {
validateParent(parentResourceClassNameId, parentResourcePrimKey);
long kbArticleClassNameId = classNameLocalService.getClassNameId(
KBArticleConstants.getClassName());
if (parentResourceClassNameId == kbArticleClassNameId) {
KBArticle parentKBArticle = getLatestKBArticle(
parentResourcePrimKey, WorkflowConstants.STATUS_ANY);
List<Long> ancestorResourcePrimaryKeys =
parentKBArticle.getAncestorResourcePrimaryKeys();
if (ancestorResourcePrimaryKeys.contains(
kbArticle.getResourcePrimKey())) {
throw new KBArticleParentException(
String.format(
"Cannot move KBArticle %s inside its descendant " +
"KBArticle %s",
kbArticle.getResourcePrimKey(),
parentKBArticle.getResourcePrimKey()));
}
}
}
protected void validateParent(
long resourceClassNameId, long resourcePrimKey)
throws PortalException {
long kbArticleClassNameId = classNameLocalService.getClassNameId(
KBArticleConstants.getClassName());
long kbFolderClassNameId = classNameLocalService.getClassNameId(
KBFolderConstants.getClassName());
if ((resourceClassNameId != kbArticleClassNameId) &&
(resourceClassNameId != kbFolderClassNameId)) {
throw new KBArticleParentException(
String.format(
"Invalid parent with resource class name ID %s and " +
"resource primary key %s",
resourceClassNameId, resourcePrimKey));
}
}
protected void validateParentStatus(
long parentResourceClassNameId, long parentResourcePrimKey,
int status)
throws PortalException {
long kbFolderClassNameId = classNameLocalService.getClassNameId(
KBFolder.class);
if (parentResourceClassNameId == kbFolderClassNameId) {
return;
}
KBArticle kbArticle = fetchLatestKBArticle(
parentResourcePrimKey, WorkflowConstants.STATUS_APPROVED);
if ((kbArticle == null) &&
(status == WorkflowConstants.STATUS_APPROVED)) {
throw new KBArticleStatusException();
}
}
protected void validateSourceURL(String sourceURL) throws PortalException {
if (Validator.isNull(sourceURL)) {
return;
}
if (!Validator.isUrl(sourceURL)) {
throw new KBArticleSourceURLException(sourceURL);
}
}
protected void validateUrlTitle(
long groupId, long kbFolderId, String urlTitle)
throws PortalException {
if (Validator.isNull(urlTitle)) {
return;
}
if (!KnowledgeBaseUtil.isValidUrlTitle(urlTitle)) {
throw new KBArticleUrlTitleException.
MustNotContainInvalidCharacters(urlTitle);
}
int urlTitleMaxSize = ModelHintsUtil.getMaxLength(
KBArticle.class.getName(), "urlTitle");
if (urlTitle.length() > urlTitleMaxSize) {
throw new KBArticleUrlTitleException.MustNotExceedMaximumSize(
urlTitle, urlTitleMaxSize);
}
Collection<KBArticle> kbArticles = kbArticlePersistence.findByG_KBFI_UT(
groupId, kbFolderId, urlTitle.substring(1));
if (!kbArticles.isEmpty()) {
throw new KBArticleUrlTitleException.MustNotBeDuplicate(urlTitle);
}
}
@ServiceReference(type = ConfigurationProvider.class)
protected ConfigurationProvider configurationProvider;
@ServiceReference(type = IndexerRegistry.class)
protected IndexerRegistry indexerRegistry;
@ServiceReference(type = IndexWriterHelper.class)
protected IndexWriterHelper indexWriterHelper;
@ServiceReference(type = KBArticleImporter.class)
protected KBArticleImporter kbArticleImporter;
@BeanReference(type = PortletFileRepository.class)
protected PortletFileRepository portletFileRepository;
@ServiceReference(type = SubscriptionLocalService.class)
protected SubscriptionLocalService subscriptionLocalService;
private static final int[] _STATUSES = {
WorkflowConstants.STATUS_APPROVED, WorkflowConstants.STATUS_PENDING
};
private static final long _TICKET_EXPIRATION = Time.HOUR;
private static final Log _log = LogFactoryUtil.getLog(
KBArticleLocalServiceImpl.class);
}