org.codice.ddf.catalog.ui.query.FeedbackApplication.java Source code

Java tutorial

Introduction

Here is the source code for org.codice.ddf.catalog.ui.query.FeedbackApplication.java

Source

/**
 * Copyright (c) Codice Foundation
 *
 * <p>This is free software: you can redistribute it and/or modify it under the terms of the GNU
 * Lesser General Public License as published by the Free Software Foundation, either version 3 of
 * the License, or any later version.
 *
 * <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details. A copy of the GNU Lesser General Public
 * License is distributed along with this program and can be found at
 * <http://www.gnu.org/licenses/lgpl.html>.
 */
package org.codice.ddf.catalog.ui.query;

import static spark.Spark.exception;
import static spark.Spark.post;
import static spark.route.RouteOverview.enableRouteOverview;

import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Template;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import ddf.security.Subject;
import ddf.security.SubjectUtils;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.shiro.SecurityUtils;
import org.codice.ddf.catalog.ui.config.ConfigurationApplication;
import org.codice.ddf.catalog.ui.query.feedback.FeedbackRequest;
import org.codice.ddf.catalog.ui.util.EndpointUtil;
import org.codice.ddf.platform.email.SmtpClient;
import org.codice.gsonsupport.GsonTypeAdapters;
import org.codice.gsonsupport.GsonTypeAdapters.LongDoubleTypeAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import spark.servlet.SparkApplication;

public class FeedbackApplication implements SparkApplication {
    private static final String APPLICATION_JSON = "application/json";

    private static final String UNKNOWN = "Unknown";

    private static final Logger LOGGER = LoggerFactory.getLogger(FeedbackApplication.class);

    private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting()
            .registerTypeAdapterFactory(LongDoubleTypeAdapter.FACTORY).create();

    private ConfigurationApplication configurationApplication;

    private Template subjectTemplate;

    private Template bodyTemplate;

    private SmtpClient smtpClient;

    private String emailDestination;

    private EndpointUtil util;

    @Override
    public void init() {
        post("/feedback", APPLICATION_JSON, (req, res) -> {
            if (StringUtils.isNotEmpty(emailDestination)) {
                FeedbackRequest feedback = parseFeedbackRequest(util.safeGetBody(req));
                feedback.setAuthUsername(getCurrentUser());

                String emailSubject = getEmailSubject(feedback);
                String emailBody = getEmailBody(feedback);
                if (emailBody != null) {
                    emailBody = emailBody.replaceAll("\\\\n", "\n");
                } else {
                    emailBody = "<html/>";
                }

                Session emailSession = smtpClient.createSession();
                MimeMessage message = new MimeMessage(emailSession);
                message.addRecipient(Message.RecipientType.TO, new InternetAddress(emailDestination));
                message.setSubject(emailSubject);
                message.setContent(emailBody, "text/html; charset=utf-8");
                smtpClient.send(message);

                res.body("{}");
                res.status(200);
                return res;
            } else {
                res.status(500);
                res.body("No destination email configured, feedback cannot be submitted.");
                LOGGER.debug("Feedback submission failed, destination email is not configured.");
                return res;
            }
        });

        exception(Exception.class, (e, request, response) -> {
            response.status(500);
            response.body("Error submitting feedback");
            LOGGER.debug("Feedback submission failed", e);
        });

        enableRouteOverview();
    }

    public void setConfigurationApplication(ConfigurationApplication configurationApplication) {
        this.configurationApplication = configurationApplication;
        initConfigurationAppValues(true);
    }

    public void setSmtpClient(SmtpClient smtpClient) {
        this.smtpClient = smtpClient;
    }

    public void setEndpointUtil(EndpointUtil util) {
        this.util = util;
    }

    public String getEmailDestination() {
        return emailDestination;
    }

    public void setEmailDestination(String emailDestination) {
        this.emailDestination = emailDestination;
    }

    public void refresh(Map<String, Object> configuration) {
        if (MapUtils.isEmpty(configuration)) {
            return;
        }

        SmtpClient configSmtpClient = (SmtpClient) configuration.get("smtpClient");
        if (configSmtpClient != null) {
            this.smtpClient = configSmtpClient;
        }

        this.emailDestination = configurationApplication.getQueryFeedbackEmailDestination();
        initConfigurationAppValues(true);
    }

