1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portlet.wiki.service.impl;
24  
25  import com.liferay.portal.PortalException;
26  import com.liferay.portal.SystemException;
27  import com.liferay.portal.kernel.language.LanguageUtil;
28  import com.liferay.portal.kernel.util.GetterUtil;
29  import com.liferay.portal.kernel.util.HtmlUtil;
30  import com.liferay.portal.kernel.util.ObjectValuePair;
31  import com.liferay.portal.kernel.util.StringPool;
32  import com.liferay.portal.kernel.util.StringUtil;
33  import com.liferay.portal.security.permission.ActionKeys;
34  import com.liferay.portal.theme.ThemeDisplay;
35  import com.liferay.portal.util.ContentUtil;
36  import com.liferay.portal.util.PortalUtil;
37  import com.liferay.portal.util.PortletKeys;
38  import com.liferay.portal.util.PropsUtil;
39  import com.liferay.portal.velocity.VelocityUtil;
40  import com.liferay.portlet.wiki.model.WikiNode;
41  import com.liferay.portlet.wiki.model.WikiPage;
42  import com.liferay.portlet.wiki.service.base.WikiPageServiceBaseImpl;
43  import com.liferay.portlet.wiki.service.permission.WikiNodePermission;
44  import com.liferay.portlet.wiki.service.permission.WikiPagePermission;
45  import com.liferay.portlet.wiki.util.WikiUtil;
46  import com.liferay.portlet.wiki.util.comparator.PageCreateDateComparator;
47  import com.liferay.util.RSSUtil;
48  import com.liferay.util.diff.DiffResult;
49  import com.liferay.util.diff.DiffUtil;
50  
51  import com.sun.syndication.feed.synd.SyndContent;
52  import com.sun.syndication.feed.synd.SyndContentImpl;
53  import com.sun.syndication.feed.synd.SyndEntry;
54  import com.sun.syndication.feed.synd.SyndEntryImpl;
55  import com.sun.syndication.feed.synd.SyndFeed;
56  import com.sun.syndication.feed.synd.SyndFeedImpl;
57  import com.sun.syndication.io.FeedException;
58  
59  import java.io.IOException;
60  import java.io.StringReader;
61  
62  import java.util.ArrayList;
63  import java.util.HashMap;
64  import java.util.Iterator;
65  import java.util.List;
66  import java.util.Locale;
67  import java.util.Map;
68  
69  import javax.portlet.PortletPreferences;
70  
71  /**
72   * <a href="WikiPageServiceImpl.java.html"><b><i>View Source</i></b></a>
73   *
74   * @author Brian Wing Shun Chan
75   * @author Jorge Ferrer
76   *
77   */
78  public class WikiPageServiceImpl extends WikiPageServiceBaseImpl {
79  
80      public WikiPage addPage(
81              long nodeId, String title, PortletPreferences prefs,
82              ThemeDisplay themeDisplay)
83          throws PortalException, SystemException {
84  
85          WikiNodePermission.check(
86              getPermissionChecker(), nodeId, ActionKeys.ADD_PAGE);
87  
88          return wikiPageLocalService.addPage(
89              getUserId(), nodeId, title, prefs, themeDisplay);
90      }
91  
92      public void addPageAttachments(
93              long nodeId, String title,
94              List<ObjectValuePair<String, byte[]>> files)
95          throws PortalException, SystemException {
96  
97          WikiNodePermission.check(
98              getPermissionChecker(), nodeId, ActionKeys.ADD_ATTACHMENT);
99  
100         wikiPageLocalService.addPageAttachments(nodeId, title, files);
101     }
102 
103     public void deletePage(long nodeId, String title)
104         throws PortalException, SystemException {
105 
106         WikiPagePermission.check(
107             getPermissionChecker(), nodeId, title, ActionKeys.DELETE);
108 
109         wikiPageLocalService.deletePage(nodeId, title);
110     }
111 
112     public void deletePageAttachment(long nodeId, String title, String fileName)
113         throws PortalException, SystemException {
114 
115         WikiPagePermission.check(
116             getPermissionChecker(), nodeId, title, ActionKeys.DELETE);
117 
118         wikiPageLocalService.deletePageAttachment(nodeId, title, fileName);
119     }
120 
121     public List<WikiPage> getNodePages(long nodeId, int max)
122         throws PortalException, SystemException {
123 
124         List<WikiPage> pages = new ArrayList<WikiPage>();
125 
126         Iterator<WikiPage> itr = wikiPageLocalService.getPages(nodeId, true, 0,
127             _MAX_END).iterator();
128 
129         while (itr.hasNext() && (pages.size() < max)) {
130             WikiPage page = itr.next();
131 
132             if (WikiPagePermission.contains(getPermissionChecker(), page,
133                     ActionKeys.VIEW)) {
134 
135                 pages.add(page);
136             }
137         }
138 
139         return pages;
140     }
141 
142     public String getNodePagesRSS(
143             long nodeId, int max, String type, double version,
144             String displayStyle, String feedURL, String entryURL)
145         throws PortalException, SystemException {
146 
147         WikiNodePermission.check(
148             getPermissionChecker(), nodeId, ActionKeys.VIEW);
149 
150         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
151 
152         long companyId = node.getCompanyId();
153         String name = node.getName();
154         String description = node.getDescription();
155         List<WikiPage> pages = getNodePages(nodeId, max);
156         boolean diff = false;
157         Locale locale = null;
158 
159         return exportToRSS(
160             companyId, name, description, type, version, displayStyle,
161             feedURL, entryURL, pages, diff, locale);
162     }
163 
164     public WikiPage getPage(long nodeId, String title)
165         throws PortalException, SystemException {
166 
167         WikiPagePermission.check(
168             getPermissionChecker(), nodeId, title, ActionKeys.VIEW);
169 
170         return wikiPageLocalService.getPage(nodeId, title);
171     }
172 
173     public WikiPage getPage(long nodeId, String title, double version)
174         throws PortalException, SystemException {
175 
176         WikiPagePermission.check(
177             getPermissionChecker(), nodeId, title, ActionKeys.VIEW);
178 
179         return wikiPageLocalService.getPage(nodeId, title, version);
180     }
181 
182     public String getPagesRSS(
183             long companyId, long nodeId, String title, int max, String type,
184             double version, String displayStyle, String feedURL,
185             String entryURL, Locale locale)
186         throws PortalException, SystemException {
187 
188         WikiPagePermission.check(
189             getPermissionChecker(), nodeId, title, ActionKeys.VIEW);
190 
191         String description = title;
192         List<WikiPage> pages = wikiPageLocalService.getPages(
193             nodeId, title, 0, _MAX_END, new PageCreateDateComparator(true));
194         boolean diff = true;
195 
196         return exportToRSS(
197             companyId, title, description, type, version, displayStyle, feedURL,
198             entryURL, pages, diff, locale);
199     }
200 
201     public void movePage(
202             long nodeId, String title, String newTitle,
203             PortletPreferences prefs, ThemeDisplay themeDisplay)
204         throws PortalException, SystemException {
205 
206         WikiNodePermission.check(
207             getPermissionChecker(), nodeId, ActionKeys.ADD_PAGE);
208 
209         WikiPagePermission.check(
210             getPermissionChecker(), nodeId, title, ActionKeys.UPDATE);
211 
212         wikiPageLocalService.movePage(
213             getUserId(), nodeId, title, newTitle, prefs, themeDisplay);
214     }
215 
216     public WikiPage revertPage(
217             long nodeId, String title, double version, PortletPreferences prefs,
218             ThemeDisplay themeDisplay)
219         throws PortalException, SystemException {
220 
221         WikiPagePermission.check(
222             getPermissionChecker(), nodeId, title, ActionKeys.UPDATE);
223 
224         return wikiPageLocalService.revertPage(
225             getUserId(), nodeId, title, version, prefs, themeDisplay);
226     }
227 
228     public void subscribePage(long nodeId, String title)
229         throws PortalException, SystemException {
230 
231         WikiPagePermission.check(
232             getPermissionChecker(), nodeId, title, ActionKeys.SUBSCRIBE);
233 
234         wikiPageLocalService.subscribePage(getUserId(), nodeId, title);
235     }
236 
237     public void unsubscribePage(long nodeId, String title)
238         throws PortalException, SystemException {
239 
240         WikiPagePermission.check(
241             getPermissionChecker(), nodeId, title, ActionKeys.SUBSCRIBE);
242 
243         wikiPageLocalService.unsubscribePage(getUserId(), nodeId, title);
244     }
245 
246     public WikiPage updatePage(
247             long nodeId, String title, double version, String content,
248             String format, String parentTitle, String redirectTitle,
249             String[] tagsEntries, PortletPreferences prefs,
250             ThemeDisplay themeDisplay)
251         throws PortalException, SystemException {
252 
253         WikiPagePermission.check(
254             getPermissionChecker(), nodeId, title, ActionKeys.UPDATE);
255 
256         return wikiPageLocalService.updatePage(
257             getUserId(), nodeId, title, version, content, format, parentTitle,
258             redirectTitle, tagsEntries, prefs, themeDisplay);
259     }
260 
261     protected String exportToRSS(
262             long companyId, String name, String description, String type,
263             double version, String displayStyle, String feedURL,
264             String entryURL, List<WikiPage> pages, boolean diff, Locale locale)
265         throws SystemException {
266 
267         SyndFeed syndFeed = new SyndFeedImpl();
268 
269         syndFeed.setFeedType(type + "_" + version);
270         syndFeed.setTitle(name);
271         syndFeed.setLink(feedURL);
272         syndFeed.setDescription(description);
273 
274         List<SyndEntry> entries = new ArrayList<SyndEntry>();
275 
276         syndFeed.setEntries(entries);
277 
278         WikiPage latestPage = null;
279 
280         for (WikiPage page : pages) {
281             String author = PortalUtil.getUserName(
282                 page.getUserId(), page.getUserName());
283 
284             String link = entryURL;
285 
286             SyndEntry syndEntry = new SyndEntryImpl();
287 
288             syndEntry.setAuthor(author);
289             syndEntry.setTitle(
290                 page.getTitle() + StringPool.SPACE + page.getVersion());
291             syndEntry.setPublishedDate(page.getCreateDate());
292 
293             SyndContent syndContent = new SyndContentImpl();
294 
295             syndContent.setType("html");
296 
297             if (diff) {
298                 if (latestPage != null) {
299                     link +=
300                         "?" + PortalUtil.getPortletNamespace(PortletKeys.WIKI) +
301                             "version=" + page.getVersion();
302 
303                     String value = getPageDiff(
304                         companyId, latestPage, page, locale);
305 
306                     syndContent.setValue(value);
307 
308                     syndEntry.setDescription(syndContent);
309 
310                     entries.add(syndEntry);
311                 }
312             }
313             else {
314                 String value = null;
315 
316                 if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_ABSTRACT)) {
317                     value = StringUtil.shorten(
318                         HtmlUtil.extractText(page.getContent()),
319                         _RSS_ABSTRACT_LENGTH, StringPool.BLANK);
320                 }
321                 else if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_TITLE)) {
322                     value = StringPool.BLANK;
323                 }
324                 else {
325                     value = page.getContent();
326                 }
327 
328                 syndContent.setValue(value);
329 
330                 syndEntry.setDescription(syndContent);
331 
332                 entries.add(syndEntry);
333             }
334 
335             syndEntry.setLink(link);
336 
337             latestPage = page;
338         }
339 
340         try {
341             return RSSUtil.export(syndFeed);
342         }
343         catch (FeedException fe) {
344             throw new SystemException(fe);
345         }
346         catch (IOException ioe) {
347             throw new SystemException(ioe);
348         }
349     }
350 
351     protected String getPageDiff(
352             long companyId, WikiPage latestPage, WikiPage page,
353             Locale locale)
354         throws SystemException {
355 
356         String sourceContent = WikiUtil.processContent(latestPage.getContent());
357         String targetContent = WikiUtil.processContent(page.getContent());
358 
359         sourceContent = HtmlUtil.escape(sourceContent);
360         targetContent = HtmlUtil.escape(targetContent);
361 
362         List<DiffResult>[] diffResults = DiffUtil.diff(
363             new StringReader(sourceContent), new StringReader(targetContent));
364 
365         String template = ContentUtil.get(
366             "com/liferay/portlet/wiki/dependencies/rss.vm");
367 
368         Map<String, Object> variables = new HashMap<String, Object>();
369 
370         variables.put("companyId", companyId);
371         variables.put("contextLine", DiffUtil.CONTEXT_LINE);
372         variables.put("diffUtil", new DiffUtil());
373         variables.put("languageUtil", LanguageUtil.getLanguage());
374         variables.put("locale", locale);
375         variables.put("sourceResults", diffResults[0]);
376         variables.put("targetResults", diffResults[1]);
377 
378         try {
379             return VelocityUtil.evaluate(template, variables);
380         }
381         catch (Exception e) {
382             throw new SystemException(e);
383         }
384     }
385 
386     private static final int _MAX_END = 200;
387 
388     private static final int _RSS_ABSTRACT_LENGTH = GetterUtil.getInteger(
389         PropsUtil.get(PropsUtil.WIKI_RSS_ABSTRACT_LENGTH));
390 
391 }