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