001
014
015 package com.liferay.portlet.wiki.util;
016
017 import com.liferay.portal.kernel.configuration.Filter;
018 import com.liferay.portal.kernel.exception.PortalException;
019 import com.liferay.portal.kernel.exception.SystemException;
020 import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
021 import com.liferay.portal.kernel.portlet.LiferayPortletURL;
022 import com.liferay.portal.kernel.util.DiffHtmlUtil;
023 import com.liferay.portal.kernel.util.GetterUtil;
024 import com.liferay.portal.kernel.util.HtmlUtil;
025 import com.liferay.portal.kernel.util.HttpUtil;
026 import com.liferay.portal.kernel.util.InstancePool;
027 import com.liferay.portal.kernel.util.ListUtil;
028 import com.liferay.portal.kernel.util.OrderByComparator;
029 import com.liferay.portal.kernel.util.ParamUtil;
030 import com.liferay.portal.kernel.util.PropsKeys;
031 import com.liferay.portal.kernel.util.StringBundler;
032 import com.liferay.portal.kernel.util.StringPool;
033 import com.liferay.portal.kernel.util.StringUtil;
034 import com.liferay.portal.kernel.util.Validator;
035 import com.liferay.portal.security.permission.ActionKeys;
036 import com.liferay.portal.security.permission.PermissionChecker;
037 import com.liferay.portal.theme.ThemeDisplay;
038 import com.liferay.portal.util.PortalUtil;
039 import com.liferay.portal.util.PropsUtil;
040 import com.liferay.portal.util.PropsValues;
041 import com.liferay.portal.util.WebKeys;
042 import com.liferay.portlet.PortletURLUtil;
043 import com.liferay.portlet.wiki.PageContentException;
044 import com.liferay.portlet.wiki.WikiFormatException;
045 import com.liferay.portlet.wiki.engines.WikiEngine;
046 import com.liferay.portlet.wiki.model.WikiNode;
047 import com.liferay.portlet.wiki.model.WikiPage;
048 import com.liferay.portlet.wiki.model.WikiPageDisplay;
049 import com.liferay.portlet.wiki.service.WikiNodeLocalServiceUtil;
050 import com.liferay.portlet.wiki.service.permission.WikiNodePermission;
051 import com.liferay.portlet.wiki.util.comparator.PageCreateDateComparator;
052 import com.liferay.portlet.wiki.util.comparator.PageTitleComparator;
053 import com.liferay.portlet.wiki.util.comparator.PageVersionComparator;
054 import com.liferay.util.ContentUtil;
055
056 import java.io.IOException;
057
058 import java.util.ArrayList;
059 import java.util.Arrays;
060 import java.util.Collections;
061 import java.util.HashSet;
062 import java.util.Iterator;
063 import java.util.List;
064 import java.util.Map;
065 import java.util.Set;
066 import java.util.concurrent.ConcurrentHashMap;
067 import java.util.regex.Matcher;
068 import java.util.regex.Pattern;
069
070 import javax.portlet.PortletPreferences;
071 import javax.portlet.PortletRequest;
072 import javax.portlet.PortletURL;
073 import javax.portlet.RenderRequest;
074 import javax.portlet.RenderResponse;
075
076
080 public class WikiUtil {
081
082 public static String convert(
083 WikiPage page, PortletURL viewPageURL, PortletURL editPageURL,
084 String attachmentURLPrefix)
085 throws PageContentException, WikiFormatException {
086
087 return _instance._convert(
088 page, viewPageURL, editPageURL, attachmentURLPrefix);
089 }
090
091 public static String diffHtml(
092 WikiPage sourcePage, WikiPage targetPage, PortletURL viewPageURL,
093 PortletURL editPageURL, String attachmentURLPrefix)
094 throws Exception {
095
096 String sourceContent = StringPool.BLANK;
097 String targetContent = StringPool.BLANK;
098
099 if (sourcePage != null) {
100 sourceContent = WikiUtil.convert(
101 sourcePage, viewPageURL, editPageURL, attachmentURLPrefix);
102 }
103
104 if (targetPage != null) {
105 targetContent = WikiUtil.convert(
106 targetPage, viewPageURL, editPageURL, attachmentURLPrefix);
107 }
108
109 return DiffHtmlUtil.diff(
110 new UnsyncStringReader(sourceContent),
111 new UnsyncStringReader(targetContent));
112 }
113
114 public static List<WikiPage> filterOrphans(List<WikiPage> pages)
115 throws PortalException {
116
117 List<Map<String, Boolean>> pageTitles =
118 new ArrayList<Map<String, Boolean>>();
119
120 for (WikiPage page : pages) {
121 pageTitles.add(WikiCacheUtil.getOutgoingLinks(page));
122 }
123
124 Set<WikiPage> notOrphans = new HashSet<WikiPage>();
125
126 for (WikiPage page : pages) {
127 for (Map<String, Boolean> pageTitle : pageTitles) {
128 String pageTitleLowerCase = page.getTitle();
129
130 if (pageTitle.get(pageTitleLowerCase) != null) {
131 notOrphans.add(page);
132
133 break;
134 }
135 }
136 }
137
138 List<WikiPage> orphans = new ArrayList<WikiPage>();
139
140 for (WikiPage page : pages) {
141 if (!notOrphans.contains(page)) {
142 orphans.add(page);
143 }
144 }
145
146 orphans = ListUtil.sort(orphans);
147
148 return orphans;
149 }
150
151 public static String getEditPage(String format) {
152 return _instance._getEditPage(format);
153 }
154
155 public static String getEmailFromAddress(
156 PortletPreferences preferences, long companyId)
157 throws SystemException {
158
159 return PortalUtil.getEmailFromAddress(
160 preferences, companyId, PropsValues.WIKI_EMAIL_FROM_ADDRESS);
161 }
162
163 public static String getEmailFromName(
164 PortletPreferences preferences, long companyId)
165 throws SystemException {
166
167 return PortalUtil.getEmailFromName(
168 preferences, companyId, PropsValues.WIKI_EMAIL_FROM_NAME);
169 }
170
171 public static String getEmailPageAddedBody(PortletPreferences preferences) {
172 String emailPageAddedBody = preferences.getValue(
173 "emailPageAddedBody", StringPool.BLANK);
174
175 if (Validator.isNotNull(emailPageAddedBody)) {
176 return emailPageAddedBody;
177 }
178 else {
179 return ContentUtil.get(
180 PropsUtil.get(PropsKeys.WIKI_EMAIL_PAGE_ADDED_BODY));
181 }
182 }
183
184 public static boolean getEmailPageAddedEnabled(
185 PortletPreferences preferences) {
186
187 String emailPageAddedEnabled = preferences.getValue(
188 "emailPageAddedEnabled", StringPool.BLANK);
189
190 if (Validator.isNotNull(emailPageAddedEnabled)) {
191 return GetterUtil.getBoolean(emailPageAddedEnabled);
192 }
193 else {
194 return GetterUtil.getBoolean(
195 PropsUtil.get(PropsKeys.WIKI_EMAIL_PAGE_ADDED_ENABLED));
196 }
197 }
198
199 public static String getEmailPageAddedSignature(
200 PortletPreferences preferences) {
201
202 String emailPageAddedSignature = preferences.getValue(
203 "emailPageAddedSignature", StringPool.BLANK);
204
205 if (Validator.isNotNull(emailPageAddedSignature)) {
206 return emailPageAddedSignature;
207 }
208 else {
209 return ContentUtil.get(
210 PropsUtil.get(PropsKeys.WIKI_EMAIL_PAGE_ADDED_SIGNATURE));
211 }
212 }
213
214 public static String getEmailPageAddedSubjectPrefix(
215 PortletPreferences preferences) {
216
217 String emailPageAddedSubjectPrefix = preferences.getValue(
218 "emailPageAddedSubjectPrefix", StringPool.BLANK);
219
220 if (Validator.isNotNull(emailPageAddedSubjectPrefix)) {
221 return emailPageAddedSubjectPrefix;
222 }
223 else {
224 return ContentUtil.get(
225 PropsUtil.get(PropsKeys.WIKI_EMAIL_PAGE_ADDED_SUBJECT_PREFIX));
226 }
227 }
228
229 public static String getEmailPageUpdatedBody(
230 PortletPreferences preferences) {
231
232 String emailPageUpdatedBody = preferences.getValue(
233 "emailPageUpdatedBody", StringPool.BLANK);
234
235 if (Validator.isNotNull(emailPageUpdatedBody)) {
236 return emailPageUpdatedBody;
237 }
238 else {
239 return ContentUtil.get(
240 PropsUtil.get(PropsKeys.WIKI_EMAIL_PAGE_UPDATED_BODY));
241 }
242 }
243
244 public static boolean getEmailPageUpdatedEnabled(
245 PortletPreferences preferences) {
246
247 String emailPageUpdatedEnabled = preferences.getValue(
248 "emailPageUpdatedEnabled", StringPool.BLANK);
249
250 if (Validator.isNotNull(emailPageUpdatedEnabled)) {
251 return GetterUtil.getBoolean(emailPageUpdatedEnabled);
252 }
253 else {
254 return GetterUtil.getBoolean(
255 PropsUtil.get(PropsKeys.WIKI_EMAIL_PAGE_UPDATED_ENABLED));
256 }
257 }
258
259 public static String getEmailPageUpdatedSignature(
260 PortletPreferences preferences) {
261
262 String emailPageUpdatedSignature = preferences.getValue(
263 "emailPageUpdatedSignature", StringPool.BLANK);
264
265 if (Validator.isNotNull(emailPageUpdatedSignature)) {
266 return emailPageUpdatedSignature;
267 }
268 else {
269 return ContentUtil.get(
270 PropsUtil.get(PropsKeys.WIKI_EMAIL_PAGE_UPDATED_SIGNATURE));
271 }
272 }
273
274 public static String getEmailPageUpdatedSubjectPrefix(
275 PortletPreferences preferences) {
276
277 String emailPageUpdatedSubject = preferences.getValue(
278 "emailPageUpdatedSubjectPrefix", StringPool.BLANK);
279
280 if (Validator.isNotNull(emailPageUpdatedSubject)) {
281 return emailPageUpdatedSubject;
282 }
283 else {
284 return ContentUtil.get(
285 PropsUtil.get(
286 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_SUBJECT_PREFIX));
287 }
288 }
289
290 public static WikiNode getFirstNode(PortletRequest portletRequest)
291 throws PortalException, SystemException {
292
293 ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
294 WebKeys.THEME_DISPLAY);
295 long groupId = themeDisplay.getScopeGroupId();
296 PermissionChecker permissionChecker =
297 themeDisplay.getPermissionChecker();
298
299 List<WikiNode> nodes = WikiNodeLocalServiceUtil.getNodes(groupId);
300
301 PortletPreferences preferences = portletRequest.getPreferences();
302 String[] visibleNodeNames = StringUtil.split(
303 preferences.getValue("visibleNodes", null));
304 nodes = orderNodes(nodes, visibleNodeNames);
305
306 String[] hiddenNodes = StringUtil.split(
307 preferences.getValue("hiddenNodes", StringPool.BLANK));
308 Arrays.sort(hiddenNodes);
309
310 for (WikiNode node : nodes) {
311 if ((Arrays.binarySearch(hiddenNodes, node.getName()) < 0) &&
312 (WikiNodePermission.contains(
313 permissionChecker, node, ActionKeys.VIEW))) {
314
315 return node;
316 }
317 }
318
319 return null;
320 }
321
322 public static String getFormattedContent(
323 RenderRequest renderRequest, RenderResponse renderResponse,
324 WikiPage wikiPage, PortletURL viewPageURL, PortletURL editPageURL,
325 String title, boolean preview)
326 throws Exception {
327
328 ThemeDisplay themeDisplay = (ThemeDisplay)renderRequest.getAttribute(
329 WebKeys.THEME_DISPLAY);
330
331 double version = ParamUtil.getDouble(renderRequest, "version");
332
333 PortletURL curViewPageURL = PortletURLUtil.clone(
334 viewPageURL, renderResponse);
335 PortletURL curEditPageURL = PortletURLUtil.clone(
336 editPageURL, renderResponse);
337
338 StringBundler sb = new StringBundler();
339
340 sb.append(themeDisplay.getPathMain());
341 sb.append("/wiki/get_page_attachment?p_l_id=");
342 sb.append(themeDisplay.getPlid());
343 sb.append("&nodeId=");
344 sb.append(wikiPage.getNodeId());
345 sb.append("&title=");
346 sb.append(HttpUtil.encodeURL(wikiPage.getTitle()));
347 sb.append("&fileName=");
348
349 String attachmentURLPrefix = sb.toString();
350
351 if (!preview && (version == 0)) {
352 WikiPageDisplay pageDisplay = WikiCacheUtil.getDisplay(
353 wikiPage.getNodeId(), title, curViewPageURL, curEditPageURL,
354 attachmentURLPrefix);
355
356 if (pageDisplay != null) {
357 return pageDisplay.getFormattedContent();
358 }
359 }
360
361 return WikiUtil.convert(
362 wikiPage, curViewPageURL, curEditPageURL, attachmentURLPrefix);
363 }
364
365 public static String getHelpPage(String format) {
366 return _instance._getHelpPage(format);
367 }
368
369 public static String getHelpURL(String format) {
370 return _instance._getHelpURL(format);
371 }
372
373 public static Map<String, Boolean> getLinks(WikiPage page)
374 throws PageContentException {
375
376 return _instance._getLinks(page);
377 }
378
379 public static List<String> getNodeNames(List<WikiNode> nodes) {
380 List<String> nodeNames = new ArrayList<String>(nodes.size());
381
382 for (WikiNode node : nodes) {
383 nodeNames.add(node.getName());
384 }
385
386 return nodeNames;
387 }
388
389 public static List<WikiNode> getNodes(
390 List<WikiNode> nodes, String[] hiddenNodes,
391 PermissionChecker permissionChecker) {
392
393 nodes = ListUtil.copy(nodes);
394
395 Arrays.sort(hiddenNodes);
396
397 Iterator<WikiNode> itr = nodes.iterator();
398
399 while (itr.hasNext()) {
400 WikiNode node = itr.next();
401
402 if (!(Arrays.binarySearch(hiddenNodes, node.getName()) < 0) ||
403 !WikiNodePermission.contains(
404 permissionChecker, node, ActionKeys.VIEW)) {
405
406 itr.remove();
407 }
408 }
409
410 return nodes;
411 }
412
413 public static OrderByComparator getPageOrderByComparator(
414 String orderByCol, String orderByType) {
415
416 boolean orderByAsc = false;
417
418 if (orderByType.equals("asc")) {
419 orderByAsc = true;
420 }
421
422 OrderByComparator orderByComparator = null;
423
424 if (orderByCol.equals("modifiedDate")) {
425 orderByComparator = new PageCreateDateComparator(orderByAsc);
426 }
427 else if (orderByCol.equals("title")) {
428 orderByComparator = new PageTitleComparator(orderByAsc);
429 }
430 else if (orderByCol.equals("version")) {
431 orderByComparator = new PageVersionComparator(orderByAsc);
432 }
433
434 return orderByComparator;
435 }
436
437 public static List<WikiNode> orderNodes(
438 List<WikiNode> nodes, String[] visibleNodeNames) {
439
440 if ((visibleNodeNames == null) || (visibleNodeNames.length == 0)) {
441 return nodes;
442 }
443
444 nodes = ListUtil.copy(nodes);
445
446 List<WikiNode> orderedNodes = new ArrayList<WikiNode>(nodes.size());
447
448 for (String visibleNodeName : visibleNodeNames) {
449 for (WikiNode node : nodes) {
450 if (node.getName().equals(visibleNodeName)) {
451 orderedNodes.add(node);
452
453 nodes.remove(node);
454
455 break;
456 }
457 }
458 }
459
460 orderedNodes.addAll(nodes);
461
462 return orderedNodes;
463 }
464
465 public static String processContent(String content) {
466 content = content.replaceAll("</p>", "</p>\n");
467 content = content.replaceAll("</br>", "</br>\n");
468 content = content.replaceAll("</div>", "</div>\n");
469
470 return content;
471 }
472
473 public static boolean validate(long nodeId, String content, String format)
474 throws WikiFormatException {
475
476 return _instance._validate(nodeId, content, format);
477 }
478
479 private String _convert(
480 WikiPage page, PortletURL viewPageURL, PortletURL editPageURL,
481 String attachmentURLPrefix)
482 throws PageContentException, WikiFormatException {
483
484 LiferayPortletURL liferayViewPageURL = (LiferayPortletURL)viewPageURL;
485 LiferayPortletURL liferayEditPageURL = (LiferayPortletURL)editPageURL;
486
487 WikiEngine engine = _getEngine(page.getFormat());
488
489 String content = engine.convert(
490 page, viewPageURL, editPageURL, attachmentURLPrefix);
491
492 String editPageURLString = StringPool.BLANK;
493
494 if (editPageURL != null) {
495 liferayEditPageURL.setParameter("title", "__REPLACEMENT__", false);
496
497 editPageURLString = editPageURL.toString();
498
499 editPageURLString = StringUtil.replace(
500 editPageURLString, "__REPLACEMENT__", "$1");
501 }
502
503 Matcher matcher = _editPageURLPattern.matcher(content);
504
505 content = _convertURLs(editPageURLString, matcher);
506
507 String viewPageURLString = StringPool.BLANK;
508
509 if (viewPageURL != null) {
510 liferayViewPageURL.setParameter("title", "__REPLACEMENT__", false);
511
512 viewPageURLString = viewPageURL.toString();
513
514 viewPageURLString = StringUtil.replace(
515 viewPageURLString, "__REPLACEMENT__", "$1");
516 }
517
518 matcher = _viewPageURLPattern.matcher(content);
519
520 content = _convertURLs(viewPageURLString, matcher);
521
522 content = _replaceAttachments(
523 content, page.getTitle(), attachmentURLPrefix);
524
525 return content;
526 }
527
528 private String _convertURLs(String url, Matcher matcher) {
529 StringBuffer sb = new StringBuffer();
530
531 while (matcher.find()) {
532 String replacement = null;
533
534 if (matcher.groupCount() >= 1) {
535 String encodedTitle = HttpUtil.encodeURL(
536 HtmlUtil.unescape(matcher.group(1)));
537
538 replacement = url.replace("$1", encodedTitle);
539 }
540 else {
541 replacement = url;
542 }
543
544 matcher.appendReplacement(sb, replacement);
545 }
546
547 return matcher.appendTail(sb).toString();
548 }
549
550 private String _getEditPage(String format) {
551 return PropsUtil.get(
552 PropsKeys.WIKI_FORMATS_EDIT_PAGE, new Filter(format));
553 }
554
555 private WikiEngine _getEngine(String format) throws WikiFormatException {
556 WikiEngine engine = _engines.get(format);
557
558 if (engine != null) {
559 return engine;
560 }
561
562 synchronized (_engines) {
563 engine = _engines.get(format);
564
565 if (engine != null) {
566 return engine;
567 }
568
569 try {
570 String engineClass = PropsUtil.get(
571 PropsKeys.WIKI_FORMATS_ENGINE, new Filter(format));
572
573 if (engineClass == null) {
574 throw new WikiFormatException(format);
575 }
576
577 if (!InstancePool.contains(engineClass)) {
578 engine = (WikiEngine)InstancePool.get(engineClass);
579
580 engine.setMainConfiguration(
581 _readConfigurationFile(
582 PropsKeys.WIKI_FORMATS_CONFIGURATION_MAIN, format));
583
584 engine.setInterWikiConfiguration(
585 _readConfigurationFile(
586 PropsKeys.WIKI_FORMATS_CONFIGURATION_INTERWIKI,
587 format));
588 }
589 else {
590 engine = (WikiEngine)InstancePool.get(engineClass);
591 }
592
593 _engines.put(format, engine);
594
595 return engine;
596 }
597 catch (Exception e) {
598 throw new WikiFormatException(e);
599 }
600 }
601 }
602
603 private String _getHelpPage(String format) {
604 return PropsUtil.get(
605 PropsKeys.WIKI_FORMATS_HELP_PAGE, new Filter(format));
606 }
607
608 private String _getHelpURL(String format) {
609 return PropsUtil.get(
610 PropsKeys.WIKI_FORMATS_HELP_URL, new Filter(format));
611 }
612
613 private Map<String, Boolean> _getLinks(WikiPage page)
614 throws PageContentException {
615
616 try {
617 return _getEngine(page.getFormat()).getOutgoingLinks(page);
618 }
619 catch (WikiFormatException wfe) {
620 return Collections.emptyMap();
621 }
622 }
623
624 private String _readConfigurationFile(String propertyName, String format)
625 throws IOException {
626
627 ClassLoader classLoader = getClass().getClassLoader();
628
629 String configurationFile = PropsUtil.get(
630 propertyName, new Filter(format));
631
632 if (Validator.isNotNull(configurationFile)) {
633 return HttpUtil.URLtoString(
634 classLoader.getResource(configurationFile));
635 }
636 else {
637 return StringPool.BLANK;
638 }
639 }
640
641 private String _replaceAttachments(
642 String content, String title, String attachmentURLPrefix) {
643
644 content = StringUtil.replace(content, "[$WIKI_PAGE_NAME$]", title);
645
646 content = StringUtil.replace(
647 content, "[$ATTACHMENT_URL_PREFIX$]", attachmentURLPrefix);
648
649 return content;
650 }
651
652 private boolean _validate(long nodeId, String content, String format)
653 throws WikiFormatException {
654
655 return _getEngine(format).validate(nodeId, content);
656 }
657
658 private static WikiUtil _instance = new WikiUtil();
659
660 private static Pattern _editPageURLPattern = Pattern.compile(
661 "\\[\\$BEGIN_PAGE_TITLE_EDIT\\$\\](.*?)" +
662 "\\[\\$END_PAGE_TITLE_EDIT\\$\\]");
663 private static Pattern _viewPageURLPattern = Pattern.compile(
664 "\\[\\$BEGIN_PAGE_TITLE\\$\\](.*?)\\[\\$END_PAGE_TITLE\\$\\]");
665
666 private Map<String, WikiEngine> _engines =
667 new ConcurrentHashMap<String, WikiEngine>();
668
669 }