1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portlet.wiki.service.impl;
16  
17  import com.liferay.documentlibrary.DuplicateDirectoryException;
18  import com.liferay.documentlibrary.DuplicateFileException;
19  import com.liferay.documentlibrary.NoSuchDirectoryException;
20  import com.liferay.documentlibrary.NoSuchFileException;
21  import com.liferay.portal.kernel.exception.PortalException;
22  import com.liferay.portal.kernel.exception.SystemException;
23  import com.liferay.portal.kernel.language.LanguageUtil;
24  import com.liferay.portal.kernel.messaging.DestinationNames;
25  import com.liferay.portal.kernel.messaging.Message;
26  import com.liferay.portal.kernel.messaging.MessageBusUtil;
27  import com.liferay.portal.kernel.search.Indexer;
28  import com.liferay.portal.kernel.search.IndexerRegistryUtil;
29  import com.liferay.portal.kernel.util.CalendarFactoryUtil;
30  import com.liferay.portal.kernel.util.ContentTypes;
31  import com.liferay.portal.kernel.util.HttpUtil;
32  import com.liferay.portal.kernel.util.ListUtil;
33  import com.liferay.portal.kernel.util.MathUtil;
34  import com.liferay.portal.kernel.util.NotificationThreadLocal;
35  import com.liferay.portal.kernel.util.ObjectValuePair;
36  import com.liferay.portal.kernel.util.OrderByComparator;
37  import com.liferay.portal.kernel.util.StringBundler;
38  import com.liferay.portal.kernel.util.StringPool;
39  import com.liferay.portal.kernel.util.StringUtil;
40  import com.liferay.portal.kernel.util.Validator;
41  import com.liferay.portal.kernel.workflow.WorkflowConstants;
42  import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
43  import com.liferay.portal.model.Company;
44  import com.liferay.portal.model.CompanyConstants;
45  import com.liferay.portal.model.Group;
46  import com.liferay.portal.model.GroupConstants;
47  import com.liferay.portal.model.ResourceConstants;
48  import com.liferay.portal.model.User;
49  import com.liferay.portal.security.permission.ActionKeys;
50  import com.liferay.portal.service.ServiceContext;
51  import com.liferay.portal.service.ServiceContextUtil;
52  import com.liferay.portal.util.Portal;
53  import com.liferay.portal.util.PortalUtil;
54  import com.liferay.portal.util.PortletKeys;
55  import com.liferay.portal.util.PropsValues;
56  import com.liferay.portlet.asset.NoSuchEntryException;
57  import com.liferay.portlet.asset.model.AssetEntry;
58  import com.liferay.portlet.expando.model.ExpandoBridge;
59  import com.liferay.portlet.wiki.DuplicatePageException;
60  import com.liferay.portlet.wiki.NoSuchPageException;
61  import com.liferay.portlet.wiki.NoSuchPageResourceException;
62  import com.liferay.portlet.wiki.PageContentException;
63  import com.liferay.portlet.wiki.PageTitleException;
64  import com.liferay.portlet.wiki.PageVersionException;
65  import com.liferay.portlet.wiki.model.WikiNode;
66  import com.liferay.portlet.wiki.model.WikiPage;
67  import com.liferay.portlet.wiki.model.WikiPageConstants;
68  import com.liferay.portlet.wiki.model.WikiPageDisplay;
69  import com.liferay.portlet.wiki.model.WikiPageResource;
70  import com.liferay.portlet.wiki.model.impl.WikiPageDisplayImpl;
71  import com.liferay.portlet.wiki.model.impl.WikiPageImpl;
72  import com.liferay.portlet.wiki.service.base.WikiPageLocalServiceBaseImpl;
73  import com.liferay.portlet.wiki.social.WikiActivityKeys;
74  import com.liferay.portlet.wiki.util.WikiCacheThreadLocal;
75  import com.liferay.portlet.wiki.util.WikiCacheUtil;
76  import com.liferay.portlet.wiki.util.WikiUtil;
77  import com.liferay.portlet.wiki.util.comparator.PageCreateDateComparator;
78  import com.liferay.portlet.wiki.util.comparator.PageVersionComparator;
79  import com.liferay.util.UniqueList;
80  
81  import java.io.InputStream;
82  
83  import java.util.ArrayList;
84  import java.util.Calendar;
85  import java.util.Date;
86  import java.util.HashSet;
87  import java.util.Iterator;
88  import java.util.LinkedHashMap;
89  import java.util.List;
90  import java.util.Map;
91  import java.util.Set;
92  import java.util.regex.Matcher;
93  import java.util.regex.Pattern;
94  
95  import javax.portlet.PortletPreferences;
96  import javax.portlet.PortletURL;
97  import javax.portlet.WindowState;
98  
99  /**
100  * <a href="WikiPageLocalServiceImpl.java.html"><b><i>View Source</i></b></a>
101  *
102  * @author Brian Wing Shun Chan
103  * @author Jorge Ferrer
104  * @author Raymond Augé
105  * @author Bruno Farache
106  * @author Julio Camarero
107  * @author Wesley Gong
108  * @author Marcellus Tavares
109  * @author Zsigmond Rab
110  * @author Zsolt Berentey
111  */
112 public class WikiPageLocalServiceImpl extends WikiPageLocalServiceBaseImpl {
113 
114     public WikiPage addPage(
115             long userId, long nodeId, String title, String content,
116             String summary, boolean minorEdit, ServiceContext serviceContext)
117         throws PortalException, SystemException {
118 
119         String uuid = null;
120         double version = WikiPageConstants.DEFAULT_VERSION;
121         String format = WikiPageConstants.DEFAULT_FORMAT;
122         boolean head = false;
123         String parentTitle = null;
124         String redirectTitle = null;
125 
126         return addPage(
127             uuid, userId, nodeId, title, version, content, summary, minorEdit,
128             format, head, parentTitle, redirectTitle, serviceContext);
129     }
130 
131     public WikiPage addPage(
132             String uuid, long userId, long nodeId, String title, double version,
133             String content, String summary, boolean minorEdit, String format,
134             boolean head, String parentTitle, String redirectTitle,
135             ServiceContext serviceContext)
136         throws PortalException, SystemException {
137 
138         // Page
139 
140         User user = userPersistence.findByPrimaryKey(userId);
141         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
142 
143         Date now = new Date();
144 
145         validate(title, nodeId, content, format);
146 
147         long pageId = counterLocalService.increment();
148 
149         long resourcePrimKey =
150             wikiPageResourceLocalService.getPageResourcePrimKey(nodeId, title);
151 
152         WikiPage page = wikiPagePersistence.create(pageId);
153 
154         page.setUuid(uuid);
155         page.setResourcePrimKey(resourcePrimKey);
156         page.setGroupId(node.getGroupId());
157         page.setCompanyId(user.getCompanyId());
158         page.setUserId(user.getUserId());
159         page.setUserName(user.getFullName());
160         page.setCreateDate(serviceContext.getCreateDate(now));
161         page.setModifiedDate(serviceContext.getModifiedDate(now));
162         page.setNodeId(nodeId);
163         page.setTitle(title);
164         page.setVersion(version);
165         page.setMinorEdit(minorEdit);
166         page.setContent(content);
167         page.setStatus(WorkflowConstants.STATUS_DRAFT);
168         page.setSummary(summary);
169         page.setFormat(format);
170         page.setHead(head);
171         page.setParentTitle(parentTitle);
172         page.setRedirectTitle(redirectTitle);
173 
174         wikiPagePersistence.update(page, false);
175 
176         // Resources
177 
178         if (serviceContext.getAddCommunityPermissions() ||
179             serviceContext.getAddGuestPermissions()) {
180 
181             addPageResources(
182                 page, serviceContext.getAddCommunityPermissions(),
183                 serviceContext.getAddGuestPermissions());
184         }
185         else {
186             addPageResources(
187                 page, serviceContext.getCommunityPermissions(),
188                 serviceContext.getGuestPermissions());
189         }
190 
191         // Node
192 
193         node.setLastPostDate(serviceContext.getModifiedDate(now));
194 
195         wikiNodePersistence.update(node, false);
196 
197         // Asset
198 
199         updateAsset(
200             userId, page, serviceContext.getAssetCategoryIds(),
201             serviceContext.getAssetTagNames());
202 
203         // Expando
204 
205         ExpandoBridge expandoBridge = page.getExpandoBridge();
206 
207         expandoBridge.setAttributes(serviceContext);
208 
209         // Message boards
210 
211         if (PropsValues.WIKI_PAGE_COMMENTS_ENABLED) {
212             mbMessageLocalService.addDiscussionMessage(
213                 userId, page.getUserName(), page.getGroupId(),
214                 WikiPage.class.getName(), resourcePrimKey,
215                 WorkflowConstants.ACTION_PUBLISH);
216         }
217 
218         // Workflow
219 
220         WorkflowHandlerRegistryUtil.startWorkflowInstance(
221             user.getCompanyId(), page.getGroupId(), userId,
222             WikiPage.class.getName(), page.getResourcePrimKey(), page,
223             serviceContext);
224 
225         return page;
226     }
227 
228     public void addPageAttachment(
229             long companyId, String dirName, Date modifiedDate, String fileName,
230             InputStream inputStream)
231         throws PortalException, SystemException {
232 
233         if (inputStream == null) {
234             return;
235         }
236 
237         String portletId = CompanyConstants.SYSTEM_STRING;
238         long groupId = GroupConstants.DEFAULT_PARENT_GROUP_ID;
239         long repositoryId = CompanyConstants.SYSTEM;
240 
241         try {
242             dlService.addDirectory(companyId, repositoryId, dirName);
243         }
244         catch (DuplicateDirectoryException dde) {
245         }
246 
247         try {
248             dlLocalService.addFile(
249                 companyId, portletId, groupId, repositoryId,
250                 dirName + "/" + fileName, false, 0, StringPool.BLANK,
251                 modifiedDate, new ServiceContext(), inputStream);
252         }
253         catch (DuplicateFileException dfe) {
254         }
255     }
256 
257     public void addPageAttachments(
258             long nodeId, String title,
259             List<ObjectValuePair<String, byte[]>> files)
260         throws PortalException, SystemException {
261 
262         if (files.size() == 0) {
263             return;
264         }
265 
266         WikiPage page = getPage(nodeId, title);
267 
268         long companyId = page.getCompanyId();
269         String portletId = CompanyConstants.SYSTEM_STRING;
270         long groupId = GroupConstants.DEFAULT_PARENT_GROUP_ID;
271         long repositoryId = CompanyConstants.SYSTEM;
272         String dirName = page.getAttachmentsDir();
273 
274         try {
275             dlService.addDirectory(companyId, repositoryId, dirName);
276         }
277         catch (DuplicateDirectoryException dde) {
278         }
279 
280         for (int i = 0; i < files.size(); i++) {
281             ObjectValuePair<String, byte[]> ovp = files.get(i);
282 
283             String fileName = ovp.getKey();
284             byte[] bytes = ovp.getValue();
285 
286             if (Validator.isNull(fileName)) {
287                 continue;
288             }
289 
290             try {
291                 dlService.addFile(
292                     companyId, portletId, groupId, repositoryId,
293                     dirName + "/" + fileName, 0, StringPool.BLANK,
294                     page.getModifiedDate(), new ServiceContext(), bytes);
295             }
296             catch (DuplicateFileException dfe) {
297             }
298         }
299     }
300 
301     public void addPageResources(
302             long nodeId, String title, boolean addCommunityPermissions,
303             boolean addGuestPermissions)
304         throws PortalException, SystemException {
305 
306         WikiPage page = getPage(nodeId, title);
307 
308         addPageResources(page, addCommunityPermissions, addGuestPermissions);
309     }
310 
311     public void addPageResources(
312             WikiPage page, boolean addCommunityPermissions,
313             boolean addGuestPermissions)
314         throws PortalException, SystemException {
315 
316         resourceLocalService.addResources(
317             page.getCompanyId(), page.getGroupId(), page.getUserId(),
318             WikiPage.class.getName(), page.getResourcePrimKey(), false,
319             addCommunityPermissions, addGuestPermissions);
320     }
321 
322     public void addPageResources(
323             long nodeId, String title, String[] communityPermissions,
324             String[] guestPermissions)
325         throws PortalException, SystemException {
326 
327         WikiPage page = getPage(nodeId, title);
328 
329         addPageResources(page, communityPermissions, guestPermissions);
330     }
331 
332     public void addPageResources(
333             WikiPage page, String[] communityPermissions,
334             String[] guestPermissions)
335         throws PortalException, SystemException {
336 
337         resourceLocalService.addModelResources(
338             page.getCompanyId(), page.getGroupId(), page.getUserId(),
339             WikiPage.class.getName(), page.getResourcePrimKey(),
340             communityPermissions, guestPermissions);
341     }
342 
343     public void changeParent(
344             long userId, long nodeId, String title, String newParentTitle,
345             ServiceContext serviceContext)
346         throws PortalException, SystemException {
347 
348         if (Validator.isNotNull(newParentTitle)) {
349             WikiPage parentPage = getPage(nodeId, newParentTitle);
350 
351             if (Validator.isNotNull(parentPage.getRedirectTitle())) {
352                 newParentTitle = parentPage.getRedirectTitle();
353             }
354         }
355 
356         WikiPage page = getPage(nodeId, title);
357 
358         String originalParentTitle = page.getParentTitle();
359 
360         double version = page.getVersion();
361         String content = page.getContent();
362         String summary = LanguageUtil.format(
363             ServiceContextUtil.getLocale(serviceContext),
364             "changed-parent-from-x", originalParentTitle);
365         boolean minorEdit = false;
366         String format = page.getFormat();
367         String redirectTitle = page.getRedirectTitle();
368 
369         long[] assetCategoryIds = assetCategoryLocalService.getCategoryIds(
370             WikiPage.class.getName(), page.getResourcePrimKey());
371         String[] assetTagNames = assetTagLocalService.getTagNames(
372             WikiPage.class.getName(), page.getResourcePrimKey());
373 
374         serviceContext.setAssetCategoryIds(assetCategoryIds);
375         serviceContext.setAssetTagNames(assetTagNames);
376 
377         updatePage(
378             userId, nodeId, title, version, content, summary, minorEdit,
379             format, newParentTitle, redirectTitle, serviceContext);
380 
381         List<WikiPage> oldPages = wikiPagePersistence.findByN_T_H(
382             nodeId, title, false);
383 
384         for (WikiPage oldPage : oldPages) {
385             oldPage.setParentTitle(originalParentTitle);
386 
387             wikiPagePersistence.update(oldPage, false);
388         }
389     }
390 
391     public void deletePage(long nodeId, String title)
392         throws PortalException, SystemException {
393 
394         List<WikiPage> pages = wikiPagePersistence.findByN_T_H(
395             nodeId, title, true, 0, 1);
396 
397         if (!pages.isEmpty()) {
398             WikiPage page = pages.iterator().next();
399 
400             deletePage(page);
401         }
402     }
403 
404     public void deletePage(WikiPage page)
405         throws PortalException, SystemException {
406 
407         // Children
408 
409         List<WikiPage> children = wikiPagePersistence.findByN_H_P(
410             page.getNodeId(), true, page.getTitle());
411 
412         for (WikiPage curPage : children) {
413             deletePage(curPage);
414         }
415 
416         // Indexer
417 
418         Indexer indexer = IndexerRegistryUtil.getIndexer(WikiPage.class);
419 
420         indexer.delete(page);
421 
422         // Attachments
423 
424         long companyId = page.getCompanyId();
425         String portletId = CompanyConstants.SYSTEM_STRING;
426         long repositoryId = CompanyConstants.SYSTEM;
427         String dirName = page.getAttachmentsDir();
428 
429         try {
430             dlService.deleteDirectory(
431                 companyId, portletId, repositoryId, dirName);
432         }
433         catch (NoSuchDirectoryException nsde) {
434         }
435 
436         // Subscriptions
437 
438         subscriptionLocalService.deleteSubscriptions(
439             page.getCompanyId(), WikiPage.class.getName(),
440             page.getResourcePrimKey());
441 
442         // Social
443 
444         socialActivityLocalService.deleteActivities(
445             WikiPage.class.getName(), page.getResourcePrimKey());
446 
447         // Message boards
448 
449         mbMessageLocalService.deleteDiscussionMessages(
450             WikiPage.class.getName(), page.getResourcePrimKey());
451 
452         // Expando
453 
454         expandoValueLocalService.deleteValues(
455             WikiPage.class.getName(), page.getResourcePrimKey());
456 
457         // Asset
458 
459         assetEntryLocalService.deleteEntry(
460             WikiPage.class.getName(), page.getPrimaryKey());
461         assetEntryLocalService.deleteEntry(
462             WikiPage.class.getName(), page.getResourcePrimKey());
463 
464         // Resources
465 
466         resourceLocalService.deleteResource(
467             page.getCompanyId(), WikiPage.class.getName(),
468             ResourceConstants.SCOPE_INDIVIDUAL, page.getResourcePrimKey());
469 
470         // Resource
471 
472         try {
473             wikiPageResourceLocalService.deletePageResource(
474                 page.getNodeId(), page.getTitle());
475         }
476         catch (NoSuchPageResourceException nspre) {
477         }
478 
479         // All versions
480 
481         wikiPagePersistence.removeByN_T(page.getNodeId(), page.getTitle());
482 
483         // All referrals
484 
485         wikiPagePersistence.removeByN_R(page.getNodeId(), page.getTitle());
486 
487         // Cache
488 
489         clearPageCache(page);
490         clearReferralsCache(page);
491     }
492 
493     public void deletePageAttachment(long nodeId, String title, String fileName)
494         throws PortalException, SystemException {
495 
496         if (Validator.isNull(fileName)) {
497             return;
498         }
499 
500         WikiPage page = getPage(nodeId, title);
501 
502         long companyId = page.getCompanyId();
503         String portletId = CompanyConstants.SYSTEM_STRING;
504         long repositoryId = CompanyConstants.SYSTEM;
505 
506         try {
507             dlService.deleteFile(companyId, portletId, repositoryId, fileName);
508         }
509         catch (NoSuchFileException nsfe) {
510         }
511     }
512 
513     public void deletePages(long nodeId)
514         throws PortalException, SystemException {
515 
516         Iterator<WikiPage> itr = wikiPagePersistence.findByN_H_P(
517             nodeId, true, StringPool.BLANK).iterator();
518 
519         while (itr.hasNext()) {
520             WikiPage page = itr.next();
521 
522             deletePage(page);
523         }
524     }
525 
526     public List<WikiPage> getChildren(
527             long nodeId, boolean head, String parentTitle)
528         throws SystemException {
529 
530         return wikiPagePersistence.findByN_H_P_S(
531             nodeId, head, parentTitle, WorkflowConstants.STATUS_APPROVED);
532     }
533 
534     public WikiPage getDraftPage(long nodeId, String title)
535         throws PortalException, SystemException {
536 
537         List<WikiPage> pages = wikiPagePersistence.findByN_T_S(
538             nodeId, title, WorkflowConstants.STATUS_DRAFT, 0, 1);
539 
540         if (!pages.isEmpty()) {
541             return pages.get(0);
542         }
543         else {
544             pages = wikiPagePersistence.findByN_T_S(
545                 nodeId, title, WorkflowConstants.STATUS_PENDING, 0, 1);
546 
547             if (!pages.isEmpty()) {
548                 return pages.get(0);
549             }
550             else {
551                 throw new NoSuchPageException();
552             }
553         }
554 
555     }
556 
557     public List<WikiPage> getDraftPages(
558             long userId, long nodeId, int start, int end)
559         throws SystemException {
560 
561         if (userId > 0) {
562             return wikiPagePersistence.findByU_N_S(
563                 nodeId, userId, WorkflowConstants.STATUS_DRAFT, start, end,
564                 new PageCreateDateComparator(false));
565         }
566         else {
567             return wikiPagePersistence.findByN_S(
568                 nodeId, WorkflowConstants.STATUS_DRAFT, start, end,
569                 new PageCreateDateComparator(false));
570         }
571     }
572 
573     public int getDraftPagesCount(long userId, long nodeId)
574         throws SystemException {
575 
576         if (userId > 0) {
577             return wikiPagePersistence.countByU_N_S(
578                 nodeId, userId, WorkflowConstants.STATUS_DRAFT);
579         }
580         else {
581             return wikiPagePersistence.countByN_S(
582                 nodeId, WorkflowConstants.STATUS_DRAFT);
583         }
584     }
585 
586     public List<WikiPage> getIncomingLinks(long nodeId, String title)
587         throws PortalException, SystemException {
588 
589         List<WikiPage> links = new UniqueList<WikiPage>();
590 
591         List<WikiPage> pages = wikiPagePersistence.findByN_H(nodeId, true);
592 
593         for (WikiPage page : pages) {
594             if (isLinkedTo(page, title)) {
595                 links.add(page);
596             }
597         }
598 
599         List<WikiPage> referrals = wikiPagePersistence.findByN_R(nodeId, title);
600 
601         for (WikiPage referral : referrals) {
602             for (WikiPage page : pages) {
603                 if (isLinkedTo(page, referral.getTitle())) {
604                     links.add(page);
605                 }
606             }
607         }
608 
609         return ListUtil.sort(links);
610     }
611 
612     public List<WikiPage> getNoAssetPages() throws SystemException {
613         return wikiPageFinder.findByNoAssets();
614     }
615 
616     public List<WikiPage> getOrphans(long nodeId)
617         throws PortalException, SystemException {
618 
619         List<Map<String, Boolean>> pageTitles =
620             new ArrayList<Map<String, Boolean>>();
621 
622         List<WikiPage> pages = wikiPagePersistence.findByN_H_S(
623             nodeId, true, WorkflowConstants.STATUS_APPROVED);
624 
625         for (WikiPage page : pages) {
626             pageTitles.add(WikiCacheUtil.getOutgoingLinks(page));
627         }
628 
629         Set<WikiPage> notOrphans = new HashSet<WikiPage>();
630 
631         for (WikiPage page : pages) {
632             for (Map<String, Boolean> pageTitle : pageTitles) {
633                 if (pageTitle.get(page.getTitle().toLowerCase()) != null) {
634                     notOrphans.add(page);
635 
636                     break;
637                 }
638             }
639         }
640 
641         List<WikiPage> orphans = new ArrayList<WikiPage>();
642 
643         for (WikiPage page : pages) {
644             if (!notOrphans.contains(page)) {
645                 orphans.add(page);
646             }
647         }
648 
649         orphans = ListUtil.sort(orphans);
650 
651         return orphans;
652     }
653 
654     public List<WikiPage> getOutgoingLinks(long nodeId, String title)
655         throws PortalException, SystemException {
656 
657         WikiPage page = getPage(nodeId, title);
658 
659         Map<String, WikiPage> pages = new LinkedHashMap<String, WikiPage>();
660 
661         Map<String, Boolean> links = WikiCacheUtil.getOutgoingLinks(page);
662 
663         for (String curTitle : links.keySet()) {
664             Boolean exists = links.get(curTitle);
665 
666             if (exists) {
667                 if (!pages.containsKey(curTitle)) {
668                     pages.put(curTitle, getPage(nodeId, curTitle));
669                 }
670             }
671             else {
672                 WikiPageImpl newPage = new WikiPageImpl();
673 
674                 newPage.setNew(true);
675                 newPage.setNodeId(nodeId);
676                 newPage.setTitle(curTitle);
677 
678                 if (!pages.containsKey(curTitle)) {
679                     pages.put(curTitle, newPage);
680                 }
681             }
682         }
683 
684         return ListUtil.fromCollection(pages.values());
685     }
686 
687     public WikiPage getPage(long resourcePrimKey)
688         throws PortalException, SystemException {
689 
690         WikiPageResource wikiPageResource =
691             wikiPageResourceLocalService.getPageResource(resourcePrimKey);
692 
693         return getPage(
694             wikiPageResource.getNodeId(), wikiPageResource.getTitle());
695     }
696 
697     public WikiPage getPage(long nodeId, String title)
698         throws PortalException, SystemException {
699 
700         List<WikiPage> pages = wikiPagePersistence.findByN_T_H(
701             nodeId, title, true, 0, 1);
702 
703         if (!pages.isEmpty()) {
704             return pages.get(0);
705         }
706         else {
707             throw new NoSuchPageException();
708         }
709     }
710 
711     public WikiPage getPage(long nodeId, String title, boolean head)
712         throws PortalException, SystemException {
713 
714         List<WikiPage> pages = wikiPagePersistence.findByN_T_H(
715             nodeId, title, head, 0, 1);
716 
717         if (!pages.isEmpty()) {
718             return pages.get(0);
719         }
720         else {
721             throw new NoSuchPageException();
722         }
723     }
724 
725     public WikiPage getPage(long nodeId, String title, double version)
726         throws PortalException, SystemException {
727 
728         WikiPage page = null;
729 
730         if (version == 0) {
731             page = getPage(nodeId, title);
732         }
733         else {
734             page = wikiPagePersistence.findByN_T_V(nodeId, title, version);
735         }
736 
737         return page;
738     }
739 
740     public WikiPageDisplay getPageDisplay(
741             long nodeId, String title, PortletURL viewPageURL,
742             PortletURL editPageURL, String attachmentURLPrefix)
743         throws PortalException, SystemException {
744 
745         WikiPage page = getPage(nodeId, title);
746 
747         String formattedContent = WikiUtil.convert(
748             page, viewPageURL, editPageURL, attachmentURLPrefix);
749 
750         return new WikiPageDisplayImpl(
751             page.getUserId(), page.getNodeId(), page.getTitle(),
752             page.getVersion(), page.getContent(), formattedContent,
753             page.getFormat(), page.getHead(), page.getAttachmentsFiles());
754     }
755 
756     public List<WikiPage> getPages(long nodeId, int start, int end)
757         throws SystemException {
758 
759         return wikiPagePersistence.findByNodeId(
760             nodeId, start, end, new PageCreateDateComparator(false));
761     }
762 
763     public List<WikiPage> getPages(String format) throws SystemException {
764         return wikiPagePersistence.findByFormat(format);
765     }
766 
767     public List<WikiPage> getPages(
768             long nodeId, String title, int start, int end)
769         throws SystemException {
770 
771         return wikiPagePersistence.findByN_T(
772             nodeId, title, start, end, new PageCreateDateComparator(false));
773     }
774 
775     public List<WikiPage> getPages(
776             long nodeId, String title, int start, int end,
777             OrderByComparator obc)
778         throws SystemException {
779 
780         return wikiPagePersistence.findByN_T(nodeId, title, start, end, obc);
781     }
782 
783     public List<WikiPage> getPages(
784             long nodeId, boolean head, int start, int end)
785         throws SystemException {
786 
787         return wikiPagePersistence.findByN_H_S(
788             nodeId, head, WorkflowConstants.STATUS_APPROVED, start, end,
789             new PageCreateDateComparator(false));
790     }
791 
792     public List<WikiPage> getPages(
793             long resourcePrimKey, long nodeId, int status)
794         throws SystemException {
795 
796         return wikiPagePersistence.findByR_N_S(resourcePrimKey, nodeId, status);
797     }
798 
799     public List<WikiPage> getPages(
800             long nodeId, String title, boolean head, int start, int end)
801         throws SystemException {
802 
803         return wikiPagePersistence.findByN_T_H(
804             nodeId, title, head, start, end,
805             new PageCreateDateComparator(false));
806     }
807 
808     public int getPagesCount(long nodeId) throws SystemException {
809         return wikiPagePersistence.countByNodeId(nodeId);
810     }
811 
812     public int getPagesCount(long nodeId, String title)
813         throws SystemException {
814 
815         return wikiPagePersistence.countByN_T(nodeId, title);
816     }
817 
818     public int getPagesCount(long nodeId, boolean head)
819         throws SystemException {
820 
821         return wikiPagePersistence.countByN_H_S(
822             nodeId, head, WorkflowConstants.STATUS_APPROVED);
823     }
824 
825     public int getPagesCount(long nodeId, String title, boolean head)
826         throws SystemException {
827 
828         return wikiPagePersistence.countByN_T_H(nodeId, title, head);
829     }
830 
831     public int getPagesCount(String format) throws SystemException {
832         return wikiPagePersistence.countByFormat(format);
833     }
834 
835     public List<WikiPage> getRecentChanges(long nodeId, int start, int end)
836         throws SystemException {
837 
838         Calendar cal = CalendarFactoryUtil.getCalendar();
839 
840         cal.add(Calendar.WEEK_OF_YEAR, -1);
841 
842         return wikiPageFinder.findByCreateDate(
843             nodeId, cal.getTime(), false, start, end);
844     }
845 
846     public int getRecentChangesCount(long nodeId) throws SystemException {
847         Calendar cal = CalendarFactoryUtil.getCalendar();
848 
849         cal.add(Calendar.WEEK_OF_YEAR, -1);
850 
851         return wikiPageFinder.countByCreateDate(nodeId, cal.getTime(), false);
852     }
853 
854     public boolean hasDraftPage(long nodeId, String title)
855         throws SystemException {
856 
857         int count = wikiPagePersistence.countByN_T_S(
858             nodeId, title, WorkflowConstants.STATUS_DRAFT);
859 
860         if (count > 0) {
861             return true;
862         }
863         else {
864             return false;
865         }
866     }
867 
868     public void movePage(
869             long userId, long nodeId, String title, String newTitle,
870             ServiceContext serviceContext)
871         throws PortalException, SystemException {
872 
873         movePage(userId, nodeId, title, newTitle, true, serviceContext);
874     }
875 
876     public void movePage(
877             long userId, long nodeId, String title, String newTitle,
878             boolean strict, ServiceContext serviceContext)
879         throws PortalException, SystemException {
880 
881         validateTitle(newTitle);
882 
883         // Check if the new title already exists
884 
885         if (title.equalsIgnoreCase(newTitle)) {
886             throw new DuplicatePageException(newTitle);
887         }
888 
889         if (isUsedTitle(nodeId, newTitle)) {
890             WikiPage page = getPage(nodeId, newTitle);
891 
892             // Support moving back to a previously moved title
893 
894             if (((page.getVersion() == WikiPageConstants.DEFAULT_VERSION) &&
895                  (page.getContent().length() < 200)) ||
896                 !strict) {
897 
898                 deletePage(nodeId, newTitle);
899             }
900             else {
901                 throw new DuplicatePageException(newTitle);
902             }
903         }
904 
905         // All versions
906 
907         List<WikiPage> pageVersions = wikiPagePersistence.findByN_T(
908             nodeId, title);
909 
910         if (pageVersions.size() == 0) {
911             return;
912         }
913 
914         for (WikiPage page : pageVersions) {
915             page.setTitle(newTitle);
916 
917             wikiPagePersistence.update(page, false);
918         }
919 
920         // Children
921 
922         List<WikiPage> children = wikiPagePersistence.findByN_P(nodeId, title);
923 
924         for (WikiPage page : children) {
925             page.setParentTitle(newTitle);
926 
927             wikiPagePersistence.update(page, false);
928         }
929 
930         WikiPage page = pageVersions.get(pageVersions.size() - 1);
931 
932         long resourcePrimKey = page.getResourcePrimKey();
933 
934         // Page resource
935 
936         WikiPageResource wikiPageResource =
937             wikiPageResourcePersistence.findByPrimaryKey(resourcePrimKey);
938 
939         wikiPageResource.setTitle(newTitle);
940 
941         wikiPageResourcePersistence.update(wikiPageResource, false);
942 
943         // Create stub page at the old location
944 
945         String uuid = null;
946         double version = WikiPageConstants.DEFAULT_VERSION;
947         String summary = WikiPageConstants.MOVED + " to " + title;
948         String format = page.getFormat();
949         boolean head = true;
950         String parentTitle = page.getParentTitle();
951         String redirectTitle = page.getTitle();
952         String content =
953             StringPool.DOUBLE_OPEN_BRACKET + redirectTitle +
954                 StringPool.DOUBLE_CLOSE_BRACKET;
955 
956         addPage(
957             uuid, userId, nodeId, title, version, content, summary, false,
958             format, head, parentTitle, redirectTitle, serviceContext);
959 
960         // Move redirects to point to the page with the new title
961 
962         List<WikiPage> redirectedPages = wikiPagePersistence.findByN_R(
963             nodeId, title);
964 
965         for (WikiPage redirectedPage : redirectedPages) {
966             redirectedPage.setRedirectTitle(newTitle);
967 
968             wikiPagePersistence.update(redirectedPage, false);
969         }
970 
971         // Asset
972 
973         updateAsset(userId, page, null, null);
974 
975         // Indexer
976 
977         Indexer indexer = IndexerRegistryUtil.getIndexer(WikiPage.class);
978 
979         indexer.delete(
980             new Object[] {page.getCompanyId(), page.getNodeId(), title});
981 
982         indexer.reindex(page);
983     }
984 
985     public WikiPage revertPage(
986             long userId, long nodeId, String title, double version,
987             ServiceContext serviceContext)
988         throws PortalException, SystemException {
989 
990         WikiPage oldPage = getPage(nodeId, title, version);
991 
992         return updatePage(
993             userId, nodeId, title, 0, oldPage.getContent(),
994             WikiPageConstants.REVERTED + " to " + version, false,
995             oldPage.getFormat(), getParentPageTitle(oldPage),
996             oldPage.getRedirectTitle(), serviceContext);
997     }
998 
999     public void subscribePage(long userId, long nodeId, String title)
1000        throws PortalException, SystemException {
1001
1002        WikiPage page = getPage(nodeId, title);
1003
1004        subscriptionLocalService.addSubscription(
1005            userId, WikiPage.class.getName(), page.getResourcePrimKey());
1006    }
1007
1008    public void unsubscribePage(long userId, long nodeId, String title)
1009        throws PortalException, SystemException {
1010
1011        WikiPage page = getPage(nodeId, title);
1012
1013        subscriptionLocalService.deleteSubscription(
1014            userId, WikiPage.class.getName(), page.getResourcePrimKey());
1015    }
1016
1017    public void updateAsset(
1018            long userId, WikiPage page, long[] assetCategoryIds,
1019            String[] assetTagNames)
1020        throws PortalException, SystemException {
1021
1022        boolean visible = page.isApproved();
1023
1024        if (!page.isApproved()) {
1025            visible = true;
1026        }
1027        boolean addDraftAssetEntry = false;
1028
1029        if (!page.isApproved() &&
1030            (page.getVersion() != WikiPageConstants.DEFAULT_VERSION)) {
1031
1032            int approvedPagesCount = wikiPagePersistence.countByN_T_S(
1033                page.getNodeId(), page.getTitle(),
1034                WorkflowConstants.STATUS_APPROVED);
1035
1036            if (approvedPagesCount > 0) {
1037                addDraftAssetEntry = true;
1038            }
1039        }
1040
1041        if (addDraftAssetEntry) {
1042            assetEntryLocalService.updateEntry(
1043                userId, page.getGroupId(), WikiPage.class.getName(),
1044                page.getPrimaryKey(), assetCategoryIds, assetTagNames, false,
1045                null, null, null, null, ContentTypes.TEXT_HTML, page.getTitle(),
1046                null, null, null, 0, 0, null, false);
1047        }
1048        else {
1049            assetEntryLocalService.updateEntry(
1050                userId, page.getGroupId(), WikiPage.class.getName(),
1051                page.getResourcePrimKey(), assetCategoryIds, assetTagNames,
1052                visible, null, null, null, null, ContentTypes.TEXT_HTML,
1053                page.getTitle(), null, null, null, 0, 0, null, false);
1054        }
1055    }
1056
1057    public WikiPage updatePage(
1058            long userId, long nodeId, String title, double version,
1059            String content, String summary, boolean minorEdit, String format,
1060            String parentTitle, String redirectTitle,
1061            ServiceContext serviceContext)
1062        throws PortalException, SystemException {
1063
1064        // Page
1065
1066        User user = userPersistence.findByPrimaryKey(userId);
1067        Date now = new Date();
1068
1069        validate(nodeId, content, format);
1070
1071        WikiPage oldPage = null;
1072
1073        try {
1074            oldPage = wikiPagePersistence.findByN_T_First(nodeId, title, null);
1075        }
1076        catch (NoSuchPageException nspe) {
1077            return addPage(
1078                null, userId, nodeId, title, WikiPageConstants.DEFAULT_VERSION,
1079                content, summary, minorEdit, format, true, parentTitle,
1080                redirectTitle, serviceContext);
1081        }
1082
1083        double oldVersion = oldPage.getVersion();
1084
1085        if ((version > 0) && (version != oldVersion)) {
1086            throw new PageVersionException();
1087        }
1088
1089        long resourcePrimKey =
1090            wikiPageResourceLocalService.getPageResourcePrimKey(
1091                nodeId, title);
1092        long groupId = oldPage.getGroupId();
1093
1094        WikiPage page = oldPage;
1095
1096        double newVersion = oldVersion;
1097
1098        if (oldPage.isApproved()) {
1099            newVersion = MathUtil.format(oldVersion + 0.1, 1, 1);
1100
1101            long pageId = counterLocalService.increment();
1102
1103            page = wikiPagePersistence.create(pageId);
1104        }
1105
1106        page.setResourcePrimKey(resourcePrimKey);
1107        page.setGroupId(groupId);
1108        page.setCompanyId(user.getCompanyId());
1109        page.setUserId(user.getUserId());
1110        page.setUserName(user.getFullName());
1111        page.setCreateDate(serviceContext.getModifiedDate(now));
1112        page.setModifiedDate(serviceContext.getModifiedDate(now));
1113        page.setNodeId(nodeId);
1114        page.setTitle(title);
1115        page.setVersion(newVersion);
1116        page.setMinorEdit(minorEdit);
1117        page.setContent(content);
1118
1119        if (oldPage.isPending()) {
1120            page.setStatus(oldPage.getStatus());
1121        }
1122        else {
1123            page.setStatus(WorkflowConstants.STATUS_DRAFT);
1124        }
1125
1126        page.setSummary(summary);
1127        page.setFormat(format);
1128
1129        if (Validator.isNotNull(parentTitle)) {
1130            page.setParentTitle(parentTitle);
1131        }
1132
1133        if (Validator.isNotNull(redirectTitle)) {
1134            page.setRedirectTitle(redirectTitle);
1135        }
1136
1137        wikiPagePersistence.update(page, false);
1138
1139        // Expando
1140
1141        ExpandoBridge expandoBridge = page.getExpandoBridge();
1142
1143        expandoBridge.setAttributes(serviceContext);
1144
1145        // Node
1146
1147        WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
1148
1149        node.setLastPostDate(serviceContext.getModifiedDate(now));
1150
1151        wikiNodePersistence.update(node, false);
1152
1153        // Asset
1154
1155        updateAsset(
1156            userId, page, serviceContext.getAssetCategoryIds(),
1157            serviceContext.getAssetTagNames());
1158
1159        // Workflow
1160
1161        WorkflowHandlerRegistryUtil.startWorkflowInstance(
1162            user.getCompanyId(), page.getGroupId(), userId,
1163            WikiPage.class.getName(), page.getResourcePrimKey(), page,
1164            serviceContext);
1165
1166        return page;
1167    }
1168
1169    public WikiPage updateStatus(
1170            long userId, long resourcePrimKey, int status,
1171            ServiceContext serviceContext)
1172        throws PortalException, SystemException {
1173
1174        WikiPageResource wikiPageResource =
1175            wikiPageResourceLocalService.getPageResource(resourcePrimKey);
1176
1177        List<WikiPage> pages = wikiPagePersistence.findByN_T(
1178            wikiPageResource.getNodeId(), wikiPageResource.getTitle(), 0, 1,
1179            new PageVersionComparator());
1180
1181        WikiPage page = null;
1182
1183        if (!pages.isEmpty()) {
1184            page = pages.get(0);
1185        }
1186        else {
1187            throw new NoSuchPageException();
1188        }
1189
1190        return updateStatus(userId, page, status, serviceContext);
1191    }
1192
1193    public WikiPage updateStatus(
1194            long userId, WikiPage page, int status,
1195            ServiceContext serviceContext)
1196        throws PortalException, SystemException {
1197
1198        User user = userPersistence.findByPrimaryKey(userId);
1199        WikiNode node = wikiNodePersistence.findByPrimaryKey(page.getNodeId());
1200
1201        Date now = new Date();
1202
1203        int oldStatus = page.getStatus();
1204
1205        page.setStatus(status);
1206        page.setStatusByUserId(userId);
1207        page.setStatusByUserName(user.getFullName());
1208        page.setStatusDate(now);
1209
1210        if (status == WorkflowConstants.STATUS_APPROVED) {
1211
1212            // Asset
1213
1214            if ((oldStatus != WorkflowConstants.STATUS_APPROVED) &&
1215                (page.getVersion() != WikiPageConstants.DEFAULT_VERSION)) {
1216
1217                try {
1218                    AssetEntry draftAssetEntry =
1219                        assetEntryLocalService.getEntry(
1220                            WikiPage.class.getName(), page.getPrimaryKey());
1221
1222                    long[] assetCategoryIds = draftAssetEntry.getCategoryIds();
1223                    String[] assetTagNames = draftAssetEntry.getTagNames();
1224
1225                    assetEntryLocalService.updateEntry(
1226                        userId, page.getGroupId(), WikiPage.class.getName(),
1227                        page.getResourcePrimKey(), assetCategoryIds,
1228                        assetTagNames, true, null, null, null, null,
1229                        ContentTypes.TEXT_HTML, page.getTitle(), null, null,
1230                        null, 0, 0, null, false);
1231
1232                }
1233                catch (NoSuchEntryException nsee) {
1234                }
1235            }
1236
1237            assetEntryLocalService.updateVisible(
1238                WikiPage.class.getName(), page.getResourcePrimKey(), true);
1239
1240            // Social
1241
1242            int activity = WikiActivityKeys.ADD_PAGE;
1243
1244            if (page.getVersion() > 1.1) {
1245                activity = WikiActivityKeys.UPDATE_PAGE;
1246
1247                socialEquityLogLocalService.addEquityLogs(
1248                    userId, WikiPage.class.getName(), page.getResourcePrimKey(),
1249                    ActionKeys.UPDATE);
1250            }
1251            else {
1252                socialEquityLogLocalService.addEquityLogs(
1253                    userId, WikiPage.class.getName(), page.getResourcePrimKey(),
1254                    ActionKeys.ADD_PAGE);
1255            }
1256
1257            socialActivityLocalService.addActivity(
1258                userId, page.getGroupId(), WikiPage.class.getName(),
1259                page.getResourcePrimKey(), activity, StringPool.BLANK, 0);
1260
1261            // Subscriptions
1262
1263            if (!page.isMinorEdit() && NotificationThreadLocal.isEnabled()) {
1264                boolean update = false;
1265
1266                if (page.getVersion() > 1.1) {
1267                    update = true;
1268                }
1269
1270                notifySubscribers(node, page, serviceContext, update);
1271            }
1272
1273            // Indexer
1274
1275            Indexer indexer = IndexerRegistryUtil.getIndexer(WikiPage.class);
1276
1277            indexer.reindex(page);
1278
1279            // Cache
1280
1281            clearPageCache(page);
1282            clearReferralsCache(page);
1283
1284            // Head
1285
1286            page.setHead(true);
1287
1288            List<WikiPage> pages = wikiPagePersistence.findByN_T_H(
1289                page.getNodeId(), page.getTitle(), true);
1290
1291            for (WikiPage curPage : pages) {
1292                if (!curPage.equals(page)) {
1293                    curPage.setHead(false);
1294
1295                    wikiPagePersistence.update(curPage, false);
1296                }
1297            }
1298        }
1299        else {
1300
1301            // Head
1302
1303            page.setHead(false);
1304
1305            List<WikiPage> pages = wikiPagePersistence.findByN_T_S(
1306                page.getNodeId(), page.getTitle(),
1307                WorkflowConstants.STATUS_APPROVED);
1308
1309            for (WikiPage curPage : pages) {
1310                if (!curPage.equals(page)) {
1311                    curPage.setHead(true);
1312
1313                    wikiPagePersistence.update(curPage, false);
1314
1315                    break;
1316                }
1317            }
1318        }
1319
1320        return wikiPagePersistence.update(page, false);
1321    }
1322
1323    public void validateTitle(String title) throws PortalException {
1324        if (title.equals("all_pages") || title.equals("orphan_pages") ||
1325            title.equals("recent_changes")) {
1326
1327            throw new PageTitleException(title + " is reserved");
1328        }
1329
1330        if (Validator.isNotNull(PropsValues.WIKI_PAGE_TITLES_REGEXP)) {
1331            Pattern pattern = Pattern.compile(
1332                PropsValues.WIKI_PAGE_TITLES_REGEXP);
1333
1334            Matcher matcher = pattern.matcher(title);
1335
1336            if (!matcher.matches()) {
1337                throw new PageTitleException();
1338            }
1339        }
1340    }
1341
1342    protected void clearPageCache(WikiPage page) {
1343        if (!WikiCacheThreadLocal.isClearCache()) {
1344            return;
1345        }
1346
1347        WikiCacheUtil.clearCache(page.getNodeId(), page.getTitle());
1348    }
1349
1350    protected void clearReferralsCache(WikiPage page)
1351        throws PortalException, SystemException {
1352
1353        if (!WikiCacheThreadLocal.isClearCache()) {
1354            return;
1355        }
1356
1357        List<WikiPage> links = getIncomingLinks(
1358            page.getNodeId(), page.getTitle());
1359
1360        for (WikiPage curPage : links) {
1361            WikiCacheUtil.clearCache(curPage.getNodeId(), curPage.getTitle());
1362        }
1363    }
1364
1365    protected String getParentPageTitle(WikiPage page) {
1366
1367        // LPS-4586
1368
1369        try {
1370            WikiPage parentPage = getPage(
1371                page.getNodeId(), page.getParentTitle());
1372
1373            return parentPage.getTitle();
1374        }
1375        catch (Exception e) {
1376            return null;
1377        }
1378    }
1379
1380    protected WikiPage getPreviousVersionPage(WikiPage page)
1381        throws PortalException, SystemException {
1382
1383        double previousVersion = MathUtil.format(page.getVersion() - 0.1, 1, 1);
1384
1385        if (previousVersion < 1) {
1386            return null;
1387        }
1388
1389        return getPage(page.getNodeId(), page.getTitle(), previousVersion);
1390    }
1391
1392    protected boolean isLinkedTo(WikiPage page, String targetTitle)
1393        throws PortalException {
1394
1395        Map<String, Boolean> links = WikiCacheUtil.getOutgoingLinks(page);
1396
1397        Boolean link = links.get(targetTitle.toLowerCase());
1398
1399        if (link != null) {
1400            return true;
1401        }
1402        else {
1403            return false;
1404        }
1405    }
1406
1407    protected boolean isUsedTitle(long nodeId, String title)
1408        throws SystemException {
1409
1410        if (getPagesCount(nodeId, title, true) > 0) {
1411            return true;
1412        }
1413        else {
1414            return false;
1415        }
1416    }
1417
1418    protected void notifySubscribers(
1419            WikiNode node, WikiPage page, ServiceContext serviceContext,
1420            boolean update)
1421        throws PortalException, SystemException {
1422
1423        PortletPreferences preferences =
1424            ServiceContextUtil.getPortletPreferences(serviceContext);
1425
1426        if (preferences == null) {
1427            long ownerId = node.getGroupId();
1428            int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
1429            long plid = PortletKeys.PREFS_PLID_SHARED;
1430            String portletId = PortletKeys.WIKI;
1431            String defaultPreferences = null;
1432
1433            preferences = portletPreferencesLocalService.getPreferences(
1434                node.getCompanyId(), ownerId, ownerType, plid, portletId,
1435                defaultPreferences);
1436        }
1437
1438        if (!update && WikiUtil.getEmailPageAddedEnabled(preferences)) {
1439        }
1440        else if (update && WikiUtil.getEmailPageUpdatedEnabled(preferences)) {
1441        }
1442        else {
1443            return;
1444        }
1445
1446        Company company = companyPersistence.findByPrimaryKey(
1447            page.getCompanyId());
1448
1449        Group group = groupPersistence.findByPrimaryKey(node.getGroupId());
1450
1451        User user = userPersistence.findByPrimaryKey(page.getUserId());
1452
1453        String portalURL = serviceContext.getPortalURL();
1454        String layoutFullURL = serviceContext.getLayoutFullURL();
1455
1456        WikiPage previousVersionPage = getPreviousVersionPage(page);
1457
1458        String attachmentURLPrefix =
1459            portalURL + serviceContext.getPathMain() +
1460                "/wiki/get_page_attachment?p_l_id=" + serviceContext.getPlid() +
1461                    "&nodeId=" + page.getNodeId() + "&title=" +
1462                        HttpUtil.encodeURL(page.getTitle()) + "&fileName=";
1463
1464        String pageDiffs = StringPool.BLANK;
1465
1466        try {
1467            pageDiffs = WikiUtil.diffHtml(
1468                previousVersionPage, page, null, null, attachmentURLPrefix);
1469        }
1470        catch (Exception e) {
1471        }
1472
1473        String pageContent = null;
1474
1475        if (Validator.equals(page.getFormat(), "creole")) {
1476            pageContent = WikiUtil.convert(
1477                page, null, null, attachmentURLPrefix);
1478        }
1479        else {
1480            pageContent = page.getContent();
1481            pageContent = WikiUtil.processContent(pageContent);
1482        }
1483
1484        String pageURL = StringPool.BLANK;
1485        String diffsURL = StringPool.BLANK;
1486
1487        if (Validator.isNotNull(layoutFullURL)) {
1488            pageURL =
1489                layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "wiki/" +
1490                    node.getNodeId() + StringPool.SLASH +
1491                        HttpUtil.encodeURL(page.getTitle());
1492
1493            if (previousVersionPage != null) {
1494                StringBundler sb = new StringBundler(16);
1495
1496                sb.append(layoutFullURL);
1497                sb.append("?p_p_id=");
1498                sb.append(PortletKeys.WIKI);
1499                sb.append("&p_p_state=");
1500                sb.append(WindowState.MAXIMIZED);
1501                sb.append("&struts_action=");
1502                sb.append(HttpUtil.encodeURL("/wiki/compare_versions"));
1503                sb.append("&nodeId=");
1504                sb.append(node.getNodeId());
1505                sb.append("&title=");
1506                sb.append(HttpUtil.encodeURL(page.getTitle()));
1507                sb.append("&sourceVersion=");
1508                sb.append(previousVersionPage.getVersion());
1509                sb.append("&targetVersion=");
1510                sb.append(page.getVersion());
1511                sb.append("&type=html");
1512
1513                diffsURL = sb.toString();
1514            }
1515        }
1516
1517        String portletName = PortalUtil.getPortletTitle(PortletKeys.WIKI, user);
1518
1519        String fromName = WikiUtil.getEmailFromName(preferences);
1520        String fromAddress = WikiUtil.getEmailFromAddress(preferences);
1521
1522        String replyToAddress = fromAddress;
1523        String mailId = WikiUtil.getMailId(
1524            company.getMx(), page.getNodeId(), page.getPageId());
1525
1526        fromName = StringUtil.replace(
1527            fromName,
1528            new String[] {
1529                "[$COMPANY_ID$]",
1530                "[$COMPANY_MX$]",
1531                "[$COMPANY_NAME$]",
1532                "[$COMMUNITY_NAME$]",
1533                "[$PAGE_USER_ADDRESS$]",
1534                "[$PAGE_USER_NAME$]",
1535                "[$PORTLET_NAME$]"
1536            },
1537            new String[] {
1538                String.valueOf(company.getCompanyId()),
1539                company.getMx(),
1540                company.getName(),
1541                group.getName(),
1542                user.getEmailAddress(),
1543                user.getFullName(),
1544                portletName
1545            });
1546
1547        fromAddress = StringUtil.replace(
1548            fromAddress,
1549            new String[] {
1550                "[$COMPANY_ID$]",
1551                "[$COMPANY_MX$]",
1552                "[$COMPANY_NAME$]",
1553                "[$COMMUNITY_NAME$]",
1554                "[$PAGE_USER_ADDRESS$]",
1555                "[$PAGE_USER_NAME$]",
1556                "[$PORTLET_NAME$]"
1557            },
1558            new String[] {
1559                String.valueOf(company.getCompanyId()),
1560                company.getMx(),
1561                company.getName(),
1562                group.getName(),
1563                user.getEmailAddress(),
1564                user.getFullName(),
1565                portletName
1566            });
1567
1568        String subjectPrefix = null;
1569        String body = null;
1570        String signature = null;
1571
1572        if (update) {
1573            subjectPrefix = WikiUtil.getEmailPageUpdatedSubjectPrefix(
1574                preferences);
1575            body = WikiUtil.getEmailPageUpdatedBody(preferences);
1576            signature = WikiUtil.getEmailPageUpdatedSignature(preferences);
1577        }
1578        else {
1579            subjectPrefix = WikiUtil.getEmailPageAddedSubjectPrefix(
1580                preferences);
1581            body = WikiUtil.getEmailPageAddedBody(preferences);
1582            signature = WikiUtil.getEmailPageAddedSignature(preferences);
1583        }
1584
1585        if (Validator.isNotNull(signature)) {
1586            body += "\n" + signature;
1587        }
1588
1589        subjectPrefix = StringUtil.replace(
1590            subjectPrefix,
1591            new String[] {
1592                "[$COMPANY_ID$]",
1593                "[$COMPANY_MX$]",
1594                "[$COMPANY_NAME$]",
1595                "[$COMMUNITY_NAME$]",
1596                "[$FROM_ADDRESS$]",
1597                "[$FROM_NAME$]",
1598                "[$NODE_NAME$]",
1599                "[$PAGE_CONTENT$]",
1600                "[$PAGE_ID$]",
1601                "[$PAGE_TITLE$]",
1602                "[$PAGE_USER_ADDRESS$]",
1603                "[$PAGE_USER_NAME$]",
1604                "[$PORTAL_URL$]",
1605                "[$PORTLET_NAME$]"
1606            },
1607            new String[] {
1608                String.valueOf(company.getCompanyId()),
1609                company.getMx(),
1610                company.getName(),
1611                group.getName(),
1612                fromAddress,
1613                fromName,
1614                node.getName(),
1615                pageContent,
1616                String.valueOf(page.getPageId()),
1617                page.getTitle(),
1618                user.getEmailAddress(),
1619                user.getFullName(),
1620                company.getVirtualHost(),
1621                portletName
1622            });
1623
1624        body = StringUtil.replace(
1625            body,
1626            new String[] {
1627                "[$COMPANY_ID$]",
1628                "[$COMPANY_MX$]",
1629                "[$COMPANY_NAME$]",
1630                "[$COMMUNITY_NAME$]",
1631                "[$DIFFS_URL$]",
1632                "[$FROM_ADDRESS$]",
1633                "[$FROM_NAME$]",
1634                "[$NODE_NAME$]",
1635                "[$PAGE_CONTENT$]",
1636                "[$PAGE_DATE_UPDATE$]",
1637                "[$PAGE_DIFFS$]",
1638                "[$PAGE_ID$]",
1639                "[$PAGE_SUMMARY$]",
1640                "[$PAGE_TITLE$]",
1641                "[$PAGE_URL$]",
1642                "[$PAGE_USER_ADDRESS$]",
1643                "[$PAGE_USER_NAME$]",
1644                "[$PORTAL_URL$]",
1645                "[$PORTLET_NAME$]"
1646            },
1647            new String[] {
1648                String.valueOf(company.getCompanyId()),
1649                company.getMx(),
1650                company.getName(),
1651                group.getName(),
1652                diffsURL,
1653                fromAddress,
1654                fromName,
1655                node.getName(),
1656                pageContent,
1657                String.valueOf(page.getModifiedDate()),
1658                replaceStyles(pageDiffs),
1659                String.valueOf(page.getPageId()),
1660                page.getSummary(),
1661                page.getTitle(),
1662                pageURL,
1663                user.getEmailAddress(),
1664                user.getFullName(),
1665                company.getVirtualHost(),
1666                portletName
1667            });
1668
1669        String subject = page.getTitle();
1670
1671        if (subject.indexOf(subjectPrefix) == -1) {
1672            subject = subjectPrefix + StringPool.SPACE + subject;
1673        }
1674
1675        Message message = new Message();
1676
1677        message.put("companyId", node.getCompanyId());
1678        message.put("userId", node.getUserId());
1679        message.put("nodeId", node.getNodeId());
1680        message.put("pageResourcePrimKey", page.getResourcePrimKey());
1681        message.put("fromName", fromName);
1682        message.put("fromAddress", fromAddress);
1683        message.put("subject", subject);
1684        message.put("body", body);
1685        message.put("replyToAddress", replyToAddress);
1686        message.put("mailId", mailId);
1687        message.put("htmlFormat", Boolean.TRUE);
1688
1689        MessageBusUtil.sendMessage(DestinationNames.WIKI, message);
1690    }
1691
1692    protected String replaceStyles(String html) {
1693        return StringUtil.replace(
1694            html,
1695            new String[] {
1696                "class=\"diff-html-added\"",
1697                "class=\"diff-html-removed\"",
1698                "class=\"diff-html-changed\"",
1699                "changeType=\"diff-added-image\"",
1700                "changeType=\"diff-removed-image\"",
1701                "changeType=\"diff-changed-image\""
1702            },
1703            new String[] {
1704                "style=\"background-color: #CFC;\"",
1705                "style=\"background-color: #FDC6C6; text-decoration: " +
1706                    "line-through;\"",
1707                "style=\"border-bottom: 2px dotted blue;\"",
1708                "style=\"border: 10px solid #CFC;\"",
1709                "style=\"border: 10px solid #FDC6C6;\"",
1710                "style=\"border: 10px solid blue;\""
1711            }
1712        );
1713    }
1714
1715    protected void validate(long nodeId, String content, String format)
1716        throws PortalException {
1717
1718        if (!WikiUtil.validate(nodeId, content, format)) {
1719            throw new PageContentException();
1720        }
1721    }
1722
1723    protected void validate(
1724            String title, long nodeId, String content, String format)
1725        throws PortalException, SystemException {
1726
1727        if (Validator.isNull(title)) {
1728            throw new PageTitleException();
1729        }
1730
1731        if (isUsedTitle(nodeId, title)) {
1732            throw new DuplicatePageException();
1733        }
1734
1735        validateTitle(title);
1736
1737        validate(nodeId, content, format);
1738    }
1739
1740}