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