1   /**
2    * Copyright (c) 2000-2008 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.journal.ArticleContentException;
44  import com.liferay.portlet.journal.ArticleDisplayDateException;
45  import com.liferay.portlet.journal.ArticleExpirationDateException;
46  import com.liferay.portlet.journal.ArticleIdException;
47  import com.liferay.portlet.journal.ArticleSmallImageNameException;
48  import com.liferay.portlet.journal.ArticleSmallImageSizeException;
49  import com.liferay.portlet.journal.ArticleTitleException;
50  import com.liferay.portlet.journal.ArticleTypeException;
51  import com.liferay.portlet.journal.DuplicateArticleIdException;
52  import com.liferay.portlet.journal.NoSuchArticleException;
53  import com.liferay.portlet.journal.NoSuchStructureException;
54  import com.liferay.portlet.journal.NoSuchTemplateException;
55  import com.liferay.portlet.journal.model.JournalArticle;
56  import com.liferay.portlet.journal.model.JournalStructure;
57  import com.liferay.portlet.journal.service.JournalArticleServiceUtil;
58  import com.liferay.portlet.journal.service.JournalContentSearchLocalServiceUtil;
59  import com.liferay.portlet.journal.service.JournalStructureLocalServiceUtil;
60  import com.liferay.portlet.journal.util.JournalUtil;
61  import com.liferay.portlet.taggedcontent.util.AssetPublisherUtil;
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         Layout layout = (Layout)actionRequest.getAttribute(WebKeys.LAYOUT);
208 
209         long groupId = ParamUtil.getLong(actionRequest, "groupId");
210         String articleId = ParamUtil.getString(actionRequest, "articleId");
211         double version = ParamUtil.getDouble(actionRequest, "version");
212 
213         String articleURL = ParamUtil.getString(actionRequest, "articleURL");
214 
215         JournalArticleServiceUtil.approveArticle(
216             groupId, articleId, version, layout.getPlid(), articleURL,
217             actionRequest.getPreferences());
218     }
219 
220     protected void deleteArticles(ActionRequest actionRequest)
221         throws Exception {
222 
223         long groupId = ParamUtil.getLong(actionRequest, "groupId");
224 
225         String[] deleteArticleIds = StringUtil.split(
226             ParamUtil.getString(actionRequest, "deleteArticleIds"));
227 
228         for (int i = 0; i < deleteArticleIds.length; i++) {
229             int pos = deleteArticleIds[i].lastIndexOf(VERSION_SEPARATOR);
230 
231             String articleId = deleteArticleIds[i].substring(0, pos);
232             double version = GetterUtil.getDouble(
233                 deleteArticleIds[i].substring(
234                     pos + VERSION_SEPARATOR.length()));
235 
236             String articleURL = ParamUtil.getString(
237                 actionRequest, "articleURL");
238 
239             JournalArticleServiceUtil.deleteArticle(
240                 groupId, articleId, version, articleURL,
241                 actionRequest.getPreferences());
242 
243             JournalUtil.removeRecentArticle(actionRequest, deleteArticleIds[i]);
244         }
245     }
246 
247     protected void expireArticles(ActionRequest actionRequest)
248         throws Exception {
249 
250         long groupId = ParamUtil.getLong(actionRequest, "groupId");
251 
252         String[] expireArticleIds = StringUtil.split(
253             ParamUtil.getString(actionRequest, "expireArticleIds"));
254 
255         for (int i = 0; i < expireArticleIds.length; i++) {
256             int pos = expireArticleIds[i].lastIndexOf(VERSION_SEPARATOR);
257 
258             String articleId = expireArticleIds[i].substring(0, pos);
259             double version = GetterUtil.getDouble(
260                 expireArticleIds[i].substring(
261                     pos + VERSION_SEPARATOR.length()));
262 
263             String articleURL = ParamUtil.getString(
264                 actionRequest, "articleURL");
265 
266             JournalArticleServiceUtil.expireArticle(
267                 groupId, articleId, version, articleURL,
268                 actionRequest.getPreferences());
269         }
270     }
271 
272     protected Map<String, byte[]> getImages(UploadPortletRequest uploadRequest)
273         throws Exception {
274 
275         Map<String, byte[]> images = new HashMap<String, byte[]>();
276 
277         String imagePrefix = "structure_image_";
278 
279         Enumeration<String> enu = uploadRequest.getParameterNames();
280 
281         while (enu.hasMoreElements()) {
282             String name = enu.nextElement();
283 
284             if (name.startsWith(imagePrefix)) {
285                 File file = uploadRequest.getFile(name);
286                 byte[] bytes = FileUtil.getBytes(file);
287 
288                 if ((bytes != null) && (bytes.length > 0)) {
289                     name = name.substring(imagePrefix.length(), name.length());
290 
291                     images.put(name, bytes);
292                 }
293             }
294         }
295 
296         return images;
297     }
298 
299     protected String getSaveAndContinueRedirect(
300             PortletConfig portletConfig, ActionRequest actionRequest,
301             JournalArticle article, String redirect)
302         throws Exception {
303 
304         ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
305             WebKeys.THEME_DISPLAY);
306 
307         String originalRedirect = ParamUtil.getString(
308             actionRequest, "originalRedirect");
309 
310         PortletURLImpl portletURL = new PortletURLImpl(
311             (ActionRequestImpl)actionRequest, portletConfig.getPortletName(),
312             themeDisplay.getPlid(), PortletRequest.RENDER_PHASE);
313 
314         portletURL.setWindowState(WindowState.MAXIMIZED);
315 
316         portletURL.setParameter("struts_action", "/journal/edit_article");
317         portletURL.setParameter(Constants.CMD, Constants.UPDATE, false);
318         portletURL.setParameter("redirect", redirect, false);
319         portletURL.setParameter("originalRedirect", originalRedirect, false);
320         portletURL.setParameter(
321             "groupId", String.valueOf(article.getGroupId()), false);
322         portletURL.setParameter("articleId", article.getArticleId(), false);
323         portletURL.setParameter(
324             "version", String.valueOf(article.getVersion()), false);
325 
326         return portletURL.toString();
327     }
328 
329     protected void removeArticlesLocale(ActionRequest actionRequest)
330         throws Exception {
331 
332         long groupId = ParamUtil.getLong(actionRequest, "groupId");
333 
334         String[] removeArticleLocaleIds = StringUtil.split(
335             ParamUtil.getString(actionRequest, "deleteArticleIds"));
336 
337         for (int i = 0; i < removeArticleLocaleIds.length; i++) {
338             int pos = removeArticleLocaleIds[i].lastIndexOf(VERSION_SEPARATOR);
339 
340             String articleId = removeArticleLocaleIds[i].substring(0, pos);
341             double version = GetterUtil.getDouble(
342                 removeArticleLocaleIds[i].substring(
343                     pos + VERSION_SEPARATOR.length()));
344             String languageId = ParamUtil.getString(
345                 actionRequest, "languageId");
346 
347             JournalArticleServiceUtil.removeArticleLocale(
348                 groupId, articleId, version, languageId);
349         }
350     }
351 
352     protected JournalArticle updateArticle(ActionRequest actionRequest)
353         throws Exception {
354 
355         UploadPortletRequest uploadRequest = PortalUtil.getUploadPortletRequest(
356             actionRequest);
357 
358         String cmd = ParamUtil.getString(uploadRequest, Constants.CMD);
359 
360         Layout layout = (Layout)uploadRequest.getAttribute(WebKeys.LAYOUT);
361 
362         long groupId = ParamUtil.getLong(uploadRequest, "groupId");
363 
364         String articleId = ParamUtil.getString(uploadRequest, "articleId");
365         boolean autoArticleId = ParamUtil.getBoolean(
366             uploadRequest, "autoArticleId");
367 
368         double version = ParamUtil.getDouble(uploadRequest, "version");
369         boolean incrementVersion = ParamUtil.getBoolean(
370             uploadRequest, "incrementVersion");
371 
372         String title = ParamUtil.getString(uploadRequest, "title");
373         String description = ParamUtil.getString(uploadRequest, "description");
374         String content = ParamUtil.getString(uploadRequest, "content");
375         String type = ParamUtil.getString(uploadRequest, "type");
376         String structureId = ParamUtil.getString(uploadRequest, "structureId");
377         String templateId = ParamUtil.getString(uploadRequest, "templateId");
378 
379         String lastLanguageId = ParamUtil.getString(
380             uploadRequest, "lastLanguageId");
381         String defaultLanguageId = ParamUtil.getString(
382             uploadRequest, "defaultLanguageId");
383 
384         int displayDateMonth = ParamUtil.getInteger(
385             uploadRequest, "displayDateMonth");
386         int displayDateDay = ParamUtil.getInteger(
387             uploadRequest, "displayDateDay");
388         int displayDateYear = ParamUtil.getInteger(
389             uploadRequest, "displayDateYear");
390         int displayDateHour = ParamUtil.getInteger(
391             uploadRequest, "displayDateHour");
392         int displayDateMinute = ParamUtil.getInteger(
393             uploadRequest, "displayDateMinute");
394         int displayDateAmPm = ParamUtil.getInteger(
395             uploadRequest, "displayDateAmPm");
396 
397         if (displayDateAmPm == Calendar.PM) {
398             displayDateHour += 12;
399         }
400 
401         int expirationDateMonth = ParamUtil.getInteger(
402             uploadRequest, "expirationDateMonth");
403         int expirationDateDay = ParamUtil.getInteger(
404             uploadRequest, "expirationDateDay");
405         int expirationDateYear = ParamUtil.getInteger(
406             uploadRequest, "expirationDateYear");
407         int expirationDateHour = ParamUtil.getInteger(
408             uploadRequest, "expirationDateHour");
409         int expirationDateMinute = ParamUtil.getInteger(
410             uploadRequest, "expirationDateMinute");
411         int expirationDateAmPm = ParamUtil.getInteger(
412             uploadRequest, "expirationDateAmPm");
413         boolean neverExpire = ParamUtil.getBoolean(
414             uploadRequest, "neverExpire");
415 
416         if (expirationDateAmPm == Calendar.PM) {
417             expirationDateHour += 12;
418         }
419 
420         int reviewDateMonth = ParamUtil.getInteger(
421             uploadRequest, "reviewDateMonth");
422         int reviewDateDay = ParamUtil.getInteger(
423             uploadRequest, "reviewDateDay");
424         int reviewDateYear = ParamUtil.getInteger(
425             uploadRequest, "reviewDateYear");
426         int reviewDateHour = ParamUtil.getInteger(
427             uploadRequest, "reviewDateHour");
428         int reviewDateMinute = ParamUtil.getInteger(
429             uploadRequest, "reviewDateMinute");
430         int reviewDateAmPm = ParamUtil.getInteger(
431             uploadRequest, "reviewDateAmPm");
432         boolean neverReview = ParamUtil.getBoolean(
433             uploadRequest, "neverReview");
434 
435         if (reviewDateAmPm == Calendar.PM) {
436             reviewDateHour += 12;
437         }
438 
439         boolean indexable = ParamUtil.getBoolean(uploadRequest, "indexable");
440 
441         boolean smallImage = ParamUtil.getBoolean(uploadRequest, "smallImage");
442         String smallImageURL = ParamUtil.getString(
443             uploadRequest, "smallImageURL");
444         File smallFile = uploadRequest.getFile("smallFile");
445 
446         Map<String, byte[]> images = getImages(uploadRequest);
447 
448         String articleURL = ParamUtil.getString(uploadRequest, "articleURL");
449 
450         String[] tagsEntries = StringUtil.split(
451             ParamUtil.getString(uploadRequest, "tagsEntries"));
452 
453         String[] communityPermissions = uploadRequest.getParameterValues(
454             "communityPermissions");
455         String[] guestPermissions = uploadRequest.getParameterValues(
456             "guestPermissions");
457 
458         boolean approve = ParamUtil.getBoolean(uploadRequest, "approve");
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                 articleId, autoArticleId, layout.getPlid(), 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                 actionRequest.getPreferences(), tagsEntries,
481                 communityPermissions, guestPermissions);
482 
483             AssetPublisherUtil.addAndStoreSelection(
484                 actionRequest, JournalArticle.class.getName(),
485                 article.getResourcePrimKey(), -1);
486         }
487         else {
488 
489             // Merge current content with new content
490 
491             JournalArticle curArticle = JournalArticleServiceUtil.getArticle(
492                 groupId, articleId, version);
493 
494             if (Validator.isNull(structureId)) {
495                 if (!curArticle.isTemplateDriven()) {
496                     content = LocalizationUtil.updateLocalization(
497                         curArticle.getContent(), "static-content", content,
498                         lastLanguageId, defaultLanguageId, true);
499                 }
500             }
501             else {
502                 if (curArticle.isTemplateDriven()) {
503                     JournalStructure structure =
504                         JournalStructureLocalServiceUtil.getStructure(
505                             groupId, structureId);
506 
507                     content = JournalUtil.mergeLocaleContent(
508                         curArticle.getContent(), content, structure.getXsd());
509                     content = JournalUtil.removeOldContent(
510                         content, structure.getXsd());
511                 }
512             }
513 
514             // Update article
515 
516             article = JournalArticleServiceUtil.updateArticle(
517                 groupId, articleId, version, incrementVersion, title,
518                 description, content, type, structureId, templateId,
519                 displayDateMonth, displayDateDay, displayDateYear,
520                 displayDateHour, displayDateMinute, expirationDateMonth,
521                 expirationDateDay, expirationDateYear, expirationDateHour,
522                 expirationDateMinute, neverExpire, reviewDateMonth,
523                 reviewDateDay, reviewDateYear, reviewDateHour, reviewDateMinute,
524                 neverReview, indexable, smallImage, smallImageURL, smallFile,
525                 images, articleURL, actionRequest.getPreferences(),
526                 tagsEntries);
527         }
528 
529         if (approve) {
530             article = JournalArticleServiceUtil.approveArticle(
531                 article.getGroupId(), article.getArticleId(),
532                 article.getVersion(), layout.getPlid(), articleURL,
533                 actionRequest.getPreferences());
534         }
535 
536         // Recent articles
537 
538         JournalUtil.addRecentArticle(actionRequest, article);
539 
540         // Journal content
541 
542         String portletResource = ParamUtil.getString(
543             uploadRequest, "portletResource");
544 
545         if (Validator.isNotNull(portletResource)) {
546             PortletPreferences prefs =
547                 PortletPreferencesFactoryUtil.getPortletSetup(
548                     uploadRequest, portletResource);
549 
550             prefs.setValue("group-id", String.valueOf(article.getGroupId()));
551             prefs.setValue("article-id", article.getArticleId());
552 
553             prefs.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 }