org.fao.geonet.api.userfeedback.UserFeedbackAPI.java Source code

Java tutorial

Introduction

Here is the source code for org.fao.geonet.api.userfeedback.UserFeedbackAPI.java

Source

/*
 * Copyright (C) 2001-2016 Food and Agriculture Organization of the
 * United Nations (FAO-UN), United Nations World Food Programme (WFP)
 * and United Nations Environment Programme (UNEP)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 *
 * Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
 * Rome - Italy. email: geonetwork@osgeo.org
 */

package org.fao.geonet.api.userfeedback;

import static org.apache.commons.lang.StringUtils.isNotBlank;
import static org.fao.geonet.kernel.setting.Settings.SYSTEM_FEEDBACK_EMAIL;
import static org.fao.geonet.kernel.setting.Settings.SYSTEM_SITE_NAME_PATH;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.jcs.access.exception.ObjectNotFoundException;
import org.fao.geonet.ApplicationContextHolder;
import org.fao.geonet.api.API;
import org.fao.geonet.api.ApiParams;
import org.fao.geonet.api.ApiUtils;
import org.fao.geonet.api.tools.i18n.LanguageUtils;
import org.fao.geonet.api.userfeedback.UserFeedbackUtils.RatingAverage;
import org.fao.geonet.api.userfeedback.service.IUserFeedbackService;
import org.fao.geonet.api.users.recaptcha.RecaptchaChecker;
import org.fao.geonet.domain.AbstractMetadata;
import org.fao.geonet.domain.Metadata;
import org.fao.geonet.domain.userfeedback.RatingCriteria;
import org.fao.geonet.domain.userfeedback.RatingsSetting;
import org.fao.geonet.domain.userfeedback.UserFeedback;
import org.fao.geonet.kernel.setting.SettingManager;
import org.fao.geonet.kernel.setting.Settings;
import org.fao.geonet.repository.MetadataRepository;
import org.fao.geonet.repository.userfeedback.RatingCriteriaRepository;
import org.fao.geonet.util.MailUtil;
import org.fao.geonet.util.XslUtil;
import org.fao.geonet.utils.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import jeeves.server.UserSession;
import springfox.documentation.annotations.ApiIgnore;

/**
 * User Feedback REST API.
 */
@RequestMapping(value = { "/api", "/api/" + API.VERSION_0_1 })
@Api(value = "userfeedback", tags = "userfeedback", description = "User feedback")
@Controller("userfeedback")
public class UserFeedbackAPI {

