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