org.obiba.agate.web.rest.notification.NotificationsResource.java Source code

Java tutorial

Introduction

Here is the source code for org.obiba.agate.web.rest.notification.NotificationsResource.java

Source

/*
 * Copyright (c) 2018 OBiBa. All rights reserved.
 *
 * This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.obiba.agate.web.rest.notification;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.FormParam;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;

import org.apache.commons.lang.LocaleUtils;
import org.obiba.agate.domain.User;
import org.obiba.agate.service.ConfigurationService;
import org.obiba.agate.service.MailService;
import org.obiba.agate.service.UserService;
import org.obiba.agate.web.rest.application.ApplicationAwareResource;
import org.obiba.shiro.realm.ObibaRealm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.thymeleaf.spring4.SpringTemplateEngine;

import com.google.common.base.Strings;
import com.google.common.collect.Sets;

@Component
@Path("/notifications")
@Scope("request")
public class NotificationsResource extends ApplicationAwareResource {

    private static final Logger log = LoggerFactory.getLogger(NotificationsResource.class);

    @Inject
    private MailService mailService;

    @Inject
    private SpringTemplateEngine templateEngine;

    @Inject
    private ConfigurationService configurationService;

    @Inject
    private UserService userService;

    /**
     * Send a notification email to all active users matching the provided user names and/or belonging to the provided groups AND
     * having access to the requesting application. If no user names and no groups are specified, all active users having
     * access to the application will be notified.
     *
     * @param servletRequest
     * @param usernames
     * @param groups
     * @param subject
     * @param body body of the message (optional)
     * @param template template name to be used if message body is not specified
     * @param authHeader
     * @return
     */
    @POST
    public Response notify(@Context HttpServletRequest servletRequest,
            @FormParam("username") List<String> usernames, @FormParam("group") List<String> groups,
            @FormParam("subject") String subject, @FormParam("body") String body,
            @FormParam("template") String template,
            @HeaderParam(ObibaRealm.APPLICATION_AUTH_HEADER) String authHeader) {
        if (Strings.isNullOrEmpty(subject) && Strings.isNullOrEmpty(body))
            return Response.noContent().build();

        validateApplication(authHeader);

        Set<User> recipients = Sets.newHashSet();
        if ((usernames == null || usernames.isEmpty()) && (groups == null || groups.isEmpty())) {
            // all users having access to the application
            recipients.addAll(userService.findActiveUsersByApplication(getApplicationName()));
        } else {
            // all the specified users having access to the application
            appendRecipientsFromUsernames(usernames, recipients);
            // all the users belonging to one of the groups and having access to the application
            appendRecipientsFromGroup(groups, recipients);
        }

        if (Strings.isNullOrEmpty(template))
            sendPlainEmail(subject, body, recipients);
        else
            sendTemplateEmail(subject, template, servletRequest.getParameterMap(), recipients);

        return Response.noContent().build();
    }

    //
    // Private methods
    //

    /**
     * Send an email by processing a template with request form parameters and the recipient
     * {@link org.obiba.agate.domain.User} as a context. The Template is expected to be located in a folder having
     * the application name.
     *
     * @param subject
     * @param templateName
     * @param context
     * @param recipients
     */
    private void sendTemplateEmail(String subject, String templateName, Map<String, String[]> context,
            Set<User> recipients) {
        org.thymeleaf.context.Context ctx = new org.thymeleaf.context.Context();
        context.forEach((k, v) -> {
            if (v != null && v.length == 1) {
                ctx.setVariable(k, v[0]);
            } else {
                ctx.setVariable(k, v);
            }
        });
        String templateLocation = getApplicationName() + "/" + templateName;

        recipients.forEach(rec -> {
            ctx.setVariable("user", rec);
            ctx.setLocale(LocaleUtils.toLocale(rec.getPreferredLanguage()));
            mailService.sendEmail(rec.getEmail(), subject, templateEngine.process(templateLocation, ctx));
        });
    }

    /**
     * Send an email build with
     * @param subject
     * @param body
     * @param recipients
     */
    private void sendPlainEmail(String subject, String body, Set<User> recipients) {
        recipients.forEach(rec -> mailService.sendEmail(rec.getEmail(), subject, body));
    }

    /**
     * Lookup active users and verify its access to the application requesting the notification.
     *
     * @param servletRequest
     * @param usernames
     * @param emails
     */
    private void appendRecipientsFromUsernames(Collection<String> usernames, Collection<User> recipients) {
        if (usernames == null || usernames.isEmpty())
            return;

        List<String> applicationUsernames = userService.findActiveUsersByApplication(getApplicationName()).stream()
                .map(User::getName).collect(Collectors.toList());

        usernames.forEach(username -> {
            User user = userService.findActiveUser(username);
            if (user == null)
                user = userService.findActiveUserByEmail(username);

            if (user != null && applicationUsernames.contains(user.getName()))
                recipients.add(user);
        });
    }

    /**
     * Lookup active users belonging to one the groups and verify its access to the application requesting the notification.
     *
     * @param groups
     * @param emails
     */
    private void appendRecipientsFromGroup(Collection<String> groups, Collection<User> recipients) {
        if (groups == null || groups.isEmpty())
            return;

        // find all users in each group and having access to the application
        groups.forEach(group -> userService.findActiveUsersByApplicationAndGroup(getApplicationName(), group)
                .forEach(recipients::add));
    }
}