    /**
     * Gets rating criteria
     *
     * @param response the response
     * @return the list of rating criteria
     * @throws Exception the exception
     */
    @ApiOperation(value = "Get list of rating criteria", nickname = "getRatingCriteria")
    @RequestMapping(value = "/userfeedback/ratingcriteria", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
    @ResponseStatus(value = HttpStatus.OK)
    @ResponseBody
    public List<RatingCriteria> getRatingCriteria(@ApiIgnore final HttpServletResponse response) {
        final ApplicationContext appContext = ApplicationContextHolder.get();
        final SettingManager settingManager = appContext.getBean(SettingManager.class);
        final String functionEnabled = settingManager.getValue(Settings.SYSTEM_LOCALRATING_ENABLE);

        if (!functionEnabled.equals(RatingsSetting.ADVANCED)) {
            response.setStatus(HttpStatus.FORBIDDEN.value());
            return null;
        } else {
            RatingCriteriaRepository criteriaRepository = appContext.getBean(RatingCriteriaRepository.class);
            return criteriaRepository.findAll();
        }
    }

    /**
     * Delete user feedback.
     *
     * @param uuid the uuid
     * @return the response entity
     * @throws Exception the exception
     */
    // DELETE
    @ApiOperation(value = "Removes a user feedback", notes = "Removes a user feedback", nickname = "deleteUserFeedback")
    @RequestMapping(value = "/userfeedback/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.DELETE)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    @PreAuthorize("hasRole('Reviewer')")
    @ApiResponses(value = { @ApiResponse(code = 204, message = "User feedback removed."),
            @ApiResponse(code = 403, message = ApiParams.API_RESPONSE_NOT_ALLOWED_ONLY_REVIEWER) })
    @ResponseBody
    public ResponseEntity deleteUserFeedback(
            @ApiParam(value = "User feedback UUID.", required = true) @PathVariable(value = "uuid") final String uuid,
            final HttpServletRequest request) throws Exception {

        final ApplicationContext appContext = ApplicationContextHolder.get();
        final SettingManager settingManager = appContext.getBean(SettingManager.class);
        final String functionEnabled = settingManager.getValue(Settings.SYSTEM_LOCALRATING_ENABLE);

        if (!functionEnabled.equals(RatingsSetting.ADVANCED)) {
            return new ResponseEntity(HttpStatus.FORBIDDEN);
        }

        Log.debug("org.fao.geonet.api.userfeedback.UserFeedback", "deleteUserFeedback");

        final IUserFeedbackService userFeedbackService = getUserFeedbackService();

        userFeedbackService.removeUserFeedback(uuid, request.getRemoteAddr());

        return new ResponseEntity(HttpStatus.NO_CONTENT);
    }

    /**
     * Gets the metadata rating.
     *
     * @param metadataUuid the metadata uuid
     * @param request the request
     * @param response the response
     * @param httpSession the http session
     * @return the metadata rating
     * @throws Exception the exception
     */
    @ApiOperation(value = "Provides an average rating for a metadata record", nickname = "getMetadataUserComments")
    @RequestMapping(value = "/records/{metadataUuid}/userfeedbackrating", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
    @ResponseStatus(value = HttpStatus.OK)
    @ResponseBody
    public RatingAverage getMetadataRating(
            @ApiParam(value = "Metadata record UUID.", required = true) @PathVariable(value = "metadataUuid") final String metadataUuid,
            @ApiIgnore final HttpServletRequest request, @ApiIgnore final HttpServletResponse response,
            @ApiIgnore final HttpSession httpSession) {

        final ApplicationContext appContext = ApplicationContextHolder.get();
        final SettingManager settingManager = appContext.getBean(SettingManager.class);
        final String functionEnabled = settingManager.getValue(Settings.SYSTEM_LOCALRATING_ENABLE);

        if (!functionEnabled.equals(RatingsSetting.ADVANCED)) {
            response.setStatus(HttpStatus.FORBIDDEN.value());
            return null;
        }

        try {
            Log.debug("org.fao.geonet.api.userfeedback.UserFeedback", "getMetadataUserComments");

            // Check permission for metadata
            final AbstractMetadata metadata = ApiUtils.canViewRecord(metadataUuid, request);
            if (metadata == null) {
                printOutputMessage(response, HttpStatus.FORBIDDEN, ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_VIEW);
                return null;
            }

            final UserSession session = ApiUtils.getUserSession(httpSession);

            boolean published = true; // Takes only published comments

            // showing not published comments only to logged users (maybe better
            // restrict to Reviewers)
            if (session != null && session.isAuthenticated()) {
                published = false;
            }

            final IUserFeedbackService userFeedbackService = getUserFeedbackService();

            final UserFeedbackUtils utils = new UserFeedbackUtils();

            return utils
                    .getAverage(userFeedbackService.retrieveUserFeedbackForMetadata(metadataUuid, -1, published));
        } catch (final Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * Gets the user comment.
     *
     * @param uuid the uuid
     * @param request the request
     * @param response the response
     * @param httpSession the http session
     * @return the user comment
     * @throws Exception the exception
     */
    @ApiOperation(value = "Finds a specific user feedback", nickname = "getUserFeedback")
    @RequestMapping(value = "/userfeedback/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
    @ResponseStatus(value = HttpStatus.OK)
    @ResponseBody
    public UserFeedbackDTO getUserComment(
            @ApiParam(value = "User feedback UUID.", required = true) @PathVariable(value = "uuid") final String uuid,
            @ApiIgnore final HttpServletRequest request, @ApiIgnore final HttpServletResponse response,
            @ApiIgnore final HttpSession httpSession) throws Exception {

        final ApplicationContext appContext = ApplicationContextHolder.get();
        final SettingManager settingManager = appContext.getBean(SettingManager.class);
        final String functionEnabled = settingManager.getValue(Settings.SYSTEM_LOCALRATING_ENABLE);

        if (!functionEnabled.equals(RatingsSetting.ADVANCED)) {
            response.setStatus(HttpStatus.FORBIDDEN.value());
            return null;
        }

        Log.debug("org.fao.geonet.api.userfeedback.UserFeedback", "getUserComment");

        final IUserFeedbackService userFeedbackService = (IUserFeedbackService) ApplicationContextHolder.get()
                .getBean("userFeedbackService");

        final UserSession session = ApiUtils.getUserSession(httpSession);

        boolean published = true; // Takes only published comments

        // showing not published comments only to logged users (maybe better
        // restrict to Reviewers)
        if (session != null && session.isAuthenticated()) {
            published = false;
        }

        final UserFeedback userfeedback = userFeedbackService.retrieveUserFeedback(uuid, published);

        UserFeedbackDTO dto = null;

        if (userfeedback != null) {
            dto = UserFeedbackUtils.convertToDto(userfeedback);
        }

        // Check permission for metadata
        final AbstractMetadata metadata = ApiUtils.canViewRecord(userfeedback.getMetadata().getUuid(), request);
        if (metadata == null) {
            printOutputMessage(response, HttpStatus.FORBIDDEN, ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_VIEW);
            return null;
        }

        return dto;
    }

    /**
     * Gets the user comments for one record.
     *
     * @param response the response
     * @param httpSession the http session
     * @return the user comments
     * @throws Exception the exception
     */
    // GET
    @ApiOperation(value = "Finds a list of user feedback for a specific records. ", notes = " This list will include also the draft user feedback if the client is logged as reviewer.", nickname = "getUserCommentsOnARecord")
    @RequestMapping(value = "/records/{metadataUuid}/userfeedback", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
    @ResponseStatus(value = HttpStatus.OK)
    @ResponseBody
    public List<UserFeedbackDTO> getUserCommentsOnARecord(
            @ApiParam(value = "Metadata record UUID.", required = true) @PathVariable String metadataUuid,
            @ApiParam(value = "Maximum number of feedback to return.", required = false) @RequestParam(defaultValue = "-1", required = false) int size,
            @ApiIgnore final HttpServletResponse response, @ApiIgnore final HttpSession httpSession)
            throws Exception {

        return getUserFeedback(metadataUuid, size, response, httpSession);
    }

    /**
     * Gets the user comments.
     *
     * @param response the response
     * @param httpSession the http session
     * @return the user comments
     * @throws Exception the exception
     */
    // GET
    @ApiOperation(value = "Finds a list of user feedback records. ", notes = " This list will include also the draft user feedback if the client is logged as reviewer.", nickname = "getUserComments")
    @RequestMapping(value = "/userfeedback", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
    @ResponseStatus(value = HttpStatus.OK)
    @ResponseBody
    public List<UserFeedbackDTO> getUserComments(
            @ApiParam(value = "Metadata record UUID.", required = false) @RequestParam(defaultValue = "", required = false) String metadataUuid,
            @ApiParam(value = "Maximum number of feedback to return.", required = false) @RequestParam(defaultValue = "-1", required = false) int size,
            @ApiIgnore final HttpServletResponse response, @ApiIgnore final HttpSession httpSession)
            throws Exception {

        return getUserFeedback(metadataUuid, size, response, httpSession);
    }

    private List<UserFeedbackDTO> getUserFeedback(String metadataUuid, int size, HttpServletResponse response,
            HttpSession httpSession) {
        final ApplicationContext appContext = ApplicationContextHolder.get();
        final SettingManager settingManager = appContext.getBean(SettingManager.class);
        final String functionEnabled = settingManager.getValue(Settings.SYSTEM_LOCALRATING_ENABLE);

        if (!functionEnabled.equals(RatingsSetting.ADVANCED)) {
            response.setStatus(HttpStatus.FORBIDDEN.value());
            return null;
        }

        try {
            Log.debug("org.fao.geonet.api.userfeedback.UserFeedback", "getUserComments");

            final IUserFeedbackService userFeedbackService = getUserFeedbackService();

            final UserSession session = ApiUtils.getUserSession(httpSession);

            boolean published = true; // Takes only published comments

            // showing not published comments only to logged users (maybe better
            // restrict to Reviewers)
            if (session != null && session.isAuthenticated()) {
                published = false;
            }

            List<UserFeedback> listUserfeedback = null;

            if (metadataUuid == null || metadataUuid.equals("")) {
                listUserfeedback = userFeedbackService.retrieveUserFeedback(size, published);
            } else {
                listUserfeedback = userFeedbackService.retrieveUserFeedbackForMetadata(metadataUuid, size,
                        published);
            }

            return listUserfeedback.stream().map(feedback -> UserFeedbackUtils.convertToDto(feedback))
                    .collect(Collectors.toList());
        } catch (final Exception e) {
            e.printStackTrace();
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            return null;
        }
    }

    /**
     * Gets the user feedback service.
     *
     * @return the user feedback service
     */
    // POST
    private IUserFeedbackService getUserFeedbackService() {
        return (IUserFeedbackService) ApplicationContextHolder.get().getBean("userFeedbackService");
    }

    @Autowired
    LanguageUtils languageUtils;

    /**
     * New user feedback.
     *
     * @param userFeedbackDto the user feedback dto
     * @param httpSession the http session
     * @return the response entity
     * @throws Exception the exception
     */
    @ApiOperation(value = "Creates a user feedback", notes = "Creates a user feedback in draft status if the user is not logged in.", nickname = "newUserFeedback")
    @RequestMapping(value = "/userfeedback", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    @ResponseBody
    public ResponseEntity newUserFeedback(@ApiParam(name = "uf") @RequestBody UserFeedbackDTO userFeedbackDto,
            @ApiIgnore final HttpSession httpSession, @ApiIgnore final HttpServletRequest request)
            throws Exception {

        final ApplicationContext appContext = ApplicationContextHolder.get();
        final SettingManager settingManager = appContext.getBean(SettingManager.class);
        final String functionEnabled = settingManager.getValue(Settings.SYSTEM_LOCALRATING_ENABLE);

        if (!functionEnabled.equals(RatingsSetting.ADVANCED)) {
            return new ResponseEntity(HttpStatus.FORBIDDEN);
        }

        try {

            final UserSession session = ApiUtils.getUserSession(httpSession);

            Locale locale = languageUtils.parseAcceptLanguage(request.getLocales());
            ResourceBundle messages = ResourceBundle.getBundle("org.fao.geonet.api.Messages", locale);

            Log.debug("org.fao.geonet.api.userfeedback.UserFeedback", "newUserFeedback");

            final IUserFeedbackService userFeedbackService = getUserFeedbackService();

            boolean recaptchaEnabled = settingManager
                    .getValueAsBool(Settings.SYSTEM_USERSELFREGISTRATION_RECAPTCHA_ENABLE);

            if (recaptchaEnabled) {
                boolean validRecaptcha = RecaptchaChecker.verify(userFeedbackDto.getCaptcha(),
                        settingManager.getValue(Settings.SYSTEM_USERSELFREGISTRATION_RECAPTCHA_SECRETKEY));
                if (!validRecaptcha) {
                    return new ResponseEntity<>(messages.getString("recaptcha_not_valid"),
                            HttpStatus.PRECONDITION_FAILED);
                }
            }

            userFeedbackService.saveUserFeedback(UserFeedbackUtils.convertFromDto(userFeedbackDto,
                    session != null ? session.getPrincipal() : null), request.getRemoteAddr());

            return new ResponseEntity(HttpStatus.CREATED);
        } catch (final Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

    @ApiOperation(value = "Send an email to catalogue administrator or record's contact", notes = "", nickname = "sendEmailToContact")
    @RequestMapping(value = "/records/{metadataUuid}/alert", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    @ResponseBody
    public ResponseEntity sendEmailToContact(
            @ApiParam(value = "Metadata record UUID.", required = true) @PathVariable(value = "metadataUuid") final String metadataUuid,
            @ApiParam(value = "Recaptcha validation key.", required = false) @RequestParam(required = false, defaultValue = "") final String recaptcha,
            @ApiParam(value = "User name.", required = true) @RequestParam final String name,
            @ApiParam(value = "User organisation.", required = true) @RequestParam final String org,
            @ApiParam(value = "User email address.", required = true) @RequestParam final String email,
            @ApiParam(value = "A comment or question.", required = true) @RequestParam final String comments,
            @ApiParam(value = "User phone number.", required = false) @RequestParam(required = false, defaultValue = "") final String phone,
            @ApiParam(value = "Email subject.", required = false) @RequestParam(required = false, defaultValue = "User feedback") final String subject,
            @ApiParam(value = "User function.", required = false) @RequestParam(required = false, defaultValue = "-") final String function,
            @ApiParam(value = "Comment type.", required = false) @RequestParam(required = false, defaultValue = "-") final String type,
            @ApiParam(value = "Comment category.", required = false) @RequestParam(required = false, defaultValue = "-") final String category,
            @ApiParam(value = "List of record's contact to send this email.", required = false) @RequestParam(required = false, defaultValue = "") final String metadataEmail,
            @ApiIgnore final HttpServletRequest request) throws IOException {
        ConfigurableApplicationContext applicationContext = ApplicationContextHolder.get();
        SettingManager sm = applicationContext.getBean(SettingManager.class);
        MetadataRepository metadataRepository = applicationContext.getBean(MetadataRepository.class);

        Locale locale = languageUtils.parseAcceptLanguage(request.getLocales());
        ResourceBundle messages = ResourceBundle.getBundle("org.fao.geonet.api.Messages", locale);

        boolean recaptchaEnabled = sm.getValueAsBool(Settings.SYSTEM_USERSELFREGISTRATION_RECAPTCHA_ENABLE);

        if (recaptchaEnabled) {
            boolean validRecaptcha = RecaptchaChecker.verify(recaptcha,
                    sm.getValue(Settings.SYSTEM_USERSELFREGISTRATION_RECAPTCHA_SECRETKEY));
            if (!validRecaptcha) {
                return new ResponseEntity<>(messages.getString("recaptcha_not_valid"),
                        HttpStatus.PRECONDITION_FAILED);
            }
        }

        String to = sm.getValue(SYSTEM_FEEDBACK_EMAIL);
        String catalogueName = sm.getValue(SYSTEM_SITE_NAME_PATH);

        List<String> toAddress = new LinkedList<String>();
        toAddress.add(to);
        if (isNotBlank(metadataEmail)) {
            //Check metadata email belongs to metadata security!!
            Metadata md = metadataRepository.findOneByUuid(metadataUuid);
            if (md.getData().indexOf(metadataEmail) > 0) {
                toAddress.add(metadataEmail);
            }
        }

        String title = XslUtil.getIndexField(null, metadataUuid, "title", "");

        MailUtil.sendMail(toAddress,
                String.format(messages.getString("user_feedback_title"), catalogueName, title, subject),
                String.format(messages.getString("user_feedback_text"), name, org, function, email, phone, title,
                        type, category, comments, sm.getNodeURL(), metadataUuid),
                sm);

        return new ResponseEntity(HttpStatus.CREATED);
    }

    /**
     * Prints the output message.
     *
     * @param response the response
     * @param code the code
     * @param message the message
     * @throws IOException Signals that an I/O exception has occurred.
     */
    private void printOutputMessage(final HttpServletResponse response, final HttpStatus code, final String message)
            throws IOException {
        response.setStatus(code.value());
        final PrintWriter out = response.getWriter();
        response.setContentType("text/html");
        out.println(message);
        response.flushBuffer();
    }

    /**
     * Publish.
     *
     * @param uuid the uuid
     * @param httpSession the http session
     * @return the response entity
     * @throws Exception the exception
     */
    @ApiOperation(value = "Publishes a feedback", notes = "For reviewers", nickname = "publishFeedback")
    @RequestMapping(value = "/userfeedback/{uuid}/publish", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
    @ResponseStatus(value = HttpStatus.NO_CONTENT)
    @PreAuthorize("hasRole('Reviewer')")
    @ApiResponses(value = { @ApiResponse(code = 204, message = "User feedback published."),
            @ApiResponse(code = 403, message = ApiParams.API_RESPONSE_NOT_ALLOWED_ONLY_REVIEWER),
            @ApiResponse(code = 404, message = ApiParams.API_RESPONSE_RESOURCE_NOT_FOUND) })
    @ResponseBody
    public ResponseEntity publish(
            @ApiParam(value = "User feedback UUID.", required = true) @PathVariable(value = "uuid") final String uuid,
            @ApiIgnore final HttpSession httpSession) throws Exception {

        final ApplicationContext appContext = ApplicationContextHolder.get();
        final SettingManager settingManager = appContext.getBean(SettingManager.class);
        final String functionEnabled = settingManager.getValue(Settings.SYSTEM_LOCALRATING_ENABLE);

        if (!functionEnabled.equals(RatingsSetting.ADVANCED)) {
            return new ResponseEntity(HttpStatus.FORBIDDEN);
        }

        try {
            final UserSession session = ApiUtils.getUserSession(httpSession);
            final IUserFeedbackService userFeedbackService = getUserFeedbackService();

            userFeedbackService.publishUserFeedback(uuid, session.getPrincipal());

        } catch (final ObjectNotFoundException e) {
            return new ResponseEntity(HttpStatus.NOT_FOUND);
        } catch (final Exception e) {
            e.printStackTrace();
        }

        return new ResponseEntity(HttpStatus.NO_CONTENT);
    }
}