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