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