1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    *
5    *
6    *
7    * The contents of this file are subject to the terms of the Liferay Enterprise
8    * Subscription License ("License"). You may not use this file except in
9    * compliance with the License. You can obtain a copy of the License by
10   * contacting Liferay, Inc. See the License for the specific language governing
11   * permissions and limitations under the License, including but not limited to
12   * distribution rights 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.DiffHtmlUtil;
31  import com.liferay.portal.kernel.util.GetterUtil;
32  import com.liferay.portal.kernel.util.HttpUtil;
33  import com.liferay.portal.kernel.util.InstancePool;
34  import com.liferay.portal.kernel.util.ListUtil;
35  import com.liferay.portal.kernel.util.PropsKeys;
36  import com.liferay.portal.kernel.util.StringPool;
37  import com.liferay.portal.kernel.util.StringUtil;
38  import com.liferay.portal.kernel.util.Validator;
39  import com.liferay.portal.security.permission.ActionKeys;
40  import com.liferay.portal.security.permission.PermissionChecker;
41  import com.liferay.portal.theme.ThemeDisplay;
42  import com.liferay.portal.util.ContentUtil;
43  import com.liferay.portal.util.PropsUtil;
44  import com.liferay.portal.util.PropsValues;
45  import com.liferay.portal.util.WebKeys;
46  import com.liferay.portlet.wiki.PageContentException;
47  import com.liferay.portlet.wiki.WikiFormatException;
48  import com.liferay.portlet.wiki.engines.WikiEngine;
49  import com.liferay.portlet.wiki.model.WikiNode;
50  import com.liferay.portlet.wiki.model.WikiPage;
51  import com.liferay.portlet.wiki.service.WikiNodeLocalServiceUtil;
52  import com.liferay.portlet.wiki.service.permission.WikiNodePermission;
53  import com.liferay.portlet.wiki.util.comparator.VisibleNodesComparator;
54  
55  import java.io.IOException;
56  import java.io.StringReader;
57  
58  import java.util.Collections;
59  import java.util.HashMap;
60  import java.util.Iterator;
61  import java.util.List;
62  import java.util.Map;
63  import java.util.regex.Matcher;
64  import java.util.regex.Pattern;
65  
66  import javax.portlet.PortletPreferences;
67  import javax.portlet.PortletURL;
68  import javax.portlet.RenderRequest;
69  
70  /**
71   * <a href="WikiUtil.java.html"><b><i>View Source</i></b></a>
72   *
73   * @author Brian Wing Shun Chan
74   * @author Jorge Ferrer
75   */
76  public class WikiUtil {
77  
78      public static final String POP_PORTLET_PREFIX = "wiki.";
79  
80      public static String convert(
81              WikiPage page, PortletURL viewPageURL, PortletURL editPageURL,
82              String attachmentURLPrefix)
83          throws PageContentException, WikiFormatException {
84  
85          return _instance._convert(
86              page, viewPageURL, editPageURL, attachmentURLPrefix);
87      }
88  
89      public static String diffHtml (
90              WikiPage sourcePage, WikiPage targetPage, PortletURL viewPageURL,
91              PortletURL editPageURL, String attachmentURLPrefix)
92          throws Exception {
93  
94          String sourceContent = StringPool.BLANK;
95          String targetContent = StringPool.BLANK;
96  
97          if (sourcePage != null) {
98              sourceContent = WikiUtil.convert(
99                  sourcePage, viewPageURL, editPageURL,attachmentURLPrefix);
100         }
101 
102         if (targetPage != null) {
103             targetContent = WikiUtil.convert(
104                 targetPage, viewPageURL, editPageURL, attachmentURLPrefix);
105         }
106 
107         return DiffHtmlUtil.diff(
108             new StringReader(sourceContent),new StringReader(targetContent));
109     }
110 
111     public static String getEditPage(String format) {
112         return _instance._getEditPage(format);
113     }
114 
115     public static String getEmailFromAddress(PortletPreferences preferences) {
116         String emailFromAddress = PropsUtil.get(
117             PropsKeys.WIKI_EMAIL_FROM_ADDRESS);
118 
119         return preferences.getValue("email-from-address", emailFromAddress);
120     }
121 
122     public static String getEmailFromName(PortletPreferences preferences) {
123         String emailFromName = PropsUtil.get(PropsKeys.WIKI_EMAIL_FROM_NAME);
124 
125         return preferences.getValue("email-from-name", emailFromName);
126     }
127 
128     public static boolean getEmailPageAddedEnabled(
129         PortletPreferences preferences) {
130 
131         String emailPageAddedEnabled = preferences.getValue(
132             "email-page-added-enabled", StringPool.BLANK);
133 
134         if (Validator.isNotNull(emailPageAddedEnabled)) {
135             return GetterUtil.getBoolean(emailPageAddedEnabled);
136         }
137         else {
138             return GetterUtil.getBoolean(PropsUtil.get(
139                 PropsKeys.WIKI_EMAIL_PAGE_ADDED_ENABLED));
140         }
141     }
142 
143     public static String getEmailPageAddedBody(PortletPreferences preferences) {
144         String emailPageAddedBody = preferences.getValue(
145             "email-page-added-body", StringPool.BLANK);
146 
147         if (Validator.isNotNull(emailPageAddedBody)) {
148             return emailPageAddedBody;
149         }
150         else {
151             return ContentUtil.get(PropsUtil.get(
152                 PropsKeys.WIKI_EMAIL_PAGE_ADDED_BODY));
153         }
154     }
155 
156     public static String getEmailPageAddedSignature(
157         PortletPreferences preferences) {
158 
159         String emailPageAddedSignature = preferences.getValue(
160             "email-page-added-signature", StringPool.BLANK);
161 
162         if (Validator.isNotNull(emailPageAddedSignature)) {
163             return emailPageAddedSignature;
164         }
165         else {
166             return ContentUtil.get(PropsUtil.get(
167                 PropsKeys.WIKI_EMAIL_PAGE_ADDED_SIGNATURE));
168         }
169     }
170 
171     public static String getEmailPageAddedSubjectPrefix(
172         PortletPreferences preferences) {
173 
174         String emailPageAddedSubjectPrefix = preferences.getValue(
175             "email-page-added-subject-prefix", StringPool.BLANK);
176 
177         if (Validator.isNotNull(emailPageAddedSubjectPrefix)) {
178             return emailPageAddedSubjectPrefix;
179         }
180         else {
181             return ContentUtil.get(PropsUtil.get(
182                 PropsKeys.WIKI_EMAIL_PAGE_ADDED_SUBJECT_PREFIX));
183         }
184     }
185 
186     public static boolean getEmailPageUpdatedEnabled(
187         PortletPreferences preferences) {
188 
189         String emailPageUpdatedEnabled = preferences.getValue(
190             "email-page-updated-enabled", StringPool.BLANK);
191 
192         if (Validator.isNotNull(emailPageUpdatedEnabled)) {
193             return GetterUtil.getBoolean(emailPageUpdatedEnabled);
194         }
195         else {
196             return GetterUtil.getBoolean(PropsUtil.get(
197                 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_ENABLED));
198         }
199     }
200 
201     public static String getEmailPageUpdatedBody(
202         PortletPreferences preferences) {
203 
204         String emailPageUpdatedBody = preferences.getValue(
205             "email-page-updated-body", StringPool.BLANK);
206 
207         if (Validator.isNotNull(emailPageUpdatedBody)) {
208             return emailPageUpdatedBody;
209         }
210         else {
211             return ContentUtil.get(PropsUtil.get(
212                 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_BODY));
213         }
214     }
215 
216     public static String getEmailPageUpdatedSignature(
217         PortletPreferences preferences) {
218 
219         String emailPageUpdatedSignature = preferences.getValue(
220             "email-page-updated-signature", StringPool.BLANK);
221 
222         if (Validator.isNotNull(emailPageUpdatedSignature)) {
223             return emailPageUpdatedSignature;
224         }
225         else {
226             return ContentUtil.get(PropsUtil.get(
227                 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_SIGNATURE));
228         }
229     }
230 
231     public static String getEmailPageUpdatedSubjectPrefix(
232         PortletPreferences preferences) {
233 
234         String emailPageUpdatedSubject = preferences.getValue(
235             "email-page-updated-subject-prefix", StringPool.BLANK);
236 
237         if (Validator.isNotNull(emailPageUpdatedSubject)) {
238             return emailPageUpdatedSubject;
239         }
240         else {
241             return ContentUtil.get(PropsUtil.get(
242                 PropsKeys.WIKI_EMAIL_PAGE_UPDATED_SUBJECT_PREFIX));
243         }
244     }
245 
246     public static String getHelpPage(String format) {
247         return _instance._getHelpPage(format);
248     }
249 
250     public static String getHelpURL(String format) {
251         return _instance._getHelpURL(format);
252     }
253 
254     public static Map<String, Boolean> getLinks(WikiPage page)
255         throws PageContentException {
256 
257         return _instance._getLinks(page);
258     }
259 
260     public static String getMailId(String mx, long nodeId, long pageId) {
261         StringBuilder sb = new StringBuilder();
262 
263         sb.append(StringPool.LESS_THAN);
264         sb.append(POP_PORTLET_PREFIX);
265         sb.append(nodeId);
266         sb.append(StringPool.PERIOD);
267         sb.append(pageId);
268         sb.append(StringPool.AT);
269         sb.append(PropsValues.POP_SERVER_SUBDOMAIN);
270         sb.append(StringPool.PERIOD);
271         sb.append(mx);
272         sb.append(StringPool.GREATER_THAN);
273 
274         return sb.toString();
275     }
276 
277     public static List<WikiNode> getNodes(RenderRequest renderRequest)
278         throws PortalException, SystemException {
279 
280         ThemeDisplay themeDisplay = (ThemeDisplay)renderRequest.getAttribute(
281             WebKeys.THEME_DISPLAY);
282 
283         long groupId = themeDisplay.getScopeGroupId();
284 
285         String allNodes = ListUtil.toString(
286             WikiNodeLocalServiceUtil.getNodes(groupId), "name");
287 
288         String[] visibleNodes = StringUtil.split(
289             renderRequest.getPreferences().getValue("visible-nodes", allNodes));
290         String[] hiddenNodes = StringUtil.split(
291             renderRequest.getPreferences().getValue(
292                 "hidden-nodes", StringPool.BLANK));
293 
294         return getNodes(
295             groupId, visibleNodes, hiddenNodes,
296             themeDisplay.getPermissionChecker());
297     }
298 
299     public static List<WikiNode> getNodes(
300             long groupId, String[] visibleNodes, String[] hiddenNodes,
301             PermissionChecker permissionChecker)
302         throws PortalException, SystemException {
303 
304         List<WikiNode> nodes = WikiNodeLocalServiceUtil.getNodes(groupId);
305 
306         nodes = ListUtil.sort(nodes, new VisibleNodesComparator(visibleNodes));
307 
308         Iterator<WikiNode> itr = nodes.iterator();
309 
310         while (itr.hasNext()) {
311             WikiNode node = itr.next();
312 
313             if (ArrayUtil.contains(hiddenNodes, node.getName()) ||
314                 !WikiNodePermission.contains(
315                     permissionChecker, node.getNodeId(), ActionKeys.VIEW)) {
316 
317                 itr.remove();
318             }
319         }
320 
321         return nodes;
322     }
323 
324     public static String processContent(String content) {
325         content = content.replaceAll("</p>", "</p>\n");
326         content = content.replaceAll("</br>", "</br>\n");
327         content = content.replaceAll("</div>", "</div>\n");
328 
329         return content;
330     }
331 
332     public static boolean validate(
333             long nodeId, String content, String format)
334         throws WikiFormatException {
335 
336         return _instance._validate(nodeId, content, format);
337     }
338 
339     private String _convert(
340             WikiPage page, PortletURL viewPageURL, PortletURL editPageURL,
341             String attachmentURLPrefix)
342         throws PageContentException, WikiFormatException {
343 
344         LiferayPortletURL liferayViewPageURL = (LiferayPortletURL)viewPageURL;
345         LiferayPortletURL liferayEditPageURL = (LiferayPortletURL)editPageURL;
346 
347         WikiEngine engine = _getEngine(page.getFormat());
348 
349         String content = engine.convert(page, editPageURL);
350 
351         String editPageURLString = StringPool.BLANK;
352 
353         if (editPageURL != null) {
354             liferayEditPageURL.setParameter("title", "__REPLACEMENT__", false);
355 
356             editPageURLString = editPageURL.toString();
357 
358             editPageURLString = StringUtil.replace(
359                 editPageURLString, "__REPLACEMENT__", "$1");
360         }
361 
362         Matcher matcher = _editPageURLPattern.matcher(content);
363 
364         content = matcher.replaceAll(editPageURLString);
365 
366         String viewPageURLString = StringPool.BLANK;
367 
368         if (viewPageURL != null) {
369             liferayViewPageURL.setParameter("title", "__REPLACEMENT__", false);
370 
371             viewPageURLString = viewPageURL.toString();
372 
373             viewPageURLString = StringUtil.replace(
374                 viewPageURLString, "__REPLACEMENT__", "$1");
375         }
376 
377         matcher = _viewPageURLPattern.matcher(content);
378 
379         content = matcher.replaceAll(viewPageURLString);
380 
381         content = _replaceAttachments(
382             content, page.getTitle(), attachmentURLPrefix);
383 
384         return content;
385     }
386 
387     private String _getEditPage(String format) {
388         return PropsUtil.get(
389             PropsKeys.WIKI_FORMATS_EDIT_PAGE, new Filter(format));
390     }
391 
392     private WikiEngine _getEngine(String format) throws WikiFormatException {
393         WikiEngine engine = _engines.get(format);
394 
395         if (engine == null) {
396             try {
397                 String engineClass = PropsUtil.get(
398                     PropsKeys.WIKI_FORMATS_ENGINE, new Filter(format));
399 
400                 if (engineClass != null) {
401                     if (!InstancePool.contains(engineClass)) {
402                         engine = (WikiEngine)InstancePool.get(engineClass);
403 
404                         engine.setMainConfiguration(
405                             _readConfigurationFile(
406                                 PropsKeys.WIKI_FORMATS_CONFIGURATION_MAIN,
407                                 format));
408 
409                         engine.setInterWikiConfiguration(
410                             _readConfigurationFile(
411                                 PropsKeys.WIKI_FORMATS_CONFIGURATION_INTERWIKI,
412                                 format));
413                     }
414                     else {
415                         engine = (WikiEngine)InstancePool.get(engineClass);
416                     }
417 
418                     _engines.put(format, engine);
419                 }
420             }
421             catch (Exception e) {
422                 throw new WikiFormatException(e);
423             }
424 
425             if (engine == null) {
426                 throw new WikiFormatException(format);
427             }
428         }
429 
430         return engine;
431     }
432 
433     private String _getHelpPage(String format) {
434         return PropsUtil.get(
435             PropsKeys.WIKI_FORMATS_HELP_PAGE, new Filter(format));
436     }
437 
438     private String _getHelpURL(String format) {
439         return PropsUtil.get(
440             PropsKeys.WIKI_FORMATS_HELP_URL, new Filter(format));
441     }
442 
443     private Map<String, Boolean> _getLinks(WikiPage page)
444         throws PageContentException {
445 
446         try {
447             return _getEngine(page.getFormat()).getOutgoingLinks(page);
448         }
449         catch (WikiFormatException wfe) {
450             return Collections.EMPTY_MAP;
451         }
452     }
453 
454     private String _readConfigurationFile(String propertyName, String format)
455         throws IOException {
456 
457         ClassLoader classLoader = getClass().getClassLoader();
458 
459         String configurationFile = PropsUtil.get(
460             propertyName, new Filter(format));
461 
462         if (Validator.isNotNull(configurationFile)) {
463             return HttpUtil.URLtoString(
464                 classLoader.getResource(configurationFile));
465         }
466         else {
467             return StringPool.BLANK;
468         }
469     }
470 
471     private String _replaceAttachments(
472         String content, String title, String attachmentURLPrefix) {
473 
474         content = StringUtil.replace(content, "[$WIKI_PAGE_NAME$]", title);
475 
476         content = StringUtil.replace(
477             content, "[$ATTACHMENT_URL_PREFIX$]", attachmentURLPrefix);
478 
479         return content;
480     }
481 
482     private boolean _validate(long nodeId, String content, String format)
483         throws WikiFormatException {
484 
485         return _getEngine(format).validate(nodeId, content);
486     }
487 
488     private static WikiUtil _instance = new WikiUtil();
489 
490     private static Pattern _editPageURLPattern = Pattern.compile(
491         "\\[\\$BEGIN_PAGE_TITLE_EDIT\\$\\](.*?)\\[\\$END_PAGE_TITLE_EDIT\\$\\]");
492     private static Pattern _viewPageURLPattern = Pattern.compile(
493         "\\[\\$BEGIN_PAGE_TITLE\\$\\](.*?)\\[\\$END_PAGE_TITLE\\$\\]");
494 
495     private Map<String, WikiEngine> _engines =
496         new HashMap<String, WikiEngine>();
497 
498 }