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