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