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