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 coverImageImageSelector = null;
093                    ImageSelector smallImageImageSelector = null;
094    
095                    if (smallImage && Validator.isNotNull(smallImageFileName) &&
096                            (smallImageInputStream != null)) {
097    
098                            FileEntry fileEntry = TempFileEntryUtil.addTempFileEntry(
099                                    serviceContext.getScopeGroupId(), getUserId(),
100                                    BlogsEntry.class.getName(), smallImageFileName,
101                                    smallImageInputStream,
102                                    MimeTypesUtil.getContentType(smallImageFileName));
103    
104                            smallImageImageSelector = new ImageSelector(
105                                    fileEntry.getFileEntryId(), smallImageURL, null);
106                    }
107    
108                    return addEntry(
109                            title, StringPool.BLANK, description, content, displayDateMonth,
110                            displayDateDay, displayDateYear, displayDateHour, displayDateMinute,
111                            allowPingbacks, allowTrackbacks, trackbacks,
112                            coverImageImageSelector, smallImageImageSelector, serviceContext);
113            }
114    
115            @Override
116            public BlogsEntry addEntry(
117                            String title, String subtitle, String description, String content,
118                            int displayDateMonth, int displayDateDay, int displayDateYear,
119                            int displayDateHour, int displayDateMinute, boolean allowPingbacks,
120                            boolean allowTrackbacks, String[] trackbacks,
121                            ImageSelector coverImageImageSelector,
122                            ImageSelector smallImageImageSelector,
123                            ServiceContext serviceContext)
124                    throws PortalException {
125    
126                    BlogsPermission.check(
127                            getPermissionChecker(), serviceContext.getScopeGroupId(),
128                            ActionKeys.ADD_ENTRY);
129    
130                    return blogsEntryLocalService.addEntry(
131                            getUserId(), title, subtitle, description, content,
132                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
133                            displayDateMinute, allowPingbacks, allowTrackbacks, trackbacks,
134                            coverImageImageSelector, smallImageImageSelector, serviceContext);
135            }
136    
137            @Override
138            public void deleteEntry(long entryId) throws PortalException {
139                    BlogsEntryPermission.check(
140                            getPermissionChecker(), entryId, ActionKeys.DELETE);
141    
142                    blogsEntryLocalService.deleteEntry(entryId);
143            }
144    
145            @Override
146            public List<BlogsEntry> getCompanyEntries(
147                            long companyId, Date displayDate, int status, int max)
148                    throws PortalException {
149    
150                    List<BlogsEntry> entries = new ArrayList<BlogsEntry>();
151    
152                    boolean listNotExhausted = true;
153    
154                    QueryDefinition<BlogsEntry> queryDefinition =
155                            new QueryDefinition<BlogsEntry>(
156                                    status, false, 0, 0, new EntryDisplayDateComparator());
157    
158                    if (status == WorkflowConstants.STATUS_ANY) {
159                            queryDefinition.setStatus(WorkflowConstants.STATUS_IN_TRASH, true);
160                    }
161    
162                    while ((entries.size() < max) && listNotExhausted) {
163                            queryDefinition.setEnd(queryDefinition.getStart() + max);
164    
165                            List<BlogsEntry> entryList =
166                                    blogsEntryLocalService.getCompanyEntries(
167                                            companyId, displayDate, queryDefinition);
168    
169                            queryDefinition.setStart(queryDefinition.getStart() + max);
170    
171                            listNotExhausted = (entryList.size() == max);
172    
173                            for (BlogsEntry entry : entryList) {
174                                    if (entries.size() >= max) {
175                                            break;
176                                    }
177    
178                                    if (BlogsEntryPermission.contains(
179                                                    getPermissionChecker(), entry, ActionKeys.VIEW)) {
180    
181                                            entries.add(entry);
182                                    }
183                            }
184                    }
185    
186                    return entries;
187            }
188    
189            @Override
190            public String getCompanyEntriesRSS(
191                            long companyId, Date displayDate, int status, int max, String type,
192                            double version, String displayStyle, String feedURL,
193                            String entryURL, ThemeDisplay themeDisplay)
194                    throws PortalException {
195    
196                    Company company = companyPersistence.findByPrimaryKey(companyId);
197    
198                    String name = company.getName();
199                    List<BlogsEntry> blogsEntries = getCompanyEntries(
200                            companyId, displayDate, status, max);
201    
202                    return exportToRSS(
203                            name, name, type, version, displayStyle, feedURL, entryURL,
204                            blogsEntries, themeDisplay);
205            }
206    
207            @Override
208            public BlogsEntry getEntry(long entryId) throws PortalException {
209                    BlogsEntryPermission.check(
210                            getPermissionChecker(), entryId, ActionKeys.VIEW);
211    
212                    return blogsEntryLocalService.getEntry(entryId);
213            }
214    
215            @Override
216            public BlogsEntry getEntry(long groupId, String urlTitle)
217                    throws PortalException {
218    
219                    BlogsEntry entry = blogsEntryLocalService.getEntry(groupId, urlTitle);
220    
221                    BlogsEntryPermission.check(
222                            getPermissionChecker(), entry.getEntryId(), ActionKeys.VIEW);
223    
224                    return entry;
225            }
226    
227            @Override
228            public List<BlogsEntry> getGroupEntries(
229                    long groupId, Date displayDate, int status, int max) {
230    
231                    return getGroupEntries(groupId, displayDate, status, 0, max);
232            }
233    
234            @Override
235            public List<BlogsEntry> getGroupEntries(
236                    long groupId, Date displayDate, int status, int start, int end) {
237    
238                    if (status == WorkflowConstants.STATUS_ANY) {
239                            return blogsEntryPersistence.filterFindByG_LtD_NotS(
240                                    groupId, displayDate, WorkflowConstants.STATUS_IN_TRASH, start,
241                                    end);
242                    }
243                    else {
244                            return blogsEntryPersistence.filterFindByG_LtD_S(
245                                    groupId, displayDate, status, start, end);
246                    }
247            }
248    
249            @Override
250            public List<BlogsEntry> getGroupEntries(long groupId, int status, int max) {
251                    return getGroupEntries(groupId, status, 0, max);
252            }
253    
254            @Override
255            public List<BlogsEntry> getGroupEntries(
256                    long groupId, int status, int start, int end) {
257    
258                    if (status == WorkflowConstants.STATUS_ANY) {
259                            return blogsEntryPersistence.filterFindByG_NotS(
260                                    groupId, WorkflowConstants.STATUS_IN_TRASH, start, end);
261                    }
262                    else {
263                            return blogsEntryPersistence.filterFindByG_S(
264                                    groupId, status, start, end);
265                    }
266            }
267    
268            @Override
269            public int getGroupEntriesCount(
270                    long groupId, Date displayDate, int status) {
271    
272                    if (status == WorkflowConstants.STATUS_ANY) {
273                            return blogsEntryPersistence.filterCountByG_LtD_NotS(
274                                    groupId, displayDate, WorkflowConstants.STATUS_IN_TRASH);
275                    }
276                    else {
277                            return blogsEntryPersistence.filterCountByG_LtD_S(
278                                    groupId, displayDate, status);
279                    }
280            }
281    
282            @Override
283            public int getGroupEntriesCount(long groupId, int status) {
284                    if (status == WorkflowConstants.STATUS_ANY) {
285                            return blogsEntryPersistence.filterCountByG_NotS(
286                                    groupId, WorkflowConstants.STATUS_IN_TRASH);
287                    }
288                    else {
289                            return blogsEntryPersistence.filterCountByG_S(groupId, status);
290                    }
291            }
292    
293            @Override
294            public String getGroupEntriesRSS(
295                            long groupId, Date displayDate, int status, int max, String type,
296                            double version, String displayStyle, String feedURL,
297                            String entryURL, ThemeDisplay themeDisplay)
298                    throws PortalException {
299    
300                    Group group = groupPersistence.findByPrimaryKey(groupId);
301    
302                    String name = group.getDescriptiveName();
303                    List<BlogsEntry> blogsEntries = getGroupEntries(
304                            groupId, displayDate, status, max);
305    
306                    return exportToRSS(
307                            name, name, type, version, displayStyle, feedURL, entryURL,
308                            blogsEntries, themeDisplay);
309            }
310    
311            @Override
312            public List<BlogsEntry> getGroupsEntries(
313                            long companyId, long groupId, Date displayDate, int status, int max)
314                    throws PortalException {
315    
316                    List<BlogsEntry> entries = new ArrayList<BlogsEntry>();
317    
318                    boolean listNotExhausted = true;
319    
320                    QueryDefinition<BlogsEntry> queryDefinition =
321                            new QueryDefinition<BlogsEntry>(
322                                    status, false, 0, 0, new EntryDisplayDateComparator());
323    
324                    if (status == WorkflowConstants.STATUS_ANY) {
325                            queryDefinition.setStatus(WorkflowConstants.STATUS_IN_TRASH, true);
326                    }
327    
328                    while ((entries.size() < max) && listNotExhausted) {
329                            queryDefinition.setEnd(queryDefinition.getStart() + max);
330    
331                            List<BlogsEntry> entryList =
332                                    blogsEntryLocalService.getGroupsEntries(
333                                            companyId, groupId, displayDate, queryDefinition);
334    
335                            queryDefinition.setStart(queryDefinition.getStart() + max);
336    
337                            listNotExhausted = (entryList.size() == max);
338    
339                            for (BlogsEntry entry : entryList) {
340                                    if (entries.size() >= max) {
341                                            break;
342                                    }
343    
344                                    if (BlogsEntryPermission.contains(
345                                                    getPermissionChecker(), entry, ActionKeys.VIEW)) {
346    
347                                            entries.add(entry);
348                                    }
349                            }
350                    }
351    
352                    return entries;
353            }
354    
355            @Override
356            public List<BlogsEntry> getOrganizationEntries(
357                            long organizationId, Date displayDate, int status, int max)
358                    throws PortalException {
359    
360                    List<BlogsEntry> entries = new ArrayList<BlogsEntry>();
361    
362                    boolean listNotExhausted = true;
363    
364                    QueryDefinition<BlogsEntry> queryDefinition =
365                            new QueryDefinition<BlogsEntry>(
366                                    status, false, 0, 0, new EntryDisplayDateComparator());
367    
368                    if (status == WorkflowConstants.STATUS_ANY) {
369                            queryDefinition.setStatus(WorkflowConstants.STATUS_IN_TRASH, true);
370                    }
371    
372                    while ((entries.size() < max) && listNotExhausted) {
373                            queryDefinition.setEnd(queryDefinition.getStart() + max);
374    
375                            List<BlogsEntry> entryList = blogsEntryFinder.findByOrganizationId(
376                                    organizationId, displayDate, queryDefinition);
377    
378                            queryDefinition.setStart(queryDefinition.getStart() + max);
379    
380                            listNotExhausted = (entryList.size() == max);
381    
382                            for (BlogsEntry entry : entryList) {
383                                    if (entries.size() >= max) {
384                                            break;
385                                    }
386    
387                                    if (BlogsEntryPermission.contains(
388                                                    getPermissionChecker(), entry, ActionKeys.VIEW)) {
389    
390                                            entries.add(entry);
391                                    }
392                            }
393                    }
394    
395                    return entries;
396            }
397    
398            @Override
399            public String getOrganizationEntriesRSS(
400                            long organizationId, Date displayDate, int status, int max,
401                            String type, double version, String displayStyle, String feedURL,
402                            String entryURL, ThemeDisplay themeDisplay)
403                    throws PortalException {
404    
405                    Organization organization = organizationPersistence.findByPrimaryKey(
406                            organizationId);
407    
408                    String name = organization.getName();
409                    List<BlogsEntry> blogsEntries = getOrganizationEntries(
410                            organizationId, displayDate, status, max);
411    
412                    return exportToRSS(
413                            name, name, type, version, displayStyle, feedURL, entryURL,
414                            blogsEntries, themeDisplay);
415            }
416    
417            @Override
418            public BlogsEntry moveEntryToTrash(long entryId) throws PortalException {
419                    BlogsEntryPermission.check(
420                            getPermissionChecker(), entryId, ActionKeys.DELETE);
421    
422                    return blogsEntryLocalService.moveEntryToTrash(getUserId(), entryId);
423            }
424    
425            @Override
426            public void restoreEntryFromTrash(long entryId) throws PortalException {
427                    BlogsEntryPermission.check(
428                            getPermissionChecker(), entryId, ActionKeys.DELETE);
429    
430                    blogsEntryLocalService.restoreEntryFromTrash(getUserId(), entryId);
431            }
432    
433            @Override
434            public void subscribe(long groupId) throws PortalException {
435                    BlogsPermission.check(
436                            getPermissionChecker(), groupId, ActionKeys.SUBSCRIBE);
437    
438                    blogsEntryLocalService.subscribe(getUserId(), groupId);
439            }
440    
441            @Override
442            public void unsubscribe(long groupId) throws PortalException {
443                    BlogsPermission.check(
444                            getPermissionChecker(), groupId, ActionKeys.SUBSCRIBE);
445    
446                    blogsEntryLocalService.unsubscribe(getUserId(), groupId);
447            }
448    
449            /**
450             * @deprecated As of 7.0.0, replaced by {@link #updateEntry(long, String,
451             *             String, String, String, int, int, int, int, int, boolean,
452             *             boolean, String[], boolean, String, long, ServiceContext)}
453             */
454            @Deprecated
455            @Override
456            public BlogsEntry updateEntry(
457                            long entryId, String title, String description, String content,
458                            int displayDateMonth, int displayDateDay, int displayDateYear,
459                            int displayDateHour, int displayDateMinute, boolean allowPingbacks,
460                            boolean allowTrackbacks, String[] trackbacks, boolean smallImage,
461                            String smallImageURL, String smallImageFileName,
462                            InputStream smallImageInputStream, ServiceContext serviceContext)
463                    throws PortalException {
464    
465                    BlogsPermission.check(
466                            getPermissionChecker(), serviceContext.getScopeGroupId(),
467                            ActionKeys.UPDATE);
468    
469                    ImageSelector coverImageImageSelector = null;
470                    ImageSelector smallImageImageSelector = null;
471    
472                    if (smallImage) {
473                            if (Validator.isNotNull(smallImageFileName) &&
474                                    (smallImageInputStream != null)) {
475    
476                                    FileEntry fileEntry = TempFileEntryUtil.addTempFileEntry(
477                                            serviceContext.getScopeGroupId(), getUserId(),
478                                            BlogsEntry.class.getName(), smallImageFileName,
479                                            smallImageInputStream,
480                                            MimeTypesUtil.getContentType(smallImageFileName));
481    
482                                    smallImageImageSelector = new ImageSelector(
483                                            fileEntry.getFileEntryId(), smallImageURL, null);
484                            }
485                    }
486                    else {
487                            smallImageImageSelector = new ImageSelector(0);
488                    }
489    
490                    return updateEntry(
491                            entryId, title, StringPool.BLANK, description, content,
492                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
493                            displayDateMinute, allowPingbacks, allowTrackbacks, trackbacks,
494                            coverImageImageSelector, smallImageImageSelector, serviceContext);
495            }
496    
497            @Override
498            public BlogsEntry updateEntry(
499                            long entryId, String title, String subtitle, String description,
500                            String content, int displayDateMonth, int displayDateDay,
501                            int displayDateYear, int displayDateHour, int displayDateMinute,
502                            boolean allowPingbacks, boolean allowTrackbacks,
503                            String[] trackbacks, ImageSelector coverImageImageSelector,
504                            ImageSelector smallImageImageSelector,
505                            ServiceContext serviceContext)
506                    throws PortalException {
507    
508                    BlogsEntryPermission.check(
509                            getPermissionChecker(), entryId, ActionKeys.UPDATE);
510    
511                    return blogsEntryLocalService.updateEntry(
512                            getUserId(), entryId, title, subtitle, description, content,
513                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
514                            displayDateMinute, allowPingbacks, allowTrackbacks, trackbacks,
515                            coverImageImageSelector, smallImageImageSelector, serviceContext);
516            }
517    
518            protected String exportToRSS(
519                    String name, String description, String type, double version,
520                    String displayStyle, String feedURL, String entryURL,
521                    List<BlogsEntry> blogsEntries, ThemeDisplay themeDisplay) {
522    
523                    SyndFeed syndFeed = new SyndFeedImpl();
524    
525                    syndFeed.setDescription(description);
526    
527                    List<SyndEntry> syndEntries = new ArrayList<SyndEntry>();
528    
529                    syndFeed.setEntries(syndEntries);
530    
531                    for (BlogsEntry entry : blogsEntries) {
532                            SyndEntry syndEntry = new SyndEntryImpl();
533    
534                            String author = PortalUtil.getUserName(entry);
535    
536                            syndEntry.setAuthor(author);
537    
538                            SyndContent syndContent = new SyndContentImpl();
539    
540                            syndContent.setType(RSSUtil.ENTRY_TYPE_DEFAULT);
541    
542                            String value = null;
543    
544                            if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_ABSTRACT)) {
545                                    String summary = entry.getDescription();
546    
547                                    if (Validator.isNull(summary)) {
548                                            summary = entry.getContent();
549                                    }
550    
551                                    value = StringUtil.shorten(
552                                            HtmlUtil.extractText(summary),
553                                            PropsValues.BLOGS_RSS_ABSTRACT_LENGTH, StringPool.BLANK);
554                            }
555                            else if (displayStyle.equals(RSSUtil.DISPLAY_STYLE_TITLE)) {
556                                    value = StringPool.BLANK;
557                            }
558                            else {
559                                    value = StringUtil.replace(
560                                            entry.getContent(),
561                                            new String[] {
562                                                    "href=\"/", "src=\"/"
563                                            },
564                                            new String[] {
565                                                    "href=\"" + themeDisplay.getURLPortal() + "/",
566                                                    "src=\"" + themeDisplay.getURLPortal() + "/"
567                                            });
568                            }
569    
570                            syndContent.setValue(value);
571    
572                            syndEntry.setDescription(syndContent);
573    
574                            StringBundler sb = new StringBundler(4);
575    
576                            if (entryURL.endsWith("/blogs/rss")) {
577                                    sb.append(entryURL.substring(0, entryURL.length() - 3));
578                                    sb.append(entry.getUrlTitle());
579                            }
580                            else {
581                                    sb.append(entryURL);
582    
583                                    if (!entryURL.endsWith(StringPool.QUESTION)) {
584                                            sb.append(StringPool.AMPERSAND);
585                                    }
586    
587                                    sb.append("entryId=");
588                                    sb.append(entry.getEntryId());
589                            }
590    
591                            String link = sb.toString();
592    
593                            syndEntry.setLink(link);
594    
595                            syndEntry.setPublishedDate(entry.getDisplayDate());
596                            syndEntry.setTitle(entry.getTitle());
597                            syndEntry.setUpdatedDate(entry.getModifiedDate());
598                            syndEntry.setUri(link);
599    
600                            syndEntries.add(syndEntry);
601                    }
602    
603                    syndFeed.setFeedType(RSSUtil.getFeedType(type, version));
604    
605                    List<SyndLink> syndLinks = new ArrayList<SyndLink>();
606    
607                    syndFeed.setLinks(syndLinks);
608    
609                    SyndLink selfSyndLink = new SyndLinkImpl();
610    
611                    syndLinks.add(selfSyndLink);
612    
613                    selfSyndLink.setHref(feedURL);
614                    selfSyndLink.setRel("self");
615    
616                    if (feedURL.endsWith("/-/blogs/rss")) {
617                            SyndLink alternateSyndLink = new SyndLinkImpl();
618    
619                            syndLinks.add(alternateSyndLink);
620    
621                            alternateSyndLink.setHref(
622                                    feedURL.substring(0, feedURL.length() - 12));
623                            alternateSyndLink.setRel("alternate");
624                    }
625    
626                    syndFeed.setPublishedDate(new Date());
627                    syndFeed.setTitle(name);
628                    syndFeed.setUri(feedURL);
629    
630                    try {
631                            return RSSUtil.export(syndFeed);
632                    }
633                    catch (FeedException fe) {
634                            throw new SystemException(fe);
635                    }
636            }
637    
638    }