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