    private static FeedbackRequest parseFeedbackRequest(String json) {
        FeedbackRequest feedbackRequest = new FeedbackRequest();
        String name = UNKNOWN;
        String email = UNKNOWN;
        String searchStr = UNKNOWN;
        String workspaceId = UNKNOWN;
        String workspaceName = UNKNOWN;
        Date searchInitiated = null;
        List<Object> searchStatus = null;
        List<Object> searchResults = null;

        Map<String, Object> rootObject = GSON.fromJson(json, GsonTypeAdapters.MAP_STRING_TO_OBJECT_TYPE);

        Object userObj = rootObject.get("user");
        if (userObj instanceof Map) {
            Map<String, Object> userObject = (Map<String, Object>) userObj;
            name = (String) userObject.get("name");
            email = (String) userObject.get("email");
        }

        Object searchObj = rootObject.get("search");
        if (searchObj instanceof Map) {
            Map<String, Object> searchObject = (Map<String, Object>) searchObj;
            searchStr = (String) searchObject.get("cql");
            searchInitiated = (Date) searchObject.get("initiated");
            searchStatus = (List) searchObject.get("status");
            Object resultsObj = searchObject.get("results");
            if (resultsObj instanceof List) {
                searchResults = (List) resultsObj;
            }
        }

        Object workspaceObj = rootObject.get("workspace");
        if (workspaceObj instanceof Map) {
            Map<String, Object> workspaceObject = (Map<String, Object>) workspaceObj;
            workspaceId = (String) workspaceObject.get("id");
            workspaceName = (String) workspaceObject.get("name");
        }

        String comments = (String) rootObject.get("comments");

        feedbackRequest.setUsername(name);
        feedbackRequest.setEmail(email);
        feedbackRequest.setQuery(searchStr);
        if (searchInitiated != null) {
            feedbackRequest.setQueryInitiated(searchInitiated.toString());
        }
        if (searchResults != null) {
            String prettyPrintedJson = GSON.toJson(searchResults);
            feedbackRequest.setQueryResults(prettyPrintedJson);
        }
        if (searchStatus != null) {
            feedbackRequest
                    .setQueryStatus(searchStatus.stream().map(Object::toString).collect(Collectors.joining(", ")));
        }
        feedbackRequest.setWorkspaceId(workspaceId);
        feedbackRequest.setWorkspaceName(workspaceName);
        feedbackRequest.setComments(comments);

        return feedbackRequest;
    }

    private String getEmailSubject(FeedbackRequest feedback) {
        initConfigurationAppValues(false);
        return applyTemplate(subjectTemplate, feedback);
    }

    private String getEmailBody(FeedbackRequest feedback) {
        initConfigurationAppValues(false);
        return applyTemplate(bodyTemplate, feedback);
    }

    private String applyTemplate(Template template, FeedbackRequest feedback) {
        String templatedString = null;

        if (template != null) {
            Map<String, String> templateValueMap = getTemplateValueMap(feedback);
            try {
                templatedString = template.apply(templateValueMap);
            } catch (IOException e) {
                LOGGER.error("Unable to apply values to handle bars email body template", e);
            }
        }

        return templatedString;
    }

    private void initConfigurationAppValues(boolean reinit) {
        Handlebars handlebars = new Handlebars();

        if (reinit || subjectTemplate == null || bodyTemplate == null) {
            if (configurationApplication != null) {
                emailDestination = configurationApplication.getQueryFeedbackEmailDestination();
                String subjectTemplateStr = configurationApplication.getQueryFeedbackEmailSubjectTemplate();
                String bodyTemplateStr = configurationApplication.getQueryFeedbackEmailBodyTemplate();

                try {
                    if (subjectTemplateStr != null) {
                        subjectTemplate = handlebars.compileInline(subjectTemplateStr);
                    }

                    if (bodyTemplateStr != null) {
                        bodyTemplate = handlebars.compileInline(bodyTemplateStr);
                    }
                } catch (IOException e) {
                    LOGGER.warn("Unable to compile email templates", e);
                }
            } else {
                LOGGER.debug("Feedback configuration is not set");
            }
        }
    }

    private Map<String, String> getTemplateValueMap(FeedbackRequest feedbackRequest) {
        Map<String, String> valueMap = new HashMap<>();

        valueMap.put("auth_username", feedbackRequest.getAuthUsername());
        valueMap.put("username", StringEscapeUtils.escapeHtml4(feedbackRequest.getUsername()));
        valueMap.put("email", StringEscapeUtils.escapeHtml4(feedbackRequest.getEmail()));
        valueMap.put("workspace_id", StringEscapeUtils.escapeHtml4(feedbackRequest.getWorkspaceId()));
        valueMap.put("workspace_name", StringEscapeUtils.escapeHtml4(feedbackRequest.getWorkspaceName()));
        valueMap.put("query", StringEscapeUtils.escapeHtml4(feedbackRequest.getQuery()));
        valueMap.put("query_initiated_time", StringEscapeUtils.escapeHtml4(feedbackRequest.getQueryInitiated()));
        valueMap.put("query_status", StringEscapeUtils.escapeHtml4(feedbackRequest.getQueryStatus()));
        valueMap.put("query_results", StringEscapeUtils.escapeHtml4(feedbackRequest.getQueryResults()));
        valueMap.put("comments", StringEscapeUtils.escapeHtml4(feedbackRequest.getComments()));

        return valueMap;
    }

    private String getCurrentUser() {
        Subject subject = (Subject) SecurityUtils.getSubject();
        return SubjectUtils.getName(subject);
    }
}