1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    *
5    *
6    *
7    * The contents of this file are subject to the terms of the Liferay Enterprise
8    * Subscription License ("License"). You may not use this file except in
9    * compliance with the License. You can obtain a copy of the License by
10   * contacting Liferay, Inc. See the License for the specific language governing
11   * permissions and limitations under the License, including but not limited to
12   * distribution rights 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  public class EditArticleAction extends PortletAction {
91  
92      public static final String VERSION_SEPARATOR = "_version_";
93  
94      public void processAction(
95              ActionMapping mapping, ActionForm form, PortletConfig portletConfig,
96              ActionRequest actionRequest, ActionResponse actionResponse)
97          throws Exception {
98  
99          String cmd = ParamUtil.getString(actionRequest, Constants.CMD);
100 
101         JournalArticle article = null;
102 
103         try {
104             if (cmd.equals(Constants.ADD) || cmd.equals(Constants.UPDATE)) {
105                 article = updateArticle(actionRequest);
106             }
107             else if (cmd.equals(Constants.APPROVE)) {
108                 approveArticle(actionRequest);
109             }
110             else if (cmd.equals(Constants.DELETE)) {
111                 deleteArticles(actionRequest);
112             }
113             else if (cmd.equals(Constants.EXPIRE)) {
114                 expireArticles(actionRequest);
115             }
116             else if (cmd.equals("removeArticlesLocale")) {
117                 removeArticlesLocale(actionRequest);
118             }
119 
120             if (Validator.isNotNull(cmd)) {
121                 String redirect = ParamUtil.getString(
122                     actionRequest, "redirect");
123 
124                 if (article != null) {
125                     boolean saveAndContinue = ParamUtil.getBoolean(
126                         actionRequest, "saveAndContinue");
127 
128                     if (saveAndContinue) {
129                         redirect = getSaveAndContinueRedirect(
130                             portletConfig, actionRequest, article, redirect);
131                     }
132                 }
133 
134                 sendRedirect(actionRequest, actionResponse, redirect);
135             }
136         }
137         catch (Exception e) {
138             if (e instanceof NoSuchArticleException ||
139                 e instanceof NoSuchStructureException ||
140                 e instanceof NoSuchTemplateException ||
141                 e instanceof PrincipalException) {
142 
143                 SessionErrors.add(actionRequest, e.getClass().getName());
144 
145                 setForward(actionRequest, "portlet.journal.error");
146             }
147             else if (e instanceof ArticleContentException ||
148                      e instanceof ArticleDisplayDateException ||
149                      e instanceof ArticleExpirationDateException ||
150                      e instanceof ArticleIdException ||
151                      e instanceof ArticleSmallImageNameException ||
152                      e instanceof ArticleSmallImageSizeException ||
153                      e instanceof ArticleTitleException ||
154                      e instanceof ArticleTypeException ||
155                      e instanceof DuplicateArticleIdException) {
156 
157                 SessionErrors.add(actionRequest, e.getClass().getName());
158             }
159             else if (e instanceof TagsEntryException) {
160                 SessionErrors.add(actionRequest, e.getClass().getName(), e);
161             }
162             else {
163                 throw e;
164             }
165         }
166     }
167 
168     public ActionForward render(
169             ActionMapping mapping, ActionForm form, PortletConfig portletConfig,
170             RenderRequest renderRequest, RenderResponse renderResponse)
171         throws Exception {
172 
173         try {
174             String cmd = ParamUtil.getString(renderRequest, Constants.CMD);
175 
176             if (!cmd.equals(Constants.ADD)) {
177                 ActionUtil.getArticle(renderRequest);
178             }
179         }
180         catch (NoSuchArticleException nsse) {
181 
182             // Let this slide because the user can manually input a article id
183             // for a new article that does not yet exist.
184 
185         }
186         catch (Exception e) {
187             if (//e instanceof NoSuchArticleException ||
188                 e instanceof PrincipalException) {
189 
190                 SessionErrors.add(renderRequest, e.getClass().getName());
191 
192                 return mapping.findForward("portlet.journal.error");
193             }
194             else {
195                 throw e;
196             }
197         }
198 
199         return mapping.findForward(
200             getForward(renderRequest, "portlet.journal.edit_article"));
201     }
202 
203     protected void approveArticle(ActionRequest actionRequest)
204         throws Exception {
205 
206         Layout layout = (Layout)actionRequest.getAttribute(WebKeys.LAYOUT);
207 
208         long groupId = ParamUtil.getLong(actionRequest, "groupId");
209         String articleId = ParamUtil.getString(actionRequest, "articleId");
210         double version = ParamUtil.getDouble(actionRequest, "version");
211 
212         String articleURL = ParamUtil.getString(actionRequest, "articleURL");
213 
214         JournalArticleServiceUtil.approveArticle(
215             groupId, articleId, version, layout.getPlid(), articleURL,
216             actionRequest.getPreferences());
217     }
218 
219     protected void deleteArticles(ActionRequest actionRequest)
220         throws Exception {
221 
222         long groupId = ParamUtil.getLong(actionRequest, "groupId");
223 
224         String[] deleteArticleIds = StringUtil.split(
225             ParamUtil.getString(actionRequest, "deleteArticleIds"));
226 
227         for (int i = 0; i < deleteArticleIds.length; i++) {
228             int pos = deleteArticleIds[i].lastIndexOf(VERSION_SEPARATOR);
229 
230             String articleId = deleteArticleIds[i].substring(0, pos);
231             double version = GetterUtil.getDouble(
232                 deleteArticleIds[i].substring(
233                     pos + VERSION_SEPARATOR.length()));
234 
235             String articleURL = ParamUtil.getString(
236                 actionRequest, "articleURL");
237 
238             JournalArticleServiceUtil.deleteArticle(
239                 groupId, articleId, version, articleURL,
240                 actionRequest.getPreferences());
241 
242             JournalUtil.removeRecentArticle(actionRequest, deleteArticleIds[i]);
243         }
244     }
245 
246     protected void expireArticles(ActionRequest actionRequest)
247         throws Exception {
248 
249         long groupId = ParamUtil.getLong(actionRequest, "groupId");
250 
251         String[] expireArticleIds = StringUtil.split(
252             ParamUtil.getString(actionRequest, "expireArticleIds"));
253 
254         for (int i = 0; i < expireArticleIds.length; i++) {
255             int pos = expireArticleIds[i].lastIndexOf(VERSION_SEPARATOR);
256 
257             String articleId = expireArticleIds[i].substring(0, pos);
258             double version = GetterUtil.getDouble(
259                 expireArticleIds[i].substring(
260                     pos + VERSION_SEPARATOR.length()));
261 
262             String articleURL = ParamUtil.getString(
263                 actionRequest, "articleURL");
264 
265             JournalArticleServiceUtil.expireArticle(
266                 groupId, articleId, version, articleURL,
267                 actionRequest.getPreferences());
268         }
269     }
270 
271     protected Map<String, byte[]> getImages(UploadPortletRequest uploadRequest)
272         throws Exception {
273 
274         Map<String, byte[]> images = new HashMap<String, byte[]>();
275 
276         String imagePrefix = "structure_image_";
277 
278         Enumeration<String> enu = uploadRequest.getParameterNames();
279 
280         while (enu.hasMoreElements()) {
281             String name = enu.nextElement();
282 
283             if (name.startsWith(imagePrefix)) {
284                 File file = uploadRequest.getFile(name);
285                 byte[] bytes = FileUtil.getBytes(file);
286 
287                 if ((bytes != null) && (bytes.length > 0)) {
288                     name = name.substring(imagePrefix.length(), name.length());
289 
290                     images.put(name, bytes);
291                 }
292             }
293         }
294 
295         return images;
296     }
297 
298     protected String getSaveAndContinueRedirect(
299             PortletConfig portletConfig, ActionRequest actionRequest,
300             JournalArticle article, String redirect)
301         throws Exception {
302 
303         ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
304             WebKeys.THEME_DISPLAY);
305 
306         String originalRedirect = ParamUtil.getString(
307             actionRequest, "originalRedirect");
308 
309         PortletURLImpl portletURL = new PortletURLImpl(
310             (ActionRequestImpl)actionRequest, portletConfig.getPortletName(),
311             themeDisplay.getPlid(), PortletRequest.RENDER_PHASE);
312 
313         portletURL.setWindowState(WindowState.MAXIMIZED);
314 
315         portletURL.setParameter("struts_action", "/journal/edit_article");
316         portletURL.setParameter(Constants.CMD, Constants.UPDATE, false);
317         portletURL.setParameter("redirect", redirect, false);
318         portletURL.setParameter("originalRedirect", originalRedirect, false);
319         portletURL.setParameter(
320             "groupId", String.valueOf(article.getGroupId()), false);
321         portletURL.setParameter("articleId", article.getArticleId(), false);
322         portletURL.setParameter(
323             "version", String.valueOf(article.getVersion()), false);
324 
325         return portletURL.toString();
326     }
327 
328     protected void removeArticlesLocale(ActionRequest actionRequest)
329         throws Exception {
330 
331         long groupId = ParamUtil.getLong(actionRequest, "groupId");
332 
333         String[] removeArticleLocaleIds = StringUtil.split(
334             ParamUtil.getString(actionRequest, "deleteArticleIds"));
335 
336         for (int i = 0; i < removeArticleLocaleIds.length; i++) {
337             int pos = removeArticleLocaleIds[i].lastIndexOf(VERSION_SEPARATOR);
338 
339             String articleId = removeArticleLocaleIds[i].substring(0, pos);
340             double version = GetterUtil.getDouble(
341                 removeArticleLocaleIds[i].substring(
342                     pos + VERSION_SEPARATOR.length()));
343             String languageId = ParamUtil.getString(
344                 actionRequest, "languageId");
345 
346             JournalArticleServiceUtil.removeArticleLocale(
347                 groupId, articleId, version, languageId);
348         }
349     }
350 
351     protected JournalArticle updateArticle(ActionRequest actionRequest)
352         throws Exception {
353 
354         UploadPortletRequest uploadRequest = PortalUtil.getUploadPortletRequest(
355             actionRequest);
356 
357         String cmd = ParamUtil.getString(uploadRequest, Constants.CMD);
358 
359         Layout layout = (Layout)uploadRequest.getAttribute(WebKeys.LAYOUT);
360 
361         long groupId = ParamUtil.getLong(uploadRequest, "groupId");
362 
363         String articleId = ParamUtil.getString(uploadRequest, "articleId");
364         boolean autoArticleId = ParamUtil.getBoolean(
365             uploadRequest, "autoArticleId");
366 
367         double version = ParamUtil.getDouble(uploadRequest, "version");
368         boolean incrementVersion = ParamUtil.getBoolean(
369             uploadRequest, "incrementVersion");
370 
371         String title = ParamUtil.getString(uploadRequest, "title");
372         String description = ParamUtil.getString(uploadRequest, "description");
373         String content = ParamUtil.getString(uploadRequest, "content");
374         String type = ParamUtil.getString(uploadRequest, "type");
375         String structureId = ParamUtil.getString(uploadRequest, "structureId");
376         String templateId = ParamUtil.getString(uploadRequest, "templateId");
377 
378         String lastLanguageId = ParamUtil.getString(
379             uploadRequest, "lastLanguageId");
380         String defaultLanguageId = ParamUtil.getString(
381             uploadRequest, "defaultLanguageId");
382 
383         int displayDateMonth = ParamUtil.getInteger(
384             uploadRequest, "displayDateMonth");
385         int displayDateDay = ParamUtil.getInteger(
386             uploadRequest, "displayDateDay");
387         int displayDateYear = ParamUtil.getInteger(
388             uploadRequest, "displayDateYear");
389         int displayDateHour = ParamUtil.getInteger(
390             uploadRequest, "displayDateHour");
391         int displayDateMinute = ParamUtil.getInteger(
392             uploadRequest, "displayDateMinute");
393         int displayDateAmPm = ParamUtil.getInteger(
394             uploadRequest, "displayDateAmPm");
395 
396         if (displayDateAmPm == Calendar.PM) {
397             displayDateHour += 12;
398         }
399 
400         int expirationDateMonth = ParamUtil.getInteger(
401             uploadRequest, "expirationDateMonth");
402         int expirationDateDay = ParamUtil.getInteger(
403             uploadRequest, "expirationDateDay");
404         int expirationDateYear = ParamUtil.getInteger(
405             uploadRequest, "expirationDateYear");
406         int expirationDateHour = ParamUtil.getInteger(
407             uploadRequest, "expirationDateHour");
408         int expirationDateMinute = ParamUtil.getInteger(
409             uploadRequest, "expirationDateMinute");
410         int expirationDateAmPm = ParamUtil.getInteger(
411             uploadRequest, "expirationDateAmPm");
412         boolean neverExpire = ParamUtil.getBoolean(
413             uploadRequest, "neverExpire");
414 
415         if (expirationDateAmPm == Calendar.PM) {
416             expirationDateHour += 12;
417         }
418 
419         int reviewDateMonth = ParamUtil.getInteger(
420             uploadRequest, "reviewDateMonth");
421         int reviewDateDay = ParamUtil.getInteger(
422             uploadRequest, "reviewDateDay");
423         int reviewDateYear = ParamUtil.getInteger(
424             uploadRequest, "reviewDateYear");
425         int reviewDateHour = ParamUtil.getInteger(
426             uploadRequest, "reviewDateHour");
427         int reviewDateMinute = ParamUtil.getInteger(
428             uploadRequest, "reviewDateMinute");
429         int reviewDateAmPm = ParamUtil.getInteger(
430             uploadRequest, "reviewDateAmPm");
431         boolean neverReview = ParamUtil.getBoolean(
432             uploadRequest, "neverReview");
433 
434         if (reviewDateAmPm == Calendar.PM) {
435             reviewDateHour += 12;
436         }
437 
438         boolean indexable = ParamUtil.getBoolean(uploadRequest, "indexable");
439 
440         boolean smallImage = ParamUtil.getBoolean(uploadRequest, "smallImage");
441         String smallImageURL = ParamUtil.getString(
442             uploadRequest, "smallImageURL");
443         File smallFile = uploadRequest.getFile("smallFile");
444 
445         Map<String, byte[]> images = getImages(uploadRequest);
446 
447         String articleURL = ParamUtil.getString(uploadRequest, "articleURL");
448 
449         String[] tagsEntries = StringUtil.split(
450             ParamUtil.getString(uploadRequest, "tagsEntries"));
451 
452         String[] communityPermissions = PortalUtil.getCommunityPermissions(
453             uploadRequest);
454         String[] guestPermissions = PortalUtil.getGuestPermissions(
455             uploadRequest);
456 
457         boolean approve = ParamUtil.getBoolean(uploadRequest, "approve");
458 
459         JournalArticle article = null;
460 
461         if (cmd.equals(Constants.ADD)) {
462             if (Validator.isNull(structureId)) {
463                 content = LocalizationUtil.updateLocalization(
464                     StringPool.BLANK, "static-content", content,
465                     lastLanguageId, defaultLanguageId, true);
466             }
467 
468             // Add article
469 
470             article = JournalArticleServiceUtil.addArticle(
471                 articleId, autoArticleId, layout.getPlid(), title, description,
472                 content, type, structureId, templateId, displayDateMonth,
473                 displayDateDay, displayDateYear, displayDateHour,
474                 displayDateMinute, expirationDateMonth, expirationDateDay,
475                 expirationDateYear, expirationDateHour, expirationDateMinute,
476                 neverExpire, reviewDateMonth, reviewDateDay, reviewDateYear,
477                 reviewDateHour, reviewDateMinute, neverReview, indexable,
478                 smallImage, smallImageURL, smallFile, images, articleURL,
479                 actionRequest.getPreferences(), tagsEntries,
480                 communityPermissions, guestPermissions);
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.mergeLocaleContent(
507                         curArticle.getContent(), content, structure.getXsd());
508                     content = JournalUtil.removeOldContent(
509                         content, structure.getXsd());
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, actionRequest.getPreferences(),
525                 tagsEntries);
526         }
527 
528         if (approve) {
529             article = JournalArticleServiceUtil.approveArticle(
530                 article.getGroupId(), article.getArticleId(),
531                 article.getVersion(), layout.getPlid(), articleURL,
532                 actionRequest.getPreferences());
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 prefs =
546                 PortletPreferencesFactoryUtil.getPortletSetup(
547                     uploadRequest, portletResource);
548 
549             prefs.setValue("group-id", String.valueOf(article.getGroupId()));
550             prefs.setValue("article-id", article.getArticleId());
551 
552             prefs.store();
553 
554             updateContentSearch(
555                 actionRequest, portletResource, article.getArticleId());
556         }
557 
558         return article;
559     }
560 
561     protected void updateContentSearch(
562             ActionRequest actionRequest, String portletResource,
563             String articleId)
564         throws Exception {
565 
566         ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
567             WebKeys.THEME_DISPLAY);
568 
569         Layout layout = themeDisplay.getLayout();
570 
571         JournalContentSearchLocalServiceUtil.updateContentSearch(
572             layout.getGroupId(), layout.isPrivateLayout(), layout.getLayoutId(),
573             portletResource, articleId);
574     }
575 
576 }