001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portlet.blogs.service.impl;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.search.Indexer;
022    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
023    import com.liferay.portal.kernel.util.ContentTypes;
024    import com.liferay.portal.kernel.util.FileUtil;
025    import com.liferay.portal.kernel.util.GetterUtil;
026    import com.liferay.portal.kernel.util.HtmlUtil;
027    import com.liferay.portal.kernel.util.HttpUtil;
028    import com.liferay.portal.kernel.util.OrderByComparator;
029    import com.liferay.portal.kernel.util.PropsKeys;
030    import com.liferay.portal.kernel.util.SetUtil;
031    import com.liferay.portal.kernel.util.StringBundler;
032    import com.liferay.portal.kernel.util.StringPool;
033    import com.liferay.portal.kernel.util.StringUtil;
034    import com.liferay.portal.kernel.util.Validator;
035    import com.liferay.portal.kernel.workflow.WorkflowConstants;
036    import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
037    import com.liferay.portal.model.Group;
038    import com.liferay.portal.model.ModelHintsUtil;
039    import com.liferay.portal.model.ResourceConstants;
040    import com.liferay.portal.model.User;
041    import com.liferay.portal.service.ServiceContext;
042    import com.liferay.portal.service.ServiceContextUtil;
043    import com.liferay.portal.util.Portal;
044    import com.liferay.portal.util.PortalUtil;
045    import com.liferay.portal.util.PortletKeys;
046    import com.liferay.portal.util.PrefsPropsUtil;
047    import com.liferay.portal.util.PropsValues;
048    import com.liferay.portal.util.SubscriptionSender;
049    import com.liferay.portlet.asset.model.AssetEntry;
050    import com.liferay.portlet.asset.model.AssetLinkConstants;
051    import com.liferay.portlet.blogs.EntryContentException;
052    import com.liferay.portlet.blogs.EntryDisplayDateException;
053    import com.liferay.portlet.blogs.EntrySmallImageNameException;
054    import com.liferay.portlet.blogs.EntrySmallImageSizeException;
055    import com.liferay.portlet.blogs.EntryTitleException;
056    import com.liferay.portlet.blogs.model.BlogsEntry;
057    import com.liferay.portlet.blogs.service.base.BlogsEntryLocalServiceBaseImpl;
058    import com.liferay.portlet.blogs.social.BlogsActivityKeys;
059    import com.liferay.portlet.blogs.util.BlogsUtil;
060    import com.liferay.portlet.blogs.util.LinkbackProducerUtil;
061    import com.liferay.portlet.blogs.util.comparator.EntryDisplayDateComparator;
062    
063    import java.io.IOException;
064    import java.io.InputStream;
065    
066    import java.util.Date;
067    import java.util.HashMap;
068    import java.util.HashSet;
069    import java.util.List;
070    import java.util.Locale;
071    import java.util.Map;
072    import java.util.Set;
073    
074    import javax.portlet.PortletPreferences;
075    
076    import net.htmlparser.jericho.Source;
077    import net.htmlparser.jericho.StartTag;
078    
079    /**
080     * @author Brian Wing Shun Chan
081     * @author Wilson S. Man
082     * @author Raymond Augé
083     * @author Thiago Moreira
084     * @author Juan Fernández
085     * @author Zsolt Berentey
086     */
087    public class BlogsEntryLocalServiceImpl extends BlogsEntryLocalServiceBaseImpl {
088    
089            public BlogsEntry addEntry(
090                            long userId, String title, String description, String content,
091                            int displayDateMonth, int displayDateDay, int displayDateYear,
092                            int displayDateHour, int displayDateMinute, boolean allowPingbacks,
093                            boolean allowTrackbacks, String[] trackbacks, boolean smallImage,
094                            String smallImageURL, String smallImageFileName,
095                            InputStream smallImageInputStream, ServiceContext serviceContext)
096                    throws PortalException, SystemException {
097    
098                    // Entry
099    
100                    User user = userPersistence.findByPrimaryKey(userId);
101                    long groupId = serviceContext.getScopeGroupId();
102    
103                    Date displayDate = PortalUtil.getDate(
104                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
105                            displayDateMinute, user.getTimeZone(),
106                            new EntryDisplayDateException());
107    
108                    byte[] smallImageBytes = null;
109    
110                    try {
111                            if ((smallImageInputStream != null) && smallImage) {
112                                    smallImageBytes = FileUtil.getBytes(smallImageInputStream);
113                            }
114                    }
115                    catch (IOException ioe) {
116                    }
117    
118                    Date now = new Date();
119    
120                    validate(
121                            title, content, smallImage, smallImageURL, smallImageFileName,
122                            smallImageBytes);
123    
124                    long entryId = counterLocalService.increment();
125    
126                    BlogsEntry entry = blogsEntryPersistence.create(entryId);
127    
128                    entry.setUuid(serviceContext.getUuid());
129                    entry.setGroupId(groupId);
130                    entry.setCompanyId(user.getCompanyId());
131                    entry.setUserId(user.getUserId());
132                    entry.setUserName(user.getFullName());
133                    entry.setCreateDate(serviceContext.getCreateDate(now));
134                    entry.setModifiedDate(serviceContext.getModifiedDate(now));
135                    entry.setTitle(title);
136                    entry.setUrlTitle(getUniqueUrlTitle(entryId, groupId, title));
137                    entry.setDescription(description);
138                    entry.setContent(content);
139                    entry.setDisplayDate(displayDate);
140                    entry.setAllowPingbacks(allowPingbacks);
141                    entry.setAllowTrackbacks(allowTrackbacks);
142                    entry.setSmallImage(smallImage);
143                    entry.setSmallImageId(counterLocalService.increment());
144                    entry.setSmallImageURL(smallImageURL);
145                    entry.setStatus(WorkflowConstants.STATUS_DRAFT);
146                    entry.setStatusDate(serviceContext.getModifiedDate(now));
147                    entry.setExpandoBridgeAttributes(serviceContext);
148    
149                    blogsEntryPersistence.update(entry, false);
150    
151                    // Resources
152    
153                    if (serviceContext.getAddGroupPermissions() ||
154                            serviceContext.getAddGuestPermissions()) {
155    
156                            addEntryResources(
157                                    entry, serviceContext.getAddGroupPermissions(),
158                                    serviceContext.getAddGuestPermissions());
159                    }
160                    else {
161                            addEntryResources(
162                                    entry, serviceContext.getGroupPermissions(),
163                                    serviceContext.getGuestPermissions());
164                    }
165    
166                    // Small image
167    
168                    saveImages(
169                            smallImage, entry.getSmallImageId(), smallImageBytes);
170    
171                    // Asset
172    
173                    updateAsset(
174                            userId, entry, serviceContext.getAssetCategoryIds(),
175                            serviceContext.getAssetTagNames(),
176                            serviceContext.getAssetLinkEntryIds());
177    
178                    // Message boards
179    
180                    if (PropsValues.BLOGS_ENTRY_COMMENTS_ENABLED) {
181                            mbMessageLocalService.addDiscussionMessage(
182                                    userId, entry.getUserName(), groupId,
183                                    BlogsEntry.class.getName(), entryId,
184                                    WorkflowConstants.ACTION_PUBLISH);
185                    }
186    
187                    // Workflow
188    
189                    if ((trackbacks != null) && (trackbacks.length > 0)) {
190                            serviceContext.setAttribute("trackbacks", trackbacks);
191                    }
192                    else {
193                            serviceContext.setAttribute("trackbacks", null);
194                    }
195    
196                    WorkflowHandlerRegistryUtil.startWorkflowInstance(
197                            user.getCompanyId(), groupId, userId, BlogsEntry.class.getName(),
198                            entry.getEntryId(), entry, serviceContext);
199    
200                    return entry;
201            }
202    
203            public void addEntryResources(
204                            BlogsEntry entry, boolean addGroupPermissions,
205                            boolean addGuestPermissions)
206                    throws PortalException, SystemException {
207    
208                    resourceLocalService.addResources(
209                            entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
210                            BlogsEntry.class.getName(), entry.getEntryId(), false,
211                            addGroupPermissions, addGuestPermissions);
212            }
213    
214            public void addEntryResources(
215                            BlogsEntry entry, String[] groupPermissions,
216                            String[] guestPermissions)
217                    throws PortalException, SystemException {
218    
219                    resourceLocalService.addModelResources(
220                            entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
221                            BlogsEntry.class.getName(), entry.getEntryId(), groupPermissions,
222                            guestPermissions);
223            }
224    
225            public void addEntryResources(
226                            long entryId, boolean addGroupPermissions,
227                            boolean addGuestPermissions)
228                    throws PortalException, SystemException {
229    
230                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
231    
232                    addEntryResources(entry, addGroupPermissions, addGuestPermissions);
233            }
234    
235            public void addEntryResources(
236                            long entryId, String[] groupPermissions, String[] guestPermissions)
237                    throws PortalException, SystemException {
238    
239                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
240    
241                    addEntryResources(entry, groupPermissions, guestPermissions);
242            }
243    
244            public void deleteEntries(long groupId)
245                    throws PortalException, SystemException {
246    
247                    for (BlogsEntry entry : blogsEntryPersistence.findByGroupId(groupId)) {
248                            deleteEntry(entry);
249                    }
250            }
251    
252            public void deleteEntry(BlogsEntry entry)
253                    throws PortalException, SystemException {
254    
255                    // Entry
256    
257                    blogsEntryPersistence.remove(entry);
258    
259                    // Resources
260    
261                    resourceLocalService.deleteResource(
262                            entry.getCompanyId(), BlogsEntry.class.getName(),
263                            ResourceConstants.SCOPE_INDIVIDUAL, entry.getEntryId());
264    
265                    // Image
266    
267                    imageLocalService.deleteImage(entry.getSmallImageId());
268    
269                    // Statistics
270    
271                    blogsStatsUserLocalService.updateStatsUser(
272                            entry.getGroupId(), entry.getUserId());
273    
274                    // Asset
275    
276                    assetEntryLocalService.deleteEntry(
277                            BlogsEntry.class.getName(), entry.getEntryId());
278    
279                    // Expando
280    
281                    expandoValueLocalService.deleteValues(
282                            BlogsEntry.class.getName(), entry.getEntryId());
283    
284                    // Message boards
285    
286                    mbMessageLocalService.deleteDiscussionMessages(
287                            BlogsEntry.class.getName(), entry.getEntryId());
288    
289                    // Ratings
290    
291                    ratingsStatsLocalService.deleteStats(
292                            BlogsEntry.class.getName(), entry.getEntryId());
293    
294                    // Indexer
295    
296                    Indexer indexer = IndexerRegistryUtil.getIndexer(BlogsEntry.class);
297    
298                    indexer.delete(entry);
299    
300                    // Workflow
301    
302                    workflowInstanceLinkLocalService.deleteWorkflowInstanceLinks(
303                            entry.getCompanyId(), entry.getGroupId(),
304                            BlogsEntry.class.getName(), entry.getEntryId());
305            }
306    
307            public void deleteEntry(long entryId)
308                    throws PortalException, SystemException {
309    
310                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
311    
312                    deleteEntry(entry);
313            }
314    
315            public List<BlogsEntry> getCompanyEntries(
316                            long companyId, int status, int start, int end)
317                    throws SystemException {
318    
319                    if (status == WorkflowConstants.STATUS_ANY) {
320                            return blogsEntryPersistence.findByC_LtD(
321                                    companyId, new Date(), start, end);
322                    }
323                    else {
324                            return blogsEntryPersistence.findByC_LtD_S(
325                                    companyId, new Date(), status, start, end);
326                    }
327            }
328    
329            public List<BlogsEntry> getCompanyEntries(
330                            long companyId, int status, int start, int end,
331                            OrderByComparator obc)
332                    throws SystemException {
333    
334                    if (status == WorkflowConstants.STATUS_ANY) {
335                            return blogsEntryPersistence.findByC_LtD(
336                                    companyId, new Date(), start, end, obc);
337                    }
338                    else {
339                            return blogsEntryPersistence.findByC_LtD_S(
340                                    companyId, new Date(), status, start, end, obc);
341                    }
342            }
343    
344            public int getCompanyEntriesCount(long companyId, int status)
345                    throws SystemException {
346    
347                    if (status == WorkflowConstants.STATUS_ANY) {
348                            return blogsEntryPersistence.countByC_LtD(
349                                    companyId, new Date());
350                    }
351                    else {
352                            return blogsEntryPersistence.countByC_LtD_S(
353                                    companyId, new Date(), status);
354                    }
355            }
356    
357            public BlogsEntry[] getEntriesPrevAndNext(long entryId)
358                    throws PortalException, SystemException {
359    
360                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
361    
362                    return blogsEntryPersistence.findByG_S_PrevAndNext(
363                            entry.getEntryId(), entry.getGroupId(),
364                            WorkflowConstants.STATUS_APPROVED,
365                            new EntryDisplayDateComparator(true));
366            }
367    
368            public BlogsEntry getEntry(long entryId)
369                    throws PortalException, SystemException {
370    
371                    return blogsEntryPersistence.findByPrimaryKey(entryId);
372            }
373    
374            public BlogsEntry getEntry(long groupId, String urlTitle)
375                    throws PortalException, SystemException {
376    
377                    return blogsEntryPersistence.findByG_UT(groupId, urlTitle);
378            }
379    
380            public List<BlogsEntry> getGroupEntries(
381                            long groupId, int status, int start, int end)
382                    throws SystemException {
383    
384                    if (status == WorkflowConstants.STATUS_ANY) {
385                            return blogsEntryPersistence.findByG_LtD(
386                                    groupId, new Date(), start, end);
387                    }
388                    else {
389                            return blogsEntryPersistence.findByG_LtD_S(
390                                    groupId, new Date(), status, start, end);
391                    }
392            }
393    
394            public List<BlogsEntry> getGroupEntries(
395                            long groupId, int status, int start, int end, OrderByComparator obc)
396                    throws SystemException {
397    
398                    if (status == WorkflowConstants.STATUS_ANY) {
399                            return blogsEntryPersistence.findByG_LtD(
400                                    groupId, new Date(), start, end, obc);
401                    }
402                    else {
403                            return blogsEntryPersistence.findByG_LtD_S(
404                                    groupId, new Date(), status, start, end, obc);
405                    }
406            }
407    
408            public int getGroupEntriesCount(long groupId, int status)
409                    throws SystemException {
410    
411                    if (status == WorkflowConstants.STATUS_ANY) {
412                            return blogsEntryPersistence.countByG_LtD(groupId, new Date());
413                    }
414                    else {
415                            return blogsEntryPersistence.countByG_LtD_S(
416                                    groupId, new Date(), status);
417                    }
418            }
419    
420            public List<BlogsEntry> getGroupsEntries(
421                            long companyId, long groupId, int status, int start, int end)
422                    throws SystemException {
423    
424                    return blogsEntryFinder.findByGroupIds(
425                            companyId, groupId, status, start, end);
426            }
427    
428            public List<BlogsEntry> getGroupUserEntries(
429                            long groupId, long userId, int status, int start, int end)
430                    throws SystemException {
431    
432                    if (status == WorkflowConstants.STATUS_ANY) {
433                            return blogsEntryPersistence.findByG_U_LtD(
434                                    groupId, userId, new Date(), start, end);
435                    }
436                    else {
437                            return blogsEntryPersistence.findByG_U_LtD_S(
438                                    groupId, userId, new Date(), status, start, end);
439                    }
440            }
441    
442            public List<BlogsEntry> getGroupUserEntries(
443                            long groupId, long userId, int status, int start, int end,
444                            OrderByComparator obc)
445                    throws SystemException {
446    
447                    if (status == WorkflowConstants.STATUS_ANY) {
448                            return blogsEntryPersistence.findByG_U_LtD(
449                                    groupId, userId, new Date(), start, end, obc);
450                    }
451                    else {
452                            return blogsEntryPersistence.findByG_U_LtD_S(
453                                    groupId, userId, new Date(), status, start, end, obc);
454                    }
455            }
456    
457            public int getGroupUserEntriesCount(long groupId, long userId, int status)
458                    throws SystemException {
459    
460                    if (status == WorkflowConstants.STATUS_ANY) {
461                            return blogsEntryPersistence.countByG_U_LtD(
462                                    groupId, userId, new Date());
463                    }
464                    else {
465                            return blogsEntryPersistence.countByG_U_LtD_S(
466                                    groupId, userId, new Date(), status);
467                    }
468            }
469    
470            public List<BlogsEntry> getNoAssetEntries() throws SystemException {
471                    return blogsEntryFinder.findByNoAssets();
472            }
473    
474            public List<BlogsEntry> getOrganizationEntries(
475                            long organizationId, int status, int start, int end)
476                    throws SystemException {
477    
478                    return blogsEntryFinder.findByOrganizationId(
479                            organizationId, new Date(), status, start, end);
480            }
481    
482            public int getOrganizationEntriesCount(long organizationId, int status)
483                    throws SystemException {
484    
485                    return blogsEntryFinder.countByOrganizationId(
486                            organizationId, new Date(), status);
487            }
488    
489            public void subscribe(long userId, long groupId)
490                    throws PortalException, SystemException {
491    
492                    subscriptionLocalService.addSubscription(
493                            userId, groupId, BlogsEntry.class.getName(), groupId);
494            }
495    
496            public void unsubscribe(long userId, long groupId)
497                    throws PortalException, SystemException {
498    
499                    subscriptionLocalService.deleteSubscription(
500                            userId, BlogsEntry.class.getName(), groupId);
501            }
502    
503            public void updateAsset(
504                            long userId, BlogsEntry entry, long[] assetCategoryIds,
505                            String[] assetTagNames, long[] assetLinkEntryIds)
506                    throws PortalException, SystemException {
507    
508                    boolean visible = false;
509    
510                    if (entry.isApproved()) {
511                            visible = true;
512                    }
513    
514                    String summary = HtmlUtil.extractText(
515                            StringUtil.shorten(entry.getContent(), 500));
516    
517                    AssetEntry assetEntry = assetEntryLocalService.updateEntry(
518                            userId, entry.getGroupId(), BlogsEntry.class.getName(),
519                            entry.getEntryId(), entry.getUuid(), 0, assetCategoryIds,
520                            assetTagNames, visible, null, null, entry.getDisplayDate(), null,
521                            ContentTypes.TEXT_HTML, entry.getTitle(), null, summary, null, null,
522                            0, 0, null, false);
523    
524                    assetLinkLocalService.updateLinks(
525                            userId, assetEntry.getEntryId(), assetLinkEntryIds,
526                            AssetLinkConstants.TYPE_RELATED);
527            }
528    
529            public BlogsEntry updateEntry(
530                            long userId, long entryId, String title, String description,
531                            String content, int displayDateMonth, int displayDateDay,
532                            int displayDateYear, int displayDateHour, int displayDateMinute,
533                            boolean allowPingbacks, boolean allowTrackbacks,
534                            String[] trackbacks, boolean smallImage, String smallImageURL,
535                            String smallImageFileName, InputStream smallImageInputStream,
536                            ServiceContext serviceContext)
537                    throws PortalException, SystemException {
538    
539                    // Entry
540    
541                    User user = userPersistence.findByPrimaryKey(userId);
542    
543                    Date displayDate = PortalUtil.getDate(
544                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
545                            displayDateMinute, user.getTimeZone(),
546                            new EntryDisplayDateException());
547    
548                    byte[] smallImageBytes = null;
549    
550                    try {
551                            if ((smallImageInputStream != null) && smallImage) {
552                                    smallImageBytes = FileUtil.getBytes(smallImageInputStream);
553                            }
554                    }
555                    catch (IOException ioe) {
556                    }
557    
558                    validate(
559                            title, content, smallImage, smallImageURL, smallImageFileName,
560                            smallImageBytes);
561    
562                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
563    
564                    String oldUrlTitle = entry.getUrlTitle();
565    
566                    entry.setModifiedDate(serviceContext.getModifiedDate(null));
567                    entry.setTitle(title);
568                    entry.setUrlTitle(
569                            getUniqueUrlTitle(entryId, entry.getGroupId(), title));
570                    entry.setDescription(description);
571                    entry.setContent(content);
572                    entry.setDisplayDate(displayDate);
573                    entry.setAllowPingbacks(allowPingbacks);
574                    entry.setAllowTrackbacks(allowTrackbacks);
575                    entry.setSmallImage(smallImage);
576    
577                    if (entry.getSmallImageId() == 0) {
578                            entry.setSmallImageId(counterLocalService.increment());
579                    }
580    
581                    entry.setSmallImageURL(smallImageURL);
582    
583                    if (!entry.isPending()) {
584                            entry.setStatus(WorkflowConstants.STATUS_DRAFT);
585                    }
586    
587                    entry.setExpandoBridgeAttributes(serviceContext);
588    
589                    blogsEntryPersistence.update(entry, false);
590    
591                    // Resources
592    
593                    if ((serviceContext.getGroupPermissions() != null) ||
594                            (serviceContext.getGuestPermissions() != null)) {
595    
596                            updateEntryResources(
597                                    entry, serviceContext.getGroupPermissions(),
598                                    serviceContext.getGuestPermissions());
599                    }
600    
601                    // Small image
602    
603                    saveImages(
604                            smallImage, entry.getSmallImageId(), smallImageBytes);
605    
606                    // Asset
607    
608                    updateAsset(
609                            userId, entry, serviceContext.getAssetCategoryIds(),
610                            serviceContext.getAssetTagNames(),
611                            serviceContext.getAssetLinkEntryIds());
612    
613                    // Workflow
614    
615                    boolean pingOldTrackbacks = false;
616    
617                    if (!oldUrlTitle.equals(entry.getUrlTitle())) {
618                            pingOldTrackbacks = true;
619                    }
620    
621                    serviceContext.setAttribute(
622                            "pingOldTrackbacks", String.valueOf(pingOldTrackbacks));
623    
624                    if (Validator.isNotNull(trackbacks)) {
625                            serviceContext.setAttribute("trackbacks", trackbacks);
626                    }
627                    else {
628                            serviceContext.setAttribute("trackbacks", null);
629                    }
630    
631                    WorkflowHandlerRegistryUtil.startWorkflowInstance(
632                            user.getCompanyId(), entry.getGroupId(), userId,
633                            BlogsEntry.class.getName(), entry.getEntryId(), entry,
634                            serviceContext);
635    
636                    return entry;
637            }
638    
639            public void updateEntryResources(
640                            BlogsEntry entry, String[] groupPermissions,
641                            String[] guestPermissions)
642                    throws PortalException, SystemException {
643    
644                    resourceLocalService.updateResources(
645                            entry.getCompanyId(), entry.getGroupId(),
646                            BlogsEntry.class.getName(), entry.getEntryId(), groupPermissions,
647                            guestPermissions);
648            }
649    
650            public BlogsEntry updateStatus(
651                            long userId, long entryId, int status,
652                            ServiceContext serviceContext)
653                    throws PortalException, SystemException {
654    
655                    // Entry
656    
657                    User user = userPersistence.findByPrimaryKey(userId);
658                    Date now = new Date();
659    
660                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
661    
662                    int oldStatus = entry.getStatus();
663                    long oldStatusByUserId = entry.getStatusByUserId();
664    
665                    entry.setModifiedDate(serviceContext.getModifiedDate(now));
666                    entry.setStatus(status);
667                    entry.setStatusByUserId(user.getUserId());
668                    entry.setStatusByUserName(user.getFullName());
669                    entry.setStatusDate(serviceContext.getModifiedDate(now));
670    
671                    blogsEntryPersistence.update(entry, false);
672    
673                    Indexer indexer = IndexerRegistryUtil.getIndexer(BlogsEntry.class);
674    
675                    if (status == WorkflowConstants.STATUS_APPROVED) {
676    
677                            // Statistics
678    
679                            blogsStatsUserLocalService.updateStatsUser(
680                                    entry.getGroupId(), entry.getUserId(), entry.getDisplayDate());
681    
682                            if (oldStatus != WorkflowConstants.STATUS_APPROVED) {
683    
684                                    // Asset
685    
686                                    assetEntryLocalService.updateVisible(
687                                            BlogsEntry.class.getName(), entryId, true);
688    
689                                    // Social
690    
691                                    if (oldStatusByUserId == 0) {
692                                            socialActivityLocalService.addUniqueActivity(
693                                                    entry.getUserId(), entry.getGroupId(),
694                                                    BlogsEntry.class.getName(), entryId,
695                                                    BlogsActivityKeys.ADD_ENTRY, StringPool.BLANK, 0);
696                                    }
697                                    else {
698                                            socialActivityLocalService.addActivity(
699                                                    entry.getUserId(), entry.getGroupId(),
700                                                    BlogsEntry.class.getName(), entryId,
701                                                    BlogsActivityKeys.UPDATE_ENTRY, StringPool.BLANK, 0);
702                                    }
703                            }
704    
705                            // Indexer
706    
707                            indexer.reindex(entry);
708    
709                            // Subscriptions
710    
711                            notifySubscribers(entry, serviceContext);
712    
713                            // Ping
714    
715                            String[] trackbacks = (String[])serviceContext.getAttribute(
716                                    "trackbacks");
717                            Boolean pingOldTrackbacks = GetterUtil.getBoolean(
718                                    (String)serviceContext.getAttribute("pingOldTrackbacks"));
719    
720                            pingGoogle(entry, serviceContext);
721                            pingPingback(entry, serviceContext);
722                            pingTrackbacks(
723                                    entry, trackbacks, pingOldTrackbacks, serviceContext);
724                    }
725                    else if (status != WorkflowConstants.STATUS_APPROVED) {
726    
727                            // Asset
728    
729                            assetEntryLocalService.updateVisible(
730                                    BlogsEntry.class.getName(), entryId, false);
731    
732                            // Indexer
733    
734                            indexer.delete(entry);
735                    }
736    
737                    return entry;
738            }
739    
740            protected String getUniqueUrlTitle(
741                            long entryId, long groupId, String title)
742                    throws SystemException {
743    
744                    String urlTitle = BlogsUtil.getUrlTitle(entryId, title);
745    
746                    String newUrlTitle = ModelHintsUtil.trimString(
747                            BlogsEntry.class.getName(), "urlTitle", urlTitle);
748    
749                    for (int i = 1;; i++) {
750                            BlogsEntry entry = blogsEntryPersistence.fetchByG_UT(
751                                    groupId, newUrlTitle);
752    
753                            if ((entry == null) || (entry.getEntryId() == entryId)) {
754                                    break;
755                            }
756                            else {
757                                    String suffix = StringPool.DASH + i;
758    
759                                    String prefix = newUrlTitle;
760    
761                                    if (newUrlTitle.length() > suffix.length()) {
762                                            prefix = newUrlTitle.substring(
763                                                    0, newUrlTitle.length() - suffix.length());
764                                    }
765    
766                                    newUrlTitle = prefix + suffix;
767                            }
768                    }
769    
770                    return newUrlTitle;
771            }
772    
773            protected void notifySubscribers(
774                            BlogsEntry entry, ServiceContext serviceContext)
775                    throws SystemException {
776    
777                    if (!entry.isApproved()) {
778                            return;
779                    }
780    
781                    String layoutFullURL = serviceContext.getLayoutFullURL();
782    
783                    if (Validator.isNull(layoutFullURL)) {
784                            return;
785                    }
786    
787                    PortletPreferences preferences =
788                            ServiceContextUtil.getPortletPreferences(serviceContext);
789    
790                    if (preferences == null) {
791                            long ownerId = entry.getGroupId();
792                            int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
793                            long plid = PortletKeys.PREFS_PLID_SHARED;
794                            String portletId = PortletKeys.BLOGS;
795                            String defaultPreferences = null;
796    
797                            preferences = portletPreferencesLocalService.getPreferences(
798                                    entry.getCompanyId(), ownerId, ownerType, plid, portletId,
799                                    defaultPreferences);
800                    }
801    
802                    if (serviceContext.isCommandAdd() &&
803                            BlogsUtil.getEmailEntryAddedEnabled(preferences)) {
804                    }
805                    else if (serviceContext.isCommandUpdate() &&
806                                     BlogsUtil.getEmailEntryUpdatedEnabled(preferences)) {
807                    }
808                    else {
809                            return;
810                    }
811    
812                    String entryURL =
813                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs" +
814                                    StringPool.SLASH + entry.getEntryId();
815    
816                    String fromName = BlogsUtil.getEmailFromName(
817                            preferences, entry.getCompanyId());
818                    String fromAddress = BlogsUtil.getEmailFromAddress(
819                            preferences, entry.getCompanyId());
820    
821                    Map<Locale, String> localizedSubjectMap = null;
822                    Map<Locale, String> localizedBodyMap = null;
823    
824                    if (serviceContext.isCommandUpdate()) {
825                            localizedSubjectMap = BlogsUtil.getEmailEntryUpdatedSubjectMap(
826                                    preferences);
827                            localizedBodyMap = BlogsUtil.getEmailEntryUpdatedBodyMap(
828                                    preferences);
829                    }
830                    else {
831                            localizedSubjectMap = BlogsUtil.getEmailEntryAddedSubjectMap(
832                                    preferences);
833                            localizedBodyMap = BlogsUtil.getEmailEntryAddedBodyMap(
834                                    preferences);
835                    }
836    
837                    SubscriptionSender subscriptionSender = new SubscriptionSender();
838    
839                    subscriptionSender.setCompanyId(entry.getCompanyId());
840                    subscriptionSender.setContextAttributes(
841                            "[$BLOGS_ENTRY_URL$]", entryURL);
842                    subscriptionSender.setContextUserPrefix("BLOGS_ENTRY");
843                    subscriptionSender.setFrom(fromAddress, fromName);
844                    subscriptionSender.setHtmlFormat(true);
845                    subscriptionSender.setLocalizedBodyMap(localizedBodyMap);
846                    subscriptionSender.setLocalizedSubjectMap(localizedSubjectMap);
847                    subscriptionSender.setMailId("blogs_entry", entry.getEntryId());
848                    subscriptionSender.setPortletId(PortletKeys.BLOGS);
849                    subscriptionSender.setReplyToAddress(fromAddress);
850                    subscriptionSender.setScopeGroupId(entry.getGroupId());
851                    subscriptionSender.setUserId(entry.getUserId());
852    
853                    subscriptionSender.addPersistedSubscribers(
854                            BlogsEntry.class.getName(), entry.getGroupId());
855    
856                    subscriptionSender.flushNotificationsAsync();
857            }
858    
859            protected void pingGoogle(BlogsEntry entry, ServiceContext serviceContext)
860                    throws PortalException, SystemException {
861    
862                    if (!PropsValues.BLOGS_PING_GOOGLE_ENABLED || !entry.isApproved()) {
863                            return;
864                    }
865    
866                    String layoutFullURL = PortalUtil.getLayoutFullURL(
867                            serviceContext.getScopeGroupId(), PortletKeys.BLOGS);
868    
869                    if (Validator.isNull(layoutFullURL)) {
870                            return;
871                    }
872    
873                    if (layoutFullURL.contains("://localhost")) {
874                            if (_log.isDebugEnabled()) {
875                                    _log.debug(
876                                            "Not pinging Google because of localhost URL " +
877                                                    layoutFullURL);
878                            }
879    
880                            return;
881                    }
882    
883                    Group group = groupPersistence.findByPrimaryKey(entry.getGroupId());
884    
885                    StringBundler sb = new StringBundler(6);
886    
887                    String name = group.getDescriptiveName();
888                    String url = layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs";
889                    String changesURL =
890                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/rss";
891    
892                    sb.append("http://blogsearch.google.com/ping?name=");
893                    sb.append(HttpUtil.encodeURL(name));
894                    sb.append("&url=");
895                    sb.append(HttpUtil.encodeURL(url));
896                    sb.append("&changesURL=");
897                    sb.append(HttpUtil.encodeURL(changesURL));
898    
899                    String location = sb.toString();
900    
901                    if (_log.isInfoEnabled()) {
902                            _log.info("Pinging Google at " + location);
903                    }
904    
905                    try {
906                            String response = HttpUtil.URLtoString(sb.toString());
907    
908                            if (_log.isInfoEnabled()) {
909                                    _log.info("Google ping response: " + response);
910                            }
911                    }
912                    catch (IOException ioe) {
913                            _log.error("Unable to ping Google at " + location, ioe);
914                    }
915            }
916    
917            protected void pingPingback(
918                    BlogsEntry entry, ServiceContext serviceContext) {
919    
920                    if (!PropsValues.BLOGS_PINGBACK_ENABLED ||
921                            !entry.isAllowPingbacks() || !entry.isApproved()) {
922    
923                            return;
924                    }
925    
926                    String layoutFullURL = serviceContext.getLayoutFullURL();
927    
928                    if (Validator.isNull(layoutFullURL)) {
929                            return;
930                    }
931    
932                    String sourceUri =
933                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/" +
934                                    entry.getUrlTitle();
935    
936                    Source source = new Source(entry.getContent());
937    
938                    List<StartTag> tags = source.getAllStartTags("a");
939    
940                    for (StartTag tag : tags) {
941                            String targetUri = tag.getAttributeValue("href");
942    
943                            if (Validator.isNotNull(targetUri)) {
944                                    try {
945                                            LinkbackProducerUtil.sendPingback(sourceUri, targetUri);
946                                    }
947                                    catch (Exception e) {
948                                            _log.error("Error while sending pingback " + targetUri, e);
949                                    }
950                            }
951                    }
952            }
953    
954            protected void pingTrackbacks(
955                            BlogsEntry entry, String[] trackbacks, boolean pingOldTrackbacks,
956                            ServiceContext serviceContext)
957                    throws SystemException {
958    
959                    if (!PropsValues.BLOGS_TRACKBACK_ENABLED ||
960                            !entry.isAllowTrackbacks() || !entry.isApproved()) {
961    
962                            return;
963                    }
964    
965                    String layoutFullURL = serviceContext.getLayoutFullURL();
966    
967                    if (Validator.isNull(layoutFullURL)) {
968                            return;
969                    }
970    
971                    Map<String, String> parts = new HashMap<String, String>();
972    
973                    String excerpt = StringUtil.shorten(
974                            HtmlUtil.extractText(entry.getContent()),
975                            PropsValues.BLOGS_LINKBACK_EXCERPT_LENGTH);
976                    String url =
977                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/" +
978                                    entry.getUrlTitle();
979    
980                    parts.put("title", entry.getTitle());
981                    parts.put("excerpt", excerpt);
982                    parts.put("url", url);
983                    parts.put("blog_name", entry.getUserName());
984    
985                    Set<String> trackbacksSet = null;
986    
987                    if (Validator.isNotNull(trackbacks)) {
988                            trackbacksSet = SetUtil.fromArray(trackbacks);
989                    }
990                    else {
991                            trackbacksSet = new HashSet<String>();
992                    }
993    
994                    if (pingOldTrackbacks) {
995                            trackbacksSet.addAll(
996                                    SetUtil.fromArray(StringUtil.split(entry.getTrackbacks())));
997    
998                            entry.setTrackbacks(StringPool.BLANK);
999    
1000                            blogsEntryPersistence.update(entry, false);
1001                    }
1002    
1003                    Set<String> oldTrackbacks = SetUtil.fromArray(
1004                            StringUtil.split(entry.getTrackbacks()));
1005    
1006                    Set<String> validTrackbacks = new HashSet<String>();
1007    
1008                    for (String trackback : trackbacksSet) {
1009                            if (oldTrackbacks.contains(trackback)) {
1010                                    continue;
1011                            }
1012    
1013                            try {
1014                                    if (LinkbackProducerUtil.sendTrackback(trackback, parts)) {
1015                                            validTrackbacks.add(trackback);
1016                                    }
1017                            }
1018                            catch (Exception e) {
1019                                    _log.error("Error while sending trackback at " + trackback, e);
1020                            }
1021                    }
1022    
1023                    if (!validTrackbacks.isEmpty()) {
1024                            String newTrackbacks = StringUtil.merge(validTrackbacks);
1025    
1026                            if (Validator.isNotNull(entry.getTrackbacks())) {
1027                                    newTrackbacks += StringPool.COMMA + entry.getTrackbacks();
1028                            }
1029    
1030                            entry.setTrackbacks(newTrackbacks);
1031    
1032                            blogsEntryPersistence.update(entry, false);
1033                    }
1034            }
1035    
1036            protected void saveImages(
1037                            boolean smallImage, long smallImageId, byte[] smallImageBytes)
1038                    throws PortalException, SystemException {
1039    
1040                    if (smallImage) {
1041                            if (smallImageBytes != null) {
1042                                    imageLocalService.updateImage(smallImageId, smallImageBytes);
1043                            }
1044                    }
1045                    else {
1046                            imageLocalService.deleteImage(smallImageId);
1047                    }
1048            }
1049    
1050            protected void validate(
1051                            String title, String content, boolean smallImage,
1052                            String smallImageURL, String smallImageFileName,
1053                            byte[] smallImageBytes)
1054                    throws PortalException, SystemException {
1055    
1056                    if (Validator.isNull(title)) {
1057                            throw new EntryTitleException();
1058                    }
1059                    else if (Validator.isNull(content)) {
1060                            throw new EntryContentException();
1061                    }
1062    
1063                    String[] imageExtensions = PrefsPropsUtil.getStringArray(
1064                            PropsKeys.BLOGS_IMAGE_EXTENSIONS, StringPool.COMMA);
1065    
1066                    if (smallImage && Validator.isNull(smallImageURL) &&
1067                            (smallImageBytes != null)) {
1068    
1069                            if (smallImageFileName != null) {
1070                                    boolean validSmallImageExtension = false;
1071    
1072                                    for (String _imageExtension : imageExtensions) {
1073                                            if (StringPool.STAR.equals(_imageExtension) ||
1074                                                    StringUtil.endsWith(
1075                                                            smallImageFileName, _imageExtension)) {
1076    
1077                                                    validSmallImageExtension = true;
1078    
1079                                                    break;
1080                                            }
1081                                    }
1082    
1083                                    if (!validSmallImageExtension) {
1084                                            throw new EntrySmallImageNameException(smallImageFileName);
1085                                    }
1086                            }
1087    
1088                            long smallImageMaxSize = PrefsPropsUtil.getLong(
1089                                    PropsKeys.BLOGS_IMAGE_SMALL_MAX_SIZE);
1090    
1091                            if ((smallImageMaxSize > 0) &&
1092                                    ((smallImageBytes == null) ||
1093                                     (smallImageBytes.length > smallImageMaxSize))) {
1094    
1095                                    throw new EntrySmallImageSizeException();
1096                            }
1097                    }
1098            }
1099    
1100            private static Log _log = LogFactoryUtil.getLog(
1101                    BlogsEntryLocalServiceImpl.class);
1102    
1103    }