001    /**
002     * Copyright (c) 2000-present 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.blogs.service.impl;
016    
017    import com.liferay.portal.kernel.comment.CommentManager;
018    import com.liferay.portal.kernel.comment.CommentManagerUtil;
019    import com.liferay.portal.kernel.dao.orm.QueryDefinition;
020    import com.liferay.portal.kernel.exception.PortalException;
021    import com.liferay.portal.kernel.json.JSONFactoryUtil;
022    import com.liferay.portal.kernel.json.JSONObject;
023    import com.liferay.portal.kernel.log.Log;
024    import com.liferay.portal.kernel.log.LogFactoryUtil;
025    import com.liferay.portal.kernel.notifications.UserNotificationDefinition;
026    import com.liferay.portal.kernel.portlet.PortletProvider;
027    import com.liferay.portal.kernel.portlet.PortletProviderUtil;
028    import com.liferay.portal.kernel.repository.model.FileEntry;
029    import com.liferay.portal.kernel.repository.model.Folder;
030    import com.liferay.portal.kernel.search.Indexable;
031    import com.liferay.portal.kernel.search.IndexableType;
032    import com.liferay.portal.kernel.servlet.taglib.ui.ImageSelector;
033    import com.liferay.portal.kernel.servlet.taglib.ui.ImageSelectorProcessor;
034    import com.liferay.portal.kernel.settings.LocalizedValuesMap;
035    import com.liferay.portal.kernel.social.SocialActivityManagerUtil;
036    import com.liferay.portal.kernel.systemevent.SystemEvent;
037    import com.liferay.portal.kernel.util.ArrayUtil;
038    import com.liferay.portal.kernel.util.Constants;
039    import com.liferay.portal.kernel.util.ContentTypes;
040    import com.liferay.portal.kernel.util.FileUtil;
041    import com.liferay.portal.kernel.util.GetterUtil;
042    import com.liferay.portal.kernel.util.HtmlUtil;
043    import com.liferay.portal.kernel.util.HttpUtil;
044    import com.liferay.portal.kernel.util.LocalizationUtil;
045    import com.liferay.portal.kernel.util.MimeTypesUtil;
046    import com.liferay.portal.kernel.util.OrderByComparator;
047    import com.liferay.portal.kernel.util.ParamUtil;
048    import com.liferay.portal.kernel.util.PropsKeys;
049    import com.liferay.portal.kernel.util.SetUtil;
050    import com.liferay.portal.kernel.util.StringBundler;
051    import com.liferay.portal.kernel.util.StringPool;
052    import com.liferay.portal.kernel.util.StringUtil;
053    import com.liferay.portal.kernel.util.Time;
054    import com.liferay.portal.kernel.util.Validator;
055    import com.liferay.portal.kernel.util.WebKeys;
056    import com.liferay.portal.kernel.workflow.WorkflowConstants;
057    import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
058    import com.liferay.portal.model.Group;
059    import com.liferay.portal.model.ModelHintsUtil;
060    import com.liferay.portal.model.Repository;
061    import com.liferay.portal.model.ResourceConstants;
062    import com.liferay.portal.model.SystemEventConstants;
063    import com.liferay.portal.model.User;
064    import com.liferay.portal.portletfilerepository.PortletFileRepositoryUtil;
065    import com.liferay.portal.service.ServiceContext;
066    import com.liferay.portal.service.permission.ModelPermissions;
067    import com.liferay.portal.theme.ThemeDisplay;
068    import com.liferay.portal.util.GroupSubscriptionCheckSubscriptionSender;
069    import com.liferay.portal.util.LayoutURLUtil;
070    import com.liferay.portal.util.Portal;
071    import com.liferay.portal.util.PortalUtil;
072    import com.liferay.portal.util.PrefsPropsUtil;
073    import com.liferay.portal.util.PropsValues;
074    import com.liferay.portal.util.SubscriptionSender;
075    import com.liferay.portlet.asset.model.AssetEntry;
076    import com.liferay.portlet.asset.model.AssetLinkConstants;
077    import com.liferay.portlet.blogs.BlogsEntryAttachmentFileEntryHelper;
078    import com.liferay.portlet.blogs.BlogsGroupServiceSettings;
079    import com.liferay.portlet.blogs.EntryContentException;
080    import com.liferay.portlet.blogs.EntryCoverImageCropException;
081    import com.liferay.portlet.blogs.EntryDisplayDateException;
082    import com.liferay.portlet.blogs.EntrySmallImageNameException;
083    import com.liferay.portlet.blogs.EntrySmallImageScaleException;
084    import com.liferay.portlet.blogs.EntryTitleException;
085    import com.liferay.portlet.blogs.constants.BlogsConstants;
086    import com.liferay.portlet.blogs.model.BlogsEntry;
087    import com.liferay.portlet.blogs.service.base.BlogsEntryLocalServiceBaseImpl;
088    import com.liferay.portlet.blogs.service.permission.BlogsPermission;
089    import com.liferay.portlet.blogs.social.BlogsActivityKeys;
090    import com.liferay.portlet.blogs.util.BlogsUtil;
091    import com.liferay.portlet.blogs.util.LinkbackProducerUtil;
092    import com.liferay.portlet.blogs.util.comparator.EntryDisplayDateComparator;
093    import com.liferay.portlet.documentlibrary.model.DLFolderConstants;
094    import com.liferay.portlet.social.model.SocialActivityConstants;
095    import com.liferay.portlet.trash.model.TrashEntry;
096    
097    import java.io.IOException;
098    import java.io.InputStream;
099    import java.io.Serializable;
100    
101    import java.util.Date;
102    import java.util.HashMap;
103    import java.util.HashSet;
104    import java.util.List;
105    import java.util.Map;
106    import java.util.Set;
107    
108    import javax.portlet.PortletRequest;
109    import javax.portlet.PortletURL;
110    
111    import javax.servlet.http.HttpServletRequest;
112    
113    import net.htmlparser.jericho.Source;
114    import net.htmlparser.jericho.StartTag;
115    
116    /**
117     * Provides the local service for accessing, adding, checking, deleting,
118     * subscription handling of, trash handling of, and updating blog entries.
119     *
120     * @author Brian Wing Shun Chan
121     * @author Wilson S. Man
122     * @author Raymond Aug??
123     * @author Thiago Moreira
124     * @author Juan Fern??ndez
125     * @author Zsolt Berentey
126     */
127    public class BlogsEntryLocalServiceImpl extends BlogsEntryLocalServiceBaseImpl {
128    
129            @Override
130            public Folder addAttachmentsFolder(long userId, long groupId)
131                    throws PortalException {
132    
133                    return doAddFolder(userId, groupId, BlogsConstants.SERVICE_NAME);
134            }
135    
136            @Override
137            public void addCoverImage(long entryId, ImageSelector imageSelector)
138                    throws PortalException {
139    
140                    if (imageSelector == null) {
141                            return;
142                    }
143    
144                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
145    
146                    String coverImageURL = StringPool.BLANK;
147                    long coverImageFileEntryId = 0;
148    
149                    if (Validator.isNotNull(imageSelector.getImageURL())) {
150                            coverImageURL = imageSelector.getImageURL();
151                    }
152                    else if (imageSelector.getImageBytes() != null) {
153                            coverImageFileEntryId = addCoverImageFileEntry(
154                                    entry.getUserId(), entry.getGroupId(), entryId, imageSelector);
155                    }
156    
157                    entry.setCoverImageURL(coverImageURL);
158                    entry.setCoverImageFileEntryId(coverImageFileEntryId);
159    
160                    blogsEntryPersistence.update(entry);
161            }
162    
163            @Override
164            public BlogsEntry addEntry(
165                            long userId, String title, String content, Date displayDate,
166                            ServiceContext serviceContext)
167                    throws PortalException {
168    
169                    return addEntry(
170                            userId, title, StringPool.BLANK, StringPool.BLANK, content,
171                            displayDate, true, true, new String[0], StringPool.BLANK, null,
172                            null, serviceContext);
173            }
174    
175            @Override
176            public BlogsEntry addEntry(
177                            long userId, String title, String content,
178                            ServiceContext serviceContext)
179                    throws PortalException {
180    
181                    return addEntry(
182                            userId, title, StringPool.BLANK, StringPool.BLANK, content,
183                            new Date(), true, true, new String[0], StringPool.BLANK, null, null,
184                            serviceContext);
185            }
186    
187            /**
188             * @deprecated As of 7.0.0, replaced by {@link #addEntry(long, String,
189             *             String, String, String, int, int, int, int, int, boolean,
190             *             boolean, String[], String, ImageSelector, ImageSelector,
191             *             ServiceContext)}
192             */
193            @Deprecated
194            @Override
195            public BlogsEntry addEntry(
196                            long userId, String title, String description, String content,
197                            int displayDateMonth, int displayDateDay, int displayDateYear,
198                            int displayDateHour, int displayDateMinute, boolean allowPingbacks,
199                            boolean allowTrackbacks, String[] trackbacks, boolean smallImage,
200                            String smallImageURL, String smallImageFileName,
201                            InputStream smallImageInputStream, ServiceContext serviceContext)
202                    throws PortalException {
203    
204                    ImageSelector coverImageImageSelector = null;
205                    ImageSelector smallImageImageSelector = null;
206    
207                    if (smallImage) {
208                            if (Validator.isNotNull(smallImageFileName) &&
209                                    (smallImageInputStream != null)) {
210    
211                                    try {
212                                            byte[] bytes = FileUtil.getBytes(smallImageInputStream);
213    
214                                            smallImageImageSelector = new ImageSelector(
215                                                    bytes, smallImageFileName,
216                                                    MimeTypesUtil.getContentType(smallImageFileName), null);
217                                    }
218                                    catch (IOException ioe) {
219                                            if (_log.isErrorEnabled()) {
220                                                    _log.error("Unable to create image selector", ioe);
221                                            }
222                                    }
223                            }
224                            else if (Validator.isNotNull(smallImageURL)) {
225                                    smallImageImageSelector = new ImageSelector(smallImageURL);
226                            }
227                    }
228    
229                    return addEntry(
230                            userId, title, StringPool.BLANK, description, content,
231                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
232                            displayDateMinute, allowPingbacks, allowTrackbacks, trackbacks,
233                            StringPool.BLANK, coverImageImageSelector, smallImageImageSelector,
234                            serviceContext);
235            }
236    
237            @Indexable(type = IndexableType.REINDEX)
238            @Override
239            public BlogsEntry addEntry(
240                            long userId, String title, String subtitle, String description,
241                            String content, Date displayDate, boolean allowPingbacks,
242                            boolean allowTrackbacks, String[] trackbacks,
243                            String coverImageCaption, ImageSelector coverImageImageSelector,
244                            ImageSelector smallImageImageSelector,
245                            ServiceContext serviceContext)
246                    throws PortalException {
247    
248                    // Entry
249    
250                    User user = userPersistence.findByPrimaryKey(userId);
251                    long groupId = serviceContext.getScopeGroupId();
252    
253                    long entryId = counterLocalService.increment();
254    
255                    validate(title, content);
256    
257                    BlogsEntry entry = blogsEntryPersistence.create(entryId);
258    
259                    entry.setUuid(serviceContext.getUuid());
260                    entry.setGroupId(groupId);
261                    entry.setCompanyId(user.getCompanyId());
262                    entry.setUserId(user.getUserId());
263                    entry.setUserName(user.getFullName());
264                    entry.setTitle(title);
265                    entry.setSubtitle(subtitle);
266                    entry.setUrlTitle(
267                            getUniqueUrlTitle(entryId, title, null, serviceContext));
268                    entry.setDescription(description);
269                    entry.setContent(content);
270                    entry.setDisplayDate(displayDate);
271                    entry.setAllowPingbacks(allowPingbacks);
272                    entry.setAllowTrackbacks(allowTrackbacks);
273                    entry.setStatus(WorkflowConstants.STATUS_DRAFT);
274                    entry.setStatusByUserId(userId);
275                    entry.setStatusDate(serviceContext.getModifiedDate(null));
276                    entry.setExpandoBridgeAttributes(serviceContext);
277    
278                    blogsEntryPersistence.update(entry);
279    
280                    // Resources
281    
282                    if (serviceContext.isAddGroupPermissions() ||
283                            serviceContext.isAddGuestPermissions()) {
284    
285                            addEntryResources(
286                                    entry, serviceContext.isAddGroupPermissions(),
287                                    serviceContext.isAddGuestPermissions());
288                    }
289                    else {
290                            addEntryResources(entry, serviceContext.getModelPermissions());
291                    }
292    
293                    // Asset
294    
295                    updateAsset(
296                            userId, entry, serviceContext.getAssetCategoryIds(),
297                            serviceContext.getAssetTagNames(),
298                            serviceContext.getAssetLinkEntryIds(),
299                            serviceContext.getAssetPriority());
300    
301                    // Comment
302    
303                    addDiscussion(entry, userId, groupId);
304    
305                    // Images
306    
307                    long coverImageFileEntryId = 0;
308                    String coverImageURL = null;
309    
310                    if (coverImageImageSelector != null) {
311                            coverImageURL = coverImageImageSelector.getImageURL();
312    
313                            if (coverImageImageSelector.getImageBytes() != null) {
314                                    coverImageFileEntryId = addCoverImageFileEntry(
315                                            userId, groupId, entryId, coverImageImageSelector);
316                            }
317                    }
318    
319                    long smallImageFileEntryId = 0;
320                    String smallImageURL = null;
321    
322                    if (smallImageImageSelector != null) {
323                            smallImageURL = smallImageImageSelector.getImageURL();
324    
325                            if (smallImageImageSelector.getImageBytes() != null) {
326                                    smallImageFileEntryId = addSmallImageFileEntry(
327                                            userId, groupId, entryId, smallImageImageSelector);
328                            }
329                    }
330    
331                    validate(smallImageFileEntryId);
332    
333                    entry.setCoverImageCaption(coverImageCaption);
334                    entry.setCoverImageFileEntryId(coverImageFileEntryId);
335                    entry.setCoverImageURL(coverImageURL);
336    
337                    if ((smallImageFileEntryId != 0) ||
338                            Validator.isNotNull(smallImageURL)) {
339    
340                            entry.setSmallImage(true);
341                    }
342    
343                    entry.setSmallImageFileEntryId(smallImageFileEntryId);
344                    entry.setSmallImageURL(smallImageURL);
345    
346                    blogsEntryPersistence.update(entry);
347    
348                    // Workflow
349    
350                    if (ArrayUtil.isNotEmpty(trackbacks)) {
351                            serviceContext.setAttribute("trackbacks", trackbacks);
352                    }
353                    else {
354                            serviceContext.setAttribute("trackbacks", null);
355                    }
356    
357                    return startWorkflowInstance(userId, entry, serviceContext);
358            }
359    
360            @Override
361            public BlogsEntry addEntry(
362                            long userId, String title, String subtitle, String description,
363                            String content, int displayDateMonth, int displayDateDay,
364                            int displayDateYear, int displayDateHour, int displayDateMinute,
365                            boolean allowPingbacks, boolean allowTrackbacks,
366                            String[] trackbacks, String coverImageCaption,
367                            ImageSelector coverImageImageSelector,
368                            ImageSelector smallImageImageSelector,
369                            ServiceContext serviceContext)
370                    throws PortalException {
371    
372                    User user = userPersistence.findByPrimaryKey(userId);
373    
374                    Date displayDate = PortalUtil.getDate(
375                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
376                            displayDateMinute, user.getTimeZone(),
377                            EntryDisplayDateException.class);
378    
379                    return addEntry(
380                            userId, title, subtitle, description, content, displayDate,
381                            allowPingbacks, allowTrackbacks, trackbacks, coverImageCaption,
382                            coverImageImageSelector, smallImageImageSelector, serviceContext);
383            }
384    
385            @Override
386            public void addEntryResources(
387                            BlogsEntry entry, boolean addGroupPermissions,
388                            boolean addGuestPermissions)
389                    throws PortalException {
390    
391                    resourceLocalService.addResources(
392                            entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
393                            BlogsEntry.class.getName(), entry.getEntryId(), false,
394                            addGroupPermissions, addGuestPermissions);
395            }
396    
397            @Override
398            public void addEntryResources(
399                            BlogsEntry entry, ModelPermissions modelPermissions)
400                    throws PortalException {
401    
402                    resourceLocalService.addModelResources(
403                            entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
404                            BlogsEntry.class.getName(), entry.getEntryId(), modelPermissions);
405            }
406    
407            @Override
408            public void addEntryResources(
409                            long entryId, boolean addGroupPermissions,
410                            boolean addGuestPermissions)
411                    throws PortalException {
412    
413                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
414    
415                    addEntryResources(entry, addGroupPermissions, addGuestPermissions);
416            }
417    
418            @Override
419            public void addEntryResources(
420                            long entryId, ModelPermissions modelPermissions)
421                    throws PortalException {
422    
423                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
424    
425                    addEntryResources(entry, modelPermissions);
426            }
427    
428            @Override
429            public long addOriginalImageFileEntry(
430                            long userId, long groupId, long entryId,
431                            ImageSelector imageSelector)
432                    throws PortalException {
433    
434                    byte[] imageBytes = imageSelector.getImageBytes();
435    
436                    if (imageBytes == null) {
437                            return 0;
438                    }
439    
440                    BlogsEntryAttachmentFileEntryHelper
441                            blogsEntryAttachmentFileEntryHelper =
442                                    new BlogsEntryAttachmentFileEntryHelper();
443    
444                    Folder folder = addAttachmentsFolder(userId, groupId);
445    
446                    FileEntry originalFileEntry =
447                            blogsEntryAttachmentFileEntryHelper.
448                                    addBlogsEntryAttachmentFileEntry(
449                                            groupId, userId, entryId, folder.getFolderId(),
450                                            imageSelector.getImageTitle(),
451                                            imageSelector.getImageMimeType(), imageBytes);
452    
453                    return originalFileEntry.getFileEntryId();
454            }
455    
456            @Override
457            public void addSmallImage(long entryId, ImageSelector imageSelector)
458                    throws PortalException {
459    
460                    if (imageSelector == null) {
461                            return;
462                    }
463    
464                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
465    
466                    boolean smallImage = false;
467                    long smallImageFileEntryId = 0;
468                    String smallImageURL = StringPool.BLANK;
469    
470                    if (Validator.isNotNull(imageSelector.getImageURL())) {
471                            smallImage = true;
472    
473                            smallImageURL = imageSelector.getImageURL();
474                    }
475                    else if (imageSelector.getImageBytes() != null) {
476                            smallImage = true;
477    
478                            smallImageFileEntryId = addSmallImageFileEntry(
479                                    entry.getUserId(), entry.getGroupId(), entryId, imageSelector);
480                    }
481    
482                    entry.setSmallImage(smallImage);
483                    entry.setSmallImageFileEntryId(smallImageFileEntryId);
484                    entry.setSmallImageURL(smallImageURL);
485    
486                    blogsEntryPersistence.update(entry);
487            }
488    
489            @Override
490            public void checkEntries() throws PortalException {
491                    Date now = new Date();
492    
493                    int count = blogsEntryPersistence.countByLtD_S(
494                            now, WorkflowConstants.STATUS_SCHEDULED);
495    
496                    if (count == 0) {
497                            return;
498                    }
499    
500                    List<BlogsEntry> entries = blogsEntryPersistence.findByLtD_S(
501                            now, WorkflowConstants.STATUS_SCHEDULED);
502    
503                    for (BlogsEntry entry : entries) {
504                            ServiceContext serviceContext = new ServiceContext();
505    
506                            String[] trackbacks = StringUtil.split(entry.getTrackbacks());
507    
508                            serviceContext.setAttribute("trackbacks", trackbacks);
509    
510                            serviceContext.setCommand(Constants.UPDATE);
511    
512                            String portletId = PortletProviderUtil.getPortletId(
513                                    BlogsEntry.class.getName(), PortletProvider.Action.VIEW);
514    
515                            if (Validator.isNotNull(portletId)) {
516                                    String layoutFullURL = PortalUtil.getLayoutFullURL(
517                                            entry.getGroupId(), portletId);
518    
519                                    serviceContext.setLayoutFullURL(layoutFullURL);
520                            }
521    
522                            serviceContext.setScopeGroupId(entry.getGroupId());
523    
524                            blogsEntryLocalService.updateStatus(
525                                    entry.getStatusByUserId(), entry.getEntryId(),
526                                    WorkflowConstants.STATUS_APPROVED, serviceContext,
527                                    new HashMap<String, Serializable>());
528                    }
529            }
530    
531            @Override
532            public void deleteEntries(long groupId) throws PortalException {
533                    for (BlogsEntry entry : blogsEntryPersistence.findByGroupId(groupId)) {
534                            blogsEntryLocalService.deleteEntry(entry);
535                    }
536            }
537    
538            @Indexable(type = IndexableType.DELETE)
539            @Override
540            @SystemEvent(type = SystemEventConstants.TYPE_DELETE)
541            public BlogsEntry deleteEntry(BlogsEntry entry) throws PortalException {
542    
543                    // Entry
544    
545                    blogsEntryPersistence.remove(entry);
546    
547                    // Resources
548    
549                    resourceLocalService.deleteResource(
550                            entry.getCompanyId(), BlogsEntry.class.getName(),
551                            ResourceConstants.SCOPE_INDIVIDUAL, entry.getEntryId());
552    
553                    // Image
554    
555                    imageLocalService.deleteImage(entry.getSmallImageId());
556    
557                    // Subscriptions
558    
559                    subscriptionLocalService.deleteSubscriptions(
560                            entry.getCompanyId(), BlogsEntry.class.getName(),
561                            entry.getEntryId());
562    
563                    // Statistics
564    
565                    blogsStatsUserLocalService.updateStatsUser(
566                            entry.getGroupId(), entry.getUserId(), entry.getDisplayDate());
567    
568                    // Asset
569    
570                    assetEntryLocalService.deleteEntry(
571                            BlogsEntry.class.getName(), entry.getEntryId());
572    
573                    // Attachments
574    
575                    long coverImageFileEntryId = entry.getCoverImageFileEntryId();
576    
577                    if (coverImageFileEntryId != 0) {
578                            PortletFileRepositoryUtil.deletePortletFileEntry(
579                                    coverImageFileEntryId);
580                    }
581    
582                    long smallImageFileEntryId = entry.getSmallImageFileEntryId();
583    
584                    if (smallImageFileEntryId != 0) {
585                            PortletFileRepositoryUtil.deletePortletFileEntry(
586                                    smallImageFileEntryId);
587                    }
588    
589                    // Comment
590    
591                    deleteDiscussion(entry);
592    
593                    // Expando
594    
595                    expandoRowLocalService.deleteRows(entry.getEntryId());
596    
597                    // Ratings
598    
599                    ratingsStatsLocalService.deleteStats(
600                            BlogsEntry.class.getName(), entry.getEntryId());
601    
602                    // Trash
603    
604                    trashEntryLocalService.deleteEntry(
605                            BlogsEntry.class.getName(), entry.getEntryId());
606    
607                    // Workflow
608    
609                    workflowInstanceLinkLocalService.deleteWorkflowInstanceLinks(
610                            entry.getCompanyId(), entry.getGroupId(),
611                            BlogsEntry.class.getName(), entry.getEntryId());
612    
613                    return entry;
614            }
615    
616            @Override
617            public void deleteEntry(long entryId) throws PortalException {
618                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
619    
620                    blogsEntryLocalService.deleteEntry(entry);
621            }
622    
623            @Override
624            public Folder fetchAttachmentsFolder(long userId, long groupId) {
625                    ServiceContext serviceContext = new ServiceContext();
626    
627                    serviceContext.setAddGroupPermissions(true);
628                    serviceContext.setAddGuestPermissions(true);
629    
630                    Repository repository =
631                            PortletFileRepositoryUtil.fetchPortletRepository(
632                                    groupId, BlogsConstants.SERVICE_NAME);
633    
634                    try {
635                            Folder folder = PortletFileRepositoryUtil.getPortletFolder(
636                                    repository.getRepositoryId(),
637                                    DLFolderConstants.DEFAULT_PARENT_FOLDER_ID,
638                                    BlogsConstants.SERVICE_NAME);
639    
640                            return folder;
641                    }
642                    catch (Exception e) {
643                    }
644    
645                    return null;
646            }
647    
648            /**
649             * @deprecated As of 6.2.0, replaced by {@link #getCompanyEntries(long,
650             *             Date, QueryDefinition)}
651             */
652            @Deprecated
653            @Override
654            public List<BlogsEntry> getCompanyEntries(
655                    long companyId, Date displayDate, int status, int start, int end) {
656    
657                    QueryDefinition<BlogsEntry> queryDefinition = new QueryDefinition<>(
658                            status, start, end, null);
659    
660                    return getCompanyEntries(companyId, displayDate, queryDefinition);
661            }
662    
663            /**
664             * @deprecated As of 6.2.0, replaced by {@link #getCompanyEntries(long,
665             *             Date, QueryDefinition)}
666             */
667            @Deprecated
668            @Override
669            public List<BlogsEntry> getCompanyEntries(
670                    long companyId, Date displayDate, int status, int start, int end,
671                    OrderByComparator<BlogsEntry> obc) {
672    
673                    QueryDefinition<BlogsEntry> queryDefinition = new QueryDefinition<>(
674                            status, start, end, obc);
675    
676                    return getCompanyEntries(companyId, displayDate, queryDefinition);
677            }
678    
679            @Override
680            public List<BlogsEntry> getCompanyEntries(
681                    long companyId, Date displayDate,
682                    QueryDefinition<BlogsEntry> queryDefinition) {
683    
684                    if (queryDefinition.isExcludeStatus()) {
685                            return blogsEntryPersistence.findByC_LtD_NotS(
686                                    companyId, displayDate, queryDefinition.getStatus(),
687                                    queryDefinition.getStart(), queryDefinition.getEnd(),
688                                    queryDefinition.getOrderByComparator());
689                    }
690                    else {
691                            return blogsEntryPersistence.findByC_LtD_S(
692                                    companyId, displayDate, queryDefinition.getStatus(),
693                                    queryDefinition.getStart(), queryDefinition.getEnd(),
694                                    queryDefinition.getOrderByComparator());
695                    }
696            }
697    
698            /**
699             * @deprecated As of 6.2.0, replaced by {@link #getCompanyEntriesCount(long,
700             *             Date, QueryDefinition)}
701             */
702            @Deprecated
703            @Override
704            public int getCompanyEntriesCount(
705                    long companyId, Date displayDate, int status) {
706    
707                    QueryDefinition<BlogsEntry> queryDefinition = new QueryDefinition<>(
708                            status);
709    
710                    return getCompanyEntriesCount(companyId, displayDate, queryDefinition);
711            }
712    
713            @Override
714            public int getCompanyEntriesCount(
715                    long companyId, Date displayDate,
716                    QueryDefinition<BlogsEntry> queryDefinition) {
717    
718                    if (queryDefinition.isExcludeStatus()) {
719                            return blogsEntryPersistence.countByC_LtD_NotS(
720                                    companyId, displayDate, queryDefinition.getStatus());
721                    }
722                    else {
723                            return blogsEntryPersistence.countByC_LtD_S(
724                                    companyId, displayDate, queryDefinition.getStatus());
725                    }
726            }
727    
728            @Override
729            public BlogsEntry[] getEntriesPrevAndNext(long entryId)
730                    throws PortalException {
731    
732                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
733    
734                    return blogsEntryPersistence.findByG_S_PrevAndNext(
735                            entry.getEntryId(), entry.getGroupId(),
736                            WorkflowConstants.STATUS_APPROVED,
737                            new EntryDisplayDateComparator(true));
738            }
739    
740            @Override
741            public BlogsEntry getEntry(long entryId) throws PortalException {
742                    return blogsEntryPersistence.findByPrimaryKey(entryId);
743            }
744    
745            @Override
746            public BlogsEntry getEntry(long groupId, String urlTitle)
747                    throws PortalException {
748    
749                    return blogsEntryPersistence.findByG_UT(groupId, urlTitle);
750            }
751    
752            /**
753             * @deprecated As of 6.2.0, replaced by {@link #getGroupEntries(long, Date,
754             *             QueryDefinition)}
755             */
756            @Deprecated
757            @Override
758            public List<BlogsEntry> getGroupEntries(
759                    long groupId, Date displayDate, int status, int start, int end) {
760    
761                    QueryDefinition<BlogsEntry> queryDefinition = new QueryDefinition<>(
762                            status, start, end, null);
763    
764                    return getGroupEntries(groupId, displayDate, queryDefinition);
765            }
766    
767            /**
768             * @deprecated As of 6.2.0, replaced by {@link #getGroupEntries(long, Date,
769             *             QueryDefinition)}
770             */
771            @Deprecated
772            @Override
773            public List<BlogsEntry> getGroupEntries(
774                    long groupId, Date displayDate, int status, int start, int end,
775                    OrderByComparator<BlogsEntry> obc) {
776    
777                    QueryDefinition<BlogsEntry> queryDefinition = new QueryDefinition<>(
778                            status, start, end, obc);
779    
780                    return getGroupEntries(groupId, displayDate, queryDefinition);
781            }
782    
783            @Override
784            public List<BlogsEntry> getGroupEntries(
785                    long groupId, Date displayDate,
786                    QueryDefinition<BlogsEntry> queryDefinition) {
787    
788                    if (queryDefinition.isExcludeStatus()) {
789                            return blogsEntryPersistence.findByG_LtD_NotS(
790                                    groupId, displayDate, queryDefinition.getStatus(),
791                                    queryDefinition.getStart(), queryDefinition.getEnd(),
792                                    queryDefinition.getOrderByComparator());
793                    }
794                    else {
795                            return blogsEntryPersistence.findByG_LtD_S(
796                                    groupId, displayDate, queryDefinition.getStatus(),
797                                    queryDefinition.getStart(), queryDefinition.getEnd(),
798                                    queryDefinition.getOrderByComparator());
799                    }
800            }
801    
802            /**
803             * @deprecated As of 6.2.0, replaced by {@link #getGroupEntries(long,
804             *             QueryDefinition)}
805             */
806            @Deprecated
807            @Override
808            public List<BlogsEntry> getGroupEntries(
809                    long groupId, int status, int start, int end) {
810    
811                    QueryDefinition<BlogsEntry> queryDefinition = new QueryDefinition<>(
812                            status, start, end, null);
813    
814                    return getGroupEntries(groupId, queryDefinition);
815            }
816    
817            /**
818             * @deprecated As of 6.2.0, replaced by {@link #getGroupEntries(long,
819             *             QueryDefinition)}
820             */
821            @Deprecated
822            @Override
823            public List<BlogsEntry> getGroupEntries(
824                    long groupId, int status, int start, int end,
825                    OrderByComparator<BlogsEntry> obc) {
826    
827                    QueryDefinition<BlogsEntry> queryDefinition = new QueryDefinition<>(
828                            status, start, end, obc);
829    
830                    return getGroupEntries(groupId, queryDefinition);
831            }
832    
833            @Override
834            public List<BlogsEntry> getGroupEntries(
835                    long groupId, QueryDefinition<BlogsEntry> queryDefinition) {
836    
837                    if (queryDefinition.isExcludeStatus()) {
838                            return blogsEntryPersistence.findByG_NotS(
839                                    groupId, queryDefinition.getStatus(),
840                                    queryDefinition.getStart(), queryDefinition.getEnd(),
841                                    queryDefinition.getOrderByComparator());
842                    }
843                    else {
844                            return blogsEntryPersistence.findByG_S(
845                                    groupId, queryDefinition.getStatus(),
846                                    queryDefinition.getStart(), queryDefinition.getEnd(),
847                                    queryDefinition.getOrderByComparator());
848                    }
849            }
850    
851            /**
852             * @deprecated As of 6.2.0, replaced by {@link #getGroupEntriesCount(long,
853             *             Date, QueryDefinition)}
854             */
855            @Deprecated
856            @Override
857            public int getGroupEntriesCount(
858                    long groupId, Date displayDate, int status) {
859    
860                    QueryDefinition<BlogsEntry> queryDefinition = new QueryDefinition<>(
861                            status);
862    
863                    return getGroupEntriesCount(groupId, displayDate, queryDefinition);
864            }
865    
866            @Override
867            public int getGroupEntriesCount(
868                    long groupId, Date displayDate,
869                    QueryDefinition<BlogsEntry> queryDefinition) {
870    
871                    if (queryDefinition.isExcludeStatus()) {
872                            return blogsEntryPersistence.countByG_LtD_NotS(
873                                    groupId, displayDate, queryDefinition.getStatus());
874                    }
875                    else {
876                            return blogsEntryPersistence.countByG_LtD_S(
877                                    groupId, displayDate, queryDefinition.getStatus());
878                    }
879            }
880    
881            /**
882             * @deprecated As of 6.2.0, replaced by {@link #getGroupEntriesCount(long,
883             *             QueryDefinition)}
884             */
885            @Deprecated
886            @Override
887            public int getGroupEntriesCount(long groupId, int status) {
888                    QueryDefinition<BlogsEntry> queryDefinition = new QueryDefinition<>(
889                            status);
890    
891                    return getGroupEntriesCount(groupId, queryDefinition);
892            }
893    
894            @Override
895            public int getGroupEntriesCount(
896                    long groupId, QueryDefinition<BlogsEntry> queryDefinition) {
897    
898                    if (queryDefinition.isExcludeStatus()) {
899                            return blogsEntryPersistence.countByG_NotS(
900                                    groupId, queryDefinition.getStatus());
901                    }
902                    else {
903                            return blogsEntryPersistence.countByG_S(
904                                    groupId, queryDefinition.getStatus());
905                    }
906            }
907    
908            /**
909             * @deprecated As of 6.2.0, replaced by {@link #getGroupsEntries(long, long,
910             *             Date, QueryDefinition)}
911             */
912            @Deprecated
913            @Override
914            public List<BlogsEntry> getGroupsEntries(
915                    long companyId, long groupId, Date displayDate, int status, int start,
916                    int end) {
917    
918                    QueryDefinition<BlogsEntry> queryDefinition = new QueryDefinition<>(
919                            status, start, end, null);
920    
921                    return getGroupsEntries(
922                            companyId, groupId, displayDate, queryDefinition);
923            }
924    
925            @Override
926            public List<BlogsEntry> getGroupsEntries(
927                    long companyId, long groupId, Date displayDate,
928                    QueryDefinition<BlogsEntry> queryDefinition) {
929    
930                    return blogsEntryFinder.findByGroupIds(
931                            companyId, groupId, displayDate, queryDefinition);
932            }
933    
934            /**
935             * @deprecated As of 6.2.0, replaced by {@link #getGroupUserEntries(long,
936             *             long, Date, QueryDefinition)}
937             */
938            @Deprecated
939            @Override
940            public List<BlogsEntry> getGroupUserEntries(
941                    long groupId, long userId, Date displayDate, int status, int start,
942                    int end) {
943    
944                    QueryDefinition<BlogsEntry> queryDefinition = new QueryDefinition<>(
945                            status, start, end, null);
946    
947                    return getGroupUserEntries(
948                            groupId, userId, displayDate, queryDefinition);
949            }
950    
951            /**
952             * @deprecated As of 6.2.0, replaced by {@link #getGroupUserEntries(long,
953             *             long, Date, QueryDefinition)}
954             */
955            @Deprecated
956            @Override
957            public List<BlogsEntry> getGroupUserEntries(
958                    long groupId, long userId, Date displayDate, int status, int start,
959                    int end, OrderByComparator<BlogsEntry> obc) {
960    
961                    QueryDefinition<BlogsEntry> queryDefinition = new QueryDefinition<>(
962                            status, start, end, obc);
963    
964                    return getGroupUserEntries(
965                            groupId, userId, displayDate, queryDefinition);
966            }
967    
968            @Override
969            public List<BlogsEntry> getGroupUserEntries(
970                    long groupId, long userId, Date displayDate,
971                    QueryDefinition<BlogsEntry> queryDefinition) {
972    
973                    if (queryDefinition.isExcludeStatus()) {
974                            return blogsEntryPersistence.findByG_U_NotS(
975                                    groupId, userId, queryDefinition.getStatus(),
976                                    queryDefinition.getStart(), queryDefinition.getEnd(),
977                                    queryDefinition.getOrderByComparator());
978                    }
979                    else {
980                            return blogsEntryPersistence.findByG_U_S(
981                                    groupId, userId, queryDefinition.getStatus(),
982                                    queryDefinition.getStart(), queryDefinition.getEnd(),
983                                    queryDefinition.getOrderByComparator());
984                    }
985            }
986    
987            /**
988             * @deprecated As of 6.2.0, replaced by {@link
989             *             #getGroupUserEntriesCount(long, long, Date, QueryDefinition)}
990             */
991            @Deprecated
992            @Override
993            public int getGroupUserEntriesCount(
994                    long groupId, long userId, Date displayDate, int status) {
995    
996                    QueryDefinition<BlogsEntry> queryDefinition = new QueryDefinition<>(
997                            status);
998    
999                    return getGroupUserEntriesCount(
1000                            groupId, userId, displayDate, queryDefinition);
1001            }
1002    
1003            @Override
1004            public int getGroupUserEntriesCount(
1005                    long groupId, long userId, Date displayDate,
1006                    QueryDefinition<BlogsEntry> queryDefinition) {
1007    
1008                    if (queryDefinition.isExcludeStatus()) {
1009                            return blogsEntryPersistence.countByG_U_LtD_NotS(
1010                                    groupId, userId, displayDate, queryDefinition.getStatus());
1011                    }
1012                    else {
1013                            return blogsEntryPersistence.countByG_U_LtD_S(
1014                                    groupId, userId, displayDate, queryDefinition.getStatus());
1015                    }
1016            }
1017    
1018            @Override
1019            public List<BlogsEntry> getNoAssetEntries() {
1020                    return blogsEntryFinder.findByNoAssets();
1021            }
1022    
1023            /**
1024             * @deprecated As of 6.2.0, replaced by {@link #getOrganizationEntries(long,
1025             *             Date, QueryDefinition)}
1026             */
1027            @Deprecated
1028            @Override
1029            public List<BlogsEntry> getOrganizationEntries(
1030                    long organizationId, Date displayDate, int status, int start, int end) {
1031    
1032                    QueryDefinition<BlogsEntry> queryDefinition = new QueryDefinition<>(
1033                            status, start, end, null);
1034    
1035                    return getOrganizationEntries(
1036                            organizationId, displayDate, queryDefinition);
1037            }
1038    
1039            /**
1040             * @deprecated As of 6.2.0, replaced by {@link #getOrganizationEntries(long,
1041             *             Date, QueryDefinition)}
1042             */
1043            @Deprecated
1044            @Override
1045            public List<BlogsEntry> getOrganizationEntries(
1046                    long organizationId, Date displayDate, int status, int start, int end,
1047                    OrderByComparator<BlogsEntry> obc) {
1048    
1049                    QueryDefinition<BlogsEntry> queryDefinition = new QueryDefinition<>(
1050                            status, start, end, obc);
1051    
1052                    return getOrganizationEntries(
1053                            organizationId, displayDate, queryDefinition);
1054            }
1055    
1056            @Override
1057            public List<BlogsEntry> getOrganizationEntries(
1058                    long organizationId, Date displayDate,
1059                    QueryDefinition<BlogsEntry> queryDefinition) {
1060    
1061                    return blogsEntryFinder.findByOrganizationId(
1062                            organizationId, displayDate, queryDefinition);
1063            }
1064    
1065            /**
1066             * @deprecated As of 6.2.0, replaced by {@link
1067             *             #getOrganizationEntriesCount(long, Date, QueryDefinition)}
1068             */
1069            @Deprecated
1070            @Override
1071            public int getOrganizationEntriesCount(
1072                    long organizationId, Date displayDate, int status) {
1073    
1074                    QueryDefinition<BlogsEntry> queryDefinition = new QueryDefinition<>(
1075                            status);
1076    
1077                    return getOrganizationEntriesCount(
1078                            organizationId, displayDate, queryDefinition);
1079            }
1080    
1081            @Override
1082            public int getOrganizationEntriesCount(
1083                    long organizationId, Date displayDate,
1084                    QueryDefinition<BlogsEntry> queryDefinition) {
1085    
1086                    return blogsEntryFinder.countByOrganizationId(
1087                            organizationId, displayDate, queryDefinition);
1088            }
1089    
1090            @Override
1091            public void moveEntriesToTrash(long groupId, long userId)
1092                    throws PortalException {
1093    
1094                    List<BlogsEntry> entries = blogsEntryPersistence.findByGroupId(groupId);
1095    
1096                    for (BlogsEntry entry : entries) {
1097                            blogsEntryLocalService.moveEntryToTrash(userId, entry);
1098                    }
1099            }
1100    
1101            /**
1102             * Moves the blogs entry to the recycle bin. Social activity counters for
1103             * this entry get disabled.
1104             *
1105             * @param  userId the primary key of the user moving the blogs entry
1106             * @param  entry the blogs entry to be moved
1107             * @return the moved blogs entry
1108             */
1109            @Indexable(type = IndexableType.REINDEX)
1110            @Override
1111            public BlogsEntry moveEntryToTrash(long userId, BlogsEntry entry)
1112                    throws PortalException {
1113    
1114                    // Entry
1115    
1116                    int oldStatus = entry.getStatus();
1117    
1118                    if (oldStatus == WorkflowConstants.STATUS_PENDING) {
1119                            entry.setStatus(WorkflowConstants.STATUS_DRAFT);
1120    
1121                            blogsEntryPersistence.update(entry);
1122                    }
1123    
1124                    entry = updateStatus(
1125                            userId, entry.getEntryId(), WorkflowConstants.STATUS_IN_TRASH,
1126                            new ServiceContext());
1127    
1128                    // Social
1129    
1130                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
1131    
1132                    extraDataJSONObject.put("title", entry.getTitle());
1133    
1134                    SocialActivityManagerUtil.addActivity(
1135                            userId, entry, SocialActivityConstants.TYPE_MOVE_TO_TRASH,
1136                            extraDataJSONObject.toString(), 0);
1137    
1138                    // Workflow
1139    
1140                    if (oldStatus == WorkflowConstants.STATUS_PENDING) {
1141                            workflowInstanceLinkLocalService.deleteWorkflowInstanceLink(
1142                                    entry.getCompanyId(), entry.getGroupId(),
1143                                    BlogsEntry.class.getName(), entry.getEntryId());
1144                    }
1145    
1146                    return entry;
1147            }
1148    
1149            /**
1150             * Moves the blogs entry with the ID to the recycle bin.
1151             *
1152             * @param  userId the primary key of the user moving the blogs entry
1153             * @param  entryId the primary key of the blogs entry to be moved
1154             * @return the moved blogs entry
1155             */
1156            @Override
1157            public BlogsEntry moveEntryToTrash(long userId, long entryId)
1158                    throws PortalException {
1159    
1160                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
1161    
1162                    return blogsEntryLocalService.moveEntryToTrash(userId, entry);
1163            }
1164    
1165            /**
1166             * Restores the blogs entry with the ID from the recycle bin. Social
1167             * activity counters for this entry get activated.
1168             *
1169             * @param  userId the primary key of the user restoring the blogs entry
1170             * @param  entryId the primary key of the blogs entry to be restored
1171             * @return the restored blogs entry from the recycle bin
1172             */
1173            @Indexable(type = IndexableType.REINDEX)
1174            @Override
1175            public BlogsEntry restoreEntryFromTrash(long userId, long entryId)
1176                    throws PortalException {
1177    
1178                    // Entry
1179    
1180                    TrashEntry trashEntry = trashEntryLocalService.getEntry(
1181                            BlogsEntry.class.getName(), entryId);
1182    
1183                    BlogsEntry entry = updateStatus(
1184                            userId, entryId, trashEntry.getStatus(), new ServiceContext());
1185    
1186                    // Social
1187    
1188                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
1189    
1190                    extraDataJSONObject.put("title", entry.getTitle());
1191    
1192                    SocialActivityManagerUtil.addActivity(
1193                            userId, entry, SocialActivityConstants.TYPE_RESTORE_FROM_TRASH,
1194                            extraDataJSONObject.toString(), 0);
1195    
1196                    return entry;
1197            }
1198    
1199            @Override
1200            public void subscribe(long userId, long groupId) throws PortalException {
1201                    subscriptionLocalService.addSubscription(
1202                            userId, groupId, BlogsEntry.class.getName(), groupId);
1203            }
1204    
1205            @Override
1206            public void unsubscribe(long userId, long groupId) throws PortalException {
1207                    subscriptionLocalService.deleteSubscription(
1208                            userId, BlogsEntry.class.getName(), groupId);
1209            }
1210    
1211            @Override
1212            public void updateAsset(
1213                            long userId, BlogsEntry entry, long[] assetCategoryIds,
1214                            String[] assetTagNames, long[] assetLinkEntryIds, Double priority)
1215                    throws PortalException {
1216    
1217                    boolean visible = false;
1218    
1219                    if (entry.isApproved()) {
1220                            visible = true;
1221                    }
1222    
1223                    String summary = HtmlUtil.extractText(
1224                            StringUtil.shorten(entry.getContent(), 500));
1225    
1226                    AssetEntry assetEntry = assetEntryLocalService.updateEntry(
1227                            userId, entry.getGroupId(), entry.getCreateDate(),
1228                            entry.getModifiedDate(), BlogsEntry.class.getName(),
1229                            entry.getEntryId(), entry.getUuid(), 0, assetCategoryIds,
1230                            assetTagNames, visible, null, null, null, ContentTypes.TEXT_HTML,
1231                            entry.getTitle(), entry.getDescription(), summary, null, null, 0, 0,
1232                            priority);
1233    
1234                    assetLinkLocalService.updateLinks(
1235                            userId, assetEntry.getEntryId(), assetLinkEntryIds,
1236                            AssetLinkConstants.TYPE_RELATED);
1237            }
1238    
1239            @Override
1240            public BlogsEntry updateEntry(
1241                            long userId, long entryId, String title, String content,
1242                            ServiceContext serviceContext)
1243                    throws PortalException {
1244    
1245                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
1246    
1247                    return updateEntry(
1248                            userId, entryId, title, entry.getSubtitle(), entry.getDescription(),
1249                            content, entry.getDisplayDate(), entry.getAllowPingbacks(),
1250                            entry.getAllowTrackbacks(), StringUtil.split(entry.getTrackbacks()),
1251                            StringPool.BLANK, null, null, serviceContext);
1252            }
1253    
1254            /**
1255             * @deprecated As of 7.0.0, replaced by {@link #updateEntry(long, long,
1256             *             String, String, String, String, int, int, int, int, int,
1257             *             boolean, boolean, String[], String, ImageSelector,
1258             *             ImageSelector, ServiceContext)}
1259             */
1260            @Deprecated
1261            @Override
1262            public BlogsEntry updateEntry(
1263                            long userId, long entryId, String title, String description,
1264                            String content, int displayDateMonth, int displayDateDay,
1265                            int displayDateYear, int displayDateHour, int displayDateMinute,
1266                            boolean allowPingbacks, boolean allowTrackbacks,
1267                            String[] trackbacks, boolean smallImage, String smallImageURL,
1268                            String smallImageFileName, InputStream smallImageInputStream,
1269                            ServiceContext serviceContext)
1270                    throws PortalException {
1271    
1272                    ImageSelector coverImageImageSelector = null;
1273                    ImageSelector smallImageImageSelector = null;
1274    
1275                    if (smallImage) {
1276                            if (Validator.isNotNull(smallImageFileName) &&
1277                                    (smallImageInputStream != null)) {
1278    
1279                                    try {
1280                                            byte[] bytes = FileUtil.getBytes(smallImageInputStream);
1281    
1282                                            smallImageImageSelector = new ImageSelector(
1283                                                    bytes, smallImageFileName,
1284                                                    MimeTypesUtil.getContentType(smallImageFileName), null);
1285                                    }
1286                                    catch (IOException ioe) {
1287                                            if (_log.isErrorEnabled()) {
1288                                                    _log.error("Unable to create image selector", ioe);
1289                                            }
1290                                    }
1291                            }
1292                            else if (Validator.isNotNull(smallImageURL)) {
1293                                    smallImageImageSelector = new ImageSelector(smallImageURL);
1294                            }
1295                    }
1296                    else {
1297                            smallImageImageSelector = new ImageSelector();
1298                    }
1299    
1300                    return updateEntry(
1301                            userId, entryId, title, StringPool.BLANK, description, content,
1302                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
1303                            displayDateMinute, allowPingbacks, allowTrackbacks, trackbacks,
1304                            StringPool.BLANK, coverImageImageSelector, smallImageImageSelector,
1305                            serviceContext);
1306            }
1307    
1308            @Indexable(type = IndexableType.REINDEX)
1309            @Override
1310            public BlogsEntry updateEntry(
1311                            long userId, long entryId, String title, String subtitle,
1312                            String description, String content, Date displayDate,
1313                            boolean allowPingbacks, boolean allowTrackbacks,
1314                            String[] trackbacks, String coverImageCaption,
1315                            ImageSelector coverImageImageSelector,
1316                            ImageSelector smallImageImageSelector,
1317                            ServiceContext serviceContext)
1318                    throws PortalException {
1319    
1320                    // Entry
1321    
1322                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
1323    
1324                    validate(title, content);
1325    
1326                    String oldUrlTitle = entry.getUrlTitle();
1327    
1328                    entry.setTitle(title);
1329                    entry.setSubtitle(subtitle);
1330                    entry.setUrlTitle(
1331                            getUniqueUrlTitle(entryId, title, oldUrlTitle, serviceContext));
1332                    entry.setDescription(description);
1333                    entry.setContent(content);
1334                    entry.setDisplayDate(displayDate);
1335                    entry.setAllowPingbacks(allowPingbacks);
1336                    entry.setAllowTrackbacks(allowTrackbacks);
1337    
1338                    if (entry.isPending() || entry.isDraft()) {
1339                    }
1340                    else {
1341                            entry.setStatus(WorkflowConstants.STATUS_DRAFT);
1342                    }
1343    
1344                    entry.setExpandoBridgeAttributes(serviceContext);
1345    
1346                    blogsEntryPersistence.update(entry);
1347    
1348                    // Resources
1349    
1350                    if ((serviceContext.getGroupPermissions() != null) ||
1351                            (serviceContext.getGuestPermissions() != null)) {
1352    
1353                            updateEntryResources(entry, serviceContext.getModelPermissions());
1354                    }
1355    
1356                    // Asset
1357    
1358                    updateAsset(
1359                            userId, entry, serviceContext.getAssetCategoryIds(),
1360                            serviceContext.getAssetTagNames(),
1361                            serviceContext.getAssetLinkEntryIds(),
1362                            serviceContext.getAssetPriority());
1363    
1364                    // Images
1365    
1366                    long coverImageFileEntryId = entry.getCoverImageFileEntryId();
1367                    String coverImageURL = entry.getCoverImageURL();
1368    
1369                    long deletePreviousCoverImageFileEntryId = 0;
1370    
1371                    if (coverImageImageSelector != null) {
1372                            coverImageURL = coverImageImageSelector.getImageURL();
1373    
1374                            if (coverImageImageSelector.getImageBytes() != null) {
1375                                    coverImageFileEntryId = addCoverImageFileEntry(
1376                                            userId, entry.getGroupId(), entryId,
1377                                            coverImageImageSelector);
1378                            }
1379                            else {
1380                                    coverImageFileEntryId = 0;
1381                            }
1382    
1383                            deletePreviousCoverImageFileEntryId =
1384                                    entry.getCoverImageFileEntryId();
1385                    }
1386    
1387                    long smallImageFileEntryId = entry.getSmallImageFileEntryId();
1388                    String smallImageURL = entry.getSmallImageURL();
1389    
1390                    long deletePreviousSmallImageFileEntryId = 0;
1391    
1392                    if (smallImageImageSelector != null) {
1393                            smallImageURL = smallImageImageSelector.getImageURL();
1394    
1395                            if (smallImageImageSelector.getImageBytes() != null) {
1396                                    smallImageFileEntryId = addSmallImageFileEntry(
1397                                            userId, entry.getGroupId(), entryId,
1398                                            smallImageImageSelector);
1399                            }
1400                            else {
1401                                    smallImageFileEntryId = 0;
1402                            }
1403    
1404                            deletePreviousSmallImageFileEntryId =
1405                                    entry.getSmallImageFileEntryId();
1406                    }
1407    
1408                    validate(smallImageFileEntryId);
1409    
1410                    entry.setCoverImageCaption(coverImageCaption);
1411                    entry.setCoverImageFileEntryId(coverImageFileEntryId);
1412                    entry.setCoverImageURL(coverImageURL);
1413    
1414                    if ((smallImageFileEntryId != 0) ||
1415                            Validator.isNotNull(smallImageURL)) {
1416    
1417                            entry.setSmallImage(true);
1418                    }
1419    
1420                    entry.setSmallImageFileEntryId(smallImageFileEntryId);
1421                    entry.setSmallImageURL(smallImageURL);
1422    
1423                    blogsEntryPersistence.update(entry);
1424    
1425                    // Workflow
1426    
1427                    boolean pingOldTrackbacks = false;
1428    
1429                    if (!oldUrlTitle.equals(entry.getUrlTitle())) {
1430                            pingOldTrackbacks = true;
1431                    }
1432    
1433                    serviceContext.setAttribute(
1434                            "pingOldTrackbacks", String.valueOf(pingOldTrackbacks));
1435    
1436                    if (ArrayUtil.isNotEmpty(trackbacks)) {
1437                            serviceContext.setAttribute("trackbacks", trackbacks);
1438                    }
1439                    else {
1440                            serviceContext.setAttribute("trackbacks", null);
1441                    }
1442    
1443                    entry = startWorkflowInstance(userId, entry, serviceContext);
1444    
1445                    if (deletePreviousCoverImageFileEntryId != 0) {
1446                            PortletFileRepositoryUtil.deletePortletFileEntry(
1447                                    deletePreviousCoverImageFileEntryId);
1448                    }
1449    
1450                    if (deletePreviousSmallImageFileEntryId != 0) {
1451                            PortletFileRepositoryUtil.deletePortletFileEntry(
1452                                    deletePreviousSmallImageFileEntryId);
1453                    }
1454    
1455                    return entry;
1456            }
1457    
1458            @Override
1459            public BlogsEntry updateEntry(
1460                            long userId, long entryId, String title, String subtitle,
1461                            String description, String content, int displayDateMonth,
1462                            int displayDateDay, int displayDateYear, int displayDateHour,
1463                            int displayDateMinute, boolean allowPingbacks,
1464                            boolean allowTrackbacks, String[] trackbacks,
1465                            String coverImageCaption, ImageSelector coverImageImageSelector,
1466                            ImageSelector smallImageImageSelector,
1467                            ServiceContext serviceContext)
1468                    throws PortalException {
1469    
1470                    User user = userPersistence.findByPrimaryKey(userId);
1471    
1472                    Date displayDate = PortalUtil.getDate(
1473                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
1474                            displayDateMinute, user.getTimeZone(),
1475                            EntryDisplayDateException.class);
1476    
1477                    return updateEntry(
1478                            userId, entryId, title, subtitle, description, content, displayDate,
1479                            allowPingbacks, allowTrackbacks, trackbacks, coverImageCaption,
1480                            coverImageImageSelector, smallImageImageSelector, serviceContext);
1481            }
1482    
1483            @Override
1484            public void updateEntryResources(
1485                            BlogsEntry entry, ModelPermissions modelPermissions)
1486                    throws PortalException {
1487    
1488                    resourceLocalService.updateResources(
1489                            entry.getCompanyId(), entry.getGroupId(),
1490                            BlogsEntry.class.getName(), entry.getEntryId(), modelPermissions);
1491            }
1492    
1493            @Override
1494            public void updateEntryResources(
1495                            BlogsEntry entry, String[] groupPermissions,
1496                            String[] guestPermissions)
1497                    throws PortalException {
1498    
1499                    resourceLocalService.updateResources(
1500                            entry.getCompanyId(), entry.getGroupId(),
1501                            BlogsEntry.class.getName(), entry.getEntryId(), groupPermissions,
1502                            guestPermissions);
1503            }
1504    
1505            /**
1506             * @deprecated As of 7.0.0, replaced by {@link #updateStatus(long, long,
1507             *             int, ServiceContext, Map)}
1508             */
1509            @Deprecated
1510            @Override
1511            public BlogsEntry updateStatus(
1512                            long userId, long entryId, int status,
1513                            ServiceContext serviceContext)
1514                    throws PortalException {
1515    
1516                    return updateStatus(
1517                            userId, entryId, status, serviceContext,
1518                            new HashMap<String, Serializable>());
1519            }
1520    
1521            @Indexable(type = IndexableType.REINDEX)
1522            @Override
1523            public BlogsEntry updateStatus(
1524                            long userId, long entryId, int status,
1525                            ServiceContext serviceContext,
1526                            Map<String, Serializable> workflowContext)
1527                    throws PortalException {
1528    
1529                    // Entry
1530    
1531                    User user = userPersistence.findByPrimaryKey(userId);
1532                    Date now = new Date();
1533    
1534                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
1535    
1536                    int oldStatus = entry.getStatus();
1537    
1538                    if ((status == WorkflowConstants.STATUS_APPROVED) &&
1539                            now.before(entry.getDisplayDate())) {
1540    
1541                            status = WorkflowConstants.STATUS_SCHEDULED;
1542                    }
1543    
1544                    entry.setStatus(status);
1545                    entry.setStatusByUserId(user.getUserId());
1546                    entry.setStatusByUserName(user.getFullName());
1547                    entry.setStatusDate(serviceContext.getModifiedDate(now));
1548    
1549                    blogsEntryPersistence.update(entry);
1550    
1551                    // Statistics
1552    
1553                    blogsStatsUserLocalService.updateStatsUser(
1554                            entry.getGroupId(), entry.getUserId(), entry.getDisplayDate());
1555    
1556                    AssetEntry assetEntry = assetEntryLocalService.fetchEntry(
1557                            BlogsEntry.class.getName(), entryId);
1558    
1559                    if ((assetEntry == null) || (assetEntry.getPublishDate() == null)) {
1560                            serviceContext.setCommand(Constants.ADD);
1561                    }
1562    
1563                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
1564    
1565                    extraDataJSONObject.put("title", entry.getTitle());
1566    
1567                    if (status == WorkflowConstants.STATUS_APPROVED) {
1568    
1569                            // Asset
1570    
1571                            assetEntryLocalService.updateEntry(
1572                                    BlogsEntry.class.getName(), entryId, entry.getDisplayDate(),
1573                                    true);
1574    
1575                            // Social
1576    
1577                            if ((oldStatus != WorkflowConstants.STATUS_IN_TRASH) &&
1578                                    (oldStatus != WorkflowConstants.STATUS_SCHEDULED)) {
1579    
1580                                    if (serviceContext.isCommandUpdate()) {
1581                                            SocialActivityManagerUtil.addActivity(
1582                                                    user.getUserId(), entry, BlogsActivityKeys.UPDATE_ENTRY,
1583                                                    extraDataJSONObject.toString(), 0);
1584                                    }
1585                                    else {
1586                                            SocialActivityManagerUtil.addUniqueActivity(
1587                                                    user.getUserId(), entry, BlogsActivityKeys.ADD_ENTRY,
1588                                                    extraDataJSONObject.toString(), 0);
1589                                    }
1590                            }
1591    
1592                            // Trash
1593    
1594                            if (oldStatus == WorkflowConstants.STATUS_IN_TRASH) {
1595                                    if (PropsValues.BLOGS_ENTRY_COMMENTS_ENABLED) {
1596                                            commentManager.restoreDiscussionFromTrash(
1597                                                    BlogsEntry.class.getName(), entryId);
1598                                    }
1599    
1600                                    trashEntryLocalService.deleteEntry(
1601                                            BlogsEntry.class.getName(), entryId);
1602                            }
1603    
1604                            if (oldStatus != WorkflowConstants.STATUS_IN_TRASH) {
1605    
1606                                    // Subscriptions
1607    
1608                                    notifySubscribers(
1609                                            userId, entry, serviceContext, workflowContext);
1610    
1611                                    // Ping
1612    
1613                                    String[] trackbacks = (String[])serviceContext.getAttribute(
1614                                            "trackbacks");
1615                                    Boolean pingOldTrackbacks = ParamUtil.getBoolean(
1616                                            serviceContext, "pingOldTrackbacks");
1617    
1618                                    pingGoogle(entry, serviceContext);
1619                                    pingPingback(entry, serviceContext);
1620                                    pingTrackbacks(
1621                                            entry, trackbacks, pingOldTrackbacks, serviceContext);
1622                            }
1623                    }
1624                    else {
1625    
1626                            // Asset
1627    
1628                            assetEntryLocalService.updateVisible(
1629                                    BlogsEntry.class.getName(), entryId, false);
1630    
1631                            // Social
1632    
1633                            if ((status == WorkflowConstants.STATUS_SCHEDULED) &&
1634                                    (oldStatus != WorkflowConstants.STATUS_IN_TRASH)) {
1635    
1636                                    if (serviceContext.isCommandUpdate()) {
1637                                            SocialActivityManagerUtil.addActivity(
1638                                                    user.getUserId(), entry, BlogsActivityKeys.UPDATE_ENTRY,
1639                                                    extraDataJSONObject.toString(), 0);
1640                                    }
1641                                    else {
1642                                            SocialActivityManagerUtil.addUniqueActivity(
1643                                                    user.getUserId(), entry, BlogsActivityKeys.ADD_ENTRY,
1644                                                    extraDataJSONObject.toString(), 0);
1645                                    }
1646                            }
1647    
1648                            // Trash
1649    
1650                            if (status == WorkflowConstants.STATUS_IN_TRASH) {
1651                                    if (PropsValues.BLOGS_ENTRY_COMMENTS_ENABLED) {
1652                                            commentManager.moveDiscussionToTrash(
1653                                                    BlogsEntry.class.getName(), entryId);
1654                                    }
1655    
1656                                    trashEntryLocalService.addTrashEntry(
1657                                            userId, entry.getGroupId(), BlogsEntry.class.getName(),
1658                                            entry.getEntryId(), entry.getUuid(), null, oldStatus, null,
1659                                            null);
1660                            }
1661                            else if (oldStatus == WorkflowConstants.STATUS_IN_TRASH) {
1662                                    if (PropsValues.BLOGS_ENTRY_COMMENTS_ENABLED) {
1663                                            commentManager.restoreDiscussionFromTrash(
1664                                                    BlogsEntry.class.getName(), entryId);
1665                                    }
1666    
1667                                    trashEntryLocalService.deleteEntry(
1668                                            BlogsEntry.class.getName(), entryId);
1669                            }
1670                    }
1671    
1672                    return entry;
1673            }
1674    
1675            protected long addCoverImageFileEntry(
1676                            long userId, long groupId, long entryId,
1677                            ImageSelector imageSelector)
1678                    throws PortalException {
1679    
1680                    byte[] imageBytes = imageSelector.getImageBytes();
1681    
1682                    if (imageBytes == null) {
1683                            return 0;
1684                    }
1685    
1686                    try {
1687                            ImageSelectorProcessor imageSelectorProcessor =
1688                                    new ImageSelectorProcessor(imageSelector.getImageBytes());
1689    
1690                            imageBytes = imageSelectorProcessor.cropImage(
1691                                    imageSelector.getImageCropRegion());
1692    
1693                            if (imageBytes == null) {
1694                                    throw new EntryCoverImageCropException();
1695                            }
1696    
1697                            Folder folder = addCoverImageFolder(userId, groupId);
1698    
1699                            return addProcessedImageFileEntry(
1700                                    userId, groupId, entryId, folder.getFolderId(),
1701                                    imageSelector.getImageTitle(), imageSelector.getImageMimeType(),
1702                                    imageBytes);
1703                    }
1704                    catch (IOException ioe) {
1705                            throw new EntryCoverImageCropException();
1706                    }
1707            }
1708    
1709            protected Folder addCoverImageFolder(long userId, long groupId)
1710                    throws PortalException {
1711    
1712                    return doAddFolder(userId, groupId, _COVER_IMAGE_FOLDER_NAME);
1713            }
1714    
1715            protected void addDiscussion(BlogsEntry entry, long userId, long groupId)
1716                    throws PortalException {
1717    
1718                    if (PropsValues.BLOGS_ENTRY_COMMENTS_ENABLED) {
1719                            commentManager.addDiscussion(
1720                                    userId, groupId, BlogsEntry.class.getName(), entry.getEntryId(),
1721                                    entry.getUserName());
1722                    }
1723            }
1724    
1725            protected long addProcessedImageFileEntry(
1726                            long userId, long groupId, long entryId, long folderId,
1727                            String title, String mimeType, byte[] bytes)
1728                    throws PortalException {
1729    
1730                    if (Validator.isNull(title)) {
1731                            title = StringUtil.randomString() + "_processedImage_" + entryId;
1732                    }
1733    
1734                    BlogsEntryAttachmentFileEntryHelper
1735                            blogsEntryAttachmentFileEntryHelper =
1736                                    new BlogsEntryAttachmentFileEntryHelper();
1737    
1738                    FileEntry processedImageFileEntry =
1739                            blogsEntryAttachmentFileEntryHelper.
1740                                    addBlogsEntryAttachmentFileEntry(
1741                                            groupId, userId, entryId, folderId, title, mimeType, bytes);
1742    
1743                    return processedImageFileEntry.getFileEntryId();
1744            }
1745    
1746            protected long addSmallImageFileEntry(
1747                            long userId, long groupId, long entryId,
1748                            ImageSelector imageSelector)
1749                    throws PortalException {
1750    
1751                    byte[] imageBytes = imageSelector.getImageBytes();
1752    
1753                    if (imageBytes == null) {
1754                            return 0;
1755                    }
1756    
1757                    try {
1758                            BlogsGroupServiceSettings blogsGroupServiceSettings =
1759                                    BlogsGroupServiceSettings.getInstance(groupId);
1760    
1761                            ImageSelectorProcessor imageSelectorProcessor =
1762                                    new ImageSelectorProcessor(imageSelector.getImageBytes());
1763    
1764                            imageBytes = imageSelectorProcessor.scaleImage(
1765                                    blogsGroupServiceSettings.getSmallImageWidth());
1766    
1767                            if (imageBytes == null) {
1768                                    throw new EntrySmallImageScaleException();
1769                            }
1770    
1771                            Folder folder = addSmallImageFolder(userId, groupId);
1772    
1773                            return addProcessedImageFileEntry(
1774                                    userId, groupId, entryId, folder.getFolderId(),
1775                                    imageSelector.getImageTitle(), imageSelector.getImageMimeType(),
1776                                    imageBytes);
1777                    }
1778                    catch (IOException ioe) {
1779                            throw new EntrySmallImageScaleException();
1780                    }
1781            }
1782    
1783            protected Folder addSmallImageFolder(long userId, long groupId)
1784                    throws PortalException {
1785    
1786                    return doAddFolder(userId, groupId, _SMALL_IMAGE_FOLDER_NAME);
1787            }
1788    
1789            protected void deleteDiscussion(BlogsEntry entry) throws PortalException {
1790                    commentManager.deleteDiscussion(
1791                            BlogsEntry.class.getName(), entry.getEntryId());
1792            }
1793    
1794            protected Folder doAddFolder(long userId, long groupId, String folderName)
1795                    throws PortalException {
1796    
1797                    ServiceContext serviceContext = new ServiceContext();
1798    
1799                    serviceContext.setAddGroupPermissions(true);
1800                    serviceContext.setAddGuestPermissions(true);
1801    
1802                    Repository repository = PortletFileRepositoryUtil.addPortletRepository(
1803                            groupId, BlogsConstants.SERVICE_NAME, serviceContext);
1804    
1805                    Folder folder = PortletFileRepositoryUtil.addPortletFolder(
1806                            userId, repository.getRepositoryId(),
1807                            DLFolderConstants.DEFAULT_PARENT_FOLDER_ID, folderName,
1808                            serviceContext);
1809    
1810                    return folder;
1811            }
1812    
1813            protected String getEntryURL(
1814                            BlogsEntry entry, ServiceContext serviceContext)
1815                    throws PortalException {
1816    
1817                    String entryURL = GetterUtil.getString(
1818                            serviceContext.getAttribute("entryURL"));
1819    
1820                    if (Validator.isNotNull(entryURL)) {
1821                            return entryURL;
1822                    }
1823    
1824                    HttpServletRequest request = serviceContext.getRequest();
1825    
1826                    if (request == null) {
1827                            return StringPool.BLANK;
1828                    }
1829    
1830                    String portletId = PortletProviderUtil.getPortletId(
1831                            BlogsEntry.class.getName(), PortletProvider.Action.VIEW);
1832    
1833                    if (Validator.isNotNull(portletId)) {
1834                            String layoutURL = LayoutURLUtil.getLayoutURL(
1835                                    entry.getGroupId(), portletId, serviceContext);
1836    
1837                            if (Validator.isNotNull(layoutURL)) {
1838                                    return layoutURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs" +
1839                                            StringPool.SLASH + entry.getEntryId();
1840                            }
1841                    }
1842    
1843                    portletId = PortletProviderUtil.getPortletId(
1844                            BlogsEntry.class.getName(), PortletProvider.Action.MANAGE);
1845    
1846                    if (Validator.isNull(portletId)) {
1847                            return StringPool.BLANK;
1848                    }
1849    
1850                    PortletURL portletURL = PortalUtil.getControlPanelPortletURL(
1851                            request, portletId, PortletRequest.RENDER_PHASE);
1852    
1853                    portletURL.setParameter("mvcRenderCommandName", "/blogs/view_entry");
1854                    portletURL.setParameter("entryId", String.valueOf(entry.getEntryId()));
1855    
1856                    return portletURL.toString();
1857            }
1858    
1859            protected String getUniqueUrlTitle(
1860                    long entryId, long groupId, String title) {
1861    
1862                    String urlTitle = BlogsUtil.getUrlTitle(entryId, title);
1863    
1864                    for (int i = 1;; i++) {
1865                            BlogsEntry entry = blogsEntryPersistence.fetchByG_UT(
1866                                    groupId, urlTitle);
1867    
1868                            if ((entry == null) || (entryId == entry.getEntryId())) {
1869                                    break;
1870                            }
1871                            else {
1872                                    String suffix = StringPool.DASH + i;
1873    
1874                                    String prefix = urlTitle;
1875    
1876                                    if (urlTitle.length() > suffix.length()) {
1877                                            prefix = urlTitle.substring(
1878                                                    0, urlTitle.length() - suffix.length());
1879                                    }
1880    
1881                                    urlTitle = prefix + suffix;
1882                            }
1883                    }
1884    
1885                    return urlTitle;
1886            }
1887    
1888            protected String getUniqueUrlTitle(
1889                    long entryId, String title, String oldUrlTitle,
1890                    ServiceContext serviceContext) {
1891    
1892                    String serviceContextUrlTitle = ParamUtil.getString(
1893                            serviceContext, "urlTitle");
1894    
1895                    String urlTitle = null;
1896    
1897                    if (Validator.isNotNull(serviceContextUrlTitle)) {
1898                            urlTitle = BlogsUtil.getUrlTitle(entryId, serviceContextUrlTitle);
1899                    }
1900                    else if (Validator.isNotNull(oldUrlTitle)) {
1901                            return oldUrlTitle;
1902                    }
1903                    else {
1904                            urlTitle = getUniqueUrlTitle(
1905                                    entryId, serviceContext.getScopeGroupId(), title);
1906                    }
1907    
1908                    BlogsEntry urlTitleEntry = blogsEntryPersistence.fetchByG_UT(
1909                            serviceContext.getScopeGroupId(), urlTitle);
1910    
1911                    if ((urlTitleEntry != null) &&
1912                            (urlTitleEntry.getEntryId() != entryId)) {
1913    
1914                            urlTitle = getUniqueUrlTitle(
1915                                    entryId, serviceContext.getScopeGroupId(), urlTitle);
1916                    }
1917    
1918                    return urlTitle;
1919            }
1920    
1921            protected void notifySubscribers(
1922                            long userId, BlogsEntry entry, ServiceContext serviceContext,
1923                            Map<String, Serializable> workflowContext)
1924                    throws PortalException {
1925    
1926                    String entryURL = (String)workflowContext.get(
1927                            WorkflowConstants.CONTEXT_URL);
1928    
1929                    if (!entry.isApproved() || Validator.isNull(entryURL)) {
1930                            return;
1931                    }
1932    
1933                    BlogsGroupServiceSettings blogsGroupServiceSettings =
1934                            BlogsGroupServiceSettings.getInstance(entry.getGroupId());
1935    
1936                    boolean sendEmailEntryUpdated = GetterUtil.getBoolean(
1937                            serviceContext.getAttribute("sendEmailEntryUpdated"));
1938    
1939                    if (serviceContext.isCommandAdd() &&
1940                            blogsGroupServiceSettings.isEmailEntryAddedEnabled()) {
1941                    }
1942                    else if (sendEmailEntryUpdated && serviceContext.isCommandUpdate() &&
1943                                     blogsGroupServiceSettings.isEmailEntryUpdatedEnabled()) {
1944                    }
1945                    else {
1946                            return;
1947                    }
1948    
1949                    Group group = groupPersistence.findByPrimaryKey(entry.getGroupId());
1950    
1951                    String entryTitle = entry.getTitle();
1952    
1953                    String fromName = blogsGroupServiceSettings.getEmailFromName();
1954                    String fromAddress = blogsGroupServiceSettings.getEmailFromAddress();
1955    
1956                    LocalizedValuesMap subjectLocalizedValuesMap = null;
1957                    LocalizedValuesMap bodyLocalizedValuesMap = null;
1958    
1959                    if (serviceContext.isCommandUpdate()) {
1960                            subjectLocalizedValuesMap =
1961                                    blogsGroupServiceSettings.getEmailEntryUpdatedSubject();
1962                            bodyLocalizedValuesMap =
1963                                    blogsGroupServiceSettings.getEmailEntryUpdatedBody();
1964                    }
1965                    else {
1966                            subjectLocalizedValuesMap =
1967                                    blogsGroupServiceSettings.getEmailEntryAddedSubject();
1968                            bodyLocalizedValuesMap =
1969                                    blogsGroupServiceSettings.getEmailEntryAddedBody();
1970                    }
1971    
1972                    SubscriptionSender subscriptionSender =
1973                            new GroupSubscriptionCheckSubscriptionSender(
1974                                    BlogsPermission.RESOURCE_NAME);
1975    
1976                    subscriptionSender.setClassPK(entry.getEntryId());
1977                    subscriptionSender.setClassName(entry.getModelClassName());
1978                    subscriptionSender.setCompanyId(entry.getCompanyId());
1979                    subscriptionSender.setContextAttribute(
1980                            "[$BLOGS_ENTRY_CONTENT$]",
1981                            StringUtil.shorten(HtmlUtil.stripHtml(entry.getContent()), 500),
1982                            false);
1983                    subscriptionSender.setContextAttributes(
1984                            "[$BLOGS_ENTRY_CREATE_DATE$]",
1985                            Time.getSimpleDate(entry.getCreateDate(), "yyyy/MM/dd"),
1986                            "[$BLOGS_ENTRY_DESCRIPTION$]", entry.getDescription(),
1987                            "[$BLOGS_ENTRY_SITE_NAME$]",
1988                            group.getDescriptiveName(serviceContext.getLocale()),
1989                            "[$BLOGS_ENTRY_STATUS_BY_USER_NAME$]", entry.getStatusByUserName(),
1990                            "[$BLOGS_ENTRY_TITLE$]", entryTitle,
1991                            "[$BLOGS_ENTRY_UPDATE_COMMENT$]",
1992                            HtmlUtil.replaceNewLine(
1993                                    GetterUtil.getString(
1994                                            serviceContext.getAttribute("emailEntryUpdatedComment"))),
1995                            "[$BLOGS_ENTRY_URL$]", entryURL,
1996                            "[$BLOGS_ENTRY_USER_PORTRAIT_URL$]",
1997                            workflowContext.get(WorkflowConstants.CONTEXT_USER_PORTRAIT_URL),
1998                            "[$BLOGS_ENTRY_USER_URL$]",
1999                            workflowContext.get(WorkflowConstants.CONTEXT_USER_URL));
2000                    subscriptionSender.setContextCreatorUserPrefix("BLOGS_ENTRY");
2001                    subscriptionSender.setCreatorUserId(entry.getUserId());
2002                    subscriptionSender.setCurrentUserId(userId);
2003                    subscriptionSender.setEntryTitle(entryTitle);
2004                    subscriptionSender.setEntryURL(entryURL);
2005                    subscriptionSender.setFrom(fromAddress, fromName);
2006                    subscriptionSender.setHtmlFormat(true);
2007    
2008                    if (bodyLocalizedValuesMap != null) {
2009                            subscriptionSender.setLocalizedBodyMap(
2010                                    LocalizationUtil.getMap(bodyLocalizedValuesMap));
2011                    }
2012    
2013                    if (subjectLocalizedValuesMap != null) {
2014                            subscriptionSender.setLocalizedSubjectMap(
2015                                    LocalizationUtil.getMap(subjectLocalizedValuesMap));
2016                    }
2017    
2018                    subscriptionSender.setMailId("blogs_entry", entry.getEntryId());
2019    
2020                    int notificationType =
2021                            UserNotificationDefinition.NOTIFICATION_TYPE_ADD_ENTRY;
2022    
2023                    if (serviceContext.isCommandUpdate()) {
2024                            notificationType =
2025                                    UserNotificationDefinition.NOTIFICATION_TYPE_UPDATE_ENTRY;
2026                    }
2027    
2028                    subscriptionSender.setNotificationType(notificationType);
2029    
2030                    String portletId = PortletProviderUtil.getPortletId(
2031                            BlogsEntry.class.getName(), PortletProvider.Action.VIEW);
2032    
2033                    subscriptionSender.setPortletId(portletId);
2034                    subscriptionSender.setReplyToAddress(fromAddress);
2035                    subscriptionSender.setScopeGroupId(entry.getGroupId());
2036                    subscriptionSender.setServiceContext(serviceContext);
2037    
2038                    subscriptionSender.addPersistedSubscribers(
2039                            BlogsEntry.class.getName(), entry.getGroupId());
2040    
2041                    subscriptionSender.addPersistedSubscribers(
2042                            BlogsEntry.class.getName(), entry.getEntryId());
2043    
2044                    subscriptionSender.flushNotificationsAsync();
2045            }
2046    
2047            protected void pingGoogle(BlogsEntry entry, ServiceContext serviceContext)
2048                    throws PortalException {
2049    
2050                    if (!PropsValues.BLOGS_PING_GOOGLE_ENABLED || !entry.isApproved()) {
2051                            return;
2052                    }
2053    
2054                    String portletId = PortletProviderUtil.getPortletId(
2055                            BlogsEntry.class.getName(), PortletProvider.Action.MANAGE);
2056    
2057                    if (Validator.isNull(portletId)) {
2058                            if (_log.isDebugEnabled()) {
2059                                    _log.debug(
2060                                            "Not pinging Google because there is no blogs portlet " +
2061                                                    "provider");
2062                            }
2063    
2064                            return;
2065                    }
2066    
2067                    String layoutFullURL = PortalUtil.getLayoutFullURL(
2068                            serviceContext.getScopeGroupId(), portletId);
2069    
2070                    if (Validator.isNull(layoutFullURL)) {
2071                            return;
2072                    }
2073    
2074                    if (layoutFullURL.contains("://localhost")) {
2075                            if (_log.isDebugEnabled()) {
2076                                    _log.debug(
2077                                            "Not pinging Google because of localhost URL " +
2078                                                    layoutFullURL);
2079                            }
2080    
2081                            return;
2082                    }
2083    
2084                    Group group = groupPersistence.findByPrimaryKey(entry.getGroupId());
2085    
2086                    StringBundler sb = new StringBundler(6);
2087    
2088                    String name = group.getDescriptiveName();
2089                    String url = layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs";
2090                    String changesURL = serviceContext.getPathMain() + "/blogs/rss";
2091    
2092                    sb.append("http://blogsearch.google.com/ping?name=");
2093                    sb.append(HttpUtil.encodeURL(name));
2094                    sb.append("&url=");
2095                    sb.append(HttpUtil.encodeURL(url));
2096                    sb.append("&changesURL=");
2097                    sb.append(HttpUtil.encodeURL(changesURL));
2098    
2099                    String location = sb.toString();
2100    
2101                    if (_log.isInfoEnabled()) {
2102                            _log.info("Pinging Google at " + location);
2103                    }
2104    
2105                    try {
2106                            String response = HttpUtil.URLtoString(sb.toString());
2107    
2108                            if (_log.isInfoEnabled()) {
2109                                    _log.info("Google ping response: " + response);
2110                            }
2111                    }
2112                    catch (IOException ioe) {
2113                            _log.error("Unable to ping Google at " + location, ioe);
2114                    }
2115            }
2116    
2117            protected void pingPingback(BlogsEntry entry, ServiceContext serviceContext)
2118                    throws PortalException {
2119    
2120                    if (!PropsValues.BLOGS_PINGBACK_ENABLED ||
2121                            !entry.isAllowPingbacks() || !entry.isApproved()) {
2122    
2123                            return;
2124                    }
2125    
2126                    HttpServletRequest request = serviceContext.getRequest();
2127    
2128                    if (request == null) {
2129                            return;
2130                    }
2131    
2132                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
2133                            WebKeys.THEME_DISPLAY);
2134    
2135                    String layoutFullURL = PortalUtil.getLayoutFullURL(themeDisplay);
2136    
2137                    if (Validator.isNull(layoutFullURL)) {
2138                            return;
2139                    }
2140    
2141                    String sourceUri =
2142                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/" +
2143                                    entry.getUrlTitle();
2144    
2145                    Source source = new Source(entry.getContent());
2146    
2147                    List<StartTag> tags = source.getAllStartTags("a");
2148    
2149                    for (StartTag tag : tags) {
2150                            String targetUri = tag.getAttributeValue("href");
2151    
2152                            if (Validator.isNotNull(targetUri)) {
2153                                    try {
2154                                            LinkbackProducerUtil.sendPingback(sourceUri, targetUri);
2155                                    }
2156                                    catch (Exception e) {
2157                                            _log.error("Error while sending pingback " + targetUri, e);
2158                                    }
2159                            }
2160                    }
2161            }
2162    
2163            protected void pingTrackbacks(
2164                            BlogsEntry entry, String[] trackbacks, boolean pingOldTrackbacks,
2165                            ServiceContext serviceContext)
2166                    throws PortalException {
2167    
2168                    if (!PropsValues.BLOGS_TRACKBACK_ENABLED ||
2169                            !entry.isAllowTrackbacks() || !entry.isApproved()) {
2170    
2171                            return;
2172                    }
2173    
2174                    HttpServletRequest request = serviceContext.getRequest();
2175    
2176                    if (request == null) {
2177                            return;
2178                    }
2179    
2180                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
2181                            WebKeys.THEME_DISPLAY);
2182    
2183                    String layoutFullURL = PortalUtil.getLayoutFullURL(themeDisplay);
2184    
2185                    if (Validator.isNull(layoutFullURL)) {
2186                            return;
2187                    }
2188    
2189                    Map<String, String> parts = new HashMap<>();
2190    
2191                    String excerpt = StringUtil.shorten(
2192                            HtmlUtil.extractText(entry.getContent()),
2193                            PropsValues.BLOGS_LINKBACK_EXCERPT_LENGTH);
2194                    String url =
2195                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/" +
2196                                    entry.getUrlTitle();
2197    
2198                    parts.put("title", entry.getTitle());
2199                    parts.put("excerpt", excerpt);
2200                    parts.put("url", url);
2201                    parts.put("blog_name", entry.getUserName());
2202    
2203                    Set<String> trackbacksSet = null;
2204    
2205                    if (ArrayUtil.isNotEmpty(trackbacks)) {
2206                            trackbacksSet = SetUtil.fromArray(trackbacks);
2207                    }
2208                    else {
2209                            trackbacksSet = new HashSet<>();
2210                    }
2211    
2212                    if (pingOldTrackbacks) {
2213                            trackbacksSet.addAll(
2214                                    SetUtil.fromArray(StringUtil.split(entry.getTrackbacks())));
2215    
2216                            entry.setTrackbacks(StringPool.BLANK);
2217    
2218                            blogsEntryPersistence.update(entry);
2219                    }
2220    
2221                    Set<String> oldTrackbacks = SetUtil.fromArray(
2222                            StringUtil.split(entry.getTrackbacks()));
2223    
2224                    Set<String> validTrackbacks = new HashSet<>();
2225    
2226                    for (String trackback : trackbacksSet) {
2227                            if (oldTrackbacks.contains(trackback)) {
2228                                    continue;
2229                            }
2230    
2231                            try {
2232                                    if (LinkbackProducerUtil.sendTrackback(trackback, parts)) {
2233                                            validTrackbacks.add(trackback);
2234                                    }
2235                            }
2236                            catch (Exception e) {
2237                                    _log.error("Error while sending trackback at " + trackback, e);
2238                            }
2239                    }
2240    
2241                    if (!validTrackbacks.isEmpty()) {
2242                            String newTrackbacks = StringUtil.merge(validTrackbacks);
2243    
2244                            if (Validator.isNotNull(entry.getTrackbacks())) {
2245                                    newTrackbacks += StringPool.COMMA + entry.getTrackbacks();
2246                            }
2247    
2248                            entry.setTrackbacks(newTrackbacks);
2249    
2250                            blogsEntryPersistence.update(entry);
2251                    }
2252            }
2253    
2254            protected BlogsEntry startWorkflowInstance(
2255                            long userId, BlogsEntry entry, ServiceContext serviceContext)
2256                    throws PortalException {
2257    
2258                    Map<String, Serializable> workflowContext = new HashMap<>();
2259    
2260                    workflowContext.put(
2261                            WorkflowConstants.CONTEXT_URL, getEntryURL(entry, serviceContext));
2262    
2263                    String userPortraitURL = StringPool.BLANK;
2264                    String userURL = StringPool.BLANK;
2265    
2266                    if (serviceContext.getThemeDisplay() != null) {
2267                            User user = userPersistence.findByPrimaryKey(userId);
2268    
2269                            userPortraitURL = user.getPortraitURL(
2270                                    serviceContext.getThemeDisplay());
2271                            userURL = user.getDisplayURL(serviceContext.getThemeDisplay());
2272                    }
2273    
2274                    workflowContext.put(
2275                            WorkflowConstants.CONTEXT_USER_PORTRAIT_URL, userPortraitURL);
2276                    workflowContext.put(WorkflowConstants.CONTEXT_USER_URL, userURL);
2277    
2278                    return WorkflowHandlerRegistryUtil.startWorkflowInstance(
2279                            entry.getCompanyId(), entry.getGroupId(), userId,
2280                            BlogsEntry.class.getName(), entry.getEntryId(), entry,
2281                            serviceContext, workflowContext);
2282            }
2283    
2284            protected void validate(long smallImageFileEntryId) throws PortalException {
2285                    String[] imageExtensions = PrefsPropsUtil.getStringArray(
2286                            PropsKeys.BLOGS_IMAGE_EXTENSIONS, StringPool.COMMA);
2287    
2288                    if (smallImageFileEntryId != 0) {
2289                            FileEntry fileEntry = PortletFileRepositoryUtil.getPortletFileEntry(
2290                                    smallImageFileEntryId);
2291    
2292                            boolean validSmallImageExtension = false;
2293    
2294                            for (String _imageExtension : imageExtensions) {
2295                                    if (StringPool.STAR.equals(_imageExtension) ||
2296                                            _imageExtension.equals(
2297                                                    StringPool.PERIOD + fileEntry.getExtension())) {
2298    
2299                                            validSmallImageExtension = true;
2300    
2301                                            break;
2302                                    }
2303                            }
2304    
2305                            if (!validSmallImageExtension) {
2306                                    throw new EntrySmallImageNameException(
2307                                            "Invalid small image for file entry " +
2308                                                    smallImageFileEntryId);
2309                            }
2310                    }
2311            }
2312    
2313            protected void validate(String title, String content)
2314                    throws PortalException {
2315    
2316                    if (Validator.isNull(title)) {
2317                            throw new EntryTitleException("Title is null");
2318                    }
2319    
2320                    int titleMaxLength = ModelHintsUtil.getMaxLength(
2321                            BlogsEntry.class.getName(), "title");
2322    
2323                    if (title.length() > titleMaxLength) {
2324                            throw new EntryTitleException(
2325                                    "Title has more than " + titleMaxLength + " characters");
2326                    }
2327    
2328                    if (Validator.isNull(content)) {
2329                            throw new EntryContentException("Content is null");
2330                    }
2331    
2332                    int contentMaxLength = ModelHintsUtil.getMaxLength(
2333                            BlogsEntry.class.getName(), "content");
2334    
2335                    if (content.length() > contentMaxLength) {
2336                            throw new EntryContentException(
2337                                    "Content has more than " + contentMaxLength + " characters");
2338                    }
2339            }
2340    
2341            protected CommentManager commentManager =
2342                    CommentManagerUtil.getCommentManager();
2343    
2344            private static final String _COVER_IMAGE_FOLDER_NAME = "Cover Image";
2345    
2346            private static final String _SMALL_IMAGE_FOLDER_NAME = "Small Image";
2347    
2348            private static final Log _log = LogFactoryUtil.getLog(
2349                    BlogsEntryLocalServiceImpl.class);
2350    
2351    }