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