1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portlet.journal.action;
24  
25  import com.liferay.portal.kernel.servlet.SessionErrors;
26  import com.liferay.portal.kernel.upload.UploadPortletRequest;
27  import com.liferay.portal.kernel.util.Constants;
28  import com.liferay.portal.kernel.util.FileUtil;
29  import com.liferay.portal.kernel.util.GetterUtil;
30  import com.liferay.portal.kernel.util.ParamUtil;
31  import com.liferay.portal.kernel.util.StringPool;
32  import com.liferay.portal.kernel.util.StringUtil;
33  import com.liferay.portal.kernel.util.Validator;
34  import com.liferay.portal.model.Layout;
35  import com.liferay.portal.security.auth.PrincipalException;
36  import com.liferay.portal.service.ServiceContext;
37  import com.liferay.portal.service.ServiceContextFactory;
38  import com.liferay.portal.struts.PortletAction;
39  import com.liferay.portal.theme.ThemeDisplay;
40  import com.liferay.portal.util.PortalUtil;
41  import com.liferay.portal.util.WebKeys;
42  import com.liferay.portlet.ActionRequestImpl;
43  import com.liferay.portlet.PortletPreferencesFactoryUtil;
44  import com.liferay.portlet.PortletURLImpl;
45  import com.liferay.portlet.assetpublisher.util.AssetPublisherUtil;
46  import com.liferay.portlet.journal.ArticleContentException;
47  import com.liferay.portlet.journal.ArticleDisplayDateException;
48  import com.liferay.portlet.journal.ArticleExpirationDateException;
49  import com.liferay.portlet.journal.ArticleIdException;
50  import com.liferay.portlet.journal.ArticleSmallImageNameException;
51  import com.liferay.portlet.journal.ArticleSmallImageSizeException;
52  import com.liferay.portlet.journal.ArticleTitleException;
53  import com.liferay.portlet.journal.ArticleTypeException;
54  import com.liferay.portlet.journal.DuplicateArticleIdException;
55  import com.liferay.portlet.journal.NoSuchArticleException;
56  import com.liferay.portlet.journal.NoSuchStructureException;
57  import com.liferay.portlet.journal.NoSuchTemplateException;
58  import com.liferay.portlet.journal.model.JournalArticle;
59  import com.liferay.portlet.journal.model.JournalStructure;
60  import com.liferay.portlet.journal.service.JournalArticleServiceUtil;
61  import com.liferay.portlet.journal.service.JournalContentSearchLocalServiceUtil;
62  import com.liferay.portlet.journal.service.JournalStructureLocalServiceUtil;
63  import com.liferay.portlet.journal.util.JournalUtil;
64  import com.liferay.portlet.tags.TagsEntryException;
65  import com.liferay.util.LocalizationUtil;
66  
67  import java.io.File;
68  
69  import java.util.Calendar;
70  import java.util.Enumeration;
71  import java.util.HashMap;
72  import java.util.Map;
73  
74  import javax.portlet.ActionRequest;
75  import javax.portlet.ActionResponse;
76  import javax.portlet.PortletConfig;
77  import javax.portlet.PortletPreferences;
78  import javax.portlet.PortletRequest;
79  import javax.portlet.RenderRequest;
80  import javax.portlet.RenderResponse;
81  import javax.portlet.WindowState;
82  
83  import org.apache.struts.action.ActionForm;
84  import org.apache.struts.action.ActionForward;
85  import org.apache.struts.action.ActionMapping;
86  
87  /**
88   * <a href="EditArticleAction.java.html"><b><i>View Source</i></b></a>
89   *
90   * @author Brian Wing Shun Chan
91   * @author Raymond Augé
92   *
93   */
94  public class EditArticleAction extends PortletAction {
95  
96      public static final String VERSION_SEPARATOR = "_version_";
97  
98      public void processAction(
99              ActionMapping mapping, ActionForm form, PortletConfig portletConfig,
100             ActionRequest actionRequest, ActionResponse actionResponse)
101         throws Exception {
102 
103         String cmd = ParamUtil.getString(actionRequest, Constants.CMD);
104 
105         JournalArticle article = null;
106 
107         try {
108             if (cmd.equals(Constants.ADD) || cmd.equals(Constants.UPDATE)) {
109                 article = updateArticle(actionRequest);
110             }
111             else if (cmd.equals(Constants.APPROVE)) {
112                 approveArticle(actionRequest);
113             }
114             else if (cmd.equals(Constants.DELETE)) {
115                 deleteArticles(actionRequest);
116             }
117             else if (cmd.equals(Constants.EXPIRE)) {
118                 expireArticles(actionRequest);
119             }
120             else if (cmd.equals("removeArticlesLocale")) {
121                 removeArticlesLocale(actionRequest);
122             }
123 
124             if (Validator.isNotNull(cmd)) {
125                 String redirect = ParamUtil.getString(
126                     actionRequest, "redirect");
127 
128                 if (article != null) {
129                     boolean saveAndContinue = ParamUtil.getBoolean(
130                         actionRequest, "saveAndContinue");
131 
132                     if (saveAndContinue) {
133                         redirect = getSaveAndContinueRedirect(
134                             portletConfig, actionRequest, article, redirect);
135                     }
136                 }
137 
138                 sendRedirect(actionRequest, actionResponse, redirect);
139             }
140         }
141         catch (Exception e) {
142             if (e instanceof NoSuchArticleException ||
143                 e instanceof NoSuchStructureException ||
144                 e instanceof NoSuchTemplateException ||
145                 e instanceof PrincipalException) {
146 
147                 SessionErrors.add(actionRequest, e.getClass().getName());
148 
149                 setForward(actionRequest, "portlet.journal.error");
150             }
151             else if (e instanceof ArticleContentException ||
152                      e instanceof ArticleDisplayDateException ||
153                      e instanceof ArticleExpirationDateException ||
154                      e instanceof ArticleIdException ||
155                      e instanceof ArticleSmallImageNameException ||
156                      e instanceof ArticleSmallImageSizeException ||
157                      e instanceof ArticleTitleException ||
158                      e instanceof ArticleTypeException ||
159                      e instanceof DuplicateArticleIdException) {
160 
161                 SessionErrors.add(actionRequest, e.getClass().getName());
162             }
163             else if (e instanceof TagsEntryException) {
164                 SessionErrors.add(actionRequest, e.getClass().getName(), e);
165             }
166             else {
167                 throw e;
168             }
169         }
170     }
171 
172     public ActionForward render(
173             ActionMapping mapping, ActionForm form, PortletConfig portletConfig,
174             RenderRequest renderRequest, RenderResponse renderResponse)
175         throws Exception {
176 
177         try {
178             String cmd = ParamUtil.getString(renderRequest, Constants.CMD);
179 
180             if (!cmd.equals(Constants.ADD)) {
181                 ActionUtil.getArticle(renderRequest);
182             }
183         }
184         catch (NoSuchArticleException nsse) {
185 
186             // Let this slide because the user can manually input a article id
187             // for a new article that does not yet exist.
188 
189         }
190         catch (Exception e) {
191             if (//e instanceof NoSuchArticleException ||
192                 e instanceof PrincipalException) {
193 
194                 SessionErrors.add(renderRequest, e.getClass().getName());
195 
196                 return mapping.findForward("portlet.journal.error");
197             }
198             else {
199                 throw e;
200             }
201         }
202 
203         return mapping.findForward(
204             getForward(renderRequest, "portlet.journal.edit_article"));
205     }
206 
207     protected void approveArticle(ActionRequest actionRequest)
208         throws Exception {
209 
210         long groupId = ParamUtil.getLong(actionRequest, "groupId");
211         String articleId = ParamUtil.getString(actionRequest, "articleId");
212         double version = ParamUtil.getDouble(actionRequest, "version");
213 
214         String articleURL = ParamUtil.getString(actionRequest, "articleURL");
215 
216         ServiceContext serviceContext = ServiceContextFactory.getInstance(
217             JournalArticle.class.getName(), actionRequest);
218 
219         JournalArticleServiceUtil.approveArticle(
220             groupId, articleId, version, articleURL, serviceContext);
221     }
222 
223     protected void deleteArticles(ActionRequest actionRequest)
224         throws Exception {
225 
226         long groupId = ParamUtil.getLong(actionRequest, "groupId");
227 
228         String[] deleteArticleIds = StringUtil.split(
229             ParamUtil.getString(actionRequest, "deleteArticleIds"));
230 
231         ServiceContext serviceContext = ServiceContextFactory.getInstance(
232             JournalArticle.class.getName(), actionRequest);
233 
234         for (int i = 0; i < deleteArticleIds.length; i++) {
235             int pos = deleteArticleIds[i].lastIndexOf(VERSION_SEPARATOR);
236 
237             String articleId = deleteArticleIds[i].substring(0, pos);
238             double version = GetterUtil.getDouble(
239                 deleteArticleIds[i].substring(
240                     pos + VERSION_SEPARATOR.length()));
241 
242             String articleURL = ParamUtil.getString(
243                 actionRequest, "articleURL");
244 
245             JournalArticleServiceUtil.deleteArticle(
246                 groupId, articleId, version, articleURL, serviceContext);
247 
248             JournalUtil.removeRecentArticle(actionRequest, deleteArticleIds[i]);
249         }
250     }
251 
252     protected void expireArticles(ActionRequest actionRequest)
253         throws Exception {
254 
255         long groupId = ParamUtil.getLong(actionRequest, "groupId");
256 
257         String[] expireArticleIds = StringUtil.split(
258             ParamUtil.getString(actionRequest, "expireArticleIds"));
259 
260         ServiceContext serviceContext = ServiceContextFactory.getInstance(
261             JournalArticle.class.getName(), actionRequest);
262 
263         for (int i = 0; i < expireArticleIds.length; i++) {
264             int pos = expireArticleIds[i].lastIndexOf(VERSION_SEPARATOR);
265 
266             String articleId = expireArticleIds[i].substring(0, pos);
267             double version = GetterUtil.getDouble(
268                 expireArticleIds[i].substring(
269                     pos + VERSION_SEPARATOR.length()));
270 
271             String articleURL = ParamUtil.getString(
272                 actionRequest, "articleURL");
273 
274             JournalArticleServiceUtil.expireArticle(
275                 groupId, articleId, version, articleURL, serviceContext);
276         }
277     }
278 
279     protected Map<String, byte[]> getImages(UploadPortletRequest uploadRequest)
280         throws Exception {
281 
282         Map<String, byte[]> images = new HashMap<String, byte[]>();
283 
284         String imagePrefix = "structure_image_";
285 
286         Enumeration<String> enu = uploadRequest.getParameterNames();
287 
288         while (enu.hasMoreElements()) {
289             String name = enu.nextElement();
290 
291             if (name.startsWith(imagePrefix)) {
292                 File file = uploadRequest.getFile(name);
293                 byte[] bytes = FileUtil.getBytes(file);
294 
295                 if ((bytes != null) && (bytes.length > 0)) {
296                     name = name.substring(imagePrefix.length(), name.length());
297 
298                     images.put(name, bytes);
299                 }
300             }
301         }
302 
303         return images;
304     }
305 
306     protected String getSaveAndContinueRedirect(
307             PortletConfig portletConfig, ActionRequest actionRequest,
308             JournalArticle article, String redirect)
309         throws Exception {
310 
311         ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
312             WebKeys.THEME_DISPLAY);
313 
314         String originalRedirect = ParamUtil.getString(
315             actionRequest, "originalRedirect");
316 
317         PortletURLImpl portletURL = new PortletURLImpl(
318             (ActionRequestImpl)actionRequest, portletConfig.getPortletName(),
319             themeDisplay.getPlid(), PortletRequest.RENDER_PHASE);
320 
321         portletURL.setWindowState(WindowState.MAXIMIZED);
322 
323         portletURL.setParameter("struts_action", "/journal/edit_article");
324         portletURL.setParameter(Constants.CMD, Constants.UPDATE, false);
325         portletURL.setParameter("redirect", redirect, false);
326         portletURL.setParameter("originalRedirect", originalRedirect, false);
327         portletURL.setParameter(
328             "groupId", String.valueOf(article.getGroupId()), false);
329         portletURL.setParameter("articleId", article.getArticleId(), false);
330         portletURL.setParameter(
331             "version", String.valueOf(article.getVersion()), false);
332 
333         return portletURL.toString();
334     }
335 
336     protected void removeArticlesLocale(ActionRequest actionRequest)
337         throws Exception {
338 
339         long groupId = ParamUtil.getLong(actionRequest, "groupId");
340 
341         String[] removeArticleLocaleIds = StringUtil.split(
342             ParamUtil.getString(actionRequest, "deleteArticleIds"));
343 
344         for (int i = 0; i < removeArticleLocaleIds.length; i++) {
345             int pos = removeArticleLocaleIds[i].lastIndexOf(VERSION_SEPARATOR);
346 
347             String articleId = removeArticleLocaleIds[i].substring(0, pos);
348             double version = GetterUtil.getDouble(
349                 removeArticleLocaleIds[i].substring(
350                     pos + VERSION_SEPARATOR.length()));
351             String languageId = ParamUtil.getString(
352                 actionRequest, "languageId");
353 
354             JournalArticleServiceUtil.removeArticleLocale(
355                 groupId, articleId, version, languageId);
356         }
357     }
358 
359     protected JournalArticle updateArticle(ActionRequest actionRequest)
360         throws Exception {
361 
362         UploadPortletRequest uploadRequest = PortalUtil.getUploadPortletRequest(
363             actionRequest);
364 
365         String cmd = ParamUtil.getString(uploadRequest, Constants.CMD);
366 
367         long groupId = ParamUtil.getLong(uploadRequest, "groupId");
368 
369         String articleId = ParamUtil.getString(uploadRequest, "articleId");
370         boolean autoArticleId = ParamUtil.getBoolean(
371             uploadRequest, "autoArticleId");
372 
373         double version = ParamUtil.getDouble(uploadRequest, "version");
374         boolean incrementVersion = ParamUtil.getBoolean(
375             uploadRequest, "incrementVersion");
376 
377         String title = ParamUtil.getString(uploadRequest, "title");
378         String description = ParamUtil.getString(uploadRequest, "description");
379         String content = ParamUtil.getString(uploadRequest, "content");
380         String type = ParamUtil.getString(uploadRequest, "type");
381         String structureId = ParamUtil.getString(uploadRequest, "structureId");
382         String templateId = ParamUtil.getString(uploadRequest, "templateId");
383 
384         String lastLanguageId = ParamUtil.getString(
385             uploadRequest, "lastLanguageId");
386         String defaultLanguageId = ParamUtil.getString(
387             uploadRequest, "defaultLanguageId");
388 
389         int displayDateMonth = ParamUtil.getInteger(
390             uploadRequest, "displayDateMonth");
391         int displayDateDay = ParamUtil.getInteger(
392             uploadRequest, "displayDateDay");
393         int displayDateYear = ParamUtil.getInteger(
394             uploadRequest, "displayDateYear");
395         int displayDateHour = ParamUtil.getInteger(
396             uploadRequest, "displayDateHour");
397         int displayDateMinute = ParamUtil.getInteger(
398             uploadRequest, "displayDateMinute");
399         int displayDateAmPm = ParamUtil.getInteger(
400             uploadRequest, "displayDateAmPm");
401 
402         if (displayDateAmPm == Calendar.PM) {
403             displayDateHour += 12;
404         }
405 
406         int expirationDateMonth = ParamUtil.getInteger(
407             uploadRequest, "expirationDateMonth");
408         int expirationDateDay = ParamUtil.getInteger(
409             uploadRequest, "expirationDateDay");
410         int expirationDateYear = ParamUtil.getInteger(
411             uploadRequest, "expirationDateYear");
412         int expirationDateHour = ParamUtil.getInteger(
413             uploadRequest, "expirationDateHour");
414         int expirationDateMinute = ParamUtil.getInteger(
415             uploadRequest, "expirationDateMinute");
416         int expirationDateAmPm = ParamUtil.getInteger(
417             uploadRequest, "expirationDateAmPm");
418         boolean neverExpire = ParamUtil.getBoolean(
419             uploadRequest, "neverExpire");
420 
421         if (expirationDateAmPm == Calendar.PM) {
422             expirationDateHour += 12;
423         }
424 
425         int reviewDateMonth = ParamUtil.getInteger(
426             uploadRequest, "reviewDateMonth");
427         int reviewDateDay = ParamUtil.getInteger(
428             uploadRequest, "reviewDateDay");
429         int reviewDateYear = ParamUtil.getInteger(
430             uploadRequest, "reviewDateYear");
431         int reviewDateHour = ParamUtil.getInteger(
432             uploadRequest, "reviewDateHour");
433         int reviewDateMinute = ParamUtil.getInteger(
434             uploadRequest, "reviewDateMinute");
435         int reviewDateAmPm = ParamUtil.getInteger(
436             uploadRequest, "reviewDateAmPm");
437         boolean neverReview = ParamUtil.getBoolean(
438             uploadRequest, "neverReview");
439 
440         if (reviewDateAmPm == Calendar.PM) {
441             reviewDateHour += 12;
442         }
443 
444         boolean indexable = ParamUtil.getBoolean(uploadRequest, "indexable");
445 
446         boolean smallImage = ParamUtil.getBoolean(uploadRequest, "smallImage");
447         String smallImageURL = ParamUtil.getString(
448             uploadRequest, "smallImageURL");
449         File smallFile = uploadRequest.getFile("smallFile");
450 
451         Map<String, byte[]> images = getImages(uploadRequest);
452 
453         String articleURL = ParamUtil.getString(uploadRequest, "articleURL");
454 
455         ServiceContext serviceContext = ServiceContextFactory.getInstance(
456             JournalArticle.class.getName(), actionRequest);
457 
458         JournalArticle article = null;
459 
460         if (cmd.equals(Constants.ADD)) {
461             if (Validator.isNull(structureId)) {
462                 content = LocalizationUtil.updateLocalization(
463                     StringPool.BLANK, "static-content", content,
464                     lastLanguageId, defaultLanguageId, true);
465             }
466 
467             // Add article
468 
469             article = JournalArticleServiceUtil.addArticle(
470                 groupId, articleId, autoArticleId, title, description,
471                 content, type, structureId, templateId, displayDateMonth,
472                 displayDateDay, displayDateYear, displayDateHour,
473                 displayDateMinute, expirationDateMonth, expirationDateDay,
474                 expirationDateYear, expirationDateHour, expirationDateMinute,
475                 neverExpire, reviewDateMonth, reviewDateDay, reviewDateYear,
476                 reviewDateHour, reviewDateMinute, neverReview, indexable,
477                 smallImage, smallImageURL, smallFile, images, articleURL,
478                 serviceContext);
479 
480             AssetPublisherUtil.addAndStoreSelection(
481                 actionRequest, JournalArticle.class.getName(),
482                 article.getResourcePrimKey(), -1);
483         }
484         else {
485 
486             // Merge current content with new content
487 
488             JournalArticle curArticle = JournalArticleServiceUtil.getArticle(
489                 groupId, articleId, version);
490 
491             if (Validator.isNull(structureId)) {
492                 if (!curArticle.isTemplateDriven()) {
493                     content = LocalizationUtil.updateLocalization(
494                         curArticle.getContent(), "static-content", content,
495                         lastLanguageId, defaultLanguageId, true);
496                 }
497             }
498             else {
499                 if (curArticle.isTemplateDriven()) {
500                     JournalStructure structure =
501                         JournalStructureLocalServiceUtil.getStructure(
502                             groupId, structureId);
503 
504                     content = JournalUtil.mergeArticleContent(
505                         curArticle.getContent(), content);
506                     content = JournalUtil.removeOldContent(
507                         content, structure.getMergedXsd());
508                 }
509             }
510 
511             // Update article
512 
513             article = JournalArticleServiceUtil.updateArticle(
514                 groupId, articleId, version, incrementVersion, title,
515                 description, content, type, structureId, templateId,
516                 displayDateMonth, displayDateDay, displayDateYear,
517                 displayDateHour, displayDateMinute, expirationDateMonth,
518                 expirationDateDay, expirationDateYear, expirationDateHour,
519                 expirationDateMinute, neverExpire, reviewDateMonth,
520                 reviewDateDay, reviewDateYear, reviewDateHour, reviewDateMinute,
521                 neverReview, indexable, smallImage, smallImageURL, smallFile,
522                 images, articleURL, serviceContext);
523         }
524 
525         boolean approve = ParamUtil.getBoolean(uploadRequest, "approve");
526 
527         if (approve) {
528             article = JournalArticleServiceUtil.approveArticle(
529                 article.getGroupId(), article.getArticleId(),
530                 article.getVersion(), articleURL, serviceContext);
531         }
532 
533         // Recent articles
534 
535         JournalUtil.addRecentArticle(actionRequest, article);
536 
537         // Journal content
538 
539         String portletResource = ParamUtil.getString(
540             uploadRequest, "portletResource");
541 
542         if (Validator.isNotNull(portletResource)) {
543             PortletPreferences preferences =
544                 PortletPreferencesFactoryUtil.getPortletSetup(
545                     uploadRequest, portletResource);
546 
547             preferences.setValue(
548                 "group-id", String.valueOf(article.getGroupId()));
549             preferences.setValue("article-id", article.getArticleId());
550 
551             preferences.store();
552 
553             updateContentSearch(
554                 actionRequest, portletResource, article.getArticleId());
555         }
556 
557         return article;
558     }
559 
560     protected void updateContentSearch(
561             ActionRequest actionRequest, String portletResource,
562             String articleId)
563         throws Exception {
564 
565         ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
566             WebKeys.THEME_DISPLAY);
567 
568         Layout layout = themeDisplay.getLayout();
569 
570         JournalContentSearchLocalServiceUtil.updateContentSearch(
571             layout.getGroupId(), layout.isPrivateLayout(), layout.getLayoutId(),
572             portletResource, articleId);
573     }
574 
575 }