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