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