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 languageId = ParamUtil.getString(actionRequest, "languageId");
317 
318         String originalRedirect = ParamUtil.getString(
319             actionRequest, "originalRedirect");
320 
321         PortletURLImpl portletURL = new PortletURLImpl(
322             (ActionRequestImpl)actionRequest, portletConfig.getPortletName(),
323             themeDisplay.getPlid(), PortletRequest.RENDER_PHASE);
324 
325         portletURL.setWindowState(WindowState.MAXIMIZED);
326 
327         portletURL.setParameter("struts_action", "/journal/edit_article");
328         portletURL.setParameter(Constants.CMD, Constants.UPDATE, false);
329         portletURL.setParameter("redirect", redirect, false);
330         portletURL.setParameter("originalRedirect", originalRedirect, false);
331         portletURL.setParameter(
332             "groupId", String.valueOf(article.getGroupId()), false);
333         portletURL.setParameter("articleId", article.getArticleId(), false);
334         portletURL.setParameter(
335             "version", String.valueOf(article.getVersion()), false);
336         portletURL.setParameter("languageId", languageId, false);
337 
338         return portletURL.toString();
339     }
340 
341     protected void removeArticlesLocale(ActionRequest actionRequest)
342         throws Exception {
343 
344         long groupId = ParamUtil.getLong(actionRequest, "groupId");
345 
346         String[] removeArticleLocaleIds = StringUtil.split(
347             ParamUtil.getString(actionRequest, "deleteArticleIds"));
348 
349         for (int i = 0; i < removeArticleLocaleIds.length; i++) {
350             int pos = removeArticleLocaleIds[i].lastIndexOf(VERSION_SEPARATOR);
351 
352             String articleId = removeArticleLocaleIds[i].substring(0, pos);
353             double version = GetterUtil.getDouble(
354                 removeArticleLocaleIds[i].substring(
355                     pos + VERSION_SEPARATOR.length()));
356             String languageId = ParamUtil.getString(
357                 actionRequest, "languageId");
358 
359             JournalArticleServiceUtil.removeArticleLocale(
360                 groupId, articleId, version, languageId);
361         }
362     }
363 
364     protected JournalArticle updateArticle(ActionRequest actionRequest)
365         throws Exception {
366 
367         UploadPortletRequest uploadRequest = PortalUtil.getUploadPortletRequest(
368             actionRequest);
369 
370         String cmd = ParamUtil.getString(uploadRequest, Constants.CMD);
371 
372         long groupId = ParamUtil.getLong(uploadRequest, "groupId");
373 
374         String articleId = ParamUtil.getString(uploadRequest, "articleId");
375         boolean autoArticleId = ParamUtil.getBoolean(
376             uploadRequest, "autoArticleId");
377 
378         double version = ParamUtil.getDouble(uploadRequest, "version");
379         boolean incrementVersion = ParamUtil.getBoolean(
380             uploadRequest, "incrementVersion");
381 
382         String title = ParamUtil.getString(uploadRequest, "title");
383         String description = ParamUtil.getString(uploadRequest, "description");
384         String content = ParamUtil.getString(uploadRequest, "content");
385         String type = ParamUtil.getString(uploadRequest, "type");
386         String structureId = ParamUtil.getString(uploadRequest, "structureId");
387         String templateId = ParamUtil.getString(uploadRequest, "templateId");
388 
389         String lastLanguageId = ParamUtil.getString(
390             uploadRequest, "lastLanguageId");
391         String defaultLanguageId = ParamUtil.getString(
392             uploadRequest, "defaultLanguageId");
393 
394         int displayDateMonth = ParamUtil.getInteger(
395             uploadRequest, "displayDateMonth");
396         int displayDateDay = ParamUtil.getInteger(
397             uploadRequest, "displayDateDay");
398         int displayDateYear = ParamUtil.getInteger(
399             uploadRequest, "displayDateYear");
400         int displayDateHour = ParamUtil.getInteger(
401             uploadRequest, "displayDateHour");
402         int displayDateMinute = ParamUtil.getInteger(
403             uploadRequest, "displayDateMinute");
404         int displayDateAmPm = ParamUtil.getInteger(
405             uploadRequest, "displayDateAmPm");
406 
407         if (displayDateAmPm == Calendar.PM) {
408             displayDateHour += 12;
409         }
410 
411         int expirationDateMonth = ParamUtil.getInteger(
412             uploadRequest, "expirationDateMonth");
413         int expirationDateDay = ParamUtil.getInteger(
414             uploadRequest, "expirationDateDay");
415         int expirationDateYear = ParamUtil.getInteger(
416             uploadRequest, "expirationDateYear");
417         int expirationDateHour = ParamUtil.getInteger(
418             uploadRequest, "expirationDateHour");
419         int expirationDateMinute = ParamUtil.getInteger(
420             uploadRequest, "expirationDateMinute");
421         int expirationDateAmPm = ParamUtil.getInteger(
422             uploadRequest, "expirationDateAmPm");
423         boolean neverExpire = ParamUtil.getBoolean(
424             uploadRequest, "neverExpire");
425 
426         if (expirationDateAmPm == Calendar.PM) {
427             expirationDateHour += 12;
428         }
429 
430         int reviewDateMonth = ParamUtil.getInteger(
431             uploadRequest, "reviewDateMonth");
432         int reviewDateDay = ParamUtil.getInteger(
433             uploadRequest, "reviewDateDay");
434         int reviewDateYear = ParamUtil.getInteger(
435             uploadRequest, "reviewDateYear");
436         int reviewDateHour = ParamUtil.getInteger(
437             uploadRequest, "reviewDateHour");
438         int reviewDateMinute = ParamUtil.getInteger(
439             uploadRequest, "reviewDateMinute");
440         int reviewDateAmPm = ParamUtil.getInteger(
441             uploadRequest, "reviewDateAmPm");
442         boolean neverReview = ParamUtil.getBoolean(
443             uploadRequest, "neverReview");
444 
445         if (reviewDateAmPm == Calendar.PM) {
446             reviewDateHour += 12;
447         }
448 
449         boolean indexable = ParamUtil.getBoolean(uploadRequest, "indexable");
450 
451         boolean smallImage = ParamUtil.getBoolean(uploadRequest, "smallImage");
452         String smallImageURL = ParamUtil.getString(
453             uploadRequest, "smallImageURL");
454         File smallFile = uploadRequest.getFile("smallFile");
455 
456         Map<String, byte[]> images = getImages(uploadRequest);
457 
458         String articleURL = ParamUtil.getString(uploadRequest, "articleURL");
459 
460         ServiceContext serviceContext = ServiceContextFactory.getInstance(
461             JournalArticle.class.getName(), actionRequest);
462 
463         JournalArticle article = null;
464 
465         if (cmd.equals(Constants.ADD)) {
466             if (Validator.isNull(structureId)) {
467                 content = LocalizationUtil.updateLocalization(
468                     StringPool.BLANK, "static-content", content,
469                     lastLanguageId, defaultLanguageId, true);
470             }
471 
472             // Add article
473 
474             article = JournalArticleServiceUtil.addArticle(
475                 groupId, articleId, autoArticleId, title, description,
476                 content, type, structureId, templateId, displayDateMonth,
477                 displayDateDay, displayDateYear, displayDateHour,
478                 displayDateMinute, expirationDateMonth, expirationDateDay,
479                 expirationDateYear, expirationDateHour, expirationDateMinute,
480                 neverExpire, reviewDateMonth, reviewDateDay, reviewDateYear,
481                 reviewDateHour, reviewDateMinute, neverReview, indexable,
482                 smallImage, smallImageURL, smallFile, images, articleURL,
483                 serviceContext);
484 
485             AssetPublisherUtil.addAndStoreSelection(
486                 actionRequest, JournalArticle.class.getName(),
487                 article.getResourcePrimKey(), -1);
488         }
489         else {
490 
491             // Merge current content with new content
492 
493             JournalArticle curArticle = JournalArticleServiceUtil.getArticle(
494                 groupId, articleId, version);
495 
496             if (Validator.isNull(structureId)) {
497                 if (!curArticle.isTemplateDriven()) {
498                     content = LocalizationUtil.updateLocalization(
499                         curArticle.getContent(), "static-content", content,
500                         lastLanguageId, defaultLanguageId, true);
501                 }
502             }
503             else {
504                 if (curArticle.isTemplateDriven()) {
505                     JournalStructure structure =
506                         JournalStructureLocalServiceUtil.getStructure(
507                             groupId, structureId);
508 
509                     content = JournalUtil.mergeArticleContent(
510                         curArticle.getContent(), content);
511                     content = JournalUtil.removeOldContent(
512                         content, structure.getMergedXsd());
513                 }
514             }
515 
516             // Update article
517 
518             article = JournalArticleServiceUtil.updateArticle(
519                 groupId, articleId, version, incrementVersion, title,
520                 description, content, type, structureId, templateId,
521                 displayDateMonth, displayDateDay, displayDateYear,
522                 displayDateHour, displayDateMinute, expirationDateMonth,
523                 expirationDateDay, expirationDateYear, expirationDateHour,
524                 expirationDateMinute, neverExpire, reviewDateMonth,
525                 reviewDateDay, reviewDateYear, reviewDateHour, reviewDateMinute,
526                 neverReview, indexable, smallImage, smallImageURL, smallFile,
527                 images, articleURL, serviceContext);
528         }
529 
530         boolean approve = ParamUtil.getBoolean(uploadRequest, "approve");
531 
532         if (approve) {
533             article = JournalArticleServiceUtil.approveArticle(
534                 article.getGroupId(), article.getArticleId(),
535                 article.getVersion(), articleURL, serviceContext);
536         }
537 
538         // Recent articles
539 
540         JournalUtil.addRecentArticle(actionRequest, article);
541 
542         // Journal content
543 
544         String portletResource = ParamUtil.getString(
545             uploadRequest, "portletResource");
546 
547         if (Validator.isNotNull(portletResource)) {
548             PortletPreferences preferences =
549                 PortletPreferencesFactoryUtil.getPortletSetup(
550                     uploadRequest, portletResource);
551 
552             preferences.setValue(
553                 "group-id", String.valueOf(article.getGroupId()));
554             preferences.setValue("article-id", article.getArticleId());
555 
556             preferences.store();
557 
558             updateContentSearch(
559                 actionRequest, portletResource, article.getArticleId());
560         }
561 
562         return article;
563     }
564 
565     protected void updateContentSearch(
566             ActionRequest actionRequest, String portletResource,
567             String articleId)
568         throws Exception {
569 
570         ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
571             WebKeys.THEME_DISPLAY);
572 
573         Layout layout = themeDisplay.getLayout();
574 
575         JournalContentSearchLocalServiceUtil.updateContentSearch(
576             layout.getGroupId(), layout.isPrivateLayout(), layout.getLayoutId(),
577             portletResource, articleId);
578     }
579 
580 }