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