Skip to content

Commit

Permalink
[Backport 4.2.x] Fix user application feedback (#8204)
Browse files Browse the repository at this point in the history
* Fix user application feedback

* Update setting help text and change in the footer the 'Contact' after the 'About' link
  • Loading branch information
josegar74 authored Jun 20, 2024
1 parent 69467f4 commit 7943409
Show file tree
Hide file tree
Showing 15 changed files with 267 additions and 56 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,15 @@ See [Configuring Shibboleth](../managing-users-and-groups/authentication-mode.md

Enable the self registration form. See [User Self-Registration](../managing-users-and-groups/user-self-registration.md).

## system/userFeedback
## User application feedback

!!! warning "Deprecated"
Enabling the setting, displays in the application footer a link to a page that allows sending comments about the application.

![](img/application-feedback-link.png)

3.0.0
![](img/application-feedback.png)

It requires an email server configured.

## Link in metadata records

Expand Down
99 changes: 81 additions & 18 deletions services/src/main/java/org/fao/geonet/api/site/SiteApi.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2001-2023 Food and Agriculture Organization of the
* Copyright (C) 2001-2024 Food and Agriculture Organization of the
* United Nations (FAO-UN), United Nations World Food Programme (WFP)
* and United Nations Environment Programme (UNEP)
*
Expand Down Expand Up @@ -43,10 +43,12 @@
import org.fao.geonet.api.ApiParams;
import org.fao.geonet.api.ApiUtils;
import org.fao.geonet.api.OpenApiConfig;
import org.fao.geonet.api.exception.FeatureNotEnabledException;
import org.fao.geonet.api.exception.NotAllowedException;
import org.fao.geonet.api.site.model.SettingSet;
import org.fao.geonet.api.site.model.SettingsListResponse;
import org.fao.geonet.api.tools.i18n.LanguageUtils;
import org.fao.geonet.api.users.recaptcha.RecaptchaChecker;
import org.fao.geonet.constants.Geonet;
import org.fao.geonet.doi.client.DoiManager;
import org.fao.geonet.domain.*;
Expand All @@ -69,6 +71,7 @@
import org.fao.geonet.repository.*;
import org.fao.geonet.repository.specification.MetadataSpecs;
import org.fao.geonet.resources.Resources;
import org.fao.geonet.util.MailUtil;
import org.fao.geonet.utils.FilePathChecker;
import org.fao.geonet.utils.Log;
import org.fao.geonet.utils.ProxyInfo;
Expand All @@ -78,18 +81,12 @@
import org.springframework.http.HttpEntity;
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.PutMapping;
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 org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletRegistration;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
Expand All @@ -101,19 +98,12 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Optional;
import java.util.TimeZone;
import java.util.*;

import static org.apache.commons.fileupload.util.Streams.checkFileName;
import static org.fao.geonet.api.ApiParams.API_CLASS_CATALOG_TAG;
import static org.fao.geonet.constants.Geonet.Path.IMPORT_STYLESHEETS_SCHEMA_PREFIX;
import static org.fao.geonet.kernel.setting.Settings.SYSTEM_FEEDBACK_EMAIL;

/**
*
Expand Down Expand Up @@ -903,4 +893,77 @@ public List<String> getXslTransformations(
return list;
}
}


@io.swagger.v3.oas.annotations.Operation(
summary = "Send an email to catalogue administrator with feedback about the application",
description = "")
@PostMapping(
value = "/userfeedback",
produces = MediaType.APPLICATION_JSON_VALUE
)
@ResponseStatus(HttpStatus.CREATED)
@ResponseBody
public ResponseEntity<String> sendApplicationUserFeedback(
@Parameter(
description = "Recaptcha validation key."
)
@RequestParam(required = false, defaultValue = "") final String recaptcha,
@Parameter(
description = "User name.",
required = true
)
@RequestParam final String name,
@Parameter(
description = "User organisation.",
required = true
)
@RequestParam final String org,
@Parameter(
description = "User email address.",
required = true
)
@RequestParam final String email,
@Parameter(
description = "A comment or question.",
required = true
)
@RequestParam final String comments,
@Parameter(hidden = true) final HttpServletRequest request
) throws Exception {
Locale locale = languageUtils.parseAcceptLanguage(request.getLocales());
ResourceBundle messages = ResourceBundle.getBundle("org.fao.geonet.api.Messages", locale);

boolean feedbackEnabled = settingManager.getValueAsBool(Settings.SYSTEM_USERFEEDBACK_ENABLE, false);
if (!feedbackEnabled) {
throw new FeatureNotEnabledException(
"Application feedback is not enabled.")
.withMessageKey("exception.resourceNotEnabled.applicationFeedback")
.withDescriptionKey("exception.resourceNotEnabled.applicationFeedback.description");
}

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

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

String to = settingManager.getValue(SYSTEM_FEEDBACK_EMAIL);

Set<String> toAddress = new HashSet<>();
toAddress.add(to);

MailUtil.sendMail(new ArrayList<>(toAddress),
messages.getString("site_user_feedback_title"),
String.format(
messages.getString("site_user_feedback_text"),
name, email, org, comments),
settingManager);
return new ResponseEntity<>(HttpStatus.CREATED);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2001-2016 Food and Agriculture Organization of the
* Copyright (C) 2001-2024 Food and Agriculture Organization of the
* United Nations (FAO-UN), United Nations World Food Programme (WFP)
* and United Nations Environment Programme (UNEP)
*
Expand Down Expand Up @@ -31,28 +31,81 @@
*/
module.directive("gnContactUsForm", [
"$http",
function ($http) {
"$translate",
"vcRecaptchaService",
"gnConfigService",
"gnConfig",
function ($http, $translate, vcRecaptchaService, gnConfigService, gnConfig) {
return {
restrict: "A",
replace: true,
scope: {
user: "="
},
templateUrl: "../../catalog/components/share/" + "partials/contactusform.html",
templateUrl:
"../../catalog/components/contactus/" + "partials/contactusform.html",
link: function (scope, element, attrs) {
scope.send = function (formId) {
$http({
url: "contact.send@json",
method: "POST",
data: $(formId).serialize(),
headers: { "Content-Type": "application/x-www-form-urlencoded" }
}).then(function (response) {
// TODO: report no email sent
if (response.status === 200) {
scope.success = true;
} else {
gnConfigService.load().then(function (c) {
scope.recaptchaEnabled =
gnConfig["system.userSelfRegistration.recaptcha.enable"];
scope.recaptchaKey =
gnConfig["system.userSelfRegistration.recaptcha.publickey"];
});

scope.resolveRecaptcha = false;

function initModel() {
scope.feedbackModel = {
name: scope.user.name,
email: scope.user.email,
org: "",
comments: ""
};
}

initModel();

scope.send = function (form, formId) {
if (scope.recaptchaEnabled) {
if (vcRecaptchaService.getResponse() === "") {
scope.resolveRecaptcha = true;

var deferred = $q.defer();
deferred.resolve("");
return deferred.promise;
}
});
scope.resolveRecaptcha = false;
scope.captcha = vcRecaptchaService.getResponse();
$("#recaptcha").val(scope.captcha);
}

if (form.$valid) {
$http({
url: "../api/site/userfeedback",
method: "POST",
data: $(formId).serialize(),
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
}).then(
function (response) {
scope.$emit("StatusUpdated", {
msg: $translate.instant("feebackSent"),
timeout: 2,
type: "info"
});
initModel();
},
function (response) {
scope.success = false;
scope.$emit("StatusUpdated", {
msg: $translate.instant("feebackSentError"),
timeout: 0,
type: "danger"
});
}
);
}
};
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,74 @@
<form class="form-horizontal" role="form" id="gn-contact-us-form">
<form class="form-horizontal" role="form" id="gn-contact-us-form" name="gnContactUsForm">
<input type="hidden" name="_csrf" value="{{csrf}}" />
<div class="form-group">
<label class="col-sm-3 control-label" data-translate="">name</label>
<div class="form-group gn-required">
<label class="col-sm-3 control-label gn-required" data-translate="">name</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="name" data-ng-model="user.name" />
<input
type="text"
class="form-control"
name="name"
data-ng-required="true"
data-ng-model="feedbackModel.name"
/>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" data-translate="">email</label>
<div class="form-group gn-required">
<label class="col-sm-3 control-label gn-required" data-translate="">email</label>
<div class="col-sm-9">
<input type="email" class="form-control" name="email" ata-ng-model="user.email" />
<input
type="email"
class="form-control"
name="email"
data-ng-required="true"
data-ng-model="feedbackModel.email"
/>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" data-translate="">organization</label>
<div class="form-group gn-required">
<label class="col-sm-3 control-label gn-required" data-translate=""
>organization</label
>
<div class="col-sm-9">
<input type="text" class="form-control" name="org" />
<input
type="text"
class="form-control"
name="org"
data-ng-required="true"
data-ng-model="feedbackModel.org"
/>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" data-translate="">comments</label>
<div class="form-group gn-required">
<label class="col-sm-3 control-label gn-required" data-translate="">comments</label>
<div class="col-sm-9">
<textarea class="form-control" name="comments" data-gn-autogrow="" />
<textarea
class="form-control"
name="comments"
data-ng-required="true"
data-gn-autogrow=""
data-ng-model="feedbackModel.comments"
></textarea>
</div>
</div>
<button class="btn btn-primary pull-right" data-ng-click="send('#gn-contact-us-form')">

<div class="form-group" data-ng-if="recaptchaEnabled">
<div vc-recaptcha class="col-lg-8" theme="'light'" key="recaptchaKey"></div>

<span
class="col-lg-8"
style="color: red"
data-ng-show="resolveRecaptcha"
data-translate=""
>
resolveCaptcha
</span>
</div>

<button
class="btn btn-primary pull-right"
data-ng-click="send(gnContactUsForm, '#gn-contact-us-form')"
data-ng-disabled="!gnContactUsForm.$valid"
>
<i class="fa fa-envelope"></i>&nbsp;<span data-translate="">send</span>
</button>
<p class="alert alert-info" data-ng-if="success" data-translate="">feebackSent</p>
</form>
6 changes: 5 additions & 1 deletion web-ui/src/main/resources/catalog/js/CatController.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2001-2016 Food and Agriculture Organization of the
* Copyright (C) 2001-2024 Food and Agriculture Organization of the
* United Nations (FAO-UN), United Nations World Food Programme (WFP)
* and United Nations Environment Programme (UNEP)
*
Expand Down Expand Up @@ -1608,6 +1608,10 @@
return gnGlobalSettings.gnCfg.mods.footer.showApplicationInfoAndLinksInFooter;
};

$scope.getContactusVisible = function () {
return gnConfig[gnConfig.key.isFeedbackEnabled];
};

function detectNode(detector) {
if (detector.regexp) {
var res = new RegExp(detector.regexp).exec(location.pathname);
Expand Down
12 changes: 10 additions & 2 deletions web-ui/src/main/resources/catalog/js/ContactUsController.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,17 @@

goog.require("gn_contactus_directive");

var module = angular.module("gn_contact_us_controller", ["gn_contactus_directive"]);
var module = angular.module("gn_contact_us_controller", [
"gn_contactus_directive",
"vcRecaptcha"
]);

module.constant("$LOCALES", ["core"]);
module.config([
"$LOCALES",
function ($LOCALES) {
$LOCALES.push("/../api/i18n/packages/search");
}
]);

/**
*
Expand Down
Loading

0 comments on commit 7943409

Please sign in to comment.