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