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.messageboards.LockedThreadException;
052    import com.liferay.portlet.messageboards.MessageBodyException;
053    import com.liferay.portlet.messageboards.MessageSubjectException;
054    import com.liferay.portlet.messageboards.NoSuchMessageException;
055    import com.liferay.portlet.messageboards.RequiredMessageException;
056    import com.liferay.portlet.messageboards.model.MBMessage;
057    import com.liferay.portlet.messageboards.model.MBMessageConstants;
058    import com.liferay.portlet.messageboards.service.MBMessageServiceUtil;
059    import com.liferay.portlet.messageboards.service.MBThreadLocalServiceUtil;
060    import com.liferay.portlet.messageboards.service.MBThreadServiceUtil;
061    import com.liferay.portlet.messageboards.service.permission.MBMessagePermission;
062    import com.liferay.portlet.messageboards.util.MBUtil;
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.PortletPreferences;
073    import javax.portlet.PortletURL;
074    import javax.portlet.RenderRequest;
075    import javax.portlet.RenderResponse;
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                                    String redirect = getRedirect(
137                                            actionRequest, actionResponse, message);
138    
139                                    sendRedirect(actionRequest, actionResponse, redirect);
140                            }
141                    }
142                    catch (Exception e) {
143                            if (e instanceof NoSuchMessageException ||
144                                    e instanceof PrincipalException ||
145                                    e instanceof RequiredMessageException) {
146    
147                                    SessionErrors.add(actionRequest, e.getClass());
148    
149                                    setForward(actionRequest, "portlet.message_boards.error");
150                            }
151                            else if (e instanceof CaptchaMaxChallengesException ||
152                                             e instanceof CaptchaTextException ||
153                                             e instanceof DuplicateFileException ||
154                                             e instanceof FileExtensionException ||
155                                             e instanceof FileNameException ||
156                                             e instanceof FileSizeException ||
157                                             e instanceof LiferayFileItemException ||
158                                             e instanceof LockedThreadException ||
159                                             e instanceof MessageBodyException ||
160                                             e instanceof MessageSubjectException ||
161                                             e instanceof SanitizerException) {
162    
163                                    UploadException uploadException =
164                                            (UploadException)actionRequest.getAttribute(
165                                                    WebKeys.UPLOAD_EXCEPTION);
166    
167                                    if (uploadException != null) {
168                                            String uploadExceptionRedirect = ParamUtil.getString(
169                                                    actionRequest, "uploadExceptionRedirect");
170    
171                                            actionResponse.sendRedirect(uploadExceptionRedirect);
172                                    }
173    
174                                    SessionErrors.add(actionRequest, e.getClass());
175                            }
176                            else if (e instanceof AssetCategoryException ||
177                                             e instanceof AssetTagException) {
178    
179                                    SessionErrors.add(actionRequest, e.getClass(), e);
180                            }
181                            else {
182                                    Throwable cause = e.getCause();
183    
184                                    if (cause instanceof SanitizerException) {
185                                            SessionErrors.add(actionRequest, SanitizerException.class);
186                                    }
187                                    else {
188                                            throw e;
189                                    }
190                            }
191                    }
192            }
193    
194            @Override
195            public ActionForward render(
196                            ActionMapping actionMapping, ActionForm actionForm,
197                            PortletConfig portletConfig, RenderRequest renderRequest,
198                            RenderResponse renderResponse)
199                    throws Exception {
200    
201                    try {
202                            ActionUtil.getMessage(renderRequest);
203                    }
204                    catch (Exception e) {
205                            if (e instanceof NoSuchMessageException ||
206                                    e instanceof PrincipalException) {
207    
208                                    SessionErrors.add(renderRequest, e.getClass());
209    
210                                    return actionMapping.findForward(
211                                            "portlet.message_boards.error");
212                            }
213                            else {
214                                    throw e;
215                            }
216                    }
217    
218                    return actionMapping.findForward(
219                            getForward(renderRequest, "portlet.message_boards.edit_message"));
220            }
221    
222            protected void deleteMessage(ActionRequest actionRequest) throws Exception {
223                    long messageId = ParamUtil.getLong(actionRequest, "messageId");
224    
225                    MBMessageServiceUtil.deleteMessage(messageId);
226            }
227    
228            protected String getRedirect(
229                    ActionRequest actionRequest, ActionResponse actionResponse,
230                    MBMessage message) {
231    
232                    if (message == null) {
233                            String redirect = ParamUtil.getString(actionRequest, "redirect");
234    
235                            return redirect;
236                    }
237    
238                    int workflowAction = ParamUtil.getInteger(
239                            actionRequest, "workflowAction", WorkflowConstants.ACTION_PUBLISH);
240    
241                    if (workflowAction == WorkflowConstants.ACTION_SAVE_DRAFT) {
242                            return getSaveAndContinueRedirect(
243                                    actionRequest, actionResponse, message);
244                    }
245                    else if (message == null) {
246                            return ParamUtil.getString(actionRequest, "redirect");
247                    }
248    
249                    ActionResponseImpl actionResponseImpl =
250                            (ActionResponseImpl)actionResponse;
251    
252                    PortletURL portletURL = actionResponseImpl.createRenderURL();
253    
254                    portletURL.setParameter(
255                            "struts_action", "/message_boards/view_message");
256                    portletURL.setParameter(
257                            "messageId", String.valueOf(message.getMessageId()));
258    
259                    return portletURL.toString();
260            }
261    
262            protected String getSaveAndContinueRedirect(
263                    ActionRequest actionRequest, ActionResponse actionResponse,
264                    MBMessage message) {
265    
266                    String redirect = ParamUtil.getString(actionRequest, "redirect");
267    
268                    boolean preview = ParamUtil.getBoolean(actionRequest, "preview");
269    
270                    PortletURL portletURL =
271                            ((ActionResponseImpl)actionResponse).createRenderURL();
272    
273                    portletURL.setParameter(
274                            "struts_action", "/message_boards/edit_message");
275                    portletURL.setParameter("redirect", redirect);
276                    portletURL.setParameter(
277                            "messageId", String.valueOf(message.getMessageId()));
278                    portletURL.setParameter("preview", String.valueOf(preview));
279    
280                    return portletURL.toString();
281            }
282    
283            protected void lockThreads(ActionRequest actionRequest) throws Exception {
284                    long threadId = ParamUtil.getLong(actionRequest, "threadId");
285    
286                    if (threadId > 0) {
287                            MBThreadServiceUtil.lockThread(threadId);
288                    }
289                    else {
290                            long[] threadIds = StringUtil.split(
291                                    ParamUtil.getString(actionRequest, "threadIds"), 0L);
292    
293                            for (int i = 0; i < threadIds.length; i++) {
294                                    MBThreadServiceUtil.lockThread(threadIds[i]);
295                            }
296                    }
297            }
298    
299            protected void subscribeMessage(ActionRequest actionRequest)
300                    throws Exception {
301    
302                    long messageId = ParamUtil.getLong(actionRequest, "messageId");
303    
304                    MBMessageServiceUtil.subscribeMessage(messageId);
305            }
306    
307            protected void unlockThreads(ActionRequest actionRequest) throws Exception {
308                    long threadId = ParamUtil.getLong(actionRequest, "threadId");
309    
310                    if (threadId > 0) {
311                            MBThreadServiceUtil.unlockThread(threadId);
312                    }
313                    else {
314                            long[] threadIds = StringUtil.split(
315                                    ParamUtil.getString(actionRequest, "threadIds"), 0L);
316    
317                            for (int i = 0; i < threadIds.length; i++) {
318                                    MBThreadServiceUtil.unlockThread(threadIds[i]);
319                            }
320                    }
321            }
322    
323            protected void unsubscribeMessage(ActionRequest actionRequest)
324                    throws Exception {
325    
326                    long messageId = ParamUtil.getLong(actionRequest, "messageId");
327    
328                    MBMessageServiceUtil.unsubscribeMessage(messageId);
329            }
330    
331            protected MBMessage updateMessage(
332                            ActionRequest actionRequest, ActionResponse actionResponse)
333                    throws Exception {
334    
335                    PortletPreferences portletPreferences = actionRequest.getPreferences();
336    
337                    ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
338                            WebKeys.THEME_DISPLAY);
339    
340                    long messageId = ParamUtil.getLong(actionRequest, "messageId");
341    
342                    long groupId = themeDisplay.getScopeGroupId();
343                    long categoryId = ParamUtil.getLong(actionRequest, "mbCategoryId");
344                    long threadId = ParamUtil.getLong(actionRequest, "threadId");
345                    long parentMessageId = ParamUtil.getLong(
346                            actionRequest, "parentMessageId");
347                    String subject = ParamUtil.getString(actionRequest, "subject");
348                    String body = ParamUtil.getString(actionRequest, "body");
349    
350                    String format = GetterUtil.getString(
351                            portletPreferences.getValue("messageFormat", null),
352                            MBMessageConstants.DEFAULT_FORMAT);
353    
354                    if (!MBUtil.isValidMessageFormat(format)) {
355                            format = "html";
356                    }
357    
358                    List<ObjectValuePair<String, InputStream>> inputStreamOVPs =
359                            new ArrayList<ObjectValuePair<String, InputStream>>(5);
360    
361                    try {
362                            UploadPortletRequest uploadPortletRequest =
363                                    PortalUtil.getUploadPortletRequest(actionRequest);
364    
365                            for (int i = 1; i <= 5; i++) {
366                                    String fileName = uploadPortletRequest.getFileName(
367                                            "msgFile" + i);
368                                    InputStream inputStream = uploadPortletRequest.getFileAsStream(
369                                            "msgFile" + i);
370    
371                                    if ((inputStream == null) || Validator.isNull(fileName)) {
372                                            continue;
373                                    }
374    
375                                    ObjectValuePair<String, InputStream> inputStreamOVP =
376                                            new ObjectValuePair<String, InputStream>(
377                                                    fileName, inputStream);
378    
379                                    inputStreamOVPs.add(inputStreamOVP);
380                            }
381    
382                            boolean question = ParamUtil.getBoolean(actionRequest, "question");
383                            boolean anonymous = ParamUtil.getBoolean(
384                                    actionRequest, "anonymous");
385                            double priority = ParamUtil.getDouble(actionRequest, "priority");
386                            boolean allowPingbacks = ParamUtil.getBoolean(
387                                    actionRequest, "allowPingbacks");
388    
389                            ServiceContext serviceContext = ServiceContextFactory.getInstance(
390                                    MBMessage.class.getName(), actionRequest);
391    
392                            boolean preview = ParamUtil.getBoolean(actionRequest, "preview");
393    
394                            serviceContext.setAttribute("preview", preview);
395    
396                            MBMessage message = null;
397    
398                            if (messageId <= 0) {
399                                    if (PropsValues.
400                                                    CAPTCHA_CHECK_PORTLET_MESSAGE_BOARDS_EDIT_MESSAGE) {
401    
402                                            CaptchaUtil.check(actionRequest);
403                                    }
404    
405                                    if (threadId <= 0) {
406    
407                                            // Post new thread
408    
409                                            message = MBMessageServiceUtil.addMessage(
410                                                    groupId, categoryId, subject, body, format,
411                                                    inputStreamOVPs, anonymous, priority, allowPingbacks,
412                                                    serviceContext);
413    
414                                            if (question) {
415                                                    MBThreadLocalServiceUtil.updateQuestion(
416                                                            message.getThreadId(), true);
417                                            }
418                                    }
419                                    else {
420    
421                                            // Post reply
422    
423                                            message = MBMessageServiceUtil.addMessage(
424                                                    parentMessageId, subject, body, format, inputStreamOVPs,
425                                                    anonymous, priority, allowPingbacks, serviceContext);
426                                    }
427                            }
428                            else {
429                                    List<String> existingFiles = new ArrayList<String>();
430    
431                                    for (int i = 1; i <= 5; i++) {
432                                            String path = ParamUtil.getString(
433                                                    actionRequest, "existingPath" + i);
434    
435                                            if (Validator.isNotNull(path)) {
436                                                    existingFiles.add(path);
437                                            }
438                                    }
439    
440                                    // Update message
441    
442                                    message = MBMessageServiceUtil.updateMessage(
443                                            messageId, subject, body, inputStreamOVPs, existingFiles,
444                                            priority, allowPingbacks, serviceContext);
445    
446                                    if (message.isRoot()) {
447                                            MBThreadLocalServiceUtil.updateQuestion(
448                                                    message.getThreadId(), question);
449                                    }
450                            }
451    
452                            PermissionChecker permissionChecker =
453                                    themeDisplay.getPermissionChecker();
454    
455                            boolean subscribe = ParamUtil.getBoolean(
456                                    actionRequest, "subscribe");
457    
458                            if (!preview && subscribe &&
459                                    MBMessagePermission.contains(
460                                            permissionChecker, message, ActionKeys.SUBSCRIBE)) {
461    
462                                    MBMessageServiceUtil.subscribeMessage(message.getMessageId());
463                            }
464    
465                            return message;
466                    }
467                    finally {
468                            for (ObjectValuePair<String, InputStream> inputStreamOVP :
469                                            inputStreamOVPs) {
470    
471                                    InputStream inputStream = inputStreamOVP.getValue();
472    
473                                    StreamUtil.cleanUp(inputStream);
474                            }
475                    }
476            }
477    
478    }