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