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