/** * 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.web.internal.portlet; import com.liferay.asset.kernel.exception.AssetCategoryException; import com.liferay.asset.kernel.exception.AssetTagException; import com.liferay.document.library.display.context.DLMimeTypeDisplayContext; import com.liferay.document.library.kernel.exception.DuplicateFileException; import com.liferay.document.library.kernel.exception.FileNameException; import com.liferay.document.library.kernel.exception.FileSizeException; import com.liferay.document.library.kernel.exception.NoSuchFileException; import com.liferay.knowledge.base.constants.KBArticleConstants; import com.liferay.knowledge.base.constants.KBCommentConstants; import com.liferay.knowledge.base.constants.KBFolderConstants; import com.liferay.knowledge.base.exception.KBArticleContentException; import com.liferay.knowledge.base.exception.KBArticlePriorityException; import com.liferay.knowledge.base.exception.KBArticleTitleException; import com.liferay.knowledge.base.exception.KBCommentContentException; import com.liferay.knowledge.base.exception.NoSuchArticleException; import com.liferay.knowledge.base.exception.NoSuchCommentException; import com.liferay.knowledge.base.model.KBArticle; import com.liferay.knowledge.base.model.KBComment; import com.liferay.knowledge.base.service.KBArticleService; import com.liferay.knowledge.base.service.KBCommentLocalService; import com.liferay.knowledge.base.service.KBCommentService; import com.liferay.knowledge.base.service.KBFolderService; import com.liferay.knowledge.base.service.KBTemplateService; import com.liferay.knowledge.base.service.util.AdminUtil; import com.liferay.knowledge.base.service.util.KnowledgeBaseConstants; import com.liferay.portal.kernel.exception.PortalException; import com.liferay.portal.kernel.json.JSONFactory; import com.liferay.portal.kernel.json.JSONObject; import com.liferay.portal.kernel.portlet.LiferayWindowState; import com.liferay.portal.kernel.portlet.PortletResponseUtil; import com.liferay.portal.kernel.portlet.bridges.mvc.MVCPortlet; import com.liferay.portal.kernel.security.auth.PrincipalException; import com.liferay.portal.kernel.service.ServiceContext; import com.liferay.portal.kernel.service.ServiceContextFactory; import com.liferay.portal.kernel.servlet.SessionMessages; import com.liferay.portal.kernel.theme.PortletDisplay; import com.liferay.portal.kernel.theme.ThemeDisplay; import com.liferay.portal.kernel.upload.LiferayFileItemException; import com.liferay.portal.kernel.upload.UploadException; import com.liferay.portal.kernel.upload.UploadPortletRequest; import com.liferay.portal.kernel.upload.UploadRequestSizeException; import com.liferay.portal.kernel.util.Constants; import com.liferay.portal.kernel.util.ContentTypes; import com.liferay.portal.kernel.util.GetterUtil; import com.liferay.portal.kernel.util.HttpUtil; import com.liferay.portal.kernel.util.ParamUtil; import com.liferay.portal.kernel.util.Portal; import com.liferay.portal.kernel.util.PortalUtil; import com.liferay.portal.kernel.util.StreamUtil; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.Validator; import com.liferay.portal.kernel.util.WebKeys; import com.liferay.portal.kernel.workflow.WorkflowConstants; import java.io.IOException; import java.io.InputStream; import javax.portlet.ActionRequest; import javax.portlet.ActionResponse; import javax.portlet.PortletContext; import javax.portlet.PortletException; import javax.portlet.PortletPreferences; import javax.portlet.PortletRequest; import javax.portlet.PortletRequestDispatcher; import javax.portlet.PortletSession; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; import javax.portlet.ResourceRequest; import javax.portlet.ResourceResponse; import javax.portlet.WindowState; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.component.annotations.ReferencePolicyOption; /** * @author Adolfo PĂ©rez */ public abstract class BaseKBPortlet extends MVCPortlet { public void addTempAttachment( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { UploadPortletRequest uploadPortletRequest = portal.getUploadPortletRequest(actionRequest); checkExceededSizeLimit(actionRequest); ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute( WebKeys.THEME_DISPLAY); long resourcePrimKey = ParamUtil.getLong( actionRequest, "resourcePrimKey"); String sourceFileName = uploadPortletRequest.getFileName("file"); InputStream inputStream = null; try { inputStream = uploadPortletRequest.getFileAsStream("file"); String mimeType = uploadPortletRequest.getContentType("file"); kbArticleService.addTempAttachment( themeDisplay.getScopeGroupId(), resourcePrimKey, sourceFileName, KnowledgeBaseConstants.TEMP_FOLDER_NAME, inputStream, mimeType); } finally { StreamUtil.cleanUp(inputStream); } } public void deleteKBArticle( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { long resourcePrimKey = ParamUtil.getLong( actionRequest, "resourcePrimKey"); deleteKBArticle(actionRequest, actionResponse, resourcePrimKey); } public void deleteKBComment( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute( WebKeys.THEME_DISPLAY); if (!themeDisplay.isSignedIn()) { return; } long kbCommentId = ParamUtil.getLong(actionRequest, "kbCommentId"); kbCommentService.deleteKBComment(kbCommentId); SessionMessages.add(actionRequest, "suggestionDeleted"); } public void deleteKBComments( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute( WebKeys.THEME_DISPLAY); if (!themeDisplay.isSignedIn()) { return; } long[] deleteKBCommentIds = ParamUtil.getLongValues( actionRequest, "rowIdsKBComment"); for (long deleteKBCommentId : deleteKBCommentIds) { kbCommentService.deleteKBComment(deleteKBCommentId); } SessionMessages.add(actionRequest, "suggestionsDeleted"); } public void deleteTempAttachment( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute( WebKeys.THEME_DISPLAY); long resourcePrimKey = ParamUtil.getLong( actionRequest, "resourcePrimKey"); String fileName = ParamUtil.getString(actionRequest, "fileName"); JSONObject jsonObject = jsonFactory.createJSONObject(); try { kbArticleService.deleteTempAttachment( themeDisplay.getScopeGroupId(), resourcePrimKey, fileName, KnowledgeBaseConstants.TEMP_FOLDER_NAME); jsonObject.put("deleted", Boolean.TRUE); } catch (Exception e) { String errorMessage = themeDisplay.translate( "an-unexpected-error-occurred-while-deleting-the-file"); jsonObject.put("deleted", Boolean.FALSE); jsonObject.put("errorMessage", errorMessage); } writeJSON(actionRequest, actionResponse, jsonObject); } public void moveKBObject( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { long resourceClassNameId = ParamUtil.getLong( actionRequest, "resourceClassNameId"); long resourcePrimKey = ParamUtil.getLong( actionRequest, "resourcePrimKey"); long parentResourceClassNameId = ParamUtil.getLong( actionRequest, "parentResourceClassNameId", portal.getClassNameId(KBFolderConstants.getClassName())); long parentResourcePrimKey = ParamUtil.getLong( actionRequest, "parentResourcePrimKey", KBFolderConstants.DEFAULT_PARENT_FOLDER_ID); double priority = ParamUtil.getDouble(actionRequest, "priority"); long kbArticleClassNameId = portal.getClassNameId( KBArticleConstants.getClassName()); if (resourceClassNameId == kbArticleClassNameId) { kbArticleService.moveKBArticle( resourcePrimKey, parentResourceClassNameId, parentResourcePrimKey, priority); } else { kbFolderService.moveKBFolder( resourcePrimKey, parentResourcePrimKey); } } @Override public void render( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { String cmd = ParamUtil.getString(renderRequest, Constants.CMD); if (Validator.isNotNull(cmd) && cmd.equals("compareVersions")) { compareVersions(renderRequest); } doRender(renderRequest, renderResponse); super.render(renderRequest, renderResponse); } public void serveKBArticleRSS( ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws Exception { PortletPreferences portletPreferences = resourceRequest.getPreferences(); boolean enableRss = GetterUtil.getBoolean( portletPreferences.getValue("enableRss", null), true); if (!portal.isRSSFeedsEnabled() || !enableRss) { portal.sendRSSFeedsDisabledError(resourceRequest, resourceResponse); return; } ThemeDisplay themeDisplay = (ThemeDisplay)resourceRequest.getAttribute( WebKeys.THEME_DISPLAY); long resourcePrimKey = ParamUtil.getLong( resourceRequest, "resourcePrimKey"); int rssDelta = ParamUtil.getInteger(resourceRequest, "rssDelta"); String rssDisplayStyle = ParamUtil.getString( resourceRequest, "rssDisplayStyle"); String rssFormat = ParamUtil.getString(resourceRequest, "rssFormat"); String rss = kbArticleService.getKBArticleRSS( resourcePrimKey, WorkflowConstants.STATUS_APPROVED, rssDelta, rssDisplayStyle, rssFormat, themeDisplay); PortletResponseUtil.sendFile( resourceRequest, resourceResponse, null, rss.getBytes(StringPool.UTF8), ContentTypes.TEXT_XML_UTF8); } @Override public void serveResource( ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws IOException, PortletException { try { String resourceID = resourceRequest.getResourceID(); if (resourceID.equals("compareVersions")) { long resourcePrimKey = ParamUtil.getLong( resourceRequest, "resourcePrimKey"); double sourceVersion = ParamUtil.getDouble( resourceRequest, "filterSourceVersion"); double targetVersion = ParamUtil.getDouble( resourceRequest, "filterTargetVersion"); String diffHtmlResults = null; try { diffHtmlResults = AdminUtil.getKBArticleDiff( resourcePrimKey, GetterUtil.getInteger(sourceVersion), GetterUtil.getInteger(targetVersion), "content"); } catch (Exception e) { try { HttpServletRequest request = PortalUtil.getHttpServletRequest(resourceRequest); HttpServletResponse response = PortalUtil.getHttpServletResponse(resourceResponse); PortalUtil.sendError(e, request, response); } catch (ServletException se) { } } resourceRequest.setAttribute( WebKeys.DIFF_HTML_RESULTS, diffHtmlResults); PortletSession portletSession = resourceRequest.getPortletSession(); PortletContext portletContext = portletSession.getPortletContext(); PortletRequestDispatcher portletRequestDispatcher = portletContext.getRequestDispatcher( "/admin/common/compare_versions_diff_html.jsp"); portletRequestDispatcher.include( resourceRequest, resourceResponse); } else if (resourceID.equals("kbArticleRSS")) { serveKBArticleRSS(resourceRequest, resourceResponse); } } catch (IOException ioe) { throw ioe; } catch (PortletException pe) { throw pe; } catch (Exception e) { throw new PortletException(e); } } public void subscribeKBArticle( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute( WebKeys.THEME_DISPLAY); long resourcePrimKey = ParamUtil.getLong( actionRequest, "resourcePrimKey"); kbArticleService.subscribeKBArticle( themeDisplay.getScopeGroupId(), resourcePrimKey); } public void unsubscribeKBArticle( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { long resourcePrimKey = ParamUtil.getLong( actionRequest, "resourcePrimKey"); kbArticleService.unsubscribeKBArticle(resourcePrimKey); } public void updateKBArticle( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { String portletId = portal.getPortletId(actionRequest); String cmd = ParamUtil.getString(actionRequest, Constants.CMD); long resourcePrimKey = ParamUtil.getLong( actionRequest, "resourcePrimKey"); long parentResourceClassNameId = ParamUtil.getLong( actionRequest, "parentResourceClassNameId", portal.getClassNameId(KBFolderConstants.getClassName())); long parentResourcePrimKey = ParamUtil.getLong( actionRequest, "parentResourcePrimKey", KBFolderConstants.DEFAULT_PARENT_FOLDER_ID); String title = ParamUtil.getString(actionRequest, "title"); String urlTitle = ParamUtil.getString(actionRequest, "urlTitle"); String content = ParamUtil.getString(actionRequest, "content"); String description = ParamUtil.getString(actionRequest, "description"); String sourceURL = ParamUtil.getString(actionRequest, "sourceURL"); String[] sections = actionRequest.getParameterValues("sections"); String[] selectedFileNames = ParamUtil.getParameterValues( actionRequest, "selectedFileName"); long[] removeFileEntryIds = ParamUtil.getLongValues( actionRequest, "removeFileEntryIds"); int workflowAction = ParamUtil.getInteger( actionRequest, "workflowAction"); KBArticle kbArticle = null; ServiceContext serviceContext = ServiceContextFactory.getInstance( KBArticle.class.getName(), actionRequest); if (cmd.equals(Constants.ADD)) { kbArticle = kbArticleService.addKBArticle( portletId, parentResourceClassNameId, parentResourcePrimKey, title, urlTitle, content, description, sourceURL, sections, selectedFileNames, serviceContext); } else if (cmd.equals(Constants.REVERT)) { int version = ParamUtil.getInteger( actionRequest, "version", KBArticleConstants.DEFAULT_VERSION); kbArticle = kbArticleService.revertKBArticle( resourcePrimKey, version, serviceContext); } else if (cmd.equals(Constants.UPDATE)) { kbArticle = kbArticleService.updateKBArticle( resourcePrimKey, title, content, description, sourceURL, sections, selectedFileNames, removeFileEntryIds, serviceContext); } if (!cmd.equals(Constants.ADD) && !cmd.equals(Constants.UPDATE)) { return; } if (workflowAction == WorkflowConstants.ACTION_SAVE_DRAFT) { String editURL = buildEditURL( actionRequest, actionResponse, kbArticle); actionRequest.setAttribute(WebKeys.REDIRECT, editURL); } String redirect = PortalUtil.escapeRedirect( ParamUtil.getString(actionRequest, "redirect")); WindowState windowState = actionRequest.getWindowState(); if (cmd.equals(Constants.ADD) && Validator.isNotNull(redirect) && windowState.equals(LiferayWindowState.POP_UP)) { actionRequest.setAttribute( WebKeys.REDIRECT, getContentRedirect( KBArticle.class, kbArticle.getResourcePrimKey(), redirect)); } } public void updateKBComment( ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute( WebKeys.THEME_DISPLAY); if (!themeDisplay.isSignedIn()) { return; } String cmd = ParamUtil.getString(actionRequest, Constants.CMD); long kbCommentId = ParamUtil.getLong(actionRequest, "kbCommentId"); long classNameId = ParamUtil.getLong(actionRequest, "classNameId"); long classPK = ParamUtil.getLong(actionRequest, "classPK"); String content = ParamUtil.getString(actionRequest, "content"); int status = ParamUtil.getInteger( actionRequest, "status", KBCommentConstants.STATUS_ANY); ServiceContext serviceContext = ServiceContextFactory.getInstance( KBComment.class.getName(), actionRequest); if (cmd.equals(Constants.ADD)) { kbCommentLocalService.addKBComment( themeDisplay.getUserId(), classNameId, classPK, content, serviceContext); } else if (cmd.equals(Constants.UPDATE)) { if (status == KBCommentConstants.STATUS_ANY) { KBComment kbComment = kbCommentService.getKBComment( kbCommentId); status = kbComment.getStatus(); } kbCommentLocalService.updateKBComment( kbCommentId, classNameId, classPK, content, status, serviceContext); } SessionMessages.add(actionRequest, "suggestionSaved"); } public void updateKBCommentStatus( ActionRequest actionRequest, ActionResponse actionResponse) throws PortalException { long kbCommentId = ParamUtil.getLong(actionRequest, "kbCommentId"); int status = ParamUtil.getInteger(actionRequest, "kbCommentStatus"); ServiceContext serviceContext = ServiceContextFactory.getInstance( KBComment.class.getName(), actionRequest); kbCommentService.updateStatus(kbCommentId, status, serviceContext); SessionMessages.add(actionRequest, "suggestionStatusUpdated"); } protected String buildEditURL( ActionRequest actionRequest, ActionResponse actionResponse, KBArticle kbArticle) throws PortalException { ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute( WebKeys.THEME_DISPLAY); PortletDisplay portletDisplay = themeDisplay.getPortletDisplay(); String editURL = portal.getLayoutFullURL(themeDisplay); editURL = HttpUtil.setParameter( editURL, "p_p_id", portletDisplay.getId()); editURL = HttpUtil.setParameter( editURL, actionResponse.getNamespace() + "mvcPath", templatePath + "edit_article.jsp"); editURL = HttpUtil.setParameter( editURL, actionResponse.getNamespace() + "redirect", getRedirect(actionRequest, actionResponse)); editURL = HttpUtil.setParameter( editURL, actionResponse.getNamespace() + "resourcePrimKey", kbArticle.getResourcePrimKey()); editURL = HttpUtil.setParameter( editURL, actionResponse.getNamespace() + "status", WorkflowConstants.STATUS_ANY); return editURL; } protected void checkExceededSizeLimit(PortletRequest portletRequest) throws PortalException { UploadException uploadException = (UploadException)portletRequest.getAttribute( WebKeys.UPLOAD_EXCEPTION); if (uploadException != null) { Throwable cause = uploadException.getCause(); if (uploadException.isExceededFileSizeLimit()) { throw new FileSizeException(cause); } if (uploadException.isExceededLiferayFileItemSizeLimit()) { throw new LiferayFileItemException(cause); } if (uploadException.isExceededUploadRequestSizeLimit()) { throw new UploadRequestSizeException(cause); } throw new PortalException(cause); } } protected void compareVersions(RenderRequest renderRequest) throws PortletException { long resourcePrimKey = ParamUtil.getLong( renderRequest, "resourcePrimKey"); double sourceVersion = ParamUtil.getDouble( renderRequest, "sourceVersion"); double targetVersion = ParamUtil.getDouble( renderRequest, "targetVersion"); String diffHtmlResults = null; try { diffHtmlResults = AdminUtil.getKBArticleDiff( resourcePrimKey, GetterUtil.getInteger(sourceVersion), GetterUtil.getInteger(targetVersion), "content"); } catch (Exception e) { throw new PortletException(e); } renderRequest.setAttribute(WebKeys.DIFF_HTML_RESULTS, diffHtmlResults); } protected void deleteKBArticle( ActionRequest actionRequest, ActionResponse actionResponse, long resourcePrimKey) throws Exception { kbArticleService.deleteKBArticle(resourcePrimKey); } protected abstract void doRender( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException; protected String getContentRedirect( Class<?> clazz, long classPK, String redirect) { String portletId = HttpUtil.getParameter(redirect, "p_p_id", false); String namespace = PortalUtil.getPortletNamespace(portletId); redirect = HttpUtil.addParameter( redirect, namespace + "className", clazz.getName()); redirect = HttpUtil.addParameter( redirect, namespace + "classPK", classPK); return redirect; } @Override protected boolean isSessionErrorException(Throwable cause) { if (cause instanceof AssetCategoryException || cause instanceof AssetTagException || cause instanceof DuplicateFileException || cause instanceof FileNameException || cause instanceof FileSizeException || cause instanceof KBArticleContentException || cause instanceof KBArticlePriorityException || cause instanceof KBArticleTitleException || cause instanceof KBCommentContentException || cause instanceof NoSuchArticleException || cause instanceof NoSuchCommentException || cause instanceof NoSuchFileException || cause instanceof PrincipalException || super.isSessionErrorException(cause)) { return true; } return false; } @Reference( cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY ) protected void setDLMimeTypeDisplayContext( DLMimeTypeDisplayContext dlMimeTypeDisplayContext) { this.dlMimeTypeDisplayContext = dlMimeTypeDisplayContext; } @Reference(unbind = "-") protected void setJSONFactory(JSONFactory jsonFactory) { this.jsonFactory = jsonFactory; } @Reference(unbind = "-") protected void setKBArticleService(KBArticleService kbArticleService) { this.kbArticleService = kbArticleService; } @Reference(unbind = "-") protected void setKBCommentLocalService( KBCommentLocalService kbCommentLocalService) { this.kbCommentLocalService = kbCommentLocalService; } @Reference(unbind = "-") protected void setKBCommentService(KBCommentService kbCommentService) { this.kbCommentService = kbCommentService; } @Reference(unbind = "-") protected void setKBFolderService(KBFolderService kbFolderService) { this.kbFolderService = kbFolderService; } @Reference(unbind = "-") protected void setKBTemplateService(KBTemplateService kbTemplateService) { this.kbTemplateService = kbTemplateService; } @Reference(unbind = "-") protected void setPortal(Portal portal) { this.portal = portal; } protected void unsetDLMimeTypeDisplayContext( DLMimeTypeDisplayContext dlMimeTypeDisplayContext) { this.dlMimeTypeDisplayContext = null; } protected DLMimeTypeDisplayContext dlMimeTypeDisplayContext; protected JSONFactory jsonFactory; protected KBArticleService kbArticleService; protected KBCommentLocalService kbCommentLocalService; protected KBCommentService kbCommentService; protected KBFolderService kbFolderService; protected KBTemplateService kbTemplateService; protected Portal portal; }