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.announcements.service.impl;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.interval.IntervalActionProcessor;
019    import com.liferay.portal.kernel.language.LanguageUtil;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.portlet.PortletProvider;
023    import com.liferay.portal.kernel.portlet.PortletProviderUtil;
024    import com.liferay.portal.kernel.util.ListUtil;
025    import com.liferay.portal.kernel.util.OrderByComparator;
026    import com.liferay.portal.kernel.util.PropsKeys;
027    import com.liferay.portal.kernel.util.Time;
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.model.ResourceConstants;
034    import com.liferay.portal.model.Role;
035    import com.liferay.portal.model.RoleConstants;
036    import com.liferay.portal.model.User;
037    import com.liferay.portal.model.UserGroup;
038    import com.liferay.portal.util.PortalUtil;
039    import com.liferay.portal.util.PrefsPropsUtil;
040    import com.liferay.portal.util.PropsValues;
041    import com.liferay.portal.util.SubscriptionSender;
042    import com.liferay.portlet.announcements.exception.EntryContentException;
043    import com.liferay.portlet.announcements.exception.EntryDisplayDateException;
044    import com.liferay.portlet.announcements.exception.EntryExpirationDateException;
045    import com.liferay.portlet.announcements.exception.EntryTitleException;
046    import com.liferay.portlet.announcements.exception.EntryURLException;
047    import com.liferay.portlet.announcements.model.AnnouncementsDelivery;
048    import com.liferay.portlet.announcements.model.AnnouncementsEntry;
049    import com.liferay.portlet.announcements.service.base.AnnouncementsEntryLocalServiceBaseImpl;
050    import com.liferay.util.ContentUtil;
051    
052    import java.util.Date;
053    import java.util.LinkedHashMap;
054    import java.util.List;
055    import java.util.Locale;
056    
057    /**
058     * @author Brian Wing Shun Chan
059     * @author Raymond Aug??
060     */
061    public class AnnouncementsEntryLocalServiceImpl
062            extends AnnouncementsEntryLocalServiceBaseImpl {
063    
064            @Override
065            public AnnouncementsEntry addEntry(
066                            long userId, long classNameId, long classPK, String title,
067                            String content, String url, String type, int displayDateMonth,
068                            int displayDateDay, int displayDateYear, int displayDateHour,
069                            int displayDateMinute, boolean displayImmediately,
070                            int expirationDateMonth, int expirationDateDay,
071                            int expirationDateYear, int expirationDateHour,
072                            int expirationDateMinute, int priority, boolean alert)
073                    throws PortalException {
074    
075                    // Entry
076    
077                    User user = userPersistence.findByPrimaryKey(userId);
078    
079                    Date displayDate = new Date();
080    
081                    if (!displayImmediately) {
082                            displayDate = PortalUtil.getDate(
083                                    displayDateMonth, displayDateDay, displayDateYear,
084                                    displayDateHour, displayDateMinute, user.getTimeZone(),
085                                    EntryDisplayDateException.class);
086                    }
087    
088                    Date expirationDate = PortalUtil.getDate(
089                            expirationDateMonth, expirationDateDay, expirationDateYear,
090                            expirationDateHour, expirationDateMinute, user.getTimeZone(),
091                            EntryExpirationDateException.class);
092    
093                    validate(title, content, url);
094    
095                    long entryId = counterLocalService.increment();
096    
097                    AnnouncementsEntry entry = announcementsEntryPersistence.create(
098                            entryId);
099    
100                    entry.setCompanyId(user.getCompanyId());
101                    entry.setUserId(user.getUserId());
102                    entry.setUserName(user.getFullName());
103                    entry.setClassNameId(classNameId);
104                    entry.setClassPK(classPK);
105                    entry.setTitle(title);
106                    entry.setContent(content);
107                    entry.setUrl(url);
108                    entry.setType(type);
109                    entry.setDisplayDate(displayDate);
110                    entry.setExpirationDate(expirationDate);
111                    entry.setPriority(priority);
112                    entry.setAlert(alert);
113    
114                    announcementsEntryPersistence.update(entry);
115    
116                    // Resources
117    
118                    resourceLocalService.addResources(
119                            user.getCompanyId(), 0, user.getUserId(),
120                            AnnouncementsEntry.class.getName(), entry.getEntryId(), false,
121                            false, false);
122    
123                    return entry;
124            }
125    
126            /**
127             * @deprecated As of 6.2.0, replaced by {@link #addEntry(long, long, long,
128             *             String, String, String, String, int, int, int, int, int,
129             *             boolean, int, int, int, int, int, int, boolean)}
130             */
131            @Deprecated
132            @Override
133            public AnnouncementsEntry addEntry(
134                            long userId, long classNameId, long classPK, String title,
135                            String content, String url, String type, int displayDateMonth,
136                            int displayDateDay, int displayDateYear, int displayDateHour,
137                            int displayDateMinute, int expirationDateMonth,
138                            int expirationDateDay, int expirationDateYear,
139                            int expirationDateHour, int expirationDateMinute, int priority,
140                            boolean alert)
141                    throws PortalException {
142    
143                    return addEntry(
144                            userId, classNameId, classPK, title, content, url, type,
145                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
146                            displayDateMinute, false, expirationDateMonth, expirationDateDay,
147                            expirationDateYear, expirationDateHour, expirationDateMinute,
148                            priority, alert);
149            }
150    
151            @Override
152            public void checkEntries() throws PortalException {
153                    Date now = new Date();
154    
155                    if (_previousCheckDate == null) {
156                            _previousCheckDate = new Date(
157                                    now.getTime() - _ANNOUNCEMENTS_ENTRY_CHECK_INTERVAL);
158                    }
159    
160                    List<AnnouncementsEntry> entries =
161                            announcementsEntryFinder.findByDisplayDate(now, _previousCheckDate);
162    
163                    if (_log.isDebugEnabled()) {
164                            _log.debug("Processing " + entries.size() + " entries");
165                    }
166    
167                    for (AnnouncementsEntry entry : entries) {
168                            notifyUsers(entry);
169                    }
170    
171                    _previousCheckDate = now;
172            }
173    
174            @Override
175            public void deleteEntry(AnnouncementsEntry entry) throws PortalException {
176    
177                    // Entry
178    
179                    announcementsEntryPersistence.remove(entry);
180    
181                    // Resources
182    
183                    resourceLocalService.deleteResource(
184                            entry.getCompanyId(), AnnouncementsEntry.class.getName(),
185                            ResourceConstants.SCOPE_INDIVIDUAL, entry.getEntryId());
186    
187                    // Flags
188    
189                    announcementsFlagLocalService.deleteFlags(entry.getEntryId());
190            }
191    
192            @Override
193            public void deleteEntry(long entryId) throws PortalException {
194                    AnnouncementsEntry entry =
195                            announcementsEntryPersistence.findByPrimaryKey(entryId);
196    
197                    deleteEntry(entry);
198            }
199    
200            @Override
201            public List<AnnouncementsEntry> getEntries(
202                    long userId, LinkedHashMap<Long, long[]> scopes, boolean alert,
203                    int flagValue, int start, int end) {
204    
205                    return getEntries(
206                            userId, scopes, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, alert, flagValue,
207                            start, end);
208            }
209    
210            @Override
211            public List<AnnouncementsEntry> getEntries(
212                    long userId, LinkedHashMap<Long, long[]> scopes, int displayDateMonth,
213                    int displayDateDay, int displayDateYear, int displayDateHour,
214                    int displayDateMinute, int expirationDateMonth, int expirationDateDay,
215                    int expirationDateYear, int expirationDateHour,
216                    int expirationDateMinute, boolean alert, int flagValue, int start,
217                    int end) {
218    
219                    return announcementsEntryFinder.findByScopes(
220                            userId, scopes, displayDateMonth, displayDateDay, displayDateYear,
221                            displayDateHour, displayDateMinute, expirationDateMonth,
222                            expirationDateDay, expirationDateYear, expirationDateHour,
223                            expirationDateMinute, alert, flagValue, start, end);
224            }
225    
226            @Override
227            public List<AnnouncementsEntry> getEntries(
228                    long classNameId, long classPK, boolean alert, int start, int end) {
229    
230                    return announcementsEntryPersistence.findByC_C_A(
231                            classNameId, classPK, alert, start, end);
232            }
233    
234            @Override
235            public List<AnnouncementsEntry> getEntries(
236                    long userId, long classNameId, long[] classPKs, int displayDateMonth,
237                    int displayDateDay, int displayDateYear, int displayDateHour,
238                    int displayDateMinute, int expirationDateMonth, int expirationDateDay,
239                    int expirationDateYear, int expirationDateHour,
240                    int expirationDateMinute, boolean alert, int flagValue, int start,
241                    int end) {
242    
243                    return announcementsEntryFinder.findByScope(
244                            userId, classNameId, classPKs, displayDateMonth, displayDateDay,
245                            displayDateYear, displayDateHour, displayDateMinute,
246                            expirationDateMonth, expirationDateDay, expirationDateYear,
247                            expirationDateHour, expirationDateMinute, alert, flagValue, start,
248                            end);
249            }
250    
251            @Override
252            public int getEntriesCount(
253                    long userId, LinkedHashMap<Long, long[]> scopes, boolean alert,
254                    int flagValue) {
255    
256                    return getEntriesCount(
257                            userId, scopes, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, alert, flagValue);
258            }
259    
260            @Override
261            public int getEntriesCount(
262                    long userId, LinkedHashMap<Long, long[]> scopes, int displayDateMonth,
263                    int displayDateDay, int displayDateYear, int displayDateHour,
264                    int displayDateMinute, int expirationDateMonth, int expirationDateDay,
265                    int expirationDateYear, int expirationDateHour,
266                    int expirationDateMinute, boolean alert, int flagValue) {
267    
268                    return announcementsEntryFinder.countByScopes(
269                            userId, scopes, displayDateMonth, displayDateDay, displayDateYear,
270                            displayDateHour, displayDateMinute, expirationDateMonth,
271                            expirationDateDay, expirationDateYear, expirationDateHour,
272                            expirationDateMinute, alert, flagValue);
273            }
274    
275            @Override
276            public int getEntriesCount(long classNameId, long classPK, boolean alert) {
277                    return announcementsEntryPersistence.countByC_C_A(
278                            classNameId, classPK, alert);
279            }
280    
281            @Override
282            public int getEntriesCount(
283                    long userId, long classNameId, long[] classPKs, boolean alert,
284                    int flagValue) {
285    
286                    return getEntriesCount(
287                            userId, classNameId, classPKs, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, alert,
288                            flagValue);
289            }
290    
291            @Override
292            public int getEntriesCount(
293                    long userId, long classNameId, long[] classPKs, int displayDateMonth,
294                    int displayDateDay, int displayDateYear, int displayDateHour,
295                    int displayDateMinute, int expirationDateMonth, int expirationDateDay,
296                    int expirationDateYear, int expirationDateHour,
297                    int expirationDateMinute, boolean alert, int flagValue) {
298    
299                    return announcementsEntryFinder.countByScope(
300                            userId, classNameId, classPKs, displayDateMonth, displayDateDay,
301                            displayDateYear, displayDateHour, displayDateMinute,
302                            expirationDateMonth, expirationDateDay, expirationDateYear,
303                            expirationDateHour, expirationDateMinute, alert, flagValue);
304            }
305    
306            @Override
307            public AnnouncementsEntry getEntry(long entryId) throws PortalException {
308                    return announcementsEntryPersistence.findByPrimaryKey(entryId);
309            }
310    
311            @Override
312            public List<AnnouncementsEntry> getUserEntries(
313                    long userId, int start, int end) {
314    
315                    return announcementsEntryPersistence.findByUserId(userId, start, end);
316            }
317    
318            @Override
319            public int getUserEntriesCount(long userId) {
320                    return announcementsEntryPersistence.countByUserId(userId);
321            }
322    
323            @Override
324            public AnnouncementsEntry updateEntry(
325                            long userId, long entryId, String title, String content, String url,
326                            String type, int displayDateMonth, int displayDateDay,
327                            int displayDateYear, int displayDateHour, int displayDateMinute,
328                            boolean displayImmediately, int expirationDateMonth,
329                            int expirationDateDay, int expirationDateYear,
330                            int expirationDateHour, int expirationDateMinute, int priority)
331                    throws PortalException {
332    
333                    // Entry
334    
335                    User user = userPersistence.findByPrimaryKey(userId);
336    
337                    Date displayDate = new Date();
338    
339                    if (!displayImmediately) {
340                            displayDate = PortalUtil.getDate(
341                                    displayDateMonth, displayDateDay, displayDateYear,
342                                    displayDateHour, displayDateMinute, user.getTimeZone(),
343                                    EntryDisplayDateException.class);
344                    }
345    
346                    Date expirationDate = PortalUtil.getDate(
347                            expirationDateMonth, expirationDateDay, expirationDateYear,
348                            expirationDateHour, expirationDateMinute, user.getTimeZone(),
349                            EntryExpirationDateException.class);
350    
351                    validate(title, content, url);
352    
353                    AnnouncementsEntry entry =
354                            announcementsEntryPersistence.findByPrimaryKey(entryId);
355    
356                    entry.setTitle(title);
357                    entry.setContent(content);
358                    entry.setUrl(url);
359                    entry.setType(type);
360                    entry.setDisplayDate(displayDate);
361                    entry.setExpirationDate(expirationDate);
362                    entry.setPriority(priority);
363    
364                    announcementsEntryPersistence.update(entry);
365    
366                    // Flags
367    
368                    announcementsFlagLocalService.deleteFlags(entry.getEntryId());
369    
370                    return entry;
371            }
372    
373            protected void notifyUsers(AnnouncementsEntry entry)
374                    throws PortalException {
375    
376                    Company company = companyPersistence.findByPrimaryKey(
377                            entry.getCompanyId());
378    
379                    String className = entry.getClassName();
380                    long classPK = entry.getClassPK();
381    
382                    String toName = PropsValues.ANNOUNCEMENTS_EMAIL_TO_NAME;
383                    String toAddress = PropsValues.ANNOUNCEMENTS_EMAIL_TO_ADDRESS;
384    
385                    long teamId = 0;
386    
387                    LinkedHashMap<String, Object> params = new LinkedHashMap<>();
388    
389                    params.put("announcementsDeliveryEmailOrSms", entry.getType());
390    
391                    if (classPK > 0) {
392                            if (className.equals(Group.class.getName())) {
393                                    Group group = groupPersistence.findByPrimaryKey(classPK);
394    
395                                    toName = group.getDescriptiveName();
396    
397                                    params.put("inherit", Boolean.TRUE);
398                                    params.put("usersGroups", classPK);
399                            }
400                            else if (className.equals(Organization.class.getName())) {
401                                    Organization organization =
402                                            organizationPersistence.findByPrimaryKey(classPK);
403    
404                                    toName = organization.getName();
405    
406                                    params.put(
407                                            "usersOrgsTree",
408                                            ListUtil.fromArray(new Organization[] {organization}));
409                            }
410                            else if (className.equals(Role.class.getName())) {
411                                    Role role = rolePersistence.findByPrimaryKey(classPK);
412    
413                                    toName = role.getName();
414    
415                                    if (role.getType() == RoleConstants.TYPE_REGULAR) {
416                                            params.put("inherit", Boolean.TRUE);
417                                            params.put("usersRoles", classPK);
418                                    }
419                                    else if (role.isTeam()) {
420                                            teamId = role.getClassPK();
421                                    }
422                                    else {
423                                            params.put(
424                                                    "userGroupRole", new Long[] {Long.valueOf(0), classPK});
425                                    }
426                            }
427                            else if (className.equals(UserGroup.class.getName())) {
428                                    UserGroup userGroup = userGroupPersistence.findByPrimaryKey(
429                                            classPK);
430    
431                                    toName = userGroup.getName();
432    
433                                    params.put("usersUserGroups", classPK);
434                            }
435                    }
436    
437                    if (className.equals(User.class.getName())) {
438                            User user = userPersistence.findByPrimaryKey(classPK);
439    
440                            if (Validator.isNull(user.getEmailAddress())) {
441                                    return;
442                            }
443    
444                            notifyUsers(
445                                    ListUtil.fromArray(new User[] {user}), entry,
446                                    company.getLocale(), user.getEmailAddress(),
447                                    user.getFullName());
448                    }
449                    else {
450                            notifyUsers(entry, teamId, params, toName, toAddress, company);
451                    }
452            }
453    
454            protected void notifyUsers(
455                            final AnnouncementsEntry entry, final long teamId,
456                            final LinkedHashMap<String, Object> params, final String toName,
457                            final String toAddress, final Company company)
458                    throws PortalException {
459    
460                    int total = 0;
461    
462                    if (teamId > 0) {
463                            total = userLocalService.getTeamUsersCount(teamId);
464                    }
465                    else {
466                            total = userLocalService.searchCount(
467                                    company.getCompanyId(), null, WorkflowConstants.STATUS_APPROVED,
468                                    params);
469                    }
470    
471                    final IntervalActionProcessor<Void> intervalActionProcessor =
472                            new IntervalActionProcessor<>(total);
473    
474                    intervalActionProcessor.setPerformIntervalActionMethod(
475                            new IntervalActionProcessor.PerformIntervalActionMethod<Void>() {
476    
477                                    @Override
478                                    public Void performIntervalAction(int start, int end)
479                                            throws PortalException {
480    
481                                            List<User> users = null;
482    
483                                            if (teamId > 0) {
484                                                    users = userLocalService.getTeamUsers(
485                                                            teamId, start, end);
486                                            }
487                                            else {
488                                                    users = userLocalService.search(
489                                                            company.getCompanyId(), null,
490                                                            WorkflowConstants.STATUS_APPROVED, params, start,
491                                                            end, (OrderByComparator<User>)null);
492                                            }
493    
494                                            notifyUsers(
495                                                    users, entry, company.getLocale(), toAddress, toName);
496    
497                                            intervalActionProcessor.incrementStart(users.size());
498    
499                                            return null;
500                                    }
501    
502                            });
503    
504                    intervalActionProcessor.performIntervalActions();
505            }
506    
507            protected void notifyUsers(
508                            List<User> users, AnnouncementsEntry entry, Locale locale,
509                            String toAddress, String toName)
510                    throws PortalException {
511    
512                    if (_log.isDebugEnabled()) {
513                            _log.debug("Notifying " + users.size() + " users");
514                    }
515    
516                    boolean notifyUsers = false;
517    
518                    SubscriptionSender subscriptionSender = new SubscriptionSender();
519    
520                    for (User user : users) {
521                            AnnouncementsDelivery announcementsDelivery =
522                                    announcementsDeliveryLocalService.getUserDelivery(
523                                            user.getUserId(), entry.getType());
524    
525                            if (announcementsDelivery.isEmail()) {
526                                    subscriptionSender.addRuntimeSubscribers(
527                                            user.getEmailAddress(), user.getFullName());
528    
529                                    notifyUsers = true;
530                            }
531    
532                            if (announcementsDelivery.isSms()) {
533                                    String smsSn = user.getContact().getSmsSn();
534    
535                                    subscriptionSender.addRuntimeSubscribers(
536                                            smsSn, user.getFullName());
537    
538                                    notifyUsers = true;
539                            }
540                    }
541    
542                    if (!notifyUsers) {
543                            return;
544                    }
545    
546                    String body = ContentUtil.get(PropsValues.ANNOUNCEMENTS_EMAIL_BODY);
547                    String fromAddress = PrefsPropsUtil.getStringFromNames(
548                            entry.getCompanyId(), PropsKeys.ANNOUNCEMENTS_EMAIL_FROM_ADDRESS,
549                            PropsKeys.ADMIN_EMAIL_FROM_ADDRESS);
550                    String fromName = PrefsPropsUtil.getStringFromNames(
551                            entry.getCompanyId(), PropsKeys.ANNOUNCEMENTS_EMAIL_FROM_NAME,
552                            PropsKeys.ADMIN_EMAIL_FROM_NAME);
553                    String subject = ContentUtil.get(
554                            PropsValues.ANNOUNCEMENTS_EMAIL_SUBJECT);
555    
556                    subscriptionSender.setBody(body);
557                    subscriptionSender.setCompanyId(entry.getCompanyId());
558                    subscriptionSender.setContextAttribute(
559                            "[$ENTRY_CONTENT$]", entry.getContent(), false);
560                    subscriptionSender.setContextAttributes(
561                            "[$ENTRY_ID$]", entry.getEntryId(), "[$ENTRY_TITLE$]",
562                            entry.getTitle(), "[$ENTRY_TYPE$]",
563                            LanguageUtil.get(locale, entry.getType()), "[$ENTRY_URL$]",
564                            entry.getUrl(), "[$PORTLET_NAME$]",
565                            LanguageUtil.get(
566                                    locale, (entry.isAlert() ? "alert" : "announcement")));
567                    subscriptionSender.setFrom(fromAddress, fromName);
568                    subscriptionSender.setHtmlFormat(true);
569                    subscriptionSender.setMailId("announcements_entry", entry.getEntryId());
570    
571                    String portletId = PortletProviderUtil.getPortletId(
572                            AnnouncementsEntry.class.getName(), PortletProvider.Action.VIEW);
573    
574                    subscriptionSender.setPortletId(portletId);
575    
576                    subscriptionSender.setScopeGroupId(entry.getGroupId());
577                    subscriptionSender.setSubject(subject);
578    
579                    subscriptionSender.addRuntimeSubscribers(toAddress, toName);
580    
581                    subscriptionSender.flushNotificationsAsync();
582            }
583    
584            protected void validate(String title, String content, String url)
585                    throws PortalException {
586    
587                    if (Validator.isNull(title)) {
588                            throw new EntryTitleException();
589                    }
590    
591                    if (Validator.isNull(content)) {
592                            throw new EntryContentException();
593                    }
594    
595                    if (Validator.isNotNull(url) && !Validator.isUrl(url)) {
596                            throw new EntryURLException();
597                    }
598            }
599    
600            private static final long _ANNOUNCEMENTS_ENTRY_CHECK_INTERVAL =
601                    PropsValues.ANNOUNCEMENTS_ENTRY_CHECK_INTERVAL * Time.MINUTE;
602    
603            private static final Log _log = LogFactoryUtil.getLog(
604                    AnnouncementsEntryLocalServiceImpl.class);
605    
606            private Date _previousCheckDate;
607    
608    }