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