001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.wiki.service.impl;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
020    import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
021    import com.liferay.portal.kernel.language.LanguageUtil;
022    import com.liferay.portal.kernel.template.Template;
023    import com.liferay.portal.kernel.template.TemplateContextType;
024    import com.liferay.portal.kernel.template.TemplateManager;
025    import com.liferay.portal.kernel.template.TemplateManagerUtil;
026    import com.liferay.portal.kernel.template.TemplateResource;
027    import com.liferay.portal.kernel.template.URLTemplateResource;
028    import com.liferay.portal.kernel.util.Diff;
029    import com.liferay.portal.kernel.util.DiffResult;
030    import com.liferay.portal.kernel.util.DiffUtil;
031    import com.liferay.portal.kernel.util.HtmlUtil;
032    import com.liferay.portal.kernel.util.HttpUtil;
033    import com.liferay.portal.kernel.util.ObjectValuePair;
034    import com.liferay.portal.kernel.util.StringBundler;
035    import com.liferay.portal.kernel.util.StringPool;
036    import com.liferay.portal.kernel.util.StringUtil;
037    import com.liferay.portal.security.permission.ActionKeys;
038    import com.liferay.portal.service.ServiceContext;
039    import com.liferay.portal.util.PortalUtil;
040    import com.liferay.portal.util.PortletKeys;
041    import com.liferay.portal.util.PropsValues;
042    import com.liferay.portlet.wiki.model.WikiNode;
043    import com.liferay.portlet.wiki.model.WikiPage;
044    import com.liferay.portlet.wiki.model.WikiPageConstants;
045    import com.liferay.portlet.wiki.service.base.WikiPageServiceBaseImpl;
046    import com.liferay.portlet.wiki.service.permission.WikiNodePermission;
047    import com.liferay.portlet.wiki.service.permission.WikiPagePermission;
048    import com.liferay.portlet.wiki.util.WikiUtil;
049    import com.liferay.portlet.wiki.util.comparator.PageCreateDateComparator;
050    import com.liferay.util.RSSUtil;
051    
052    import com.sun.syndication.feed.synd.SyndContent;
053    import com.sun.syndication.feed.synd.SyndContentImpl;
054    import com.sun.syndication.feed.synd.SyndEntry;
055    import com.sun.syndication.feed.synd.SyndEntryImpl;
056    import com.sun.syndication.feed.synd.SyndFeed;
057    import com.sun.syndication.feed.synd.SyndFeedImpl;
058    import com.sun.syndication.feed.synd.SyndLink;
059    import com.sun.syndication.feed.synd.SyndLinkImpl;
060    import com.sun.syndication.io.FeedException;
061    
062    import java.io.File;
063    import java.io.InputStream;
064    
065    import java.net.URL;
066    
067    import java.util.ArrayList;
068    import java.util.Date;
069    import java.util.List;
070    import java.util.Locale;
071    
072    /**
073     * @author Brian Wing Shun Chan
074     * @author Jorge Ferrer
075     * @author Raymond Augé
076     */
077    public class WikiPageServiceImpl extends WikiPageServiceBaseImpl {
078    
079            public WikiPageServiceImpl() {
080                    Class<?> clazz = getClass();
081    
082                    ClassLoader classLoader = clazz.getClassLoader();
083    
084                    String templateId = "com/liferay/portlet/wiki/dependencies/rss.vm";
085    
086                    URL url = classLoader.getResource(templateId);
087    
088                    _templateResource = new URLTemplateResource(templateId, url);
089            }
090    
091            public WikiPage addPage(
092                            long nodeId, String title, String content, String summary,
093                            boolean minorEdit, ServiceContext serviceContext)
094                    throws PortalException, SystemException {
095    
096                    WikiNodePermission.check(
097                            getPermissionChecker(), nodeId, ActionKeys.ADD_PAGE);
098    
099                    return wikiPageLocalService.addPage(
100                            getUserId(), nodeId, title, content, summary, minorEdit,
101                            serviceContext);
102            }
103    
104            public WikiPage addPage(
105                            long nodeId, String title, String content, String summary,
106                            boolean minorEdit, String format, String parentTitle,
107                            String redirectTitle, ServiceContext serviceContext)
108                    throws PortalException, SystemException {
109    
110                    WikiNodePermission.check(
111                            getPermissionChecker(), nodeId, ActionKeys.ADD_PAGE);
112    
113                    return wikiPageLocalService.addPage(
114                            getUserId(), nodeId, title, WikiPageConstants.VERSION_DEFAULT,
115                            content, summary, minorEdit, format, true, parentTitle,
116                            redirectTitle, serviceContext);
117            }
118    
119            public void addPageAttachment(
120                            long nodeId, String title, String fileName, File file)
121                    throws PortalException, SystemException {
122    
123                    WikiNodePermission.check(
124                            getPermissionChecker(), nodeId, ActionKeys.ADD_ATTACHMENT);
125    
126                    wikiPageLocalService.addPageAttachment(
127                            getUserId(), nodeId, title, fileName, file);
128            }
129    
130            public void addPageAttachment(
131                            long nodeId, String title, String fileName, InputStream inputStream)
132                    throws PortalException, SystemException {
133    
134                    WikiNodePermission.check(
135                            getPermissionChecker(), nodeId, ActionKeys.ADD_ATTACHMENT);
136    
137                    wikiPageLocalService.addPageAttachment(
138                            getUserId(), nodeId, title, fileName, inputStream);
139            }
140    
141            public void addPageAttachments(
142                            long nodeId, String title,
143                            List<ObjectValuePair<String, InputStream>> inputStreamOVPs)
144                    throws PortalException, SystemException {
145    
146                    WikiNodePermission.check(
147                            getPermissionChecker(), nodeId, ActionKeys.ADD_ATTACHMENT);
148    
149                    wikiPageLocalService.addPageAttachments(
150                            getUserId(), nodeId, title, inputStreamOVPs);
151            }
152    
153            public String addTempPageAttachment(
154                            long nodeId, String fileName, String tempFolderName,
155                            InputStream inputStream)
156                    throws PortalException, SystemException {
157    
158                    WikiNodePermission.check(
159                            getPermissionChecker(), nodeId, ActionKeys.ADD_ATTACHMENT);
160    
161                    return wikiPageLocalService.addTempPageAttachment(
162                            getUserId(), fileName, tempFolderName, inputStream);
163            }
164    
165            public void changeParent(
166                            long nodeId, String title, String newParentTitle,
167                            ServiceContext serviceContext)
168                    throws PortalException, SystemException {
169    
170                    WikiPagePermission.check(
171                            getPermissionChecker(), nodeId, title, ActionKeys.DELETE);
172    
173                    WikiNodePermission.check(
174                            getPermissionChecker(), nodeId, ActionKeys.ADD_PAGE);
175    
176                    wikiPageLocalService.changeParent(
177                            getUserId(), nodeId, title, newParentTitle, serviceContext);
178            }
179    
180            public void deletePage(long nodeId, String title)
181                    throws PortalException, SystemException {
182    
183                    WikiPagePermission.check(
184                            getPermissionChecker(), nodeId, title, ActionKeys.DELETE);
185    
186                    wikiPageLocalService.deletePage(nodeId, title);
187            }
188    
189            public void deletePage(long nodeId, String title, double version)
190                    throws PortalException, SystemException {
191    
192                    WikiPagePermission.check(
193                            getPermissionChecker(), nodeId, title, version, ActionKeys.DELETE);
194    
195                    wikiPageLocalService.deletePage(nodeId, title, version);
196            }
197    
198            public void deletePageAttachment(long nodeId, String title, String fileName)
199                    throws PortalException, SystemException {
200    
201                    WikiPagePermission.check(
202                            getPermissionChecker(), nodeId, title, ActionKeys.DELETE);
203    
204                    wikiPageLocalService.deletePageAttachment(nodeId, title, fileName);
205            }
206    
207            public void deletePageAttachments(long nodeId, String title)
208                    throws PortalException, SystemException {
209    
210                    WikiPagePermission.check(
211                            getPermissionChecker(), nodeId, title, ActionKeys.DELETE);
212    
213                    wikiPageLocalService.deletePageAttachments(nodeId, title);
214            }
215    
216            public void deleteTempPageAttachment(
217                            long nodeId, String fileName, String tempFolderName)
218                    throws PortalException, SystemException {
219    
220                    WikiNodePermission.check(
221                            getPermissionChecker(), nodeId, ActionKeys.ADD_ATTACHMENT);
222    
223                    wikiPageLocalService.deleteTempPageAttachment(
224                            getUserId(), fileName, tempFolderName);
225            }
226    
227            public WikiPage getDraftPage(long nodeId, String title)
228                    throws PortalException, SystemException {
229    
230                    WikiPagePermission.check(
231                            getPermissionChecker(), nodeId, title, ActionKeys.VIEW);
232    
233                    return wikiPageLocalService.getDraftPage(nodeId, title);
234            }
235    
236            public List<WikiPage> getNodePages(long nodeId, int max)
237                    throws PortalException, SystemException {
238    
239                    List<WikiPage> pages = new ArrayList<WikiPage>();
240    
241                    int lastIntervalStart = 0;
242                    boolean listNotExhausted = true;
243    
244                    while ((pages.size() < max) && listNotExhausted) {
245                            List<WikiPage> pageList = wikiPageLocalService.getPages(
246                                    nodeId, true, lastIntervalStart, lastIntervalStart + max);
247    
248                            lastIntervalStart += max;
249                            listNotExhausted = (pageList.size() == max);
250    
251                            for (WikiPage page : pageList) {
252                                    if (pages.size() >= max) {
253                                            break;
254                                    }
255    
256                                    if (WikiPagePermission.contains(
257                                                    getPermissionChecker(), page, ActionKeys.VIEW)) {
258    
259                                            pages.add(page);
260                                    }
261                            }
262                    }
263    
264                    return pages;
265            }
266    
267            public String getNodePagesRSS(
268                            long nodeId, int max, String type, double version,
269                            String displayStyle, String feedURL, String entryURL)
270                    throws PortalException, SystemException {
271    
272                    WikiNodePermission.check(
273                            getPermissionChecker(), nodeId, ActionKeys.VIEW);
274    
275                    WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
276    
277                    long companyId = node.getCompanyId();
278                    String name = node.getName();
279                    String description = node.getDescription();
280                    List<WikiPage> pages = getNodePages(nodeId, max);
281                    boolean diff = false;
282                    Locale locale = null;
283    
284                    return exportToRSS(
285                            companyId, name, description, type, version, displayStyle, feedURL,
286                            entryURL, pages, diff, locale);
287            }
288    
289            public WikiPage getPage(long nodeId, String title)
290                    throws PortalException, SystemException {
291    
292                    WikiPagePermission.check(
293                            getPermissionChecker(), nodeId, title, ActionKeys.VIEW);
294    
295                    return wikiPageLocalService.getPage(nodeId, title);
296            }
297    
298            public WikiPage getPage(long nodeId, String title, Boolean head)
299                    throws PortalException, SystemException {
300    
301                    WikiPagePermission.check(
302                            getPermissionChecker(), nodeId, title, ActionKeys.VIEW);
303    
304                    return wikiPageLocalService.getPage(nodeId, title, head);
305            }
306    
307            public WikiPage getPage(long nodeId, String title, double version)
308                    throws PortalException, SystemException {
309    
310                    WikiPagePermission.check(
311                            getPermissionChecker(), nodeId, title, ActionKeys.VIEW);
312    
313                    return wikiPageLocalService.getPage(nodeId, title, version);
314            }
315    
316            public String getPagesRSS(
317                            long companyId, long nodeId, String title, int max, String type,
318                            double version, String displayStyle, String feedURL,
319                            String entryURL, Locale locale)
320                    throws PortalException, SystemException {
321    
322                    WikiPagePermission.check(
323                            getPermissionChecker(), nodeId, title, ActionKeys.VIEW);
324    
325                    String description = title;
326                    List<WikiPage> pages = wikiPageLocalService.getPages(
327                            nodeId, title, 0, max, new PageCreateDateComparator(true));
328                    boolean diff = true;
329    
330                    return exportToRSS(
331                            companyId, title, description, type, version, displayStyle, feedURL,
332                            entryURL, pages, diff, locale);
333            }
334    
335            public String[] getTempPageAttachmentNames(
336                            long nodeId, String tempFolderName)
337                    throws PortalException, SystemException {
338    
339                    WikiNodePermission.check(
340                            getPermissionChecker(), nodeId, ActionKeys.ADD_ATTACHMENT);
341    
342                    return wikiPageLocalService.getTempPageAttachmentNames(
343                            getUserId(), tempFolderName);
344            }
345    
346            public void movePage(
347                            long nodeId, String title, String newTitle,
348                            ServiceContext serviceContext)
349                    throws PortalException, SystemException {
350    
351                    WikiPagePermission.check(
352                            getPermissionChecker(), nodeId, title, ActionKeys.DELETE);
353    
354                    WikiNodePermission.check(
355                            getPermissionChecker(), nodeId, ActionKeys.ADD_PAGE);
356    
357                    wikiPageLocalService.movePage(
358                            getUserId(), nodeId, title, newTitle, serviceContext);
359            }
360    
361            public void movePageAttachmentFromTrash(
362                            long nodeId, String title, String deletedFileName)
363                    throws PortalException, SystemException {
364    
365                    WikiNodePermission.check(
366                            getPermissionChecker(), nodeId, ActionKeys.ADD_ATTACHMENT);
367    
368                    wikiPageLocalService.movePageAttachmentFromTrash(
369                            nodeId, title, deletedFileName);
370            }
371    
372            public String movePageAttachmentToTrash(
373                            long nodeId, String title, String fileName)
374                    throws PortalException, SystemException {
375    
376                    WikiPagePermission.check(
377                            getPermissionChecker(), nodeId, title, ActionKeys.DELETE);
378    
379                    return wikiPageLocalService.movePageAttachmentToTrash(
380                            nodeId, title, fileName);
381            }
382    
383            public void movePageToTrash(long nodeId, String title)
384                    throws PortalException, SystemException {
385    
386                    WikiPagePermission.check(
387                            getPermissionChecker(), nodeId, title, ActionKeys.DELETE);
388    
389                    wikiPageLocalService.movePageToTrash(getUserId(), nodeId, title);
390            }
391    
392            public void movePageToTrash(long nodeId, String title, double version)
393                    throws PortalException, SystemException {
394    
395                    WikiPagePermission.check(
396                            getPermissionChecker(), nodeId, title, version, ActionKeys.DELETE);
397    
398                    wikiPageLocalService.movePageToTrash(
399                            getUserId(), nodeId, title, version);
400            }
401    
402            public void restorePageFromTrash(long resourcePrimKey)
403                    throws PortalException, SystemException {
404    
405                    WikiPage page = wikiPageLocalService.getPage(resourcePrimKey);
406    
407                    WikiPagePermission.check(
408                            getPermissionChecker(), page, ActionKeys.DELETE);
409    
410                    wikiPageLocalService.restorePageFromTrash(getUserId(), page);
411            }
412    
413            public WikiPage revertPage(
414                            long nodeId, String title, double version,
415                            ServiceContext serviceContext)
416                    throws PortalException, SystemException {
417    
418                    WikiPagePermission.check(
419                            getPermissionChecker(), nodeId, title, ActionKeys.UPDATE);
420    
421                    return wikiPageLocalService.revertPage(
422                            getUserId(), nodeId, title, version, serviceContext);
423            }
424    
425            public void subscribePage(long nodeId, String title)
426                    throws PortalException, SystemException {
427    
428                    WikiPagePermission.check(
429                            getPermissionChecker(), nodeId, title, ActionKeys.SUBSCRIBE);
430    
431                    wikiPageLocalService.subscribePage(getUserId(), nodeId, title);
432            }
433    
434            public void unsubscribePage(long nodeId, String title)
435                    throws PortalException, SystemException {
436    
437                    WikiPagePermission.check(
438                            getPermissionChecker(), nodeId, title, ActionKeys.SUBSCRIBE);
439    
440                    wikiPageLocalService.unsubscribePage(getUserId(), nodeId, title);
441            }
442    
443            public WikiPage updatePage(
444                            long nodeId, String title, double version, String content,
445                            String summary, boolean minorEdit, String format,
446                            String parentTitle, String redirectTitle,
447                            ServiceContext serviceContext)
448                    throws PortalException, SystemException {
449    
450                    WikiPagePermission.check(
451                            getPermissionChecker(), nodeId, title, ActionKeys.UPDATE);
452    
453                    return wikiPageLocalService.updatePage(
454                            getUserId(), nodeId, title, version, content, summary, minorEdit,
455                            format, parentTitle, redirectTitle, serviceContext);
456            }
457    
458            protected String exportToRSS(
459                            long companyId, String name, String description, String type,
460                            double version, String displayStyle, String feedURL,
461                            String entryURL, List<WikiPage> pages, boolean diff, Locale locale)
462                    throws SystemException {
463    
464                    SyndFeed syndFeed = new SyndFeedImpl();
465    
466                    syndFeed.setDescription(description);
467    
468                    List<SyndEntry> syndEntries = new ArrayList<SyndEntry>();
469    
470                    syndFeed.setEntries(syndEntries);
471    
472                    WikiPage latestPage = null;
473    
474                    StringBundler sb = new StringBundler(7);
475    
476                    for (WikiPage page : pages) {
477                            SyndEntry syndEntry = new SyndEntryImpl();
478    
479                            String author = PortalUtil.getUserName(page);
480    
481                            syndEntry.setAuthor(author);
482    
483                            SyndContent syndContent = new SyndContentImpl();
484    
485                            syndContent.setType(RSSUtil.ENTRY_TYPE_DEFAULT);
486    
487                            sb.setIndex(0);
488    
489                            sb.append(entryURL);
490                            sb.append(StringPool.AMPERSAND);
491                            sb.append(HttpUtil.encodeURL(page.getTitle()));
492    
493                            if (diff) {
494                                    if (latestPage != null) {
495                                            sb.append(StringPool.QUESTION);
496                                            sb.append(PortalUtil.getPortletNamespace(PortletKeys.WIKI));
497                                            sb.append("version=");
498                                            sb.append(page.getVersion());
499    
500                                            String value = getPageDiff(
501                                                    companyId, latestPage, page, locale);
502    
503                                            syndContent.setValue(value);
504    
505                                            syndEntry.setDescription(syndContent);
506    
507                                            syndEntries.add(syndEntry);
508                                    }
509                            }
510                            else {
511                                    String value = null;
512    
513                                    if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_ABSTRACT)) {
514                                            value = StringUtil.shorten(
515                                                    HtmlUtil.extractText(page.getContent()),
516                                                    PropsValues.WIKI_RSS_ABSTRACT_LENGTH, StringPool.BLANK);
517                                    }
518                                    else if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_TITLE)) {
519                                            value = StringPool.BLANK;
520                                    }
521                                    else {
522                                            value = page.getContent();
523                                    }
524    
525                                    syndContent.setValue(value);
526    
527                                    syndEntry.setDescription(syndContent);
528    
529                                    syndEntries.add(syndEntry);
530                            }
531    
532                            syndEntry.setLink(sb.toString());
533                            syndEntry.setPublishedDate(page.getCreateDate());
534    
535                            String title =
536                                    page.getTitle() + StringPool.SPACE + page.getVersion();
537    
538                            if (page.isMinorEdit()) {
539                                    title +=
540                                            StringPool.SPACE + StringPool.OPEN_PARENTHESIS +
541                                                    LanguageUtil.get(locale, "minor-edit") +
542                                                            StringPool.CLOSE_PARENTHESIS;
543                            }
544    
545                            syndEntry.setTitle(title);
546    
547                            syndEntry.setUpdatedDate(page.getModifiedDate());
548                            syndEntry.setUri(sb.toString());
549    
550                            latestPage = page;
551                    }
552    
553                    syndFeed.setFeedType(RSSUtil.getFeedType(type, version));
554    
555                    List<SyndLink> syndLinks = new ArrayList<SyndLink>();
556    
557                    syndFeed.setLinks(syndLinks);
558    
559                    SyndLink syndLinkSelf = new SyndLinkImpl();
560    
561                    syndLinks.add(syndLinkSelf);
562    
563                    syndLinkSelf.setHref(feedURL);
564                    syndLinkSelf.setRel("self");
565    
566                    syndFeed.setPublishedDate(new Date());
567                    syndFeed.setTitle(name);
568                    syndFeed.setUri(feedURL);
569                    syndFeed.setPublishedDate(new Date());
570                    syndFeed.setTitle(name);
571                    syndFeed.setUri(feedURL);
572    
573                    try {
574                            return RSSUtil.export(syndFeed);
575                    }
576                    catch (FeedException fe) {
577                            throw new SystemException(fe);
578                    }
579            }
580    
581            protected String getPageDiff(
582                            long companyId, WikiPage latestPage, WikiPage page, Locale locale)
583                    throws SystemException {
584    
585                    try {
586                            Template template = TemplateManagerUtil.getTemplate(
587                                    TemplateManager.VELOCITY, _templateResource,
588                                    TemplateContextType.STANDARD);
589    
590                            template.put("companyId", companyId);
591                            template.put("contextLine", Diff.CONTEXT_LINE);
592                            template.put("diffUtil", new DiffUtil());
593                            template.put("languageUtil", LanguageUtil.getLanguage());
594                            template.put("locale", locale);
595    
596                            String sourceContent = WikiUtil.processContent(
597                                    latestPage.getContent());
598                            String targetContent = WikiUtil.processContent(page.getContent());
599    
600                            sourceContent = HtmlUtil.escape(sourceContent);
601                            targetContent = HtmlUtil.escape(targetContent);
602    
603                            List<DiffResult>[] diffResults = DiffUtil.diff(
604                                    new UnsyncStringReader(sourceContent),
605                                    new UnsyncStringReader(targetContent));
606    
607                            template.put("sourceResults", diffResults[0]);
608                            template.put("targetResults", diffResults[1]);
609    
610                            UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
611    
612                            template.processTemplate(unsyncStringWriter);
613    
614                            return unsyncStringWriter.toString();
615                    }
616                    catch (Exception e) {
617                            throw new SystemException(e);
618                    }
619            }
620    
621            private TemplateResource _templateResource;
622    
623    }