001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.blogs.service.impl;
016    
017    import com.liferay.portal.kernel.dao.orm.QueryDefinition;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.repository.model.FileEntry;
021    import com.liferay.portal.kernel.servlet.taglib.ui.ImageSelector;
022    import com.liferay.portal.kernel.util.HtmlUtil;
023    import com.liferay.portal.kernel.util.MimeTypesUtil;
024    import com.liferay.portal.kernel.util.StringBundler;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.kernel.util.StringUtil;
027    import com.liferay.portal.kernel.util.TempFileEntryUtil;
028    import com.liferay.portal.kernel.util.Validator;
029    import com.liferay.portal.kernel.workflow.WorkflowConstants;
030    import com.liferay.portal.model.Company;
031    import com.liferay.portal.model.Group;
032    import com.liferay.portal.model.Organization;
033    import com.liferay.portal.security.permission.ActionKeys;
034    import com.liferay.portal.service.ServiceContext;
035    import com.liferay.portal.theme.ThemeDisplay;
036    import com.liferay.portal.util.PortalUtil;
037    import com.liferay.portal.util.PropsValues;
038    import com.liferay.portlet.blogs.model.BlogsEntry;
039    import com.liferay.portlet.blogs.service.base.BlogsEntryServiceBaseImpl;
040    import com.liferay.portlet.blogs.service.permission.BlogsEntryPermission;
041    import com.liferay.portlet.blogs.service.permission.BlogsPermission;
042    import com.liferay.portlet.blogs.util.comparator.EntryDisplayDateComparator;
043    import com.liferay.util.RSSUtil;
044    
045    import com.sun.syndication.feed.synd.SyndContent;
046    import com.sun.syndication.feed.synd.SyndContentImpl;
047    import com.sun.syndication.feed.synd.SyndEntry;
048    import com.sun.syndication.feed.synd.SyndEntryImpl;
049    import com.sun.syndication.feed.synd.SyndFeed;
050    import com.sun.syndication.feed.synd.SyndFeedImpl;
051    import com.sun.syndication.feed.synd.SyndLink;
052    import com.sun.syndication.feed.synd.SyndLinkImpl;
053    import com.sun.syndication.io.FeedException;
054    
055    import java.io.InputStream;
056    
057    import java.util.ArrayList;
058    import java.util.Date;
059    import java.util.List;
060    
061    /**
062     * Provides the remote service for accessing, adding, deleting, subscription
063     * handling of, trash handling of, and updating blog entries. Its methods
064     * include permission checks.
065     *
066     * @author Brian Wing Shun Chan
067     * @author Mate Thurzo
068     */
069    public class BlogsEntryServiceImpl extends BlogsEntryServiceBaseImpl {
070    
071            /**
072             * @deprecated As of 7.0.0, replaced by {@link #addEntry(String, String,
073             *             String, String, int, int, int, int, int, boolean, boolean,
074             *             String[], boolean, String, String, InputStream,
075             *             ServiceContext)}
076             */
077            @Deprecated
078            @Override
079            public BlogsEntry addEntry(
080                            String title, String description, String content,
081                            int displayDateMonth, int displayDateDay, int displayDateYear,
082                            int displayDateHour, int displayDateMinute, boolean allowPingbacks,
083                            boolean allowTrackbacks, String[] trackbacks, boolean smallImage,
084                            String smallImageURL, String smallImageFileName,
085                            InputStream smallImageInputStream, ServiceContext serviceContext)
086                    throws PortalException {
087    
088                    BlogsPermission.check(
089                            getPermissionChecker(), serviceContext.getScopeGroupId(),
090                            ActionKeys.ADD_ENTRY);
091    
092                    ImageSelector imageSelector = null;
093    
094                    if (smallImage && Validator.isNotNull(smallImageFileName) &&
095                            (smallImageInputStream != null)) {
096    
097                            FileEntry fileEntry = TempFileEntryUtil.addTempFileEntry(
098                                    serviceContext.getScopeGroupId(), getUserId(),
099                                    BlogsEntry.class.getName(), smallImageFileName,
100                                    smallImageInputStream,
101                                    MimeTypesUtil.getContentType(smallImageFileName));
102    
103                            imageSelector = new ImageSelector(
104                                    fileEntry.getFileEntryId(), smallImageURL);
105                    }
106    
107                    return addEntry(
108                            title, StringPool.BLANK, description, content, displayDateMonth,
109                            displayDateDay, displayDateYear, displayDateHour, displayDateMinute,
110                            allowPingbacks, allowTrackbacks, trackbacks, imageSelector,
111                            serviceContext);
112            }
113    
114            @Override
115            public BlogsEntry addEntry(
116                            String title, String subtitle, String description, String content,
117                            int displayDateMonth, int displayDateDay, int displayDateYear,
118                            int displayDateHour, int displayDateMinute, boolean allowPingbacks,
119                            boolean allowTrackbacks, String[] trackbacks,
120                            ImageSelector imageSelector, ServiceContext serviceContext)
121                    throws PortalException {
122    
123                    BlogsPermission.check(
124                            getPermissionChecker(), serviceContext.getScopeGroupId(),
125                            ActionKeys.ADD_ENTRY);
126    
127                    return blogsEntryLocalService.addEntry(
128                            getUserId(), title, subtitle, description, content,
129                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
130                            displayDateMinute, allowPingbacks, allowTrackbacks, trackbacks,
131                            imageSelector, serviceContext);
132            }
133    
134            @Override
135            public void deleteEntry(long entryId) throws PortalException {
136                    BlogsEntryPermission.check(
137                            getPermissionChecker(), entryId, ActionKeys.DELETE);
138    
139                    blogsEntryLocalService.deleteEntry(entryId);
140            }
141    
142            @Override
143            public List<BlogsEntry> getCompanyEntries(
144                            long companyId, Date displayDate, int status, int max)
145                    throws PortalException {
146    
147                    List<BlogsEntry> entries = new ArrayList<BlogsEntry>();
148    
149                    boolean listNotExhausted = true;
150    
151                    QueryDefinition<BlogsEntry> queryDefinition =
152                            new QueryDefinition<BlogsEntry>(
153                                    status, false, 0, 0, new EntryDisplayDateComparator());
154    
155                    if (status == WorkflowConstants.STATUS_ANY) {
156                            queryDefinition.setStatus(WorkflowConstants.STATUS_IN_TRASH, true);
157                    }
158    
159                    while ((entries.size() < max) && listNotExhausted) {
160                            queryDefinition.setEnd(queryDefinition.getStart() + max);
161    
162                            List<BlogsEntry> entryList =
163                                    blogsEntryLocalService.getCompanyEntries(
164                                            companyId, displayDate, queryDefinition);
165    
166                            queryDefinition.setStart(queryDefinition.getStart() + max);
167    
168                            listNotExhausted = (entryList.size() == max);
169    
170                            for (BlogsEntry entry : entryList) {
171                                    if (entries.size() >= max) {
172                                            break;
173                                    }
174    
175                                    if (BlogsEntryPermission.contains(
176                                                    getPermissionChecker(), entry, ActionKeys.VIEW)) {
177    
178                                            entries.add(entry);
179                                    }
180                            }
181                    }
182    
183                    return entries;
184            }
185    
186            @Override
187            public String getCompanyEntriesRSS(
188                            long companyId, Date displayDate, int status, int max, String type,
189                            double version, String displayStyle, String feedURL,
190                            String entryURL, ThemeDisplay themeDisplay)
191                    throws PortalException {
192    
193                    Company company = companyPersistence.findByPrimaryKey(companyId);
194    
195                    String name = company.getName();
196                    List<BlogsEntry> blogsEntries = getCompanyEntries(
197                            companyId, displayDate, status, max);
198    
199                    return exportToRSS(
200                            name, name, type, version, displayStyle, feedURL, entryURL,
201                            blogsEntries, themeDisplay);
202            }
203    
204            @Override
205            public BlogsEntry getEntry(long entryId) throws PortalException {
206                    BlogsEntryPermission.check(
207                            getPermissionChecker(), entryId, ActionKeys.VIEW);
208    
209                    return blogsEntryLocalService.getEntry(entryId);
210            }
211    
212            @Override
213            public BlogsEntry getEntry(long groupId, String urlTitle)
214                    throws PortalException {
215    
216                    BlogsEntry entry = blogsEntryLocalService.getEntry(groupId, urlTitle);
217    
218                    BlogsEntryPermission.check(
219                            getPermissionChecker(), entry.getEntryId(), ActionKeys.VIEW);
220    
221                    return entry;
222            }
223    
224            @Override
225            public List<BlogsEntry> getGroupEntries(
226                    long groupId, Date displayDate, int status, int max) {
227    
228                    return getGroupEntries(groupId, displayDate, status, 0, max);
229            }
230    
231            @Override
232            public List<BlogsEntry> getGroupEntries(
233                    long groupId, Date displayDate, int status, int start, int end) {
234    
235                    if (status == WorkflowConstants.STATUS_ANY) {
236                            return blogsEntryPersistence.filterFindByG_LtD_NotS(
237                                    groupId, displayDate, WorkflowConstants.STATUS_IN_TRASH, start,
238                                    end);
239                    }
240                    else {
241                            return blogsEntryPersistence.filterFindByG_LtD_S(
242                                    groupId, displayDate, status, start, end);
243                    }
244            }
245    
246            @Override
247            public List<BlogsEntry> getGroupEntries(long groupId, int status, int max) {
248                    return getGroupEntries(groupId, status, 0, max);
249            }
250    
251            @Override
252            public List<BlogsEntry> getGroupEntries(
253                    long groupId, int status, int start, int end) {
254    
255                    if (status == WorkflowConstants.STATUS_ANY) {
256                            return blogsEntryPersistence.filterFindByG_NotS(
257                                    groupId, WorkflowConstants.STATUS_IN_TRASH, start, end);
258                    }
259                    else {
260                            return blogsEntryPersistence.filterFindByG_S(
261                                    groupId, status, start, end);
262                    }
263            }
264    
265            @Override
266            public int getGroupEntriesCount(
267                    long groupId, Date displayDate, int status) {
268    
269                    if (status == WorkflowConstants.STATUS_ANY) {
270                            return blogsEntryPersistence.filterCountByG_LtD_NotS(
271                                    groupId, displayDate, WorkflowConstants.STATUS_IN_TRASH);
272                    }
273                    else {
274                            return blogsEntryPersistence.filterCountByG_LtD_S(
275                                    groupId, displayDate, status);
276                    }
277            }
278    
279            @Override
280            public int getGroupEntriesCount(long groupId, int status) {
281                    if (status == WorkflowConstants.STATUS_ANY) {
282                            return blogsEntryPersistence.filterCountByG_NotS(
283                                    groupId, WorkflowConstants.STATUS_IN_TRASH);
284                    }
285                    else {
286                            return blogsEntryPersistence.filterCountByG_S(groupId, status);
287                    }
288            }
289    
290            @Override
291            public String getGroupEntriesRSS(
292                            long groupId, Date displayDate, int status, int max, String type,
293                            double version, String displayStyle, String feedURL,
294                            String entryURL, ThemeDisplay themeDisplay)
295                    throws PortalException {
296    
297                    Group group = groupPersistence.findByPrimaryKey(groupId);
298    
299                    String name = group.getDescriptiveName();
300                    List<BlogsEntry> blogsEntries = getGroupEntries(
301                            groupId, displayDate, status, max);
302    
303                    return exportToRSS(
304                            name, name, type, version, displayStyle, feedURL, entryURL,
305                            blogsEntries, themeDisplay);
306            }
307    
308            @Override
309            public List<BlogsEntry> getGroupsEntries(
310                            long companyId, long groupId, Date displayDate, int status, int max)
311                    throws PortalException {
312    
313                    List<BlogsEntry> entries = new ArrayList<BlogsEntry>();
314    
315                    boolean listNotExhausted = true;
316    
317                    QueryDefinition<BlogsEntry> queryDefinition =
318                            new QueryDefinition<BlogsEntry>(
319                                    status, false, 0, 0, new EntryDisplayDateComparator());
320    
321                    if (status == WorkflowConstants.STATUS_ANY) {
322                            queryDefinition.setStatus(WorkflowConstants.STATUS_IN_TRASH, true);
323                    }
324    
325                    while ((entries.size() < max) && listNotExhausted) {
326                            queryDefinition.setEnd(queryDefinition.getStart() + max);
327    
328                            List<BlogsEntry> entryList =
329                                    blogsEntryLocalService.getGroupsEntries(
330                                            companyId, groupId, displayDate, queryDefinition);
331    
332                            queryDefinition.setStart(queryDefinition.getStart() + max);
333    
334                            listNotExhausted = (entryList.size() == max);
335    
336                            for (BlogsEntry entry : entryList) {
337                                    if (entries.size() >= max) {
338                                            break;
339                                    }
340    
341                                    if (BlogsEntryPermission.contains(
342                                                    getPermissionChecker(), entry, ActionKeys.VIEW)) {
343    
344                                            entries.add(entry);
345                                    }
346                            }
347                    }
348    
349                    return entries;
350            }
351    
352            @Override
353            public List<BlogsEntry> getOrganizationEntries(
354                            long organizationId, Date displayDate, int status, int max)
355                    throws PortalException {
356    
357                    List<BlogsEntry> entries = new ArrayList<BlogsEntry>();
358    
359                    boolean listNotExhausted = true;
360    
361                    QueryDefinition<BlogsEntry> queryDefinition =
362                            new QueryDefinition<BlogsEntry>(
363                                    status, false, 0, 0, new EntryDisplayDateComparator());
364    
365                    if (status == WorkflowConstants.STATUS_ANY) {
366                            queryDefinition.setStatus(WorkflowConstants.STATUS_IN_TRASH, true);
367                    }
368    
369                    while ((entries.size() < max) && listNotExhausted) {
370                            queryDefinition.setEnd(queryDefinition.getStart() + max);
371    
372                            List<BlogsEntry> entryList = blogsEntryFinder.findByOrganizationId(
373                                    organizationId, displayDate, queryDefinition);
374    
375                            queryDefinition.setStart(queryDefinition.getStart() + max);
376    
377                            listNotExhausted = (entryList.size() == max);
378    
379                            for (BlogsEntry entry : entryList) {
380                                    if (entries.size() >= max) {
381                                            break;
382                                    }
383    
384                                    if (BlogsEntryPermission.contains(
385                                                    getPermissionChecker(), entry, ActionKeys.VIEW)) {
386    
387                                            entries.add(entry);
388                                    }
389                            }
390                    }
391    
392                    return entries;
393            }
394    
395            @Override
396            public String getOrganizationEntriesRSS(
397                            long organizationId, Date displayDate, int status, int max,
398                            String type, double version, String displayStyle, String feedURL,
399                            String entryURL, ThemeDisplay themeDisplay)
400                    throws PortalException {
401    
402                    Organization organization = organizationPersistence.findByPrimaryKey(
403                            organizationId);
404    
405                    String name = organization.getName();
406                    List<BlogsEntry> blogsEntries = getOrganizationEntries(
407                            organizationId, displayDate, status, max);
408    
409                    return exportToRSS(
410                            name, name, type, version, displayStyle, feedURL, entryURL,
411                            blogsEntries, themeDisplay);
412            }
413    
414            @Override
415            public BlogsEntry moveEntryToTrash(long entryId) throws PortalException {
416                    BlogsEntryPermission.check(
417                            getPermissionChecker(), entryId, ActionKeys.DELETE);
418    
419                    return blogsEntryLocalService.moveEntryToTrash(getUserId(), entryId);
420            }
421    
422            @Override
423            public void restoreEntryFromTrash(long entryId) throws PortalException {
424                    BlogsEntryPermission.check(
425                            getPermissionChecker(), entryId, ActionKeys.DELETE);
426    
427                    blogsEntryLocalService.restoreEntryFromTrash(getUserId(), entryId);
428            }
429    
430            @Override
431            public void subscribe(long groupId) throws PortalException {
432                    BlogsPermission.check(
433                            getPermissionChecker(), groupId, ActionKeys.SUBSCRIBE);
434    
435                    blogsEntryLocalService.subscribe(getUserId(), groupId);
436            }
437    
438            @Override
439            public void unsubscribe(long groupId) throws PortalException {
440                    BlogsPermission.check(
441                            getPermissionChecker(), groupId, ActionKeys.SUBSCRIBE);
442    
443                    blogsEntryLocalService.unsubscribe(getUserId(), groupId);
444            }
445    
446            /**
447             * @deprecated As of 7.0.0, replaced by {@link #updateEntry(long, String,
448             *             String, String, String, int, int, int, int, int, boolean,
449             *             boolean, String[], boolean, String, long, ServiceContext)}
450             */
451            @Deprecated
452            @Override
453            public BlogsEntry updateEntry(
454                            long entryId, String title, String description, String content,
455                            int displayDateMonth, int displayDateDay, int displayDateYear,
456                            int displayDateHour, int displayDateMinute, boolean allowPingbacks,
457                            boolean allowTrackbacks, String[] trackbacks, boolean smallImage,
458                            String smallImageURL, String smallImageFileName,
459                            InputStream smallImageInputStream, ServiceContext serviceContext)
460                    throws PortalException {
461    
462                    BlogsPermission.check(
463                            getPermissionChecker(), serviceContext.getScopeGroupId(),
464                            ActionKeys.UPDATE);
465    
466                    ImageSelector imageSelector = null;
467    
468                    if (smallImage) {
469                            if (Validator.isNotNull(smallImageFileName) &&
470                                    (smallImageInputStream != null)) {
471    
472                                    FileEntry fileEntry = TempFileEntryUtil.addTempFileEntry(
473                                            serviceContext.getScopeGroupId(), getUserId(),
474                                            BlogsEntry.class.getName(), smallImageFileName,
475                                            smallImageInputStream,
476                                            MimeTypesUtil.getContentType(smallImageFileName));
477    
478                                    imageSelector = new ImageSelector(
479                                            fileEntry.getFileEntryId(), smallImageURL);
480                            }
481                    }
482                    else {
483                            imageSelector = new ImageSelector(0);
484                    }
485    
486                    return updateEntry(
487                            entryId, title, StringPool.BLANK, description, content,
488                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
489                            displayDateMinute, allowPingbacks, allowTrackbacks, trackbacks,
490                            imageSelector, serviceContext);
491            }
492    
493            @Override
494            public BlogsEntry updateEntry(
495                            long entryId, String title, String subtitle, String description,
496                            String content, int displayDateMonth, int displayDateDay,
497                            int displayDateYear, int displayDateHour, int displayDateMinute,
498                            boolean allowPingbacks, boolean allowTrackbacks,
499                            String[] trackbacks, ImageSelector imageSelector,
500                            ServiceContext serviceContext)
501                    throws PortalException {
502    
503                    BlogsEntryPermission.check(
504                            getPermissionChecker(), entryId, ActionKeys.UPDATE);
505    
506                    return blogsEntryLocalService.updateEntry(
507                            getUserId(), entryId, title, subtitle, description, content,
508                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
509                            displayDateMinute, allowPingbacks, allowTrackbacks, trackbacks,
510                            imageSelector, serviceContext);
511            }
512    
513            protected String exportToRSS(
514                    String name, String description, String type, double version,
515                    String displayStyle, String feedURL, String entryURL,
516                    List<BlogsEntry> blogsEntries, ThemeDisplay themeDisplay) {
517    
518                    SyndFeed syndFeed = new SyndFeedImpl();
519    
520                    syndFeed.setDescription(description);
521    
522                    List<SyndEntry> syndEntries = new ArrayList<SyndEntry>();
523    
524                    syndFeed.setEntries(syndEntries);
525    
526                    for (BlogsEntry entry : blogsEntries) {
527                            SyndEntry syndEntry = new SyndEntryImpl();
528    
529                            String author = PortalUtil.getUserName(entry);
530    
531                            syndEntry.setAuthor(author);
532    
533                            SyndContent syndContent = new SyndContentImpl();
534    
535                            syndContent.setType(RSSUtil.ENTRY_TYPE_DEFAULT);
536    
537                            String value = null;
538    
539                            if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_ABSTRACT)) {
540                                    String summary = entry.getDescription();
541    
542                                    if (Validator.isNull(summary)) {
543                                            summary = entry.getContent();
544                                    }
545    
546                                    value = StringUtil.shorten(
547                                            HtmlUtil.extractText(summary),
548                                            PropsValues.BLOGS_RSS_ABSTRACT_LENGTH, StringPool.BLANK);
549                            }
550                            else if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_TITLE)) {
551                                    value = StringPool.BLANK;
552                            }
553                            else {
554                                    value = StringUtil.replace(
555                                            entry.getContent(),
556                                            new String[] {
557                                                    "href=\"/", "src=\"/"
558                                            },
559                                            new String[] {
560                                                    "href=\"" + themeDisplay.getURLPortal() + "/",
561                                                    "src=\"" + themeDisplay.getURLPortal() + "/"
562                                            });
563                            }
564    
565                            syndContent.setValue(value);
566    
567                            syndEntry.setDescription(syndContent);
568    
569                            StringBundler sb = new StringBundler(4);
570    
571                            if (entryURL.endsWith("/blogs/rss")) {
572                                    sb.append(entryURL.substring(0, entryURL.length() - 3));
573                                    sb.append(entry.getUrlTitle());
574                            }
575                            else {
576                                    sb.append(entryURL);
577    
578                                    if (!entryURL.endsWith(StringPool.QUESTION)) {
579                                            sb.append(StringPool.AMPERSAND);
580                                    }
581    
582                                    sb.append("entryId=");
583                                    sb.append(entry.getEntryId());
584                            }
585    
586                            String link = sb.toString();
587    
588                            syndEntry.setLink(link);
589    
590                            syndEntry.setPublishedDate(entry.getDisplayDate());
591                            syndEntry.setTitle(entry.getTitle());
592                            syndEntry.setUpdatedDate(entry.getModifiedDate());
593                            syndEntry.setUri(link);
594    
595                            syndEntries.add(syndEntry);
596                    }
597    
598                    syndFeed.setFeedType(RSSUtil.getFeedType(type, version));
599    
600                    List<SyndLink> syndLinks = new ArrayList<SyndLink>();
601    
602                    syndFeed.setLinks(syndLinks);
603    
604                    SyndLink selfSyndLink = new SyndLinkImpl();
605    
606                    syndLinks.add(selfSyndLink);
607    
608                    selfSyndLink.setHref(feedURL);
609                    selfSyndLink.setRel("self");
610    
611                    if (feedURL.endsWith("/-/blogs/rss")) {
612                            SyndLink alternateSyndLink = new SyndLinkImpl();
613    
614                            syndLinks.add(alternateSyndLink);
615    
616                            alternateSyndLink.setHref(
617                                    feedURL.substring(0, feedURL.length() - 12));
618                            alternateSyndLink.setRel("alternate");
619                    }
620    
621                    syndFeed.setPublishedDate(new Date());
622                    syndFeed.setTitle(name);
623                    syndFeed.setUri(feedURL);
624    
625                    try {
626                            return RSSUtil.export(syndFeed);
627                    }
628                    catch (FeedException fe) {
629                            throw new SystemException(fe);
630                    }
631            }
632    
633    }