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