001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.messageboards.action;
016    
017    import com.liferay.portal.kernel.captcha.CaptchaMaxChallengesException;
018    import com.liferay.portal.kernel.captcha.CaptchaTextException;
019    import com.liferay.portal.kernel.captcha.CaptchaUtil;
020    import com.liferay.portal.kernel.sanitizer.SanitizerException;
021    import com.liferay.portal.kernel.servlet.SessionErrors;
022    import com.liferay.portal.kernel.upload.UploadPortletRequest;
023    import com.liferay.portal.kernel.util.Constants;
024    import com.liferay.portal.kernel.util.GetterUtil;
025    import com.liferay.portal.kernel.util.ObjectValuePair;
026    import com.liferay.portal.kernel.util.ParamUtil;
027    import com.liferay.portal.kernel.util.StreamUtil;
028    import com.liferay.portal.kernel.util.StringUtil;
029    import com.liferay.portal.kernel.util.Validator;
030    import com.liferay.portal.kernel.workflow.WorkflowConstants;
031    import com.liferay.portal.security.auth.PrincipalException;
032    import com.liferay.portal.security.permission.ActionKeys;
033    import com.liferay.portal.security.permission.PermissionChecker;
034    import com.liferay.portal.service.ServiceContext;
035    import com.liferay.portal.service.ServiceContextFactory;
036    import com.liferay.portal.struts.PortletAction;
037    import com.liferay.portal.theme.ThemeDisplay;
038    import com.liferay.portal.util.PortalUtil;
039    import com.liferay.portal.util.PropsValues;
040    import com.liferay.portal.util.WebKeys;
041    import com.liferay.portlet.ActionResponseImpl;
042    import com.liferay.portlet.asset.AssetCategoryException;
043    import com.liferay.portlet.asset.AssetTagException;
044    import com.liferay.portlet.documentlibrary.FileExtensionException;
045    import com.liferay.portlet.documentlibrary.FileNameException;
046    import com.liferay.portlet.documentlibrary.FileSizeException;
047    import com.liferay.portlet.messageboards.LockedThreadException;
048    import com.liferay.portlet.messageboards.MessageBodyException;
049    import com.liferay.portlet.messageboards.MessageSubjectException;
050    import com.liferay.portlet.messageboards.NoSuchMessageException;
051    import com.liferay.portlet.messageboards.RequiredMessageException;
052    import com.liferay.portlet.messageboards.model.MBMessage;
053    import com.liferay.portlet.messageboards.model.MBMessageConstants;
054    import com.liferay.portlet.messageboards.service.MBMessageServiceUtil;
055    import com.liferay.portlet.messageboards.service.MBThreadLocalServiceUtil;
056    import com.liferay.portlet.messageboards.service.MBThreadServiceUtil;
057    import com.liferay.portlet.messageboards.service.permission.MBMessagePermission;
058    
059    import java.io.InputStream;
060    
061    import java.util.ArrayList;
062    import java.util.List;
063    
064    import javax.portlet.ActionRequest;
065    import javax.portlet.ActionResponse;
066    import javax.portlet.PortletConfig;
067    import javax.portlet.PortletPreferences;
068    import javax.portlet.PortletURL;
069    import javax.portlet.RenderRequest;
070    import javax.portlet.RenderResponse;
071    
072    import org.apache.struts.action.ActionForm;
073    import org.apache.struts.action.ActionForward;
074    import org.apache.struts.action.ActionMapping;
075    
076    /**
077     * @author Brian Wing Shun Chan
078     * @author Daniel Sanz
079     * @author Shuyang Zhou
080     */
081    public class EditMessageAction extends PortletAction {
082    
083            @Override
084            public void processAction(
085                            ActionMapping mapping, ActionForm form, PortletConfig portletConfig,
086                            ActionRequest actionRequest, ActionResponse actionResponse)
087                    throws Exception {
088    
089                    String cmd = ParamUtil.getString(actionRequest, Constants.CMD);
090    
091                    try {
092                            MBMessage message = null;
093    
094                            if (cmd.equals(Constants.ADD) || cmd.equals(Constants.UPDATE)) {
095                                    message = updateMessage(actionRequest, actionResponse);
096                            }
097                            else if (cmd.equals(Constants.DELETE)) {
098                                    deleteMessage(actionRequest);
099                            }
100                            else if (cmd.equals(Constants.LOCK)) {
101                                    lockThreads(actionRequest);
102                            }
103                            else if (cmd.equals(Constants.SUBSCRIBE)) {
104                                    subscribeMessage(actionRequest);
105                            }
106                            else if (cmd.equals(Constants.UNLOCK)) {
107                                    unlockThreads(actionRequest);
108                            }
109                            else if (cmd.equals(Constants.UNSUBSCRIBE)) {
110                                    unsubscribeMessage(actionRequest);
111                            }
112    
113                            if (Validator.isNotNull(cmd)) {
114                                    String redirect = getRedirect(
115                                            actionRequest, actionResponse, message);
116    
117                                    sendRedirect(actionRequest, actionResponse, redirect);
118                            }
119                    }
120                    catch (Exception e) {
121                            if (e instanceof NoSuchMessageException ||
122                                    e instanceof PrincipalException ||
123                                    e instanceof RequiredMessageException) {
124    
125                                    SessionErrors.add(actionRequest, e.getClass());
126    
127                                    setForward(actionRequest, "portlet.message_boards.error");
128                            }
129                            else if (e instanceof CaptchaMaxChallengesException ||
130                                             e instanceof CaptchaTextException ||
131                                             e instanceof FileExtensionException ||
132                                             e instanceof FileNameException ||
133                                             e instanceof FileSizeException ||
134                                             e instanceof LockedThreadException ||
135                                             e instanceof MessageBodyException ||
136                                             e instanceof MessageSubjectException ||
137                                             e instanceof SanitizerException) {
138    
139                                    SessionErrors.add(actionRequest, e.getClass());
140                            }
141                            else if (e instanceof AssetCategoryException ||
142                                             e instanceof AssetTagException) {
143    
144                                    SessionErrors.add(actionRequest, e.getClass(), e);
145                            }
146                            else {
147                                    Throwable cause = e.getCause();
148    
149                                    if (cause instanceof SanitizerException) {
150                                            SessionErrors.add(actionRequest, SanitizerException.class);
151                                    }
152                                    else {
153                                            throw e;
154                                    }
155                            }
156                    }
157            }
158    
159            @Override
160            public ActionForward render(
161                            ActionMapping mapping, ActionForm form, PortletConfig portletConfig,
162                            RenderRequest renderRequest, RenderResponse renderResponse)
163                    throws Exception {
164    
165                    try {
166                            ActionUtil.getMessage(renderRequest);
167                    }
168                    catch (Exception e) {
169                            if (e instanceof NoSuchMessageException ||
170                                    e instanceof PrincipalException) {
171    
172                                    SessionErrors.add(renderRequest, e.getClass());
173    
174                                    return mapping.findForward("portlet.message_boards.error");
175                            }
176                            else {
177                                    throw e;
178                            }
179                    }
180    
181                    return mapping.findForward(
182                            getForward(renderRequest, "portlet.message_boards.edit_message"));
183            }
184    
185            protected void deleteMessage(ActionRequest actionRequest) throws Exception {
186                    long messageId = ParamUtil.getLong(actionRequest, "messageId");
187    
188                    MBMessageServiceUtil.deleteMessage(messageId);
189            }
190    
191            protected String getRedirect(
192                    ActionRequest actionRequest, ActionResponse actionResponse,
193                    MBMessage message) {
194    
195                    if (message == null) {
196                            String redirect = ParamUtil.getString(actionRequest, "redirect");
197    
198                            return redirect;
199                    }
200    
201                    int workflowAction = ParamUtil.getInteger(
202                            actionRequest, "workflowAction", WorkflowConstants.ACTION_PUBLISH);
203    
204                    if (workflowAction == WorkflowConstants.ACTION_SAVE_DRAFT) {
205                            return getSaveAndContinueRedirect(
206                                    actionRequest, actionResponse, message);
207                    }
208                    else if (message == null) {
209                            return ParamUtil.getString(actionRequest, "redirect");
210                    }
211    
212                    ActionResponseImpl actionResponseImpl =
213                            (ActionResponseImpl)actionResponse;
214    
215                    PortletURL portletURL = actionResponseImpl.createRenderURL();
216    
217                    portletURL.setParameter(
218                            "struts_action", "/message_boards/view_message");
219                    portletURL.setParameter(
220                            "messageId", String.valueOf(message.getMessageId()));
221    
222                    return portletURL.toString();
223            }
224    
225            protected String getSaveAndContinueRedirect(
226                    ActionRequest actionRequest, ActionResponse actionResponse,
227                    MBMessage message) {
228    
229                    String redirect = ParamUtil.getString(actionRequest, "redirect");
230    
231                    boolean preview = ParamUtil.getBoolean(actionRequest, "preview");
232    
233                    PortletURL portletURL =
234                            ((ActionResponseImpl)actionResponse).createRenderURL();
235    
236                    portletURL.setParameter(
237                            "struts_action", "/message_boards/edit_message");
238                    portletURL.setParameter("redirect", redirect);
239                    portletURL.setParameter(
240                            "messageId", String.valueOf(message.getMessageId()));
241                    portletURL.setParameter("preview", String.valueOf(preview));
242    
243                    return portletURL.toString();
244            }
245    
246            protected void lockThreads(ActionRequest actionRequest) throws Exception {
247                    long threadId = ParamUtil.getLong(actionRequest, "threadId");
248    
249                    if (threadId > 0) {
250                            MBThreadServiceUtil.lockThread(threadId);
251                    }
252                    else {
253                            long[] threadIds = StringUtil.split(
254                                    ParamUtil.getString(actionRequest, "threadIds"), 0L);
255    
256                            for (int i = 0; i < threadIds.length; i++) {
257                                    MBThreadServiceUtil.lockThread(threadIds[i]);
258                            }
259                    }
260            }
261    
262            protected void subscribeMessage(ActionRequest actionRequest)
263                    throws Exception {
264    
265                    long messageId = ParamUtil.getLong(actionRequest, "messageId");
266    
267                    MBMessageServiceUtil.subscribeMessage(messageId);
268            }
269    
270            protected void unlockThreads(ActionRequest actionRequest) throws Exception {
271                    long threadId = ParamUtil.getLong(actionRequest, "threadId");
272    
273                    if (threadId > 0) {
274                            MBThreadServiceUtil.unlockThread(threadId);
275                    }
276                    else {
277                            long[] threadIds = StringUtil.split(
278                                    ParamUtil.getString(actionRequest, "threadIds"), 0L);
279    
280                            for (int i = 0; i < threadIds.length; i++) {
281                                    MBThreadServiceUtil.unlockThread(threadIds[i]);
282                            }
283                    }
284            }
285    
286            protected void unsubscribeMessage(ActionRequest actionRequest)
287                    throws Exception {
288    
289                    long messageId = ParamUtil.getLong(actionRequest, "messageId");
290    
291                    MBMessageServiceUtil.unsubscribeMessage(messageId);
292            }
293    
294            protected MBMessage updateMessage(
295                            ActionRequest actionRequest, ActionResponse actionResponse)
296                    throws Exception {
297    
298                    PortletPreferences preferences = actionRequest.getPreferences();
299    
300                    ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
301                            WebKeys.THEME_DISPLAY);
302    
303                    long messageId = ParamUtil.getLong(actionRequest, "messageId");
304    
305                    long groupId = themeDisplay.getScopeGroupId();
306                    long categoryId = ParamUtil.getLong(actionRequest, "mbCategoryId");
307                    long threadId = ParamUtil.getLong(actionRequest, "threadId");
308                    long parentMessageId = ParamUtil.getLong(
309                            actionRequest, "parentMessageId");
310                    String subject = ParamUtil.getString(actionRequest, "subject");
311                    String body = ParamUtil.getString(actionRequest, "body");
312    
313                    String format = GetterUtil.getString(
314                            preferences.getValue("messageFormat", null),
315                            MBMessageConstants.DEFAULT_FORMAT);
316    
317                    List<ObjectValuePair<String, InputStream>> inputStreamOVPs =
318                            new ArrayList<ObjectValuePair<String, InputStream>>(5);
319    
320                    try {
321                            UploadPortletRequest uploadPortletRequest =
322                                    PortalUtil.getUploadPortletRequest(actionRequest);
323    
324                            for (int i = 1; i <= 5; i++) {
325                                    String fileName = uploadPortletRequest.getFileName(
326                                            "msgFile" + i);
327                                    InputStream inputStream = uploadPortletRequest.getFileAsStream(
328                                            "msgFile" + i);
329    
330                                    if ((inputStream == null) || Validator.isNull(fileName)) {
331                                            continue;
332                                    }
333    
334                                    ObjectValuePair<String, InputStream> inputStreamOVP =
335                                            new ObjectValuePair<String, InputStream>(
336                                                    fileName, inputStream);
337    
338                                    inputStreamOVPs.add(inputStreamOVP);
339                            }
340    
341                            boolean question = ParamUtil.getBoolean(actionRequest, "question");
342                            boolean anonymous = ParamUtil.getBoolean(
343                                    actionRequest, "anonymous");
344                            double priority = ParamUtil.getDouble(actionRequest, "priority");
345                            boolean allowPingbacks = ParamUtil.getBoolean(
346                                    actionRequest, "allowPingbacks");
347    
348                            ServiceContext serviceContext = ServiceContextFactory.getInstance(
349                                    MBMessage.class.getName(), actionRequest);
350    
351                            boolean preview = ParamUtil.getBoolean(actionRequest, "preview");
352    
353                            serviceContext.setAttribute("preview", preview);
354    
355                            MBMessage message = null;
356    
357                            if (messageId <= 0) {
358                                    if (PropsValues.
359                                                    CAPTCHA_CHECK_PORTLET_MESSAGE_BOARDS_EDIT_MESSAGE) {
360    
361                                            CaptchaUtil.check(actionRequest);
362                                    }
363    
364                                    if (threadId <= 0) {
365    
366                                            // Post new thread
367    
368                                            message = MBMessageServiceUtil.addMessage(
369                                                    groupId, categoryId, subject, body, format,
370                                                    inputStreamOVPs, anonymous, priority, allowPingbacks,
371                                                    serviceContext);
372    
373                                            if (question) {
374                                                    MBThreadLocalServiceUtil.updateQuestion(
375                                                            message.getThreadId(), true);
376                                            }
377                                    }
378                                    else {
379    
380                                            // Post reply
381    
382                                            message = MBMessageServiceUtil.addMessage(
383                                                    parentMessageId, subject, body, format, inputStreamOVPs,
384                                                    anonymous, priority, allowPingbacks, serviceContext);
385                                    }
386                            }
387                            else {
388                                    List<String> existingFiles = new ArrayList<String>();
389    
390                                    for (int i = 1; i <= 5; i++) {
391                                            String path = ParamUtil.getString(
392                                                    actionRequest, "existingPath" + i);
393    
394                                            if (Validator.isNotNull(path)) {
395                                                    existingFiles.add(path);
396                                            }
397                                    }
398    
399                                    // Update message
400    
401                                    message = MBMessageServiceUtil.updateMessage(
402                                            messageId, subject, body, inputStreamOVPs, existingFiles,
403                                            priority, allowPingbacks, serviceContext);
404    
405                                    if (message.isRoot()) {
406                                            MBThreadLocalServiceUtil.updateQuestion(
407                                                    message.getThreadId(), question);
408                                    }
409                            }
410    
411                            PermissionChecker permissionChecker =
412                                    themeDisplay.getPermissionChecker();
413    
414                            boolean subscribe = ParamUtil.getBoolean(
415                                    actionRequest, "subscribe");
416    
417                            if (!preview && subscribe &&
418                                    MBMessagePermission.contains(
419                                            permissionChecker, message, ActionKeys.SUBSCRIBE)) {
420    
421                                    MBMessageServiceUtil.subscribeMessage(message.getMessageId());
422                            }
423    
424                            return message;
425                    }
426                    finally {
427                            for (ObjectValuePair<String, InputStream> inputStreamOVP :
428                                            inputStreamOVPs) {
429    
430                                    InputStream inputStream = inputStreamOVP.getValue();
431    
432                                    StreamUtil.cleanUp(inputStream);
433                            }
434                    }
435            }
436    
437    }