1   /**
2    * Copyright (c) 2000-2008 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 prefs) {
93          String emailFromAddress = PropsUtil.get(
94              PropsKeys.WIKI_EMAIL_FROM_ADDRESS);
95  
96          return prefs.getValue("email-from-address", emailFromAddress);
97      }
98  
99      public static String getEmailFromName(PortletPreferences prefs) {
100         String emailFromName = PropsUtil.get(PropsKeys.WIKI_EMAIL_FROM_NAME);
101 
102         return prefs.getValue("email-from-name", emailFromName);
103     }
104 
105     public static boolean getEmailPageAddedEnabled(
106         PortletPreferences prefs) {
107 
108         String emailPageAddedEnabled = prefs.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 prefs) {
121         String emailPageAddedBody = prefs.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(PortletPreferences prefs) {
134         String emailPageAddedSignature = prefs.getValue(
135             "email-page-added-signature", StringPool.BLANK);
136 
137         if (Validator.isNotNull(emailPageAddedSignature)) {
138             return emailPageAddedSignature;
139         }
140         else {
141             return ContentUtil.get(PropsUtil.get(
142                 PropsKeys.WIKI_EMAIL_PAGE_ADDED_SIGNATURE));
143         }
144     }
145 
146     public static String getEmailPageAddedSubjectPrefix(
147         PortletPreferences prefs) {
148 
149         String emailPageAddedSubjectPrefix = prefs.getValue(
150             "email-page-added-subject-prefix", StringPool.BLANK);
151 
152         if (Validator.isNotNull(emailPageAddedSubjectPrefix)) {
153             return emailPageAddedSubjectPrefix;
154         }
155         else {
156             return ContentUtil.get(PropsUtil.get(
157                 PropsKeys.WIKI_EMAIL_PAGE_ADDED_SUBJECT_PREFIX));
158         }
159     }
160 
161     public static boolean getEmailPageUpdatedEnabled(
162         PortletPreferences prefs) {
163 
164         String emailPageUpdatedEnabled = prefs.getValue(
165             "email-page-updated-enabled", StringPool.BLANK);
166 
167         if (Validator.isNotNull(emailPageUpdatedEnabled)) {
168             return GetterUtil.getBoolean(emailPageUpdatedEnabled);
169         }
170         else {
171             return GetterUtil.getBoolean(PropsUtil.get(
172                 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_ENABLED));
173         }
174     }
175 
176     public static String getEmailPageUpdatedBody(PortletPreferences prefs) {
177         String emailPageUpdatedBody = prefs.getValue(
178             "email-page-updated-body", StringPool.BLANK);
179 
180         if (Validator.isNotNull(emailPageUpdatedBody)) {
181             return emailPageUpdatedBody;
182         }
183         else {
184             return ContentUtil.get(PropsUtil.get(
185                 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_BODY));
186         }
187     }
188 
189     public static String getEmailPageUpdatedSignature(
190         PortletPreferences prefs) {
191 
192         String emailPageUpdatedSignature = prefs.getValue(
193             "email-page-updated-signature", StringPool.BLANK);
194 
195         if (Validator.isNotNull(emailPageUpdatedSignature)) {
196             return emailPageUpdatedSignature;
197         }
198         else {
199             return ContentUtil.get(PropsUtil.get(
200                 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_SIGNATURE));
201         }
202     }
203 
204     public static String getEmailPageUpdatedSubjectPrefix(
205         PortletPreferences prefs) {
206 
207         String emailPageUpdatedSubject = prefs.getValue(
208             "email-page-updated-subject-prefix", StringPool.BLANK);
209 
210         if (Validator.isNotNull(emailPageUpdatedSubject)) {
211             return emailPageUpdatedSubject;
212         }
213         else {
214             return ContentUtil.get(PropsUtil.get(
215                 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_SUBJECT_PREFIX));
216         }
217     }
218 
219     public static String getHelpPage(String format) {
220         return _instance._getHelpPage(format);
221     }
222 
223     public static String getHelpURL(String format) {
224         return _instance._getHelpURL(format);
225     }
226 
227     public static Map<String, Boolean> getLinks(WikiPage page)
228         throws PageContentException {
229 
230         return _instance._getLinks(page);
231     }
232 
233     public static String getMailId(String mx, long nodeId, long pageId) {
234         StringBuilder sb = new StringBuilder();
235 
236         sb.append(StringPool.LESS_THAN);
237         sb.append(POP_PORTLET_PREFIX);
238         sb.append(nodeId);
239         sb.append(StringPool.PERIOD);
240         sb.append(pageId);
241         sb.append(StringPool.AT);
242         sb.append(PropsValues.POP_SERVER_SUBDOMAIN);
243         sb.append(StringPool.PERIOD);
244         sb.append(mx);
245         sb.append(StringPool.GREATER_THAN);
246 
247         return sb.toString();
248     }
249 
250     public static List<WikiNode> getNodes(RenderRequest renderRequest)
251         throws PortalException, SystemException {
252 
253         ThemeDisplay themeDisplay = (ThemeDisplay)renderRequest.getAttribute(
254             WebKeys.THEME_DISPLAY);
255 
256         long groupId = themeDisplay.getLayout().getGroupId();
257 
258         String allNodes = ListUtil.toString(
259             WikiNodeLocalServiceUtil.getNodes(groupId), "name");
260 
261         String[] visibleNodes = StringUtil.split(
262             renderRequest.getPreferences().getValue("visible-nodes", allNodes));
263         String[] hiddenNodes = StringUtil.split(
264             renderRequest.getPreferences().getValue(
265                 "hidden-nodes", StringPool.BLANK));
266 
267         return getNodes(
268             groupId, visibleNodes, hiddenNodes,
269             themeDisplay.getPermissionChecker());
270     }
271 
272     public static List<WikiNode> getNodes(
273             long groupId, String[] visibleNodes, String[] hiddenNodes,
274             PermissionChecker permissionChecker)
275         throws PortalException, SystemException {
276 
277         List<WikiNode> nodes = WikiNodeLocalServiceUtil.getNodes(groupId);
278 
279         Iterator<WikiNode> itr = nodes.iterator();
280 
281         while (itr.hasNext()) {
282             WikiNode node = itr.next();
283 
284             if (ArrayUtil.contains(hiddenNodes, node.getName()) ||
285                 !WikiNodePermission.contains(
286                     permissionChecker, node.getNodeId(), ActionKeys.VIEW)) {
287 
288                 itr.remove();
289             }
290         }
291 
292         Collections.sort(nodes, new VisibleNodesComparator(visibleNodes));
293 
294         return nodes;
295     }
296 
297     public static String processContent(String content) {
298         content = content.replaceAll("</p>", "</p>\n");
299         content = content.replaceAll("</br>", "</br>\n");
300         content = content.replaceAll("</div>", "</div>\n");
301 
302         return content;
303     }
304 
305     public static boolean validate(
306             long nodeId, String content, String format)
307         throws WikiFormatException {
308 
309         return _instance._validate(nodeId, content, format);
310     }
311 
312     private String _convert(
313             WikiPage page, PortletURL viewPageURL, PortletURL editPageURL,
314             String attachmentURLPrefix)
315         throws PageContentException, WikiFormatException {
316 
317         LiferayPortletURL liferayViewPageURL = (LiferayPortletURL)viewPageURL;
318         LiferayPortletURL liferayEditPageURL = (LiferayPortletURL)editPageURL;
319 
320         WikiEngine engine = _getEngine(page.getFormat());
321 
322         String content = engine.convert(page, editPageURL);
323 
324         liferayEditPageURL.setParameter("title", "__REPLACEMENT__", false);
325 
326         String editPageURLString = editPageURL.toString();
327 
328         editPageURLString = StringUtil.replace(
329             editPageURLString, "__REPLACEMENT__", "$1");
330 
331         Matcher matcher = _editPageURLPattern.matcher(content);
332 
333         content = matcher.replaceAll(editPageURLString);
334 
335         liferayViewPageURL.setParameter("title", "__REPLACEMENT__", false);
336 
337         String viewPageURLString = viewPageURL.toString();
338 
339         viewPageURLString = StringUtil.replace(
340             viewPageURLString, "__REPLACEMENT__", "$1");
341 
342         matcher = _viewPageURLPattern.matcher(content);
343 
344         content = matcher.replaceAll(viewPageURLString);
345 
346         content = _replaceAttachments(
347             content, page.getTitle(), attachmentURLPrefix);
348 
349         return content;
350     }
351 
352     private String _getEditPage(String format) {
353         return PropsUtil.get(
354             PropsKeys.WIKI_FORMATS_EDIT_PAGE, new Filter(format));
355     }
356 
357     private WikiEngine _getEngine(String format) throws WikiFormatException {
358         WikiEngine engine = _engines.get(format);
359 
360         if (engine == null) {
361             try {
362                 String engineClass = PropsUtil.get(
363                     PropsKeys.WIKI_FORMATS_ENGINE, new Filter(format));
364 
365                 if (engineClass != null) {
366                     if (!InstancePool.contains(engineClass)) {
367                         engine = (WikiEngine)InstancePool.get(engineClass);
368 
369                         engine.setMainConfiguration(
370                             _readConfigurationFile(
371                                 PropsKeys.WIKI_FORMATS_CONFIGURATION_MAIN,
372                                 format));
373 
374                         engine.setInterWikiConfiguration(
375                             _readConfigurationFile(
376                                 PropsKeys.WIKI_FORMATS_CONFIGURATION_INTERWIKI,
377                                 format));
378                     }
379                     else {
380                         engine = (WikiEngine)InstancePool.get(engineClass);
381                     }
382 
383                     _engines.put(format, engine);
384                 }
385             }
386             catch (Exception e) {
387                 throw new WikiFormatException(e);
388             }
389 
390             if (engine == null) {
391                 throw new WikiFormatException(format);
392             }
393         }
394 
395         return engine;
396     }
397 
398     private String _getHelpPage(String format) {
399         return PropsUtil.get(
400             PropsKeys.WIKI_FORMATS_HELP_PAGE, new Filter(format));
401     }
402 
403     private String _getHelpURL(String format) {
404         return PropsUtil.get(
405             PropsKeys.WIKI_FORMATS_HELP_URL, new Filter(format));
406     }
407 
408     private Map<String, Boolean> _getLinks(WikiPage page)
409         throws PageContentException {
410 
411         try {
412             return _getEngine(page.getFormat()).getOutgoingLinks(page);
413         }
414         catch (WikiFormatException wfe) {
415             return Collections.EMPTY_MAP;
416         }
417     }
418 
419     private String _readConfigurationFile(String propertyName, String format)
420         throws IOException {
421 
422         ClassLoader classLoader = getClass().getClassLoader();
423 
424         String configurationFile = PropsUtil.get(
425             propertyName, new Filter(format));
426 
427         if (Validator.isNotNull(configurationFile)) {
428             return HttpUtil.URLtoString(
429                 classLoader.getResource(configurationFile));
430         }
431         else {
432             return StringPool.BLANK;
433         }
434     }
435 
436     private String _replaceAttachments(
437         String content, String title, String attachmentURLPrefix) {
438 
439         content = StringUtil.replace(content, "[$WIKI_PAGE_NAME$]", title);
440 
441         content = StringUtil.replace(
442             content, "[$ATTACHMENT_URL_PREFIX$]", attachmentURLPrefix);
443 
444         return content;
445     }
446 
447     private boolean _validate(long nodeId, String content, String format)
448         throws WikiFormatException {
449 
450         return _getEngine(format).validate(nodeId, content);
451     }
452 
453     private static WikiUtil _instance = new WikiUtil();
454 
455     private static Pattern _editPageURLPattern = Pattern.compile(
456         "\\[\\$BEGIN_PAGE_TITLE_EDIT\\$\\](.*?)\\[\\$END_PAGE_TITLE_EDIT\\$\\]");
457     private static Pattern _viewPageURLPattern = Pattern.compile(
458         "\\[\\$BEGIN_PAGE_TITLE\\$\\](.*?)\\[\\$END_PAGE_TITLE\\$\\]");
459 
460     private Map<String, WikiEngine> _engines =
461         new HashMap<String, WikiEngine>();
462 
463 }