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.asset.kernel.model.AssetEntry;
018    import com.liferay.asset.kernel.model.AssetLinkConstants;
019    import com.liferay.blogs.kernel.exception.EntryContentException;
020    import com.liferay.blogs.kernel.exception.EntryCoverImageCropException;
021    import com.liferay.blogs.kernel.exception.EntryDisplayDateException;
022    import com.liferay.blogs.kernel.exception.EntrySmallImageNameException;
023    import com.liferay.blogs.kernel.exception.EntrySmallImageScaleException;
024    import com.liferay.blogs.kernel.exception.EntryTitleException;
025    import com.liferay.blogs.kernel.model.BlogsEntry;
026    import com.liferay.blogs.kernel.util.comparator.EntryDisplayDateComparator;
027    import com.liferay.document.library.kernel.model.DLFolderConstants;
028    import com.liferay.portal.kernel.comment.CommentManager;
029    import com.liferay.portal.kernel.comment.CommentManagerUtil;
030    import com.liferay.portal.kernel.dao.orm.QueryDefinition;
031    import com.liferay.portal.kernel.exception.PortalException;
032    import com.liferay.portal.kernel.json.JSONFactoryUtil;
033    import com.liferay.portal.kernel.json.JSONObject;
034    import com.liferay.portal.kernel.log.Log;
035    import com.liferay.portal.kernel.log.LogFactoryUtil;
036    import com.liferay.portal.kernel.model.Group;
037    import com.liferay.portal.kernel.model.ModelHintsUtil;
038    import com.liferay.portal.kernel.model.Repository;
039    import com.liferay.portal.kernel.model.ResourceConstants;
040    import com.liferay.portal.kernel.model.SystemEventConstants;
041    import com.liferay.portal.kernel.model.User;
042    import com.liferay.portal.kernel.notifications.UserNotificationDefinition;
043    import com.liferay.portal.kernel.portlet.PortletProvider;
044    import com.liferay.portal.kernel.portlet.PortletProviderUtil;
045    import com.liferay.portal.kernel.portletfilerepository.PortletFileRepositoryUtil;
046    import com.liferay.portal.kernel.repository.model.FileEntry;
047    import com.liferay.portal.kernel.repository.model.Folder;
048    import com.liferay.portal.kernel.search.Indexable;
049    import com.liferay.portal.kernel.search.IndexableType;
050    import com.liferay.portal.kernel.service.ServiceContext;
051    import com.liferay.portal.kernel.service.permission.ModelPermissions;
052    import com.liferay.portal.kernel.servlet.taglib.ui.ImageSelector;
053    import com.liferay.portal.kernel.servlet.taglib.ui.ImageSelectorProcessor;
054    import com.liferay.portal.kernel.settings.LocalizedValuesMap;
055    import com.liferay.portal.kernel.social.SocialActivityManagerUtil;
056    import com.liferay.portal.kernel.systemevent.SystemEvent;
057    import com.liferay.portal.kernel.theme.ThemeDisplay;
058    import com.liferay.portal.kernel.util.ArrayUtil;
059    import com.liferay.portal.kernel.util.Constants;
060    import com.liferay.portal.kernel.util.ContentTypes;
061    import com.liferay.portal.kernel.util.FileUtil;
062    import com.liferay.portal.kernel.util.GetterUtil;
063    import com.liferay.portal.kernel.util.GroupSubscriptionCheckSubscriptionSender;
064    import com.liferay.portal.kernel.util.HtmlUtil;
065    import com.liferay.portal.kernel.util.HttpUtil;
066    import com.liferay.portal.kernel.util.LocalizationUtil;
067    import com.liferay.portal.kernel.util.MimeTypesUtil;
068    import com.liferay.portal.kernel.util.ParamUtil;
069    import com.liferay.portal.kernel.util.Portal;
070    import com.liferay.portal.kernel.util.PortalUtil;
071    import com.liferay.portal.kernel.util.PropsKeys;
072    import com.liferay.portal.kernel.util.SetUtil;
073    import com.liferay.portal.kernel.util.StringBundler;
074    import com.liferay.portal.kernel.util.StringPool;
075    import com.liferay.portal.kernel.util.StringUtil;
076    import com.liferay.portal.kernel.util.SubscriptionSender;
077    import com.liferay.portal.kernel.util.Time;
078    import com.liferay.portal.kernel.util.Validator;
079    import com.liferay.portal.kernel.util.WebKeys;
080    import com.liferay.portal.kernel.workflow.WorkflowConstants;
081    import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
082    import com.liferay.portal.util.LayoutURLUtil;
083    import com.liferay.portal.util.PrefsPropsUtil;
084    import com.liferay.portal.util.PropsValues;
085    import com.liferay.portlet.blogs.BlogsEntryAttachmentFileEntryHelper;
086    import com.liferay.portlet.blogs.BlogsGroupServiceSettings;
087    import com.liferay.portlet.blogs.constants.BlogsConstants;
088    import com.liferay.portlet.blogs.service.base.BlogsEntryLocalServiceBaseImpl;
089    import com.liferay.portlet.blogs.service.permission.BlogsPermission;
090    import com.liferay.portlet.blogs.social.BlogsActivityKeys;
091    import com.liferay.portlet.blogs.util.BlogsUtil;
092    import com.liferay.portlet.blogs.util.LinkbackProducerUtil;
093    import com.liferay.social.kernel.model.SocialActivityConstants;
094    import com.liferay.trash.kernel.exception.RestoreEntryException;
095    import com.liferay.trash.kernel.exception.TrashEntryException;
096    import com.liferay.trash.kernel.model.TrashEntry;
097    
098    import java.io.IOException;
099    import java.io.InputStream;
100    import java.io.Serializable;
101    
102    import java.util.Date;
103    import java.util.HashMap;
104    import java.util.HashSet;
105    import java.util.List;
106    import java.util.Map;
107    import java.util.Set;
108    
109    import javax.portlet.PortletRequest;
110    import javax.portlet.PortletURL;
111    
112    import javax.servlet.http.HttpServletRequest;
113    
114    import net.htmlparser.jericho.Source;
115    import net.htmlparser.jericho.StartTag;
116    
117    /**
118     * Provides the local service for accessing, adding, checking, deleting,
119     * subscription handling of, trash handling of, and updating blog entries.
120     *
121     * @author Brian Wing Shun Chan
122     * @author Wilson S. Man
123     * @author Raymond Aug??
124     * @author Thiago Moreira
125     * @author Juan Fern??ndez
126     * @author Zsolt Berentey
127     */
128    public class BlogsEntryLocalServiceImpl extends BlogsEntryLocalServiceBaseImpl {
129    
130            @Override
131            public Folder addAttachmentsFolder(long userId, long groupId)
132                    throws PortalException {
133    
134                    return doAddFolder(userId, groupId, BlogsConstants.SERVICE_NAME);
135            }
136    
137            @Override
138            public void addCoverImage(long entryId, ImageSelector imageSelector)
139                    throws PortalException {
140    
141                    if (imageSelector == null) {
142                            return;
143                    }
144    
145                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
146    
147                    String coverImageURL = StringPool.BLANK;
148                    long coverImageFileEntryId = 0;
149    
150                    if (Validator.isNotNull(imageSelector.getImageURL())) {
151                            coverImageURL = imageSelector.getImageURL();
152                    }
153                    else if (imageSelector.getImageBytes() != null) {
154                            coverImageFileEntryId = addCoverImageFileEntry(
155                                    entry.getUserId(), entry.getGroupId(), entryId, imageSelector);
156                    }
157    
158                    entry.setCoverImageURL(coverImageURL);
159                    entry.setCoverImageFileEntryId(coverImageFileEntryId);
160    
161                    blogsEntryPersistence.update(entry);
162            }
163    
164            @Override
165            public BlogsEntry addEntry(
166                            long userId, String title, String content, Date displayDate,
167                            ServiceContext serviceContext)
168                    throws PortalException {
169    
170                    return addEntry(
171                            userId, title, StringPool.BLANK, StringPool.BLANK, content,
172                            displayDate, true, true, new String[0], StringPool.BLANK, null,
173                            null, serviceContext);
174            }
175    
176            @Override
177            public BlogsEntry addEntry(
178                            long userId, String title, String content,
179                            ServiceContext serviceContext)
180                    throws PortalException {
181    
182                    return addEntry(
183                            userId, title, StringPool.BLANK, StringPool.BLANK, content,
184                            new Date(), true, true, new String[0], StringPool.BLANK, null, null,
185                            serviceContext);
186            }
187    
188            /**
189             * @deprecated As of 7.0.0, replaced by {@link #addEntry(long, String,
190             *             String, String, String, int, int, int, int, int, boolean,
191             *             boolean, String[], String, ImageSelector, ImageSelector,
192             *             ServiceContext)}
193             */
194            @Deprecated
195            @Override
196            public BlogsEntry addEntry(
197                            long userId, String title, String description, String content,
198                            int displayDateMonth, int displayDateDay, int displayDateYear,
199                            int displayDateHour, int displayDateMinute, boolean allowPingbacks,
200                            boolean allowTrackbacks, String[] trackbacks, boolean smallImage,
201                            String smallImageURL, String smallImageFileName,
202                            InputStream smallImageInputStream, ServiceContext serviceContext)
203                    throws PortalException {
204    
205                    ImageSelector coverImageImageSelector = null;
206                    ImageSelector smallImageImageSelector = null;
207    
208                    if (smallImage) {
209                            if (Validator.isNotNull(smallImageFileName) &&
210                                    (smallImageInputStream != null)) {
211    
212                                    try {
213                                            byte[] bytes = FileUtil.getBytes(smallImageInputStream);
214    
215                                            smallImageImageSelector = new ImageSelector(
216                                                    bytes, smallImageFileName,
217                                                    MimeTypesUtil.getContentType(smallImageFileName), null);
218                                    }
219                                    catch (IOException ioe) {
220                                            _log.error("Unable to create image selector", ioe);
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                    if (entry.isInTrash()) {
864                            throw new TrashEntryException();
865                    }
866    
867                    int oldStatus = entry.getStatus();
868    
869                    if (oldStatus == WorkflowConstants.STATUS_PENDING) {
870                            entry.setStatus(WorkflowConstants.STATUS_DRAFT);
871    
872                            blogsEntryPersistence.update(entry);
873                    }
874    
875                    entry = updateStatus(
876                            userId, entry.getEntryId(), WorkflowConstants.STATUS_IN_TRASH,
877                            new ServiceContext());
878    
879                    // Social
880    
881                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
882    
883                    extraDataJSONObject.put("title", entry.getTitle());
884    
885                    SocialActivityManagerUtil.addActivity(
886                            userId, entry, SocialActivityConstants.TYPE_MOVE_TO_TRASH,
887                            extraDataJSONObject.toString(), 0);
888    
889                    // Workflow
890    
891                    if (oldStatus == WorkflowConstants.STATUS_PENDING) {
892                            workflowInstanceLinkLocalService.deleteWorkflowInstanceLink(
893                                    entry.getCompanyId(), entry.getGroupId(),
894                                    BlogsEntry.class.getName(), entry.getEntryId());
895                    }
896    
897                    return entry;
898            }
899    
900            /**
901             * Moves the blogs entry with the ID to the recycle bin.
902             *
903             * @param  userId the primary key of the user moving the blogs entry
904             * @param  entryId the primary key of the blogs entry to be moved
905             * @return the moved blogs entry
906             */
907            @Override
908            public BlogsEntry moveEntryToTrash(long userId, long entryId)
909                    throws PortalException {
910    
911                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
912    
913                    return blogsEntryLocalService.moveEntryToTrash(userId, entry);
914            }
915    
916            /**
917             * Restores the blogs entry with the ID from the recycle bin. Social
918             * activity counters for this entry get activated.
919             *
920             * @param  userId the primary key of the user restoring the blogs entry
921             * @param  entryId the primary key of the blogs entry to be restored
922             * @return the restored blogs entry from the recycle bin
923             */
924            @Indexable(type = IndexableType.REINDEX)
925            @Override
926            public BlogsEntry restoreEntryFromTrash(long userId, long entryId)
927                    throws PortalException {
928    
929                    // Entry
930    
931                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
932    
933                    if (!entry.isInTrash()) {
934                            throw new RestoreEntryException(
935                                    RestoreEntryException.INVALID_STATUS);
936                    }
937    
938                    TrashEntry trashEntry = trashEntryLocalService.getEntry(
939                            BlogsEntry.class.getName(), entryId);
940    
941                    entry = updateStatus(
942                            userId, entryId, trashEntry.getStatus(), new ServiceContext());
943    
944                    // Social
945    
946                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
947    
948                    extraDataJSONObject.put("title", entry.getTitle());
949    
950                    SocialActivityManagerUtil.addActivity(
951                            userId, entry, SocialActivityConstants.TYPE_RESTORE_FROM_TRASH,
952                            extraDataJSONObject.toString(), 0);
953    
954                    return entry;
955            }
956    
957            @Override
958            public void subscribe(long userId, long groupId) throws PortalException {
959                    subscriptionLocalService.addSubscription(
960                            userId, groupId, BlogsEntry.class.getName(), groupId);
961            }
962    
963            @Override
964            public void unsubscribe(long userId, long groupId) throws PortalException {
965                    subscriptionLocalService.deleteSubscription(
966                            userId, BlogsEntry.class.getName(), groupId);
967            }
968    
969            @Override
970            public void updateAsset(
971                            long userId, BlogsEntry entry, long[] assetCategoryIds,
972                            String[] assetTagNames, long[] assetLinkEntryIds, Double priority)
973                    throws PortalException {
974    
975                    boolean visible = false;
976    
977                    if (entry.isApproved()) {
978                            visible = true;
979                    }
980    
981                    String summary = HtmlUtil.extractText(
982                            StringUtil.shorten(entry.getContent(), 500));
983    
984                    AssetEntry assetEntry = assetEntryLocalService.updateEntry(
985                            userId, entry.getGroupId(), entry.getCreateDate(),
986                            entry.getModifiedDate(), BlogsEntry.class.getName(),
987                            entry.getEntryId(), entry.getUuid(), 0, assetCategoryIds,
988                            assetTagNames, true, visible, null, null, null, null,
989                            ContentTypes.TEXT_HTML, entry.getTitle(), entry.getDescription(),
990                            summary, null, null, 0, 0, priority);
991    
992                    assetLinkLocalService.updateLinks(
993                            userId, assetEntry.getEntryId(), assetLinkEntryIds,
994                            AssetLinkConstants.TYPE_RELATED);
995            }
996    
997            @Override
998            public BlogsEntry updateEntry(
999                            long userId, long entryId, String title, String content,
1000                            ServiceContext serviceContext)
1001                    throws PortalException {
1002    
1003                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
1004    
1005                    return updateEntry(
1006                            userId, entryId, title, entry.getSubtitle(), entry.getDescription(),
1007                            content, entry.getDisplayDate(), entry.getAllowPingbacks(),
1008                            entry.getAllowTrackbacks(), StringUtil.split(entry.getTrackbacks()),
1009                            StringPool.BLANK, null, null, serviceContext);
1010            }
1011    
1012            /**
1013             * @deprecated As of 7.0.0, replaced by {@link #updateEntry(long, long,
1014             *             String, String, String, String, int, int, int, int, int,
1015             *             boolean, boolean, String[], String, ImageSelector,
1016             *             ImageSelector, ServiceContext)}
1017             */
1018            @Deprecated
1019            @Override
1020            public BlogsEntry updateEntry(
1021                            long userId, long entryId, String title, String description,
1022                            String content, int displayDateMonth, int displayDateDay,
1023                            int displayDateYear, int displayDateHour, int displayDateMinute,
1024                            boolean allowPingbacks, boolean allowTrackbacks,
1025                            String[] trackbacks, boolean smallImage, String smallImageURL,
1026                            String smallImageFileName, InputStream smallImageInputStream,
1027                            ServiceContext serviceContext)
1028                    throws PortalException {
1029    
1030                    ImageSelector coverImageImageSelector = null;
1031                    ImageSelector smallImageImageSelector = null;
1032    
1033                    if (smallImage) {
1034                            if (Validator.isNotNull(smallImageFileName) &&
1035                                    (smallImageInputStream != null)) {
1036    
1037                                    try {
1038                                            byte[] bytes = FileUtil.getBytes(smallImageInputStream);
1039    
1040                                            smallImageImageSelector = new ImageSelector(
1041                                                    bytes, smallImageFileName,
1042                                                    MimeTypesUtil.getContentType(smallImageFileName), null);
1043                                    }
1044                                    catch (IOException ioe) {
1045                                            _log.error("Unable to create image selector", ioe);
1046                                    }
1047                            }
1048                            else if (Validator.isNotNull(smallImageURL)) {
1049                                    smallImageImageSelector = new ImageSelector(smallImageURL);
1050                            }
1051                    }
1052                    else {
1053                            smallImageImageSelector = new ImageSelector();
1054                    }
1055    
1056                    return updateEntry(
1057                            userId, entryId, title, StringPool.BLANK, description, content,
1058                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
1059                            displayDateMinute, allowPingbacks, allowTrackbacks, trackbacks,
1060                            StringPool.BLANK, coverImageImageSelector, smallImageImageSelector,
1061                            serviceContext);
1062            }
1063    
1064            @Indexable(type = IndexableType.REINDEX)
1065            @Override
1066            public BlogsEntry updateEntry(
1067                            long userId, long entryId, String title, String subtitle,
1068                            String description, String content, Date displayDate,
1069                            boolean allowPingbacks, boolean allowTrackbacks,
1070                            String[] trackbacks, String coverImageCaption,
1071                            ImageSelector coverImageImageSelector,
1072                            ImageSelector smallImageImageSelector,
1073                            ServiceContext serviceContext)
1074                    throws PortalException {
1075    
1076                    // Entry
1077    
1078                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
1079    
1080                    validate(title, content);
1081    
1082                    String oldUrlTitle = entry.getUrlTitle();
1083    
1084                    entry.setTitle(title);
1085                    entry.setSubtitle(subtitle);
1086                    entry.setUrlTitle(
1087                            getUniqueUrlTitle(entryId, title, oldUrlTitle, serviceContext));
1088                    entry.setDescription(description);
1089                    entry.setContent(content);
1090                    entry.setDisplayDate(displayDate);
1091                    entry.setAllowPingbacks(allowPingbacks);
1092                    entry.setAllowTrackbacks(allowTrackbacks);
1093    
1094                    if (entry.isPending() || entry.isDraft()) {
1095                    }
1096                    else {
1097                            entry.setStatus(WorkflowConstants.STATUS_DRAFT);
1098                    }
1099    
1100                    entry.setExpandoBridgeAttributes(serviceContext);
1101    
1102                    blogsEntryPersistence.update(entry);
1103    
1104                    // Resources
1105    
1106                    if ((serviceContext.getGroupPermissions() != null) ||
1107                            (serviceContext.getGuestPermissions() != null)) {
1108    
1109                            updateEntryResources(entry, serviceContext.getModelPermissions());
1110                    }
1111    
1112                    // Asset
1113    
1114                    updateAsset(
1115                            userId, entry, serviceContext.getAssetCategoryIds(),
1116                            serviceContext.getAssetTagNames(),
1117                            serviceContext.getAssetLinkEntryIds(),
1118                            serviceContext.getAssetPriority());
1119    
1120                    // Images
1121    
1122                    long coverImageFileEntryId = entry.getCoverImageFileEntryId();
1123                    String coverImageURL = entry.getCoverImageURL();
1124    
1125                    long deletePreviousCoverImageFileEntryId = 0;
1126    
1127                    if (coverImageImageSelector != null) {
1128                            coverImageURL = coverImageImageSelector.getImageURL();
1129    
1130                            if (coverImageImageSelector.getImageBytes() != null) {
1131                                    coverImageFileEntryId = addCoverImageFileEntry(
1132                                            userId, entry.getGroupId(), entryId,
1133                                            coverImageImageSelector);
1134                            }
1135                            else {
1136                                    coverImageFileEntryId = 0;
1137                            }
1138    
1139                            deletePreviousCoverImageFileEntryId =
1140                                    entry.getCoverImageFileEntryId();
1141                    }
1142    
1143                    long smallImageFileEntryId = entry.getSmallImageFileEntryId();
1144                    String smallImageURL = entry.getSmallImageURL();
1145    
1146                    long deletePreviousSmallImageFileEntryId = 0;
1147    
1148                    if (smallImageImageSelector != null) {
1149                            smallImageURL = smallImageImageSelector.getImageURL();
1150    
1151                            if (smallImageImageSelector.getImageBytes() != null) {
1152                                    smallImageFileEntryId = addSmallImageFileEntry(
1153                                            userId, entry.getGroupId(), entryId,
1154                                            smallImageImageSelector);
1155                            }
1156                            else {
1157                                    smallImageFileEntryId = 0;
1158                            }
1159    
1160                            deletePreviousSmallImageFileEntryId =
1161                                    entry.getSmallImageFileEntryId();
1162                    }
1163    
1164                    validate(smallImageFileEntryId);
1165    
1166                    entry.setCoverImageCaption(coverImageCaption);
1167                    entry.setCoverImageFileEntryId(coverImageFileEntryId);
1168                    entry.setCoverImageURL(coverImageURL);
1169    
1170                    if ((smallImageFileEntryId != 0) ||
1171                            Validator.isNotNull(smallImageURL)) {
1172    
1173                            entry.setSmallImage(true);
1174                    }
1175    
1176                    entry.setSmallImageFileEntryId(smallImageFileEntryId);
1177                    entry.setSmallImageURL(smallImageURL);
1178    
1179                    blogsEntryPersistence.update(entry);
1180    
1181                    // Workflow
1182    
1183                    boolean pingOldTrackbacks = false;
1184    
1185                    if (!oldUrlTitle.equals(entry.getUrlTitle())) {
1186                            pingOldTrackbacks = true;
1187                    }
1188    
1189                    serviceContext.setAttribute(
1190                            "pingOldTrackbacks", String.valueOf(pingOldTrackbacks));
1191    
1192                    if (ArrayUtil.isNotEmpty(trackbacks)) {
1193                            serviceContext.setAttribute("trackbacks", trackbacks);
1194                    }
1195                    else {
1196                            serviceContext.setAttribute("trackbacks", null);
1197                    }
1198    
1199                    entry = startWorkflowInstance(userId, entry, serviceContext);
1200    
1201                    if (deletePreviousCoverImageFileEntryId != 0) {
1202                            PortletFileRepositoryUtil.deletePortletFileEntry(
1203                                    deletePreviousCoverImageFileEntryId);
1204                    }
1205    
1206                    if (deletePreviousSmallImageFileEntryId != 0) {
1207                            PortletFileRepositoryUtil.deletePortletFileEntry(
1208                                    deletePreviousSmallImageFileEntryId);
1209                    }
1210    
1211                    return entry;
1212            }
1213    
1214            @Override
1215            public BlogsEntry updateEntry(
1216                            long userId, long entryId, String title, String subtitle,
1217                            String description, String content, int displayDateMonth,
1218                            int displayDateDay, int displayDateYear, int displayDateHour,
1219                            int displayDateMinute, boolean allowPingbacks,
1220                            boolean allowTrackbacks, String[] trackbacks,
1221                            String coverImageCaption, ImageSelector coverImageImageSelector,
1222                            ImageSelector smallImageImageSelector,
1223                            ServiceContext serviceContext)
1224                    throws PortalException {
1225    
1226                    User user = userPersistence.findByPrimaryKey(userId);
1227    
1228                    Date displayDate = PortalUtil.getDate(
1229                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
1230                            displayDateMinute, user.getTimeZone(),
1231                            EntryDisplayDateException.class);
1232    
1233                    return updateEntry(
1234                            userId, entryId, title, subtitle, description, content, displayDate,
1235                            allowPingbacks, allowTrackbacks, trackbacks, coverImageCaption,
1236                            coverImageImageSelector, smallImageImageSelector, serviceContext);
1237            }
1238    
1239            @Override
1240            public void updateEntryResources(
1241                            BlogsEntry entry, ModelPermissions modelPermissions)
1242                    throws PortalException {
1243    
1244                    resourceLocalService.updateResources(
1245                            entry.getCompanyId(), entry.getGroupId(),
1246                            BlogsEntry.class.getName(), entry.getEntryId(), modelPermissions);
1247            }
1248    
1249            @Override
1250            public void updateEntryResources(
1251                            BlogsEntry entry, String[] groupPermissions,
1252                            String[] guestPermissions)
1253                    throws PortalException {
1254    
1255                    resourceLocalService.updateResources(
1256                            entry.getCompanyId(), entry.getGroupId(),
1257                            BlogsEntry.class.getName(), entry.getEntryId(), groupPermissions,
1258                            guestPermissions);
1259            }
1260    
1261            /**
1262             * @deprecated As of 7.0.0, replaced by {@link #updateStatus(long, long,
1263             *             int, ServiceContext, Map)}
1264             */
1265            @Deprecated
1266            @Override
1267            public BlogsEntry updateStatus(
1268                            long userId, long entryId, int status,
1269                            ServiceContext serviceContext)
1270                    throws PortalException {
1271    
1272                    return updateStatus(
1273                            userId, entryId, status, serviceContext,
1274                            new HashMap<String, Serializable>());
1275            }
1276    
1277            @Indexable(type = IndexableType.REINDEX)
1278            @Override
1279            public BlogsEntry updateStatus(
1280                            long userId, long entryId, int status,
1281                            ServiceContext serviceContext,
1282                            Map<String, Serializable> workflowContext)
1283                    throws PortalException {
1284    
1285                    // Entry
1286    
1287                    User user = userPersistence.findByPrimaryKey(userId);
1288                    Date now = new Date();
1289    
1290                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
1291    
1292                    int oldStatus = entry.getStatus();
1293    
1294                    if ((status == WorkflowConstants.STATUS_APPROVED) &&
1295                            now.before(entry.getDisplayDate())) {
1296    
1297                            status = WorkflowConstants.STATUS_SCHEDULED;
1298                    }
1299    
1300                    entry.setStatus(status);
1301                    entry.setStatusByUserId(user.getUserId());
1302                    entry.setStatusByUserName(user.getFullName());
1303                    entry.setStatusDate(serviceContext.getModifiedDate(now));
1304    
1305                    blogsEntryPersistence.update(entry);
1306    
1307                    // Statistics
1308    
1309                    blogsStatsUserLocalService.updateStatsUser(
1310                            entry.getGroupId(), entry.getUserId(), entry.getDisplayDate());
1311    
1312                    AssetEntry assetEntry = assetEntryLocalService.fetchEntry(
1313                            BlogsEntry.class.getName(), entryId);
1314    
1315                    if ((assetEntry == null) || (assetEntry.getPublishDate() == null)) {
1316                            serviceContext.setCommand(Constants.ADD);
1317                    }
1318    
1319                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
1320    
1321                    extraDataJSONObject.put("title", entry.getTitle());
1322    
1323                    if (status == WorkflowConstants.STATUS_APPROVED) {
1324    
1325                            // Asset
1326    
1327                            assetEntryLocalService.updateEntry(
1328                                    BlogsEntry.class.getName(), entryId, entry.getDisplayDate(),
1329                                    null, true, true);
1330    
1331                            // Social
1332    
1333                            if ((oldStatus != WorkflowConstants.STATUS_IN_TRASH) &&
1334                                    (oldStatus != WorkflowConstants.STATUS_SCHEDULED)) {
1335    
1336                                    if (serviceContext.isCommandUpdate()) {
1337                                            SocialActivityManagerUtil.addActivity(
1338                                                    user.getUserId(), entry, BlogsActivityKeys.UPDATE_ENTRY,
1339                                                    extraDataJSONObject.toString(), 0);
1340                                    }
1341                                    else {
1342                                            SocialActivityManagerUtil.addUniqueActivity(
1343                                                    user.getUserId(), entry, BlogsActivityKeys.ADD_ENTRY,
1344                                                    extraDataJSONObject.toString(), 0);
1345                                    }
1346                            }
1347    
1348                            // Trash
1349    
1350                            if (oldStatus == WorkflowConstants.STATUS_IN_TRASH) {
1351                                    if (PropsValues.BLOGS_ENTRY_COMMENTS_ENABLED) {
1352                                            commentManager.restoreDiscussionFromTrash(
1353                                                    BlogsEntry.class.getName(), entryId);
1354                                    }
1355    
1356                                    trashEntryLocalService.deleteEntry(
1357                                            BlogsEntry.class.getName(), entryId);
1358                            }
1359    
1360                            if (oldStatus != WorkflowConstants.STATUS_IN_TRASH) {
1361    
1362                                    // Subscriptions
1363    
1364                                    notifySubscribers(
1365                                            userId, entry, serviceContext, workflowContext);
1366    
1367                                    // Ping
1368    
1369                                    String[] trackbacks = (String[])serviceContext.getAttribute(
1370                                            "trackbacks");
1371                                    Boolean pingOldTrackbacks = ParamUtil.getBoolean(
1372                                            serviceContext, "pingOldTrackbacks");
1373    
1374                                    pingGoogle(entry, serviceContext);
1375                                    pingPingback(entry, serviceContext);
1376                                    pingTrackbacks(
1377                                            entry, trackbacks, pingOldTrackbacks, serviceContext);
1378                            }
1379                    }
1380                    else {
1381    
1382                            // Asset
1383    
1384                            assetEntryLocalService.updateVisible(
1385                                    BlogsEntry.class.getName(), entryId, false);
1386    
1387                            // Social
1388    
1389                            if ((status == WorkflowConstants.STATUS_SCHEDULED) &&
1390                                    (oldStatus != WorkflowConstants.STATUS_IN_TRASH)) {
1391    
1392                                    if (serviceContext.isCommandUpdate()) {
1393                                            SocialActivityManagerUtil.addActivity(
1394                                                    user.getUserId(), entry, BlogsActivityKeys.UPDATE_ENTRY,
1395                                                    extraDataJSONObject.toString(), 0);
1396                                    }
1397                                    else {
1398                                            SocialActivityManagerUtil.addUniqueActivity(
1399                                                    user.getUserId(), entry, BlogsActivityKeys.ADD_ENTRY,
1400                                                    extraDataJSONObject.toString(), 0);
1401                                    }
1402                            }
1403    
1404                            // Trash
1405    
1406                            if (status == WorkflowConstants.STATUS_IN_TRASH) {
1407                                    if (PropsValues.BLOGS_ENTRY_COMMENTS_ENABLED) {
1408                                            commentManager.moveDiscussionToTrash(
1409                                                    BlogsEntry.class.getName(), entryId);
1410                                    }
1411    
1412                                    trashEntryLocalService.addTrashEntry(
1413                                            userId, entry.getGroupId(), BlogsEntry.class.getName(),
1414                                            entry.getEntryId(), entry.getUuid(), null, oldStatus, null,
1415                                            null);
1416                            }
1417                            else if (oldStatus == WorkflowConstants.STATUS_IN_TRASH) {
1418                                    if (PropsValues.BLOGS_ENTRY_COMMENTS_ENABLED) {
1419                                            commentManager.restoreDiscussionFromTrash(
1420                                                    BlogsEntry.class.getName(), entryId);
1421                                    }
1422    
1423                                    trashEntryLocalService.deleteEntry(
1424                                            BlogsEntry.class.getName(), entryId);
1425                            }
1426                    }
1427    
1428                    return entry;
1429            }
1430    
1431            protected long addCoverImageFileEntry(
1432                            long userId, long groupId, long entryId,
1433                            ImageSelector imageSelector)
1434                    throws PortalException {
1435    
1436                    byte[] imageBytes = imageSelector.getImageBytes();
1437    
1438                    if (imageBytes == null) {
1439                            return 0;
1440                    }
1441    
1442                    try {
1443                            ImageSelectorProcessor imageSelectorProcessor =
1444                                    new ImageSelectorProcessor(imageSelector.getImageBytes());
1445    
1446                            imageBytes = imageSelectorProcessor.cropImage(
1447                                    imageSelector.getImageCropRegion());
1448    
1449                            if (imageBytes == null) {
1450                                    throw new EntryCoverImageCropException();
1451                            }
1452    
1453                            Folder folder = addCoverImageFolder(userId, groupId);
1454    
1455                            return addProcessedImageFileEntry(
1456                                    userId, groupId, entryId, folder.getFolderId(),
1457                                    imageSelector.getImageTitle(), imageSelector.getImageMimeType(),
1458                                    imageBytes);
1459                    }
1460                    catch (IOException ioe) {
1461                            throw new EntryCoverImageCropException();
1462                    }
1463            }
1464    
1465            protected Folder addCoverImageFolder(long userId, long groupId)
1466                    throws PortalException {
1467    
1468                    return doAddFolder(userId, groupId, _COVER_IMAGE_FOLDER_NAME);
1469            }
1470    
1471            protected void addDiscussion(BlogsEntry entry, long userId, long groupId)
1472                    throws PortalException {
1473    
1474                    if (PropsValues.BLOGS_ENTRY_COMMENTS_ENABLED) {
1475                            commentManager.addDiscussion(
1476                                    userId, groupId, BlogsEntry.class.getName(), entry.getEntryId(),
1477                                    entry.getUserName());
1478                    }
1479            }
1480    
1481            protected long addProcessedImageFileEntry(
1482                            long userId, long groupId, long entryId, long folderId,
1483                            String title, String mimeType, byte[] bytes)
1484                    throws PortalException {
1485    
1486                    if (Validator.isNull(title)) {
1487                            title = StringUtil.randomString() + "_processedImage_" + entryId;
1488                    }
1489    
1490                    BlogsEntryAttachmentFileEntryHelper
1491                            blogsEntryAttachmentFileEntryHelper =
1492                                    new BlogsEntryAttachmentFileEntryHelper();
1493    
1494                    FileEntry processedImageFileEntry =
1495                            blogsEntryAttachmentFileEntryHelper.
1496                                    addBlogsEntryAttachmentFileEntry(
1497                                            groupId, userId, entryId, folderId, title, mimeType, bytes);
1498    
1499                    return processedImageFileEntry.getFileEntryId();
1500            }
1501    
1502            protected long addSmallImageFileEntry(
1503                            long userId, long groupId, long entryId,
1504                            ImageSelector imageSelector)
1505                    throws PortalException {
1506    
1507                    byte[] imageBytes = imageSelector.getImageBytes();
1508    
1509                    if (imageBytes == null) {
1510                            return 0;
1511                    }
1512    
1513                    try {
1514                            BlogsGroupServiceSettings blogsGroupServiceSettings =
1515                                    BlogsGroupServiceSettings.getInstance(groupId);
1516    
1517                            ImageSelectorProcessor imageSelectorProcessor =
1518                                    new ImageSelectorProcessor(imageSelector.getImageBytes());
1519    
1520                            imageBytes = imageSelectorProcessor.scaleImage(
1521                                    blogsGroupServiceSettings.getSmallImageWidth());
1522    
1523                            if (imageBytes == null) {
1524                                    throw new EntrySmallImageScaleException();
1525                            }
1526    
1527                            Folder folder = addSmallImageFolder(userId, groupId);
1528    
1529                            return addProcessedImageFileEntry(
1530                                    userId, groupId, entryId, folder.getFolderId(),
1531                                    imageSelector.getImageTitle(), imageSelector.getImageMimeType(),
1532                                    imageBytes);
1533                    }
1534                    catch (IOException ioe) {
1535                            throw new EntrySmallImageScaleException();
1536                    }
1537            }
1538    
1539            protected Folder addSmallImageFolder(long userId, long groupId)
1540                    throws PortalException {
1541    
1542                    return doAddFolder(userId, groupId, _SMALL_IMAGE_FOLDER_NAME);
1543            }
1544    
1545            protected void deleteDiscussion(BlogsEntry entry) throws PortalException {
1546                    commentManager.deleteDiscussion(
1547                            BlogsEntry.class.getName(), entry.getEntryId());
1548            }
1549    
1550            protected Folder doAddFolder(long userId, long groupId, String folderName)
1551                    throws PortalException {
1552    
1553                    ServiceContext serviceContext = new ServiceContext();
1554    
1555                    serviceContext.setAddGroupPermissions(true);
1556                    serviceContext.setAddGuestPermissions(true);
1557    
1558                    Repository repository = PortletFileRepositoryUtil.addPortletRepository(
1559                            groupId, BlogsConstants.SERVICE_NAME, serviceContext);
1560    
1561                    Folder folder = PortletFileRepositoryUtil.addPortletFolder(
1562                            userId, repository.getRepositoryId(),
1563                            DLFolderConstants.DEFAULT_PARENT_FOLDER_ID, folderName,
1564                            serviceContext);
1565    
1566                    return folder;
1567            }
1568    
1569            protected String getEntryURL(
1570                            BlogsEntry entry, ServiceContext serviceContext)
1571                    throws PortalException {
1572    
1573                    String entryURL = GetterUtil.getString(
1574                            serviceContext.getAttribute("entryURL"));
1575    
1576                    if (Validator.isNotNull(entryURL)) {
1577                            return entryURL;
1578                    }
1579    
1580                    HttpServletRequest request = serviceContext.getRequest();
1581    
1582                    if (request == null) {
1583                            return StringPool.BLANK;
1584                    }
1585    
1586                    String portletId = PortletProviderUtil.getPortletId(
1587                            BlogsEntry.class.getName(), PortletProvider.Action.VIEW);
1588    
1589                    if (Validator.isNotNull(portletId)) {
1590                            String layoutURL = LayoutURLUtil.getLayoutURL(
1591                                    entry.getGroupId(), portletId, serviceContext);
1592    
1593                            if (Validator.isNotNull(layoutURL)) {
1594                                    return layoutURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs" +
1595                                            StringPool.SLASH + entry.getEntryId();
1596                            }
1597                    }
1598    
1599                    portletId = PortletProviderUtil.getPortletId(
1600                            BlogsEntry.class.getName(), PortletProvider.Action.MANAGE);
1601    
1602                    if (Validator.isNull(portletId)) {
1603                            return StringPool.BLANK;
1604                    }
1605    
1606                    PortletURL portletURL = PortalUtil.getControlPanelPortletURL(
1607                            request, portletId, PortletRequest.RENDER_PHASE);
1608    
1609                    portletURL.setParameter("mvcRenderCommandName", "/blogs/view_entry");
1610                    portletURL.setParameter("entryId", String.valueOf(entry.getEntryId()));
1611    
1612                    return portletURL.toString();
1613            }
1614    
1615            protected String getUniqueUrlTitle(
1616                    long entryId, long groupId, String title) {
1617    
1618                    String urlTitle = BlogsUtil.getUrlTitle(entryId, title);
1619    
1620                    for (int i = 1;; i++) {
1621                            BlogsEntry entry = blogsEntryPersistence.fetchByG_UT(
1622                                    groupId, urlTitle);
1623    
1624                            if ((entry == null) || (entryId == entry.getEntryId())) {
1625                                    break;
1626                            }
1627                            else {
1628                                    String suffix = StringPool.DASH + i;
1629    
1630                                    String prefix = urlTitle;
1631    
1632                                    if (urlTitle.length() > suffix.length()) {
1633                                            prefix = urlTitle.substring(
1634                                                    0, urlTitle.length() - suffix.length());
1635                                    }
1636    
1637                                    urlTitle = prefix + suffix;
1638                            }
1639                    }
1640    
1641                    return urlTitle;
1642            }
1643    
1644            protected String getUniqueUrlTitle(
1645                    long entryId, String title, String oldUrlTitle,
1646                    ServiceContext serviceContext) {
1647    
1648                    String serviceContextUrlTitle = ParamUtil.getString(
1649                            serviceContext, "urlTitle");
1650    
1651                    String urlTitle = null;
1652    
1653                    if (Validator.isNotNull(serviceContextUrlTitle)) {
1654                            urlTitle = BlogsUtil.getUrlTitle(entryId, serviceContextUrlTitle);
1655                    }
1656                    else if (Validator.isNotNull(oldUrlTitle)) {
1657                            return oldUrlTitle;
1658                    }
1659                    else {
1660                            urlTitle = getUniqueUrlTitle(
1661                                    entryId, serviceContext.getScopeGroupId(), title);
1662                    }
1663    
1664                    BlogsEntry urlTitleEntry = blogsEntryPersistence.fetchByG_UT(
1665                            serviceContext.getScopeGroupId(), urlTitle);
1666    
1667                    if ((urlTitleEntry != null) &&
1668                            (urlTitleEntry.getEntryId() != entryId)) {
1669    
1670                            urlTitle = getUniqueUrlTitle(
1671                                    entryId, serviceContext.getScopeGroupId(), urlTitle);
1672                    }
1673    
1674                    return urlTitle;
1675            }
1676    
1677            protected void notifySubscribers(
1678                            long userId, BlogsEntry entry, ServiceContext serviceContext,
1679                            Map<String, Serializable> workflowContext)
1680                    throws PortalException {
1681    
1682                    String entryURL = (String)workflowContext.get(
1683                            WorkflowConstants.CONTEXT_URL);
1684    
1685                    if (!entry.isApproved() || Validator.isNull(entryURL)) {
1686                            return;
1687                    }
1688    
1689                    BlogsGroupServiceSettings blogsGroupServiceSettings =
1690                            BlogsGroupServiceSettings.getInstance(entry.getGroupId());
1691    
1692                    boolean sendEmailEntryUpdated = GetterUtil.getBoolean(
1693                            serviceContext.getAttribute("sendEmailEntryUpdated"));
1694    
1695                    if (serviceContext.isCommandAdd() &&
1696                            blogsGroupServiceSettings.isEmailEntryAddedEnabled()) {
1697                    }
1698                    else if (sendEmailEntryUpdated && serviceContext.isCommandUpdate() &&
1699                                     blogsGroupServiceSettings.isEmailEntryUpdatedEnabled()) {
1700                    }
1701                    else {
1702                            return;
1703                    }
1704    
1705                    Group group = groupPersistence.findByPrimaryKey(entry.getGroupId());
1706    
1707                    String entryTitle = entry.getTitle();
1708    
1709                    String fromName = blogsGroupServiceSettings.getEmailFromName();
1710                    String fromAddress = blogsGroupServiceSettings.getEmailFromAddress();
1711    
1712                    LocalizedValuesMap subjectLocalizedValuesMap = null;
1713                    LocalizedValuesMap bodyLocalizedValuesMap = null;
1714    
1715                    if (serviceContext.isCommandUpdate()) {
1716                            subjectLocalizedValuesMap =
1717                                    blogsGroupServiceSettings.getEmailEntryUpdatedSubject();
1718                            bodyLocalizedValuesMap =
1719                                    blogsGroupServiceSettings.getEmailEntryUpdatedBody();
1720                    }
1721                    else {
1722                            subjectLocalizedValuesMap =
1723                                    blogsGroupServiceSettings.getEmailEntryAddedSubject();
1724                            bodyLocalizedValuesMap =
1725                                    blogsGroupServiceSettings.getEmailEntryAddedBody();
1726                    }
1727    
1728                    SubscriptionSender subscriptionSender =
1729                            new GroupSubscriptionCheckSubscriptionSender(
1730                                    BlogsPermission.RESOURCE_NAME);
1731    
1732                    subscriptionSender.setClassPK(entry.getEntryId());
1733                    subscriptionSender.setClassName(entry.getModelClassName());
1734                    subscriptionSender.setCompanyId(entry.getCompanyId());
1735                    subscriptionSender.setContextAttribute(
1736                            "[$BLOGS_ENTRY_CONTENT$]",
1737                            StringUtil.shorten(HtmlUtil.stripHtml(entry.getContent()), 500),
1738                            false);
1739                    subscriptionSender.setContextAttributes(
1740                            "[$BLOGS_ENTRY_CREATE_DATE$]",
1741                            Time.getSimpleDate(entry.getCreateDate(), "yyyy/MM/dd"),
1742                            "[$BLOGS_ENTRY_DESCRIPTION$]", entry.getDescription(),
1743                            "[$BLOGS_ENTRY_SITE_NAME$]",
1744                            group.getDescriptiveName(serviceContext.getLocale()),
1745                            "[$BLOGS_ENTRY_STATUS_BY_USER_NAME$]", entry.getStatusByUserName(),
1746                            "[$BLOGS_ENTRY_TITLE$]", entryTitle,
1747                            "[$BLOGS_ENTRY_UPDATE_COMMENT$]",
1748                            HtmlUtil.replaceNewLine(
1749                                    GetterUtil.getString(
1750                                            serviceContext.getAttribute("emailEntryUpdatedComment"))),
1751                            "[$BLOGS_ENTRY_URL$]", entryURL,
1752                            "[$BLOGS_ENTRY_USER_PORTRAIT_URL$]",
1753                            workflowContext.get(WorkflowConstants.CONTEXT_USER_PORTRAIT_URL),
1754                            "[$BLOGS_ENTRY_USER_URL$]",
1755                            workflowContext.get(WorkflowConstants.CONTEXT_USER_URL));
1756                    subscriptionSender.setContextCreatorUserPrefix("BLOGS_ENTRY");
1757                    subscriptionSender.setCreatorUserId(entry.getUserId());
1758                    subscriptionSender.setCurrentUserId(userId);
1759                    subscriptionSender.setEntryTitle(entryTitle);
1760                    subscriptionSender.setEntryURL(entryURL);
1761                    subscriptionSender.setFrom(fromAddress, fromName);
1762                    subscriptionSender.setHtmlFormat(true);
1763    
1764                    if (bodyLocalizedValuesMap != null) {
1765                            subscriptionSender.setLocalizedBodyMap(
1766                                    LocalizationUtil.getMap(bodyLocalizedValuesMap));
1767                    }
1768    
1769                    if (subjectLocalizedValuesMap != null) {
1770                            subscriptionSender.setLocalizedSubjectMap(
1771                                    LocalizationUtil.getMap(subjectLocalizedValuesMap));
1772                    }
1773    
1774                    subscriptionSender.setMailId("blogs_entry", entry.getEntryId());
1775    
1776                    int notificationType =
1777                            UserNotificationDefinition.NOTIFICATION_TYPE_ADD_ENTRY;
1778    
1779                    if (serviceContext.isCommandUpdate()) {
1780                            notificationType =
1781                                    UserNotificationDefinition.NOTIFICATION_TYPE_UPDATE_ENTRY;
1782                    }
1783    
1784                    subscriptionSender.setNotificationType(notificationType);
1785    
1786                    String portletId = PortletProviderUtil.getPortletId(
1787                            BlogsEntry.class.getName(), PortletProvider.Action.VIEW);
1788    
1789                    subscriptionSender.setPortletId(portletId);
1790                    subscriptionSender.setReplyToAddress(fromAddress);
1791                    subscriptionSender.setScopeGroupId(entry.getGroupId());
1792                    subscriptionSender.setServiceContext(serviceContext);
1793    
1794                    subscriptionSender.addPersistedSubscribers(
1795                            BlogsEntry.class.getName(), entry.getGroupId());
1796    
1797                    subscriptionSender.addPersistedSubscribers(
1798                            BlogsEntry.class.getName(), entry.getEntryId());
1799    
1800                    subscriptionSender.flushNotificationsAsync();
1801            }
1802    
1803            protected void pingGoogle(BlogsEntry entry, ServiceContext serviceContext)
1804                    throws PortalException {
1805    
1806                    if (!PropsValues.BLOGS_PING_GOOGLE_ENABLED || !entry.isApproved()) {
1807                            return;
1808                    }
1809    
1810                    String portletId = PortletProviderUtil.getPortletId(
1811                            BlogsEntry.class.getName(), PortletProvider.Action.MANAGE);
1812    
1813                    if (Validator.isNull(portletId)) {
1814                            if (_log.isDebugEnabled()) {
1815                                    _log.debug(
1816                                            "Not pinging Google because there is no blogs portlet " +
1817                                                    "provider");
1818                            }
1819    
1820                            return;
1821                    }
1822    
1823                    String layoutFullURL = PortalUtil.getLayoutFullURL(
1824                            serviceContext.getScopeGroupId(), portletId);
1825    
1826                    if (Validator.isNull(layoutFullURL)) {
1827                            return;
1828                    }
1829    
1830                    if (layoutFullURL.contains("://localhost")) {
1831                            if (_log.isDebugEnabled()) {
1832                                    _log.debug(
1833                                            "Not pinging Google because of localhost URL " +
1834                                                    layoutFullURL);
1835                            }
1836    
1837                            return;
1838                    }
1839    
1840                    Group group = groupPersistence.findByPrimaryKey(entry.getGroupId());
1841    
1842                    StringBundler sb = new StringBundler(6);
1843    
1844                    String name = group.getDescriptiveName();
1845                    String url = layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs";
1846                    String changesURL = serviceContext.getPathMain() + "/blogs/rss";
1847    
1848                    sb.append("http://blogsearch.google.com/ping?name=");
1849                    sb.append(HttpUtil.encodeURL(name));
1850                    sb.append("&url=");
1851                    sb.append(HttpUtil.encodeURL(url));
1852                    sb.append("&changesURL=");
1853                    sb.append(HttpUtil.encodeURL(changesURL));
1854    
1855                    String location = sb.toString();
1856    
1857                    if (_log.isInfoEnabled()) {
1858                            _log.info("Pinging Google at " + location);
1859                    }
1860    
1861                    try {
1862                            String response = HttpUtil.URLtoString(sb.toString());
1863    
1864                            if (_log.isInfoEnabled()) {
1865                                    _log.info("Google ping response: " + response);
1866                            }
1867                    }
1868                    catch (IOException ioe) {
1869                            _log.error("Unable to ping Google at " + location, ioe);
1870                    }
1871            }
1872    
1873            protected void pingPingback(BlogsEntry entry, ServiceContext serviceContext)
1874                    throws PortalException {
1875    
1876                    if (!PropsValues.BLOGS_PINGBACK_ENABLED ||
1877                            !entry.isAllowPingbacks() || !entry.isApproved()) {
1878    
1879                            return;
1880                    }
1881    
1882                    HttpServletRequest request = serviceContext.getRequest();
1883    
1884                    if (request == null) {
1885                            return;
1886                    }
1887    
1888                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
1889                            WebKeys.THEME_DISPLAY);
1890    
1891                    String layoutFullURL = PortalUtil.getLayoutFullURL(themeDisplay);
1892    
1893                    if (Validator.isNull(layoutFullURL)) {
1894                            return;
1895                    }
1896    
1897                    String sourceUri =
1898                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/" +
1899                                    entry.getUrlTitle();
1900    
1901                    Source source = new Source(entry.getContent());
1902    
1903                    List<StartTag> tags = source.getAllStartTags("a");
1904    
1905                    for (StartTag tag : tags) {
1906                            String targetUri = tag.getAttributeValue("href");
1907    
1908                            if (Validator.isNotNull(targetUri)) {
1909                                    try {
1910                                            LinkbackProducerUtil.sendPingback(sourceUri, targetUri);
1911                                    }
1912                                    catch (Exception e) {
1913                                            _log.error("Error while sending pingback " + targetUri, e);
1914                                    }
1915                            }
1916                    }
1917            }
1918    
1919            protected void pingTrackbacks(
1920                            BlogsEntry entry, String[] trackbacks, boolean pingOldTrackbacks,
1921                            ServiceContext serviceContext)
1922                    throws PortalException {
1923    
1924                    if (!PropsValues.BLOGS_TRACKBACK_ENABLED ||
1925                            !entry.isAllowTrackbacks() || !entry.isApproved()) {
1926    
1927                            return;
1928                    }
1929    
1930                    HttpServletRequest request = serviceContext.getRequest();
1931    
1932                    if (request == null) {
1933                            return;
1934                    }
1935    
1936                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
1937                            WebKeys.THEME_DISPLAY);
1938    
1939                    String layoutFullURL = PortalUtil.getLayoutFullURL(themeDisplay);
1940    
1941                    if (Validator.isNull(layoutFullURL)) {
1942                            return;
1943                    }
1944    
1945                    Map<String, String> parts = new HashMap<>();
1946    
1947                    String excerpt = StringUtil.shorten(
1948                            HtmlUtil.extractText(entry.getContent()),
1949                            PropsValues.BLOGS_LINKBACK_EXCERPT_LENGTH);
1950                    String url =
1951                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/" +
1952                                    entry.getUrlTitle();
1953    
1954                    parts.put("title", entry.getTitle());
1955                    parts.put("excerpt", excerpt);
1956                    parts.put("url", url);
1957                    parts.put("blog_name", entry.getUserName());
1958    
1959                    Set<String> trackbacksSet = null;
1960    
1961                    if (ArrayUtil.isNotEmpty(trackbacks)) {
1962                            trackbacksSet = SetUtil.fromArray(trackbacks);
1963                    }
1964                    else {
1965                            trackbacksSet = new HashSet<>();
1966                    }
1967    
1968                    if (pingOldTrackbacks) {
1969                            trackbacksSet.addAll(
1970                                    SetUtil.fromArray(StringUtil.split(entry.getTrackbacks())));
1971    
1972                            entry.setTrackbacks(StringPool.BLANK);
1973    
1974                            blogsEntryPersistence.update(entry);
1975                    }
1976    
1977                    Set<String> oldTrackbacks = SetUtil.fromArray(
1978                            StringUtil.split(entry.getTrackbacks()));
1979    
1980                    Set<String> validTrackbacks = new HashSet<>();
1981    
1982                    for (String trackback : trackbacksSet) {
1983                            if (oldTrackbacks.contains(trackback)) {
1984                                    continue;
1985                            }
1986    
1987                            try {
1988                                    if (LinkbackProducerUtil.sendTrackback(trackback, parts)) {
1989                                            validTrackbacks.add(trackback);
1990                                    }
1991                            }
1992                            catch (Exception e) {
1993                                    _log.error("Error while sending trackback at " + trackback, e);
1994                            }
1995                    }
1996    
1997                    if (!validTrackbacks.isEmpty()) {
1998                            String newTrackbacks = StringUtil.merge(validTrackbacks);
1999    
2000                            if (Validator.isNotNull(entry.getTrackbacks())) {
2001                                    newTrackbacks += StringPool.COMMA + entry.getTrackbacks();
2002                            }
2003    
2004                            entry.setTrackbacks(newTrackbacks);
2005    
2006                            blogsEntryPersistence.update(entry);
2007                    }
2008            }
2009    
2010            protected BlogsEntry startWorkflowInstance(
2011                            long userId, BlogsEntry entry, ServiceContext serviceContext)
2012                    throws PortalException {
2013    
2014                    Map<String, Serializable> workflowContext = new HashMap<>();
2015    
2016                    workflowContext.put(
2017                            WorkflowConstants.CONTEXT_URL, getEntryURL(entry, serviceContext));
2018    
2019                    String userPortraitURL = StringPool.BLANK;
2020                    String userURL = StringPool.BLANK;
2021    
2022                    if (serviceContext.getThemeDisplay() != null) {
2023                            User user = userPersistence.findByPrimaryKey(userId);
2024    
2025                            userPortraitURL = user.getPortraitURL(
2026                                    serviceContext.getThemeDisplay());
2027                            userURL = user.getDisplayURL(serviceContext.getThemeDisplay());
2028                    }
2029    
2030                    workflowContext.put(
2031                            WorkflowConstants.CONTEXT_USER_PORTRAIT_URL, userPortraitURL);
2032                    workflowContext.put(WorkflowConstants.CONTEXT_USER_URL, userURL);
2033    
2034                    return WorkflowHandlerRegistryUtil.startWorkflowInstance(
2035                            entry.getCompanyId(), entry.getGroupId(), userId,
2036                            BlogsEntry.class.getName(), entry.getEntryId(), entry,
2037                            serviceContext, workflowContext);
2038            }
2039    
2040            protected void validate(long smallImageFileEntryId) throws PortalException {
2041                    String[] imageExtensions = PrefsPropsUtil.getStringArray(
2042                            PropsKeys.BLOGS_IMAGE_EXTENSIONS, StringPool.COMMA);
2043    
2044                    if (smallImageFileEntryId != 0) {
2045                            FileEntry fileEntry = PortletFileRepositoryUtil.getPortletFileEntry(
2046                                    smallImageFileEntryId);
2047    
2048                            boolean validSmallImageExtension = false;
2049    
2050                            for (String _imageExtension : imageExtensions) {
2051                                    if (StringPool.STAR.equals(_imageExtension) ||
2052                                            _imageExtension.equals(
2053                                                    StringPool.PERIOD + fileEntry.getExtension())) {
2054    
2055                                            validSmallImageExtension = true;
2056    
2057                                            break;
2058                                    }
2059                            }
2060    
2061                            if (!validSmallImageExtension) {
2062                                    throw new EntrySmallImageNameException(
2063                                            "Invalid small image for file entry " +
2064                                                    smallImageFileEntryId);
2065                            }
2066                    }
2067            }
2068    
2069            protected void validate(String title, String content)
2070                    throws PortalException {
2071    
2072                    if (Validator.isNull(title)) {
2073                            throw new EntryTitleException("Title is null");
2074                    }
2075    
2076                    int titleMaxLength = ModelHintsUtil.getMaxLength(
2077                            BlogsEntry.class.getName(), "title");
2078    
2079                    if (title.length() > titleMaxLength) {
2080                            throw new EntryTitleException(
2081                                    "Title has more than " + titleMaxLength + " characters");
2082                    }
2083    
2084                    if (Validator.isNull(content)) {
2085                            throw new EntryContentException("Content is null");
2086                    }
2087    
2088                    int contentMaxLength = ModelHintsUtil.getMaxLength(
2089                            BlogsEntry.class.getName(), "content");
2090    
2091                    if (content.length() > contentMaxLength) {
2092                            throw new EntryContentException(
2093                                    "Content has more than " + contentMaxLength + " characters");
2094                    }
2095            }
2096    
2097            protected CommentManager commentManager =
2098                    CommentManagerUtil.getCommentManager();
2099    
2100            private static final String _COVER_IMAGE_FOLDER_NAME = "Cover Image";
2101    
2102            private static final String _SMALL_IMAGE_FOLDER_NAME = "Small Image";
2103    
2104            private static final Log _log = LogFactoryUtil.getLog(
2105                    BlogsEntryLocalServiceImpl.class);
2106    
2107    }