1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portlet.wiki.util;
24  
25  import com.liferay.portal.PortalException;
26  import com.liferay.portal.SystemException;
27  import com.liferay.portal.kernel.configuration.Filter;
28  import com.liferay.portal.kernel.portlet.LiferayPortletURL;
29  import com.liferay.portal.kernel.util.ArrayUtil;
30  import com.liferay.portal.kernel.util.GetterUtil;
31  import com.liferay.portal.kernel.util.HttpUtil;
32  import com.liferay.portal.kernel.util.InstancePool;
33  import com.liferay.portal.kernel.util.ListUtil;
34  import com.liferay.portal.kernel.util.StringPool;
35  import com.liferay.portal.kernel.util.StringUtil;
36  import com.liferay.portal.kernel.util.Validator;
37  import com.liferay.portal.security.permission.ActionKeys;
38  import com.liferay.portal.security.permission.PermissionChecker;
39  import com.liferay.portal.theme.ThemeDisplay;
40  import com.liferay.portal.util.ContentUtil;
41  import com.liferay.portal.util.PropsKeys;
42  import com.liferay.portal.util.PropsUtil;
43  import com.liferay.portal.util.PropsValues;
44  import com.liferay.portal.util.WebKeys;
45  import com.liferay.portlet.wiki.PageContentException;
46  import com.liferay.portlet.wiki.WikiFormatException;
47  import com.liferay.portlet.wiki.engines.WikiEngine;
48  import com.liferay.portlet.wiki.model.WikiNode;
49  import com.liferay.portlet.wiki.model.WikiPage;
50  import com.liferay.portlet.wiki.service.WikiNodeLocalServiceUtil;
51  import com.liferay.portlet.wiki.service.permission.WikiNodePermission;
52  import com.liferay.portlet.wiki.util.comparator.VisibleNodesComparator;
53  
54  import java.io.IOException;
55  
56  import java.util.Collections;
57  import java.util.HashMap;
58  import java.util.Iterator;
59  import java.util.List;
60  import java.util.Map;
61  import java.util.regex.Matcher;
62  import java.util.regex.Pattern;
63  
64  import javax.portlet.PortletPreferences;
65  import javax.portlet.PortletURL;
66  import javax.portlet.RenderRequest;
67  
68  /**
69   * <a href="WikiUtil.java.html"><b><i>View Source</i></b></a>
70   *
71   * @author Brian Wing Shun Chan
72   * @author Jorge Ferrer
73   *
74   */
75  public class WikiUtil {
76  
77      public static final String POP_PORTLET_PREFIX = "wiki.";
78  
79      public static String convert(
80              WikiPage page, PortletURL viewPageURL, PortletURL editPageURL,
81              String attachmentURLPrefix)
82          throws PageContentException, WikiFormatException {
83  
84          return _instance._convert(
85              page, viewPageURL, editPageURL, attachmentURLPrefix);
86      }
87  
88      public static String getEditPage(String format) {
89          return _instance._getEditPage(format);
90      }
91  
92      public static String getEmailFromAddress(PortletPreferences preferences) {
93          String emailFromAddress = PropsUtil.get(
94              PropsKeys.WIKI_EMAIL_FROM_ADDRESS);
95  
96          return preferences.getValue("email-from-address", emailFromAddress);
97      }
98  
99      public static String getEmailFromName(PortletPreferences preferences) {
100         String emailFromName = PropsUtil.get(PropsKeys.WIKI_EMAIL_FROM_NAME);
101 
102         return preferences.getValue("email-from-name", emailFromName);
103     }
104 
105     public static boolean getEmailPageAddedEnabled(
106         PortletPreferences preferences) {
107 
108         String emailPageAddedEnabled = preferences.getValue(
109             "email-page-added-enabled", StringPool.BLANK);
110 
111         if (Validator.isNotNull(emailPageAddedEnabled)) {
112             return GetterUtil.getBoolean(emailPageAddedEnabled);
113         }
114         else {
115             return GetterUtil.getBoolean(PropsUtil.get(
116                 PropsKeys.WIKI_EMAIL_PAGE_ADDED_ENABLED));
117         }
118     }
119 
120     public static String getEmailPageAddedBody(PortletPreferences preferences) {
121         String emailPageAddedBody = preferences.getValue(
122             "email-page-added-body", StringPool.BLANK);
123 
124         if (Validator.isNotNull(emailPageAddedBody)) {
125             return emailPageAddedBody;
126         }
127         else {
128             return ContentUtil.get(PropsUtil.get(
129                 PropsKeys.WIKI_EMAIL_PAGE_ADDED_BODY));
130         }
131     }
132 
133     public static String getEmailPageAddedSignature(
134         PortletPreferences preferences) {
135 
136         String emailPageAddedSignature = preferences.getValue(
137             "email-page-added-signature", StringPool.BLANK);
138 
139         if (Validator.isNotNull(emailPageAddedSignature)) {
140             return emailPageAddedSignature;
141         }
142         else {
143             return ContentUtil.get(PropsUtil.get(
144                 PropsKeys.WIKI_EMAIL_PAGE_ADDED_SIGNATURE));
145         }
146     }
147 
148     public static String getEmailPageAddedSubjectPrefix(
149         PortletPreferences preferences) {
150 
151         String emailPageAddedSubjectPrefix = preferences.getValue(
152             "email-page-added-subject-prefix", StringPool.BLANK);
153 
154         if (Validator.isNotNull(emailPageAddedSubjectPrefix)) {
155             return emailPageAddedSubjectPrefix;
156         }
157         else {
158             return ContentUtil.get(PropsUtil.get(
159                 PropsKeys.WIKI_EMAIL_PAGE_ADDED_SUBJECT_PREFIX));
160         }
161     }
162 
163     public static boolean getEmailPageUpdatedEnabled(
164         PortletPreferences preferences) {
165 
166         String emailPageUpdatedEnabled = preferences.getValue(
167             "email-page-updated-enabled", StringPool.BLANK);
168 
169         if (Validator.isNotNull(emailPageUpdatedEnabled)) {
170             return GetterUtil.getBoolean(emailPageUpdatedEnabled);
171         }
172         else {
173             return GetterUtil.getBoolean(PropsUtil.get(
174                 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_ENABLED));
175         }
176     }
177 
178     public static String getEmailPageUpdatedBody(
179         PortletPreferences preferences) {
180 
181         String emailPageUpdatedBody = preferences.getValue(
182             "email-page-updated-body", StringPool.BLANK);
183 
184         if (Validator.isNotNull(emailPageUpdatedBody)) {
185             return emailPageUpdatedBody;
186         }
187         else {
188             return ContentUtil.get(PropsUtil.get(
189                 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_BODY));
190         }
191     }
192 
193     public static String getEmailPageUpdatedSignature(
194         PortletPreferences preferences) {
195 
196         String emailPageUpdatedSignature = preferences.getValue(
197             "email-page-updated-signature", StringPool.BLANK);
198 
199         if (Validator.isNotNull(emailPageUpdatedSignature)) {
200             return emailPageUpdatedSignature;
201         }
202         else {
203             return ContentUtil.get(PropsUtil.get(
204                 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_SIGNATURE));
205         }
206     }
207 
208     public static String getEmailPageUpdatedSubjectPrefix(
209         PortletPreferences preferences) {
210 
211         String emailPageUpdatedSubject = preferences.getValue(
212             "email-page-updated-subject-prefix", StringPool.BLANK);
213 
214         if (Validator.isNotNull(emailPageUpdatedSubject)) {
215             return emailPageUpdatedSubject;
216         }
217         else {
218             return ContentUtil.get(PropsUtil.get(
219                 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_SUBJECT_PREFIX));
220         }
221     }
222 
223     public static String getHelpPage(String format) {
224         return _instance._getHelpPage(format);
225     }
226 
227     public static String getHelpURL(String format) {
228         return _instance._getHelpURL(format);
229     }
230 
231     public static Map<String, Boolean> getLinks(WikiPage page)
232         throws PageContentException {
233 
234         return _instance._getLinks(page);
235     }
236 
237     public static String getMailId(String mx, long nodeId, long pageId) {
238         StringBuilder sb = new StringBuilder();
239 
240         sb.append(StringPool.LESS_THAN);
241         sb.append(POP_PORTLET_PREFIX);
242         sb.append(nodeId);
243         sb.append(StringPool.PERIOD);
244         sb.append(pageId);
245         sb.append(StringPool.AT);
246         sb.append(PropsValues.POP_SERVER_SUBDOMAIN);
247         sb.append(StringPool.PERIOD);
248         sb.append(mx);
249         sb.append(StringPool.GREATER_THAN);
250 
251         return sb.toString();
252     }
253 
254     public static List<WikiNode> getNodes(RenderRequest renderRequest)
255         throws PortalException, SystemException {
256 
257         ThemeDisplay themeDisplay = (ThemeDisplay)renderRequest.getAttribute(
258             WebKeys.THEME_DISPLAY);
259 
260         long groupId = themeDisplay.getScopeGroupId();
261 
262         String allNodes = ListUtil.toString(
263             WikiNodeLocalServiceUtil.getNodes(groupId), "name");
264 
265         String[] visibleNodes = StringUtil.split(
266             renderRequest.getPreferences().getValue("visible-nodes", allNodes));
267         String[] hiddenNodes = StringUtil.split(
268             renderRequest.getPreferences().getValue(
269                 "hidden-nodes", StringPool.BLANK));
270 
271         return getNodes(
272             groupId, visibleNodes, hiddenNodes,
273             themeDisplay.getPermissionChecker());
274     }
275 
276     public static List<WikiNode> getNodes(
277             long groupId, String[] visibleNodes, String[] hiddenNodes,
278             PermissionChecker permissionChecker)
279         throws PortalException, SystemException {
280 
281         List<WikiNode> nodes = WikiNodeLocalServiceUtil.getNodes(groupId);
282 
283         nodes = ListUtil.sort(nodes, new VisibleNodesComparator(visibleNodes));
284 
285         Iterator<WikiNode> itr = nodes.iterator();
286 
287         while (itr.hasNext()) {
288             WikiNode node = itr.next();
289 
290             if (ArrayUtil.contains(hiddenNodes, node.getName()) ||
291                 !WikiNodePermission.contains(
292                     permissionChecker, node.getNodeId(), ActionKeys.VIEW)) {
293 
294                 itr.remove();
295             }
296         }
297 
298         return nodes;
299     }
300 
301     public static String processContent(String content) {
302         content = content.replaceAll("</p>", "</p>\n");
303         content = content.replaceAll("</br>", "</br>\n");
304         content = content.replaceAll("</div>", "</div>\n");
305 
306         return content;
307     }
308 
309     public static boolean validate(
310             long nodeId, String content, String format)
311         throws WikiFormatException {
312 
313         return _instance._validate(nodeId, content, format);
314     }
315 
316     private String _convert(
317             WikiPage page, PortletURL viewPageURL, PortletURL editPageURL,
318             String attachmentURLPrefix)
319         throws PageContentException, WikiFormatException {
320 
321         LiferayPortletURL liferayViewPageURL = (LiferayPortletURL)viewPageURL;
322         LiferayPortletURL liferayEditPageURL = (LiferayPortletURL)editPageURL;
323 
324         WikiEngine engine = _getEngine(page.getFormat());
325 
326         String content = engine.convert(page, editPageURL);
327 
328         liferayEditPageURL.setParameter("title", "__REPLACEMENT__", false);
329 
330         String editPageURLString = editPageURL.toString();
331 
332         editPageURLString = StringUtil.replace(
333             editPageURLString, "__REPLACEMENT__", "$1");
334 
335         Matcher matcher = _editPageURLPattern.matcher(content);
336 
337         content = matcher.replaceAll(editPageURLString);
338 
339         liferayViewPageURL.setParameter("title", "__REPLACEMENT__", false);
340 
341         String viewPageURLString = viewPageURL.toString();
342 
343         viewPageURLString = StringUtil.replace(
344             viewPageURLString, "__REPLACEMENT__", "$1");
345 
346         matcher = _viewPageURLPattern.matcher(content);
347 
348         content = matcher.replaceAll(viewPageURLString);
349 
350         content = _replaceAttachments(
351             content, page.getTitle(), attachmentURLPrefix);
352 
353         return content;
354     }
355 
356     private String _getEditPage(String format) {
357         return PropsUtil.get(
358             PropsKeys.WIKI_FORMATS_EDIT_PAGE, new Filter(format));
359     }
360 
361     private WikiEngine _getEngine(String format) throws WikiFormatException {
362         WikiEngine engine = _engines.get(format);
363 
364         if (engine == null) {
365             try {
366                 String engineClass = PropsUtil.get(
367                     PropsKeys.WIKI_FORMATS_ENGINE, new Filter(format));
368 
369                 if (engineClass != null) {
370                     if (!InstancePool.contains(engineClass)) {
371                         engine = (WikiEngine)InstancePool.get(engineClass);
372 
373                         engine.setMainConfiguration(
374                             _readConfigurationFile(
375                                 PropsKeys.WIKI_FORMATS_CONFIGURATION_MAIN,
376                                 format));
377 
378                         engine.setInterWikiConfiguration(
379                             _readConfigurationFile(
380                                 PropsKeys.WIKI_FORMATS_CONFIGURATION_INTERWIKI,
381                                 format));
382                     }
383                     else {
384                         engine = (WikiEngine)InstancePool.get(engineClass);
385                     }
386 
387                     _engines.put(format, engine);
388                 }
389             }
390             catch (Exception e) {
391                 throw new WikiFormatException(e);
392             }
393 
394             if (engine == null) {
395                 throw new WikiFormatException(format);
396             }
397         }
398 
399         return engine;
400     }
401 
402     private String _getHelpPage(String format) {
403         return PropsUtil.get(
404             PropsKeys.WIKI_FORMATS_HELP_PAGE, new Filter(format));
405     }
406 
407     private String _getHelpURL(String format) {
408         return PropsUtil.get(
409             PropsKeys.WIKI_FORMATS_HELP_URL, new Filter(format));
410     }
411 
412     private Map<String, Boolean> _getLinks(WikiPage page)
413         throws PageContentException {
414 
415         try {
416             return _getEngine(page.getFormat()).getOutgoingLinks(page);
417         }
418         catch (WikiFormatException wfe) {
419             return Collections.EMPTY_MAP;
420         }
421     }
422 
423     private String _readConfigurationFile(String propertyName, String format)
424         throws IOException {
425 
426         ClassLoader classLoader = getClass().getClassLoader();
427 
428         String configurationFile = PropsUtil.get(
429             propertyName, new Filter(format));
430 
431         if (Validator.isNotNull(configurationFile)) {
432             return HttpUtil.URLtoString(
433                 classLoader.getResource(configurationFile));
434         }
435         else {
436             return StringPool.BLANK;
437         }
438     }
439 
440     private String _replaceAttachments(
441         String content, String title, String attachmentURLPrefix) {
442 
443         content = StringUtil.replace(content, "[$WIKI_PAGE_NAME$]", title);
444 
445         content = StringUtil.replace(
446             content, "[$ATTACHMENT_URL_PREFIX$]", attachmentURLPrefix);
447 
448         return content;
449     }
450 
451     private boolean _validate(long nodeId, String content, String format)
452         throws WikiFormatException {
453 
454         return _getEngine(format).validate(nodeId, content);
455     }
456 
457     private static WikiUtil _instance = new WikiUtil();
458 
459     private static Pattern _editPageURLPattern = Pattern.compile(
460         "\\[\\$BEGIN_PAGE_TITLE_EDIT\\$\\](.*?)\\[\\$END_PAGE_TITLE_EDIT\\$\\]");
461     private static Pattern _viewPageURLPattern = Pattern.compile(
462         "\\[\\$BEGIN_PAGE_TITLE\\$\\](.*?)\\[\\$END_PAGE_TITLE\\$\\]");
463 
464     private Map<String, WikiEngine> _engines =
465         new HashMap<String, WikiEngine>();
466 
467 }