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