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