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