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