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