1
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.Diff;
29 import com.liferay.portal.kernel.util.DiffResult;
30 import com.liferay.portal.kernel.util.DiffUtil;
31 import com.liferay.portal.kernel.util.GetterUtil;
32 import com.liferay.portal.kernel.util.HtmlUtil;
33 import com.liferay.portal.kernel.util.ObjectValuePair;
34 import com.liferay.portal.kernel.util.StringPool;
35 import com.liferay.portal.kernel.util.StringUtil;
36 import com.liferay.portal.kernel.velocity.VelocityContext;
37 import com.liferay.portal.kernel.velocity.VelocityEngineUtil;
38 import com.liferay.portal.security.permission.ActionKeys;
39 import com.liferay.portal.theme.ThemeDisplay;
40 import com.liferay.portal.util.ContentUtil;
41 import com.liferay.portal.util.PortalUtil;
42 import com.liferay.portal.util.PortletKeys;
43 import com.liferay.portal.util.PropsKeys;
44 import com.liferay.portal.util.PropsUtil;
45 import com.liferay.portlet.wiki.model.WikiNode;
46 import com.liferay.portlet.wiki.model.WikiPage;
47 import com.liferay.portlet.wiki.model.impl.WikiPageImpl;
48 import com.liferay.portlet.wiki.service.base.WikiPageServiceBaseImpl;
49 import com.liferay.portlet.wiki.service.permission.WikiNodePermission;
50 import com.liferay.portlet.wiki.service.permission.WikiPagePermission;
51 import com.liferay.portlet.wiki.util.WikiUtil;
52 import com.liferay.portlet.wiki.util.comparator.PageCreateDateComparator;
53 import com.liferay.util.RSSUtil;
54
55 import com.sun.syndication.feed.synd.SyndContent;
56 import com.sun.syndication.feed.synd.SyndContentImpl;
57 import com.sun.syndication.feed.synd.SyndEntry;
58 import com.sun.syndication.feed.synd.SyndEntryImpl;
59 import com.sun.syndication.feed.synd.SyndFeed;
60 import com.sun.syndication.feed.synd.SyndFeedImpl;
61 import com.sun.syndication.io.FeedException;
62
63 import java.io.StringReader;
64 import java.io.StringWriter;
65
66 import java.util.ArrayList;
67 import java.util.Iterator;
68 import java.util.List;
69 import java.util.Locale;
70
71 import javax.portlet.PortletPreferences;
72
73
81 public class WikiPageServiceImpl extends WikiPageServiceBaseImpl {
82
83 public WikiPage addPage(
84 long nodeId, String title, String content, String summary,
85 boolean minorEdit, PortletPreferences prefs,
86 ThemeDisplay themeDisplay)
87 throws PortalException, SystemException {
88
89 WikiNodePermission.check(
90 getPermissionChecker(), nodeId, ActionKeys.ADD_PAGE);
91
92 return wikiPageLocalService.addPage(
93 getUserId(), nodeId, title, content, summary, minorEdit, prefs,
94 themeDisplay);
95 }
96
97 public WikiPage addPage(
98 long nodeId, String title, String content, String summary,
99 boolean minorEdit, String format, String parentTitle,
100 String redirectTitle, String[] tagsEntries,
101 PortletPreferences prefs, ThemeDisplay themeDisplay)
102 throws PortalException, SystemException {
103
104 WikiNodePermission.check(
105 getPermissionChecker(), nodeId, ActionKeys.ADD_PAGE);
106
107 return wikiPageLocalService.addPage(
108 null, getUserId(), nodeId, title, WikiPageImpl.DEFAULT_VERSION,
109 content, summary, minorEdit, format, true, parentTitle,
110 redirectTitle, tagsEntries, prefs, themeDisplay);
111 }
112
113 public void addPageAttachments(
114 long nodeId, String title,
115 List<ObjectValuePair<String, byte[]>> files)
116 throws PortalException, SystemException {
117
118 WikiNodePermission.check(
119 getPermissionChecker(), nodeId, ActionKeys.ADD_ATTACHMENT);
120
121 wikiPageLocalService.addPageAttachments(nodeId, title, files);
122 }
123
124 public void changeParent(
125 long nodeId, String title, String newParentTitle,
126 PortletPreferences prefs, ThemeDisplay themeDisplay)
127 throws PortalException, SystemException {
128
129 WikiPagePermission.check(
130 getPermissionChecker(), nodeId, title, ActionKeys.DELETE);
131
132 WikiNodePermission.check(
133 getPermissionChecker(), nodeId, ActionKeys.ADD_PAGE);
134
135 wikiPageLocalService.changeParent(
136 getUserId(), nodeId, title, newParentTitle, prefs, themeDisplay);
137 }
138
139 public void deletePage(long nodeId, String title)
140 throws PortalException, SystemException {
141
142 WikiPagePermission.check(
143 getPermissionChecker(), nodeId, title, ActionKeys.DELETE);
144
145 wikiPageLocalService.deletePage(nodeId, title);
146 }
147
148 public void deletePageAttachment(long nodeId, String title, String fileName)
149 throws PortalException, SystemException {
150
151 WikiPagePermission.check(
152 getPermissionChecker(), nodeId, title, ActionKeys.DELETE);
153
154 wikiPageLocalService.deletePageAttachment(nodeId, title, fileName);
155 }
156
157 public List<WikiPage> getNodePages(long nodeId, int max)
158 throws PortalException, SystemException {
159
160 List<WikiPage> pages = new ArrayList<WikiPage>();
161
162 int lastIntervalStart = 0;
163 boolean listNotExhausted = true;
164
165 while ((pages.size() < max) && listNotExhausted) {
166 List<WikiPage> pageList = wikiPageLocalService.getPages(
167 nodeId, true, lastIntervalStart, lastIntervalStart + max);
168
169 Iterator<WikiPage> itr = pageList.iterator();
170
171 lastIntervalStart += max;
172 listNotExhausted = (pageList.size() == max);
173
174 while (itr.hasNext() && (pages.size() < max)) {
175 WikiPage page = itr.next();
176
177 if (WikiPagePermission.contains(getPermissionChecker(), page,
178 ActionKeys.VIEW)) {
179
180 pages.add(page);
181 }
182 }
183 }
184
185 return pages;
186 }
187
188 public String getNodePagesRSS(
189 long nodeId, int max, String type, double version,
190 String displayStyle, String feedURL, String entryURL)
191 throws PortalException, SystemException {
192
193 WikiNodePermission.check(
194 getPermissionChecker(), nodeId, ActionKeys.VIEW);
195
196 WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
197
198 long companyId = node.getCompanyId();
199 String name = node.getName();
200 String description = node.getDescription();
201 List<WikiPage> pages = getNodePages(nodeId, max);
202 boolean diff = false;
203 Locale locale = null;
204
205 return exportToRSS(
206 companyId, name, description, type, version, displayStyle,
207 feedURL, entryURL, pages, diff, locale);
208 }
209
210 public WikiPage getPage(long nodeId, String title)
211 throws PortalException, SystemException {
212
213 WikiPagePermission.check(
214 getPermissionChecker(), nodeId, title, ActionKeys.VIEW);
215
216 return wikiPageLocalService.getPage(nodeId, title);
217 }
218
219 public WikiPage getPage(long nodeId, String title, double version)
220 throws PortalException, SystemException {
221
222 WikiPagePermission.check(
223 getPermissionChecker(), nodeId, title, ActionKeys.VIEW);
224
225 return wikiPageLocalService.getPage(nodeId, title, version);
226 }
227
228 public String getPagesRSS(
229 long companyId, long nodeId, String title, int max, String type,
230 double version, String displayStyle, String feedURL,
231 String entryURL, Locale locale)
232 throws PortalException, SystemException {
233
234 WikiPagePermission.check(
235 getPermissionChecker(), nodeId, title, ActionKeys.VIEW);
236
237 String description = title;
238 List<WikiPage> pages = wikiPageLocalService.getPages(
239 nodeId, title, 0, max, new PageCreateDateComparator(true));
240 boolean diff = true;
241
242 return exportToRSS(
243 companyId, title, description, type, version, displayStyle, feedURL,
244 entryURL, pages, diff, locale);
245 }
246
247 public void movePage(
248 long nodeId, String title, String newTitle,
249 PortletPreferences prefs, ThemeDisplay themeDisplay)
250 throws PortalException, SystemException {
251
252 WikiPagePermission.check(
253 getPermissionChecker(), nodeId, title, ActionKeys.DELETE);
254
255 WikiNodePermission.check(
256 getPermissionChecker(), nodeId, ActionKeys.ADD_PAGE);
257
258 wikiPageLocalService.movePage(
259 getUserId(), nodeId, title, newTitle, prefs, themeDisplay);
260 }
261
262 public WikiPage revertPage(
263 long nodeId, String title, double version, PortletPreferences prefs,
264 ThemeDisplay themeDisplay)
265 throws PortalException, SystemException {
266
267 WikiPagePermission.check(
268 getPermissionChecker(), nodeId, title, ActionKeys.UPDATE);
269
270 return wikiPageLocalService.revertPage(
271 getUserId(), nodeId, title, version, prefs, themeDisplay);
272 }
273
274 public void subscribePage(long nodeId, String title)
275 throws PortalException, SystemException {
276
277 WikiPagePermission.check(
278 getPermissionChecker(), nodeId, title, ActionKeys.SUBSCRIBE);
279
280 wikiPageLocalService.subscribePage(getUserId(), nodeId, title);
281 }
282
283 public void unsubscribePage(long nodeId, String title)
284 throws PortalException, SystemException {
285
286 WikiPagePermission.check(
287 getPermissionChecker(), nodeId, title, ActionKeys.SUBSCRIBE);
288
289 wikiPageLocalService.unsubscribePage(getUserId(), nodeId, title);
290 }
291
292 public WikiPage updatePage(
293 long nodeId, String title, double version, String content,
294 String summary, boolean minorEdit, String format,
295 String parentTitle, String redirectTitle, String[] tagsEntries,
296 PortletPreferences prefs, ThemeDisplay themeDisplay)
297 throws PortalException, SystemException {
298
299 WikiPagePermission.check(
300 getPermissionChecker(), nodeId, title, ActionKeys.UPDATE);
301
302 return wikiPageLocalService.updatePage(
303 getUserId(), nodeId, title, version, content, summary, minorEdit,
304 format, parentTitle, redirectTitle, tagsEntries, prefs,
305 themeDisplay);
306 }
307
308 protected String exportToRSS(
309 long companyId, String name, String description, String type,
310 double version, String displayStyle, String feedURL,
311 String entryURL, List<WikiPage> pages, boolean diff, Locale locale)
312 throws SystemException {
313
314 SyndFeed syndFeed = new SyndFeedImpl();
315
316 syndFeed.setFeedType(RSSUtil.getFeedType(type, version));
317 syndFeed.setTitle(name);
318 syndFeed.setLink(feedURL);
319 syndFeed.setDescription(description);
320
321 List<SyndEntry> entries = new ArrayList<SyndEntry>();
322
323 syndFeed.setEntries(entries);
324
325 WikiPage latestPage = null;
326
327 for (WikiPage page : pages) {
328 String author = PortalUtil.getUserName(
329 page.getUserId(), page.getUserName());
330
331 String title =
332 page.getTitle() + StringPool.SPACE + page.getVersion();
333
334 if (page.isMinorEdit()) {
335 title +=
336 StringPool.SPACE + StringPool.OPEN_PARENTHESIS +
337 LanguageUtil.get(locale, "minor-edit") +
338 StringPool.CLOSE_PARENTHESIS;
339 }
340
341 String link = entryURL;
342
343 SyndEntry syndEntry = new SyndEntryImpl();
344
345 syndEntry.setAuthor(author);
346 syndEntry.setTitle(title);
347 syndEntry.setPublishedDate(page.getCreateDate());
348 syndEntry.setUpdatedDate(page.getModifiedDate());
349
350 SyndContent syndContent = new SyndContentImpl();
351
352 syndContent.setType(RSSUtil.DEFAULT_ENTRY_TYPE);
353
354 if (diff) {
355 if (latestPage != null) {
356 link +=
357 "?" + PortalUtil.getPortletNamespace(PortletKeys.WIKI) +
358 "version=" + page.getVersion();
359
360 String value = getPageDiff(
361 companyId, latestPage, page, locale);
362
363 syndContent.setValue(value);
364
365 syndEntry.setDescription(syndContent);
366
367 entries.add(syndEntry);
368 }
369 }
370 else {
371 String value = null;
372
373 if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_ABSTRACT)) {
374 value = StringUtil.shorten(
375 HtmlUtil.extractText(page.getContent()),
376 _RSS_ABSTRACT_LENGTH, StringPool.BLANK);
377 }
378 else if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_TITLE)) {
379 value = StringPool.BLANK;
380 }
381 else {
382 value = page.getContent();
383 }
384
385 syndContent.setValue(value);
386
387 syndEntry.setDescription(syndContent);
388
389 entries.add(syndEntry);
390 }
391
392 syndEntry.setLink(link);
393 syndEntry.setUri(syndEntry.getLink());
394
395 latestPage = page;
396 }
397
398 try {
399 return RSSUtil.export(syndFeed);
400 }
401 catch (FeedException fe) {
402 throw new SystemException(fe);
403 }
404 }
405
406 protected String getPageDiff(
407 long companyId, WikiPage latestPage, WikiPage page,
408 Locale locale)
409 throws SystemException {
410
411 String sourceContent = WikiUtil.processContent(latestPage.getContent());
412 String targetContent = WikiUtil.processContent(page.getContent());
413
414 sourceContent = HtmlUtil.escape(sourceContent);
415 targetContent = HtmlUtil.escape(targetContent);
416
417 List<DiffResult>[] diffResults = DiffUtil.diff(
418 new StringReader(sourceContent), new StringReader(targetContent));
419
420 String velocityTemplateId =
421 "com/liferay/portlet/wiki/dependencies/rss.vm";
422 String velocityTemplateContent = ContentUtil.get(velocityTemplateId);
423
424 VelocityContext velocityContext =
425 VelocityEngineUtil.getWrappedStandardToolsContext();
426
427 velocityContext.put("companyId", companyId);
428 velocityContext.put("contextLine", Diff.CONTEXT_LINE);
429 velocityContext.put("diffUtil", new DiffUtil());
430 velocityContext.put("languageUtil", LanguageUtil.getLanguage());
431 velocityContext.put("locale", locale);
432 velocityContext.put("sourceResults", diffResults[0]);
433 velocityContext.put("targetResults", diffResults[1]);
434
435 try {
436 StringWriter stringWriter = new StringWriter();
437
438 VelocityEngineUtil.mergeTemplate(
439 velocityTemplateId, velocityTemplateContent, velocityContext,
440 stringWriter);
441
442 return stringWriter.toString();
443 }
444 catch (Exception e) {
445 throw new SystemException(e);
446 }
447 }
448
449 private static final int _RSS_ABSTRACT_LENGTH = GetterUtil.getInteger(
450 PropsUtil.get(PropsKeys.WIKI_RSS_ABSTRACT_LENGTH));
451
452 }