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.util.Diff;
023    import com.liferay.portal.kernel.util.DiffResult;
024    import com.liferay.portal.kernel.util.DiffUtil;
025    import com.liferay.portal.kernel.util.HtmlUtil;
026    import com.liferay.portal.kernel.util.HttpUtil;
027    import com.liferay.portal.kernel.util.ObjectValuePair;
028    import com.liferay.portal.kernel.util.StringBundler;
029    import com.liferay.portal.kernel.util.StringPool;
030    import com.liferay.portal.kernel.util.StringUtil;
031    import com.liferay.portal.kernel.velocity.VelocityContext;
032    import com.liferay.portal.kernel.velocity.VelocityEngineUtil;
033    import com.liferay.portal.security.permission.ActionKeys;
034    import com.liferay.portal.service.ServiceContext;
035    import com.liferay.portal.util.PortalUtil;
036    import com.liferay.portal.util.PortletKeys;
037    import com.liferay.portal.util.PropsValues;
038    import com.liferay.portlet.wiki.model.WikiNode;
039    import com.liferay.portlet.wiki.model.WikiPage;
040    import com.liferay.portlet.wiki.model.WikiPageConstants;
041    import com.liferay.portlet.wiki.service.base.WikiPageServiceBaseImpl;
042    import com.liferay.portlet.wiki.service.permission.WikiNodePermission;
043    import com.liferay.portlet.wiki.service.permission.WikiPagePermission;
044    import com.liferay.portlet.wiki.util.WikiUtil;
045    import com.liferay.portlet.wiki.util.comparator.PageCreateDateComparator;
046    import com.liferay.util.ContentUtil;
047    import com.liferay.util.RSSUtil;
048    
049    import com.sun.syndication.feed.synd.SyndContent;
050    import com.sun.syndication.feed.synd.SyndContentImpl;
051    import com.sun.syndication.feed.synd.SyndEntry;
052    import com.sun.syndication.feed.synd.SyndEntryImpl;
053    import com.sun.syndication.feed.synd.SyndFeed;
054    import com.sun.syndication.feed.synd.SyndFeedImpl;
055    import com.sun.syndication.io.FeedException;
056    
057    import java.io.File;
058    import java.io.IOException;
059    import java.io.InputStream;
060    
061    import java.util.ArrayList;
062    import java.util.Iterator;
063    import java.util.List;
064    import java.util.Locale;
065    
066    /**
067     * @author Brian Wing Shun Chan
068     * @author Jorge Ferrer
069     * @author Raymond Augé
070     */
071    public class WikiPageServiceImpl extends WikiPageServiceBaseImpl {
072    
073            public WikiPage addPage(
074                            long nodeId, String title, String content, String summary,
075                            boolean minorEdit, ServiceContext serviceContext)
076                    throws PortalException, SystemException {
077    
078                    WikiNodePermission.check(
079                            getPermissionChecker(), nodeId, ActionKeys.ADD_PAGE);
080    
081                    return wikiPageLocalService.addPage(
082                            getUserId(), nodeId, title, content, summary, minorEdit,
083                            serviceContext);
084            }
085    
086            public WikiPage addPage(
087                            long nodeId, String title, String content, String summary,
088                            boolean minorEdit, String format, String parentTitle,
089                            String redirectTitle, ServiceContext serviceContext)
090                    throws PortalException, SystemException {
091    
092                    WikiNodePermission.check(
093                            getPermissionChecker(), nodeId, ActionKeys.ADD_PAGE);
094    
095                    return wikiPageLocalService.addPage(
096                            getUserId(), nodeId, title, WikiPageConstants.VERSION_DEFAULT,
097                            content, summary, minorEdit, format, true, parentTitle,
098                            redirectTitle, serviceContext);
099            }
100    
101            public void addPageAttachment(
102                            long nodeId, String title, String fileName, File file)
103                    throws PortalException, SystemException {
104    
105                    WikiNodePermission.check(
106                            getPermissionChecker(), nodeId, ActionKeys.ADD_ATTACHMENT);
107    
108                    wikiPageLocalService.addPageAttachment(
109                            getUserId(), nodeId, title, fileName, file);
110            }
111    
112            public void addPageAttachments(
113                            long nodeId, String title,
114                            List<ObjectValuePair<String, InputStream>> inputStream)
115                    throws PortalException, SystemException {
116    
117                    WikiNodePermission.check(
118                            getPermissionChecker(), nodeId, ActionKeys.ADD_ATTACHMENT);
119    
120                    wikiPageLocalService.addPageAttachments(
121                            getUserId(), nodeId, title, inputStream);
122            }
123    
124            public String addTempPageAttachment(
125                            long nodeId, String fileName, String tempFolderName,
126                            InputStream inputStream)
127                    throws IOException, PortalException, SystemException {
128    
129                    WikiNodePermission.check(
130                            getPermissionChecker(), nodeId, ActionKeys.ADD_ATTACHMENT);
131    
132                    return wikiPageLocalService.addTempPageAttachment(
133                            getUserId(), fileName, tempFolderName, inputStream);
134            }
135    
136            public void changeParent(
137                            long nodeId, String title, String newParentTitle,
138                            ServiceContext serviceContext)
139                    throws PortalException, SystemException {
140    
141                    WikiPagePermission.check(
142                            getPermissionChecker(), nodeId, title, ActionKeys.DELETE);
143    
144                    WikiNodePermission.check(
145                            getPermissionChecker(), nodeId, ActionKeys.ADD_PAGE);
146    
147                    wikiPageLocalService.changeParent(
148                            getUserId(), nodeId, title, newParentTitle, serviceContext);
149            }
150    
151            public void deletePage(long nodeId, String title)
152                    throws PortalException, SystemException {
153    
154                    WikiPagePermission.check(
155                            getPermissionChecker(), nodeId, title, ActionKeys.DELETE);
156    
157                    wikiPageLocalService.deletePage(nodeId, title);
158            }
159    
160            public void deletePage(long nodeId, String title, double version)
161                    throws PortalException, SystemException {
162    
163                    WikiPagePermission.check(
164                            getPermissionChecker(), nodeId, title, version, ActionKeys.DELETE);
165    
166                    wikiPageLocalService.deletePage(nodeId, title, version);
167            }
168    
169            public void deletePageAttachment(long nodeId, String title, String fileName)
170                    throws PortalException, SystemException {
171    
172                    WikiPagePermission.check(
173                            getPermissionChecker(), nodeId, title, ActionKeys.DELETE);
174    
175                    wikiPageLocalService.deletePageAttachment(nodeId, title, fileName);
176            }
177    
178            public void deleteTempPageAttachment(
179                            long nodeId, String fileName, String tempFolderName)
180                    throws PortalException, SystemException {
181    
182                    WikiNodePermission.check(
183                            getPermissionChecker(), nodeId, ActionKeys.ADD_ATTACHMENT);
184    
185                    wikiPageLocalService.deleteTempPageAttachment(
186                            getUserId(), fileName, tempFolderName);
187            }
188    
189            public WikiPage getDraftPage(long nodeId, String title)
190                    throws PortalException, SystemException {
191    
192                    WikiPagePermission.check(
193                            getPermissionChecker(), nodeId, title, ActionKeys.VIEW);
194    
195                    return wikiPageLocalService.getDraftPage(nodeId, title);
196            }
197    
198            public List<WikiPage> getNodePages(long nodeId, int max)
199                    throws PortalException, SystemException {
200    
201                    List<WikiPage> pages = new ArrayList<WikiPage>();
202    
203                    int lastIntervalStart = 0;
204                    boolean listNotExhausted = true;
205    
206                    while ((pages.size() < max) && listNotExhausted) {
207                            List<WikiPage> pageList = wikiPageLocalService.getPages(
208                                    nodeId, true, lastIntervalStart, lastIntervalStart + max);
209    
210                            Iterator<WikiPage> itr = pageList.iterator();
211    
212                            lastIntervalStart += max;
213                            listNotExhausted = (pageList.size() == max);
214    
215                            while (itr.hasNext() && (pages.size() < max)) {
216                                    WikiPage page = itr.next();
217    
218                                    if (WikiPagePermission.contains(getPermissionChecker(), page,
219                                                    ActionKeys.VIEW)) {
220    
221                                            pages.add(page);
222                                    }
223                            }
224                    }
225    
226                    return pages;
227            }
228    
229            public String getNodePagesRSS(
230                            long nodeId, int max, String type, double version,
231                            String displayStyle, String feedURL, String entryURL)
232                    throws PortalException, SystemException {
233    
234                    WikiNodePermission.check(
235                            getPermissionChecker(), nodeId, ActionKeys.VIEW);
236    
237                    WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
238    
239                    long companyId = node.getCompanyId();
240                    String name = node.getName();
241                    String description = node.getDescription();
242                    List<WikiPage> pages = getNodePages(nodeId, max);
243                    boolean diff = false;
244                    Locale locale = null;
245    
246                    return exportToRSS(
247                            companyId, name, description, type, version, displayStyle, feedURL,
248                            entryURL, pages, diff, locale);
249            }
250    
251            public WikiPage getPage(long nodeId, String title)
252                    throws PortalException, SystemException {
253    
254                    WikiPagePermission.check(
255                            getPermissionChecker(), nodeId, title, ActionKeys.VIEW);
256    
257                    return wikiPageLocalService.getPage(nodeId, title);
258            }
259    
260            public WikiPage getPage(long nodeId, String title, Boolean head)
261                    throws PortalException, SystemException {
262    
263                    WikiPagePermission.check(
264                            getPermissionChecker(), nodeId, title, ActionKeys.VIEW);
265    
266                    return wikiPageLocalService.getPage(nodeId, title, head);
267            }
268    
269            public WikiPage getPage(long nodeId, String title, double version)
270                    throws PortalException, SystemException {
271    
272                    WikiPagePermission.check(
273                            getPermissionChecker(), nodeId, title, ActionKeys.VIEW);
274    
275                    return wikiPageLocalService.getPage(nodeId, title, version);
276            }
277    
278            public String getPagesRSS(
279                            long companyId, long nodeId, String title, int max, String type,
280                            double version, String displayStyle, String feedURL,
281                            String entryURL, Locale locale)
282                    throws PortalException, SystemException {
283    
284                    WikiPagePermission.check(
285                            getPermissionChecker(), nodeId, title, ActionKeys.VIEW);
286    
287                    String description = title;
288                    List<WikiPage> pages = wikiPageLocalService.getPages(
289                            nodeId, title, 0, max, new PageCreateDateComparator(true));
290                    boolean diff = true;
291    
292                    return exportToRSS(
293                            companyId, title, description, type, version, displayStyle, feedURL,
294                            entryURL, pages, diff, locale);
295            }
296    
297            public String[] getTempPageAttachmentNames(
298                            long nodeId, String tempFolderName)
299                    throws PortalException, SystemException {
300    
301                    WikiNodePermission.check(
302                            getPermissionChecker(), nodeId, ActionKeys.ADD_ATTACHMENT);
303    
304                    return wikiPageLocalService.getTempPageAttachmentNames(
305                            getUserId(), tempFolderName);
306            }
307    
308            public void movePage(
309                            long nodeId, String title, String newTitle,
310                            ServiceContext serviceContext)
311                    throws PortalException, SystemException {
312    
313                    WikiPagePermission.check(
314                            getPermissionChecker(), nodeId, title, ActionKeys.DELETE);
315    
316                    WikiNodePermission.check(
317                            getPermissionChecker(), nodeId, ActionKeys.ADD_PAGE);
318    
319                    wikiPageLocalService.movePage(
320                            getUserId(), nodeId, title, newTitle, serviceContext);
321            }
322    
323            public WikiPage revertPage(
324                            long nodeId, String title, double version,
325                            ServiceContext serviceContext)
326                    throws PortalException, SystemException {
327    
328                    WikiPagePermission.check(
329                            getPermissionChecker(), nodeId, title, ActionKeys.UPDATE);
330    
331                    return wikiPageLocalService.revertPage(
332                            getUserId(), nodeId, title, version, serviceContext);
333            }
334    
335            public void subscribePage(long nodeId, String title)
336                    throws PortalException, SystemException {
337    
338                    WikiPagePermission.check(
339                            getPermissionChecker(), nodeId, title, ActionKeys.SUBSCRIBE);
340    
341                    wikiPageLocalService.subscribePage(getUserId(), nodeId, title);
342            }
343    
344            public void unsubscribePage(long nodeId, String title)
345                    throws PortalException, SystemException {
346    
347                    WikiPagePermission.check(
348                            getPermissionChecker(), nodeId, title, ActionKeys.SUBSCRIBE);
349    
350                    wikiPageLocalService.unsubscribePage(getUserId(), nodeId, title);
351            }
352    
353            public WikiPage updatePage(
354                            long nodeId, String title, double version, String content,
355                            String summary, boolean minorEdit, String format,
356                            String parentTitle, String redirectTitle,
357                            ServiceContext serviceContext)
358                    throws PortalException, SystemException {
359    
360                    WikiPagePermission.check(
361                            getPermissionChecker(), nodeId, title, ActionKeys.UPDATE);
362    
363                    return wikiPageLocalService.updatePage(
364                            getUserId(), nodeId, title, version, content, summary, minorEdit,
365                            format, parentTitle, redirectTitle, serviceContext);
366            }
367    
368            protected String exportToRSS(
369                            long companyId, String name, String description, String type,
370                            double version, String displayStyle, String feedURL,
371                            String entryURL, List<WikiPage> pages, boolean diff, Locale locale)
372                    throws SystemException {
373    
374                    SyndFeed syndFeed = new SyndFeedImpl();
375    
376                    syndFeed.setFeedType(RSSUtil.getFeedType(type, version));
377                    syndFeed.setTitle(name);
378                    syndFeed.setLink(feedURL);
379                    syndFeed.setDescription(description);
380    
381                    List<SyndEntry> syndEntries = new ArrayList<SyndEntry>();
382    
383                    syndFeed.setEntries(syndEntries);
384    
385                    WikiPage latestPage = null;
386    
387                    StringBundler link = new StringBundler(7);
388    
389                    for (WikiPage page : pages) {
390                            String author = HtmlUtil.escape(
391                                    PortalUtil.getUserName(page.getUserId(), page.getUserName()));
392    
393                            String title =
394                                    page.getTitle() + StringPool.SPACE + page.getVersion();
395    
396                            if (page.isMinorEdit()) {
397                                    title +=
398                                            StringPool.SPACE + StringPool.OPEN_PARENTHESIS +
399                                                    LanguageUtil.get(locale, "minor-edit") +
400                                                            StringPool.CLOSE_PARENTHESIS;
401                            }
402    
403                            link.setIndex(0);
404    
405                            link.append(entryURL);
406                            link.append(StringPool.AMPERSAND);
407                            link.append(HttpUtil.encodeURL(page.getTitle()));
408    
409                            SyndEntry syndEntry = new SyndEntryImpl();
410    
411                            syndEntry.setAuthor(author);
412                            syndEntry.setTitle(title);
413                            syndEntry.setPublishedDate(page.getCreateDate());
414                            syndEntry.setUpdatedDate(page.getModifiedDate());
415    
416                            SyndContent syndContent = new SyndContentImpl();
417    
418                            syndContent.setType(RSSUtil.ENTRY_TYPE_DEFAULT);
419    
420                            if (diff) {
421                                    if (latestPage != null) {
422                                            link.append(StringPool.QUESTION);
423                                            link.append(
424                                                    PortalUtil.getPortletNamespace(PortletKeys.WIKI));
425                                            link.append("version=");
426                                            link.append(page.getVersion());
427    
428                                            String value = getPageDiff(
429                                                    companyId, latestPage, page, locale);
430    
431                                            syndContent.setValue(value);
432    
433                                            syndEntry.setDescription(syndContent);
434    
435                                            syndEntries.add(syndEntry);
436                                    }
437                            }
438                            else {
439                                    String value = null;
440    
441                                    if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_ABSTRACT)) {
442                                            value = StringUtil.shorten(
443                                                    HtmlUtil.extractText(page.getContent()),
444                                                    PropsValues.WIKI_RSS_ABSTRACT_LENGTH, StringPool.BLANK);
445                                    }
446                                    else if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_TITLE)) {
447                                            value = StringPool.BLANK;
448                                    }
449                                    else {
450                                            value = page.getContent();
451                                    }
452    
453                                    syndContent.setValue(value);
454    
455                                    syndEntry.setDescription(syndContent);
456    
457                                    syndEntries.add(syndEntry);
458                            }
459    
460                            syndEntry.setLink(link.toString());
461                            syndEntry.setUri(syndEntry.getLink());
462    
463                            latestPage = page;
464                    }
465    
466                    try {
467                            return RSSUtil.export(syndFeed);
468                    }
469                    catch (FeedException fe) {
470                            throw new SystemException(fe);
471                    }
472            }
473    
474            protected String getPageDiff(
475                            long companyId, WikiPage latestPage, WikiPage page, Locale locale)
476                    throws SystemException {
477    
478                    String sourceContent = WikiUtil.processContent(latestPage.getContent());
479                    String targetContent = WikiUtil.processContent(page.getContent());
480    
481                    sourceContent = HtmlUtil.escape(sourceContent);
482                    targetContent = HtmlUtil.escape(targetContent);
483    
484                    List<DiffResult>[] diffResults = DiffUtil.diff(
485                            new UnsyncStringReader(sourceContent),
486                            new UnsyncStringReader(targetContent));
487    
488                    String velocityTemplateId =
489                            "com/liferay/portlet/wiki/dependencies/rss.vm";
490                    String velocityTemplateContent = ContentUtil.get(velocityTemplateId);
491    
492                    VelocityContext velocityContext =
493                            VelocityEngineUtil.getWrappedStandardToolsContext();
494    
495                    velocityContext.put("companyId", companyId);
496                    velocityContext.put("contextLine", Diff.CONTEXT_LINE);
497                    velocityContext.put("diffUtil", new DiffUtil());
498                    velocityContext.put("languageUtil", LanguageUtil.getLanguage());
499                    velocityContext.put("locale", locale);
500                    velocityContext.put("sourceResults", diffResults[0]);
501                    velocityContext.put("targetResults", diffResults[1]);
502    
503                    try {
504                            UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
505    
506                            VelocityEngineUtil.mergeTemplate(
507                                    velocityTemplateId, velocityTemplateContent, velocityContext,
508                                    unsyncStringWriter);
509    
510                            return unsyncStringWriter.toString();
511                    }
512                    catch (Exception e) {
513                            throw new SystemException(e);
514                    }
515            }
516    
517    }