diff --git a/src/main/java/org/nrg/xapi/rest/notifications/NotificationsApi.java b/src/main/java/org/nrg/xapi/rest/notifications/NotificationsApi.java index ec1bcf5f50c176996e789effd21d53cd117f1e78..e9a01c2599d64707104c574be167855cbf3ec0ee 100644 --- a/src/main/java/org/nrg/xapi/rest/notifications/NotificationsApi.java +++ b/src/main/java/org/nrg/xapi/rest/notifications/NotificationsApi.java @@ -1,5 +1,6 @@ package org.nrg.xapi.rest.notifications; +import com.fasterxml.jackson.core.type.TypeReference; import io.swagger.annotations.*; import org.apache.commons.lang3.StringUtils; import org.nrg.framework.annotations.XapiRestController; @@ -64,7 +65,7 @@ public class NotificationsApi extends AbstractXapiRestController { @ApiResponse(code = 403, message = "Not authorized to set site configuration properties."), @ApiResponse(code = 500, message = "Unexpected error")}) @RequestMapping(produces = {MediaType.APPLICATION_JSON_VALUE}, method = {RequestMethod.GET}) - public ResponseEntity<Properties> getAllSiteConfigProperties(@ApiParam(hidden = true) final HttpServletRequest request) throws IOException { + public ResponseEntity<Properties> getNotificationsProperties(@ApiParam(hidden = true) final HttpServletRequest request) throws IOException { final HttpStatus status = isPermitted(); if (status != null) { return new ResponseEntity<>(status); @@ -96,8 +97,8 @@ public class NotificationsApi extends AbstractXapiRestController { @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."), @ApiResponse(code = 403, message = "Not authorized to set notifications properties."), @ApiResponse(code = 500, message = "Unexpected error")}) - @RequestMapping(value = "batch", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE}, method = {RequestMethod.POST}) - public ResponseEntity<Void> setBatchNotificationsProperties(@ApiParam(value = "The map of notifications properties to be set.", required = true) @RequestBody final Properties properties) throws InitializationException { + @RequestMapping(consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE}, method = {RequestMethod.POST}) + public ResponseEntity<Void> setNotificationsProperties(@ApiParam(value = "The map of notifications properties to be set.", required = true) @RequestBody final Properties properties) throws InitializationException { final HttpStatus status = isPermitted(); if (status != null) { return new ResponseEntity<>(status); @@ -107,14 +108,16 @@ public class NotificationsApi extends AbstractXapiRestController { for (final String name : properties.stringPropertyNames()) { try { - if (StringUtils.equals(name, "notifications.emailRecipientErrorMessages")) { + if (StringUtils.equals(name, "emailRecipientErrorMessages")) { _notificationsPrefs.setEmailRecipientErrorMessages(properties.getProperty(name)); - } else if (StringUtils.equals(name, "notifications.emailRecipientIssueReports")) { + } else if (StringUtils.equals(name, "emailRecipientIssueReports")) { _notificationsPrefs.setEmailRecipientIssueReports(properties.getProperty(name)); - } else if (StringUtils.equals(name, "notifications.emailRecipientNewUserAlert")) { + } else if (StringUtils.equals(name, "emailRecipientNewUserAlert")) { _notificationsPrefs.setEmailRecipientNewUserAlert(properties.getProperty(name)); - } else if (StringUtils.equals(name, "notifications.emailRecipientUpdate")) { + } else if (StringUtils.equals(name, "emailRecipientUpdate")) { _notificationsPrefs.setEmailRecipientUpdate(properties.getProperty(name)); + } else if (StringUtils.equals(name, "smtpServer")) { + _notificationsPrefs.setSmtpServer(_serializer.deserializeJson(properties.getProperty(name), TYPE_REF_HASHMAP_STRING_STRING)); } else { _notificationsPrefs.set(properties.getProperty(name), name); } @@ -123,55 +126,30 @@ public class NotificationsApi extends AbstractXapiRestController { } } catch (InvalidPreferenceName invalidPreferenceName) { _log.error("Got an invalid preference name error for the preference: " + name + ", which is weird because the site configuration is not strict"); + } catch (IOException e) { + _log.error("An error occurred deserializing the preference: " + name + ", which is just lame."); } } - return new ResponseEntity<>(HttpStatus.OK); - } + // If any of the SMTP properties changed, then change the values for + if (properties.containsKey("smtpServer") || properties.containsKey("host") || properties.containsKey("port") || properties.containsKey("protocol") || properties.containsKey("username") || properties.containsKey("password")) { + final String host = _notificationsPrefs.getHostname(); + final int port = _notificationsPrefs.getPort(); + final String protocol = _notificationsPrefs.getProtocol(); + final String username = _notificationsPrefs.getUsername(); + final String password = _notificationsPrefs.getPassword(); - @ApiOperation(value = "Sets a map of notifications properties for mail.", notes = "Sets the notifications properties for mail specified in the map.", response = Void.class) - @ApiResponses({@ApiResponse(code = 200, message = "Notifications properties for mail successfully set."), - @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."), - @ApiResponse(code = 403, message = "Not authorized to set notifications properties for mail."), - @ApiResponse(code = 500, message = "Unexpected error")}) - @RequestMapping(value = "batchMail", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE}, method = {RequestMethod.POST}) - public ResponseEntity<Void> setBatchNotificationsPropertiesForMail(@ApiParam(value = "The map of notifications properties for mail to be set.", required = true) @RequestBody final Properties properties) throws InitializationException { - final HttpStatus status = isPermitted(); - if (status != null) { - return new ResponseEntity<>(status); - } + logConfigurationSubmit(host, port, protocol, username, password, properties); - logSetProperties(properties); + setHost(host, false); + setPort(port); + setProtocol(protocol); + setUsername(username); + setPassword(password); - for (final String name : properties.stringPropertyNames()) { - try { - _notificationsPrefs.set(properties.getProperty(name), name); - if (_log.isInfoEnabled()) { - _log.info("Set property {} to value: {}", name, properties.get(name)); - } - } catch (InvalidPreferenceName invalidPreferenceName) { - _log.error("Got an invalid preference name error for the preference: " + name + ", which is weird because the site configuration is not strict"); - } + _javaMailSender.setJavaMailProperties(getSubmittedProperties(properties)); } - String host = _notificationsPrefs.getHostname(); - int port = _notificationsPrefs.getPort(); - String protocol = _notificationsPrefs.getProtocol(); - String username = _notificationsPrefs.getUsername(); - String password = _notificationsPrefs.getPassword(); - - logConfigurationSubmit(host, port, protocol, username, password, properties); - - setHost(host, false); - setPort(port); - setProtocol(protocol); - setUsername(username); - setPassword(password); - - _javaMailSender.setJavaMailProperties(getSubmittedProperties(properties)); - - setSmtp(); - return new ResponseEntity<>(HttpStatus.OK); } @@ -245,8 +223,6 @@ public class NotificationsApi extends AbstractXapiRestController { _javaMailSender.setJavaMailProperties(getSubmittedProperties(properties)); - setSmtp(); - return getSmtpServerProperties(); } @@ -282,8 +258,6 @@ public class NotificationsApi extends AbstractXapiRestController { } } - setSmtp(); - return getSmtpServerProperties(); } @@ -304,7 +278,6 @@ public class NotificationsApi extends AbstractXapiRestController { _log.info("User " + getSessionUser().getLogin() + " setting mail host to: " + host); } setHost(host, true); - setSmtp(); return getSmtpServerProperties(); } @@ -325,7 +298,6 @@ public class NotificationsApi extends AbstractXapiRestController { _log.info("User " + getSessionUser().getLogin() + " setting mail port to: " + port); } setPort(port); - setSmtp(); return getSmtpServerProperties(); } @@ -777,28 +749,6 @@ public class NotificationsApi extends AbstractXapiRestController { return properties; } - private void setSmtp() { - final Map<String, String> smtp = new HashMap<>(); - smtp.put("host", StringUtils.defaultIfBlank(_javaMailSender.getHost(), "localhost")); - smtp.put("port", Integer.toString(_javaMailSender.getPort())); - if (StringUtils.isNotBlank(_javaMailSender.getUsername())) { - smtp.put("username", _javaMailSender.getUsername()); - } - if (StringUtils.isNotBlank(_javaMailSender.getPassword())) { - smtp.put("password", _javaMailSender.getPassword()); - } - if (StringUtils.isNotBlank(_javaMailSender.getProtocol())) { - smtp.put("protocol", _javaMailSender.getProtocol()); - } - final Properties properties = _javaMailSender.getJavaMailProperties(); - if (properties.size() > 0) { - for (final String property : properties.stringPropertyNames()) { - smtp.put(property, properties.getProperty(property)); - } - } - _notificationsPrefs.setSmtpServer(smtp); - } - private void cleanProperties(final Properties properties) { if (properties.containsKey("host")) { properties.remove("host"); @@ -877,8 +827,9 @@ public class NotificationsApi extends AbstractXapiRestController { } } - private static final Logger _log = LoggerFactory.getLogger(NotificationsApi.class); - private static final String NOT_SET = "NotSet"; + private static final Logger _log = LoggerFactory.getLogger(NotificationsApi.class); + private static final String NOT_SET = "NotSet"; + private final static TypeReference<HashMap<String, String>> TYPE_REF_HASHMAP_STRING_STRING = new TypeReference<HashMap<String, String>>() {}; private final NotificationsPreferences _notificationsPrefs; private final JavaMailSenderImpl _javaMailSender; diff --git a/src/main/java/org/nrg/xapi/rest/settings/SiteConfigApi.java b/src/main/java/org/nrg/xapi/rest/settings/SiteConfigApi.java index 4b452e8f66c428769f56f2df3b8348a4d01d0a1f..1b74e2faa9a1078df4dc5ceae2f1806af52bfe8c 100644 --- a/src/main/java/org/nrg/xapi/rest/settings/SiteConfigApi.java +++ b/src/main/java/org/nrg/xapi/rest/settings/SiteConfigApi.java @@ -55,54 +55,10 @@ public class SiteConfigApi extends AbstractXapiRestController { } } - @ApiOperation(value = "Returns a map of application build properties.", notes = "This includes the implementation version, Git commit hash, and build number and number.", response = Properties.class) - @ApiResponses({@ApiResponse(code = 200, message = "Application build properties successfully retrieved."), @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."), @ApiResponse(code = 500, message = "Unexpected error")}) - @RequestMapping(value = "buildInfo", produces = {MediaType.APPLICATION_JSON_VALUE}, method = {RequestMethod.GET}) - public ResponseEntity<Properties> getBuildInfo() { - if (_log.isDebugEnabled()) { - _log.debug("User " + getSessionUser().getUsername() + " requested the application build information."); - } - - return new ResponseEntity<>(_appInfo.getSystemProperties(), HttpStatus.OK); - } - - @ApiOperation(value = "Returns a map of extended build attributes.", notes = "The values are dependent on what attributes are set for the build. It is not unexpected that there are no extended build attributes.", response = String.class, responseContainer = "Map") - @ApiResponses({@ApiResponse(code = 200, message = "Extended build attributes successfully retrieved."), @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."), @ApiResponse(code = 500, message = "Unexpected error")}) - @RequestMapping(value = "buildInfo/attributes", produces = {MediaType.APPLICATION_JSON_VALUE}, method = {RequestMethod.GET}) - public ResponseEntity<Map<String, Map<String, String>>> getBuildAttributeInfo() { - if (_log.isDebugEnabled()) { - _log.debug("User " + getSessionUser().getUsername() + " requested the extended application build attributes."); - } - - return new ResponseEntity<>(_appInfo.getSystemAttributes(), HttpStatus.OK); - } - - @ApiOperation(value = "Returns the system uptime.", notes = "This returns the uptime as a map of time units: days, hours, minutes, and seconds.", response = String.class, responseContainer = "Map") - @ApiResponses({@ApiResponse(code = 200, message = "System uptime successfully retrieved."), @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."), @ApiResponse(code = 500, message = "Unexpected error")}) - @RequestMapping(value = "uptime", produces = {MediaType.APPLICATION_JSON_VALUE}, method = {RequestMethod.GET}) - public ResponseEntity<Map<String, String>> getSystemUptime() { - if (_log.isDebugEnabled()) { - _log.debug("User " + getSessionUser().getUsername() + " requested the system uptime map."); - } - - return new ResponseEntity<>(_appInfo.getUptime(), HttpStatus.OK); - } - - @ApiOperation(value = "Returns the system uptime.", notes = "This returns the uptime as a formatted string.", response = String.class) - @ApiResponses({@ApiResponse(code = 200, message = "System uptime successfully retrieved."), @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."), @ApiResponse(code = 500, message = "Unexpected error")}) - @RequestMapping(value = "uptime/display", produces = {MediaType.APPLICATION_JSON_VALUE}, method = {RequestMethod.GET}) - public ResponseEntity<String> getFormattedSystemUptime() { - if (_log.isDebugEnabled()) { - _log.debug("User " + getSessionUser().getUsername() + " requested the formatted system uptime."); - } - - return new ResponseEntity<>(_appInfo.getFormattedUptime(), HttpStatus.OK); - } - @ApiOperation(value = "Returns the full map of site configuration properties.", notes = "Complex objects may be returned as encapsulated JSON strings.", response = String.class, responseContainer = "Map") @ApiResponses({@ApiResponse(code = 200, message = "Site configuration properties successfully retrieved."), @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."), @ApiResponse(code = 403, message = "Not authorized to set site configuration properties."), @ApiResponse(code = 500, message = "Unexpected error")}) - @RequestMapping(produces = {MediaType.APPLICATION_JSON_VALUE}, method = {RequestMethod.GET}) - public ResponseEntity<Map<String, Object>> getAllSiteConfigProperties(final HttpServletRequest request) { + @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET) + public ResponseEntity<Map<String, Object>> getSiteConfigProperties(final HttpServletRequest request) { final HttpStatus status = isPermitted(); if (status != null) { return new ResponseEntity<>(status); @@ -126,48 +82,10 @@ public class SiteConfigApi extends AbstractXapiRestController { return new ResponseEntity<>(preferences, HttpStatus.OK); } - @ApiOperation(value = "Returns a map of the selected site configuration properties.", notes = "Complex objects may be returned as encapsulated JSON strings.", response = String.class, responseContainer = "Map") - @ApiResponses({@ApiResponse(code = 200, message = "Site configuration properties successfully retrieved."), @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."), @ApiResponse(code = 403, message = "Not authorized to set site configuration properties."), @ApiResponse(code = 500, message = "Unexpected error")}) - @RequestMapping(value = "values/{preferences}", produces = {MediaType.APPLICATION_JSON_VALUE}, method = {RequestMethod.GET}) - public ResponseEntity<Map<String, Object>> getSpecifiedSiteConfigProperties(@PathVariable final List<String> preferences) { - final HttpStatus status = isPermitted(); - if (status != null) { - return new ResponseEntity<>(status); - } - - if (_log.isDebugEnabled()) { - _log.debug("User " + getSessionUser().getUsername() + " requested the site configuration preferences " + Joiner.on(", ").join(preferences)); - } - - final Map<String, Object> values = new HashMap<>(); - for (final String preference : preferences) { - final Object value = getPreferences().get(preference); - if (value != null) { - values.put(preference, value); - } - } - return new ResponseEntity<>(values, HttpStatus.OK); - } - - @ApiOperation(value = "Returns the value of the selected site configuration property.", notes = "Complex objects may be returned as encapsulated JSON strings.", response = Object.class) - @ApiResponses({@ApiResponse(code = 200, message = "Site configuration property successfully retrieved."), @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."), @ApiResponse(code = 403, message = "Not authorized to access site configuration properties."), @ApiResponse(code = 500, message = "Unexpected error")}) - @RequestMapping(value = "{property}", produces = {MediaType.APPLICATION_JSON_VALUE}, method = {RequestMethod.GET}) - public ResponseEntity<Object> getSpecifiedSiteConfigProperty(@ApiParam(value = "The site configuration property to retrieve.", required = true) @PathVariable final String property) { - final HttpStatus status = isPermitted(); - if (status != null) { - return new ResponseEntity<>(status); - } - final Object value = getPreferences().get(property); - if (_log.isDebugEnabled()) { - _log.debug("User " + getSessionUser().getUsername() + " requested the value for the site configuration property " + property + ", got value: " + value); - } - return new ResponseEntity<>(value, HttpStatus.OK); - } - @ApiOperation(value = "Sets a map of site configuration properties.", notes = "Sets the site configuration properties specified in the map.", response = Void.class) @ApiResponses({@ApiResponse(code = 200, message = "Site configuration properties successfully set."), @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."), @ApiResponse(code = 403, message = "Not authorized to set site configuration properties."), @ApiResponse(code = 500, message = "Unexpected error")}) - @RequestMapping(value = "batch", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE}, method = {RequestMethod.POST}) - public ResponseEntity<Void> setBatchSiteConfigProperties(@ApiParam(value = "The map of site configuration properties to be set.", required = true) @RequestBody final Map<String, String> properties) throws InitializationException { + @RequestMapping(consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE}, method = RequestMethod.POST) + public ResponseEntity<Void> setSiteConfigProperties(@ApiParam(value = "The map of site configuration properties to be set.", required = true) @RequestBody final Map<String, String> properties) throws InitializationException { final HttpStatus status = isPermitted(); if (status != null) { return new ResponseEntity<>(status); @@ -202,10 +120,48 @@ public class SiteConfigApi extends AbstractXapiRestController { return new ResponseEntity<>(HttpStatus.OK); } + @ApiOperation(value = "Returns a map of the selected site configuration properties.", notes = "Complex objects may be returned as encapsulated JSON strings.", response = String.class, responseContainer = "Map") + @ApiResponses({@ApiResponse(code = 200, message = "Site configuration properties successfully retrieved."), @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."), @ApiResponse(code = 403, message = "Not authorized to set site configuration properties."), @ApiResponse(code = 500, message = "Unexpected error")}) + @RequestMapping(value = "values/{preferences}", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET) + public ResponseEntity<Map<String, Object>> getSpecifiedSiteConfigProperties(@PathVariable final List<String> preferences) { + final HttpStatus status = isPermitted(); + if (status != null) { + return new ResponseEntity<>(status); + } + + if (_log.isDebugEnabled()) { + _log.debug("User " + getSessionUser().getUsername() + " requested the site configuration preferences " + Joiner.on(", ").join(preferences)); + } + + final Map<String, Object> values = new HashMap<>(); + for (final String preference : preferences) { + final Object value = getPreferences().get(preference); + if (value != null) { + values.put(preference, value); + } + } + return new ResponseEntity<>(values, HttpStatus.OK); + } + + @ApiOperation(value = "Returns the value of the selected site configuration property.", notes = "Complex objects may be returned as encapsulated JSON strings.", response = Object.class) + @ApiResponses({@ApiResponse(code = 200, message = "Site configuration property successfully retrieved."), @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."), @ApiResponse(code = 403, message = "Not authorized to access site configuration properties."), @ApiResponse(code = 500, message = "Unexpected error")}) + @RequestMapping(value = "{property}", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET) + public ResponseEntity<Object> getSpecifiedSiteConfigProperty(@ApiParam(value = "The site configuration property to retrieve.", required = true) @PathVariable final String property) { + final HttpStatus status = isPermitted(); + if (status != null) { + return new ResponseEntity<>(status); + } + final Object value = getPreferences().get(property); + if (_log.isDebugEnabled()) { + _log.debug("User " + getSessionUser().getUsername() + " requested the value for the site configuration property " + property + ", got value: " + value); + } + return new ResponseEntity<>(value, HttpStatus.OK); + } + @ApiOperation(value = "Sets a single site configuration property.", notes = "Sets the site configuration property specified in the URL to the value set in the body.", response = Void.class) @ApiResponses({@ApiResponse(code = 200, message = "Site configuration properties successfully set."), @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."), @ApiResponse(code = 403, message = "Not authorized to set site configuration properties."), @ApiResponse(code = 500, message = "Unexpected error")}) - @RequestMapping(value = {"/{property}"}, consumes = {MediaType.APPLICATION_JSON_VALUE}, produces = {MediaType.APPLICATION_JSON_VALUE}, method = {RequestMethod.POST}) - public ResponseEntity<Void> setSiteConfigProperty(@ApiParam(value = "The map of site configuration properties to be set.", required = true) @PathVariable("property") final String property, @RequestBody final String value) throws InitializationException { + @RequestMapping(value = "{property}", consumes = {MediaType.TEXT_PLAIN_VALUE, MediaType.APPLICATION_JSON_VALUE}, produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.POST) + public ResponseEntity<Void> setSiteConfigProperty(@ApiParam(value = "The property to be set.", required = true) @PathVariable("property") final String property, @ApiParam("The value to be set for the property.") @RequestBody final String value) throws InitializationException { final HttpStatus status = isPermitted(); if (status != null) { return new ResponseEntity<>(status); @@ -230,6 +186,50 @@ public class SiteConfigApi extends AbstractXapiRestController { return new ResponseEntity<>(HttpStatus.OK); } + @ApiOperation(value = "Returns a map of application build properties.", notes = "This includes the implementation version, Git commit hash, and build number and number.", response = Properties.class) + @ApiResponses({@ApiResponse(code = 200, message = "Application build properties successfully retrieved."), @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."), @ApiResponse(code = 500, message = "Unexpected error")}) + @RequestMapping(value = "buildInfo", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET) + public ResponseEntity<Properties> getBuildInfo() { + if (_log.isDebugEnabled()) { + _log.debug("User " + getSessionUser().getUsername() + " requested the application build information."); + } + + return new ResponseEntity<>(_appInfo.getSystemProperties(), HttpStatus.OK); + } + + @ApiOperation(value = "Returns a map of extended build attributes.", notes = "The values are dependent on what attributes are set for the build. It is not unexpected that there are no extended build attributes.", response = String.class, responseContainer = "Map") + @ApiResponses({@ApiResponse(code = 200, message = "Extended build attributes successfully retrieved."), @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."), @ApiResponse(code = 500, message = "Unexpected error")}) + @RequestMapping(value = "buildInfo/attributes", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET) + public ResponseEntity<Map<String, Map<String, String>>> getBuildAttributeInfo() { + if (_log.isDebugEnabled()) { + _log.debug("User " + getSessionUser().getUsername() + " requested the extended application build attributes."); + } + + return new ResponseEntity<>(_appInfo.getSystemAttributes(), HttpStatus.OK); + } + + @ApiOperation(value = "Returns the system uptime.", notes = "This returns the uptime as a map of time units: days, hours, minutes, and seconds.", response = String.class, responseContainer = "Map") + @ApiResponses({@ApiResponse(code = 200, message = "System uptime successfully retrieved."), @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."), @ApiResponse(code = 500, message = "Unexpected error")}) + @RequestMapping(value = "uptime", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET) + public ResponseEntity<Map<String, String>> getSystemUptime() { + if (_log.isDebugEnabled()) { + _log.debug("User " + getSessionUser().getUsername() + " requested the system uptime map."); + } + + return new ResponseEntity<>(_appInfo.getUptime(), HttpStatus.OK); + } + + @ApiOperation(value = "Returns the system uptime.", notes = "This returns the uptime as a formatted string.", response = String.class) + @ApiResponses({@ApiResponse(code = 200, message = "System uptime successfully retrieved."), @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."), @ApiResponse(code = 500, message = "Unexpected error")}) + @RequestMapping(value = "uptime/display", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET) + public ResponseEntity<String> getFormattedSystemUptime() { + if (_log.isDebugEnabled()) { + _log.debug("User " + getSessionUser().getUsername() + " requested the formatted system uptime."); + } + + return new ResponseEntity<>(_appInfo.getFormattedUptime(), HttpStatus.OK); + } + private Map<String, Object> getPreferences() { if (!_hasFoundPreferences) { return _preferences.getPreferenceMap(); diff --git a/src/main/resources/META-INF/xnat/security/initialization-urls.yaml b/src/main/resources/META-INF/xnat/security/initialization-urls.yaml index 9c9b8e692953575fe5f66a6a1417e70eb5212b1f..d1d407de4d571d082301d5e79fe7f6bbe1015330 100644 --- a/src/main/resources/META-INF/xnat/security/initialization-urls.yaml +++ b/src/main/resources/META-INF/xnat/security/initialization-urls.yaml @@ -2,7 +2,7 @@ configPath: /setup nonAdminErrorPath: /app/template/Unconfigured.vm initPaths: - - /xapi/siteConfig/batch + - /xapi/siteConfig - /xapi/siteConfig/initialized - /xapi/notifications/smtp - /xapi/spawner/resolve/siteAdmin/siteSetup diff --git a/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml b/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml index 7be1a702a4a297299ae199d943851fdea92a4186..eaca940889d86f5926b041639a376e79d1eceb9c 100644 --- a/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml +++ b/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml @@ -215,9 +215,7 @@ siteInfo: label: Site Information method: POST contentType: json - action: /xapi/siteConfig/batch - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig + url: /xapi/siteConfig contents: ${siteId} ${siteUrl} @@ -233,9 +231,7 @@ adminInfo: label: Admin Information method: POST contentType: json - action: /xapi/siteConfig/batch - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig + url: /xapi/siteConfig contents: ${adminEmail} @@ -245,9 +241,7 @@ generalSecuritySettings: label: General Site Security Settings method: POST contentType: json - action: /xapi/siteConfig/batch - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig + url: /xapi/siteConfig contents: securityChannel: kind: panel.select.single @@ -286,9 +280,7 @@ userLoginsSessionControls: name: userLoginsSessionControls label: User Logins / Session Controls method: POST - action: /xapi/siteConfig/batch - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig + url: /xapi/siteConfig contentType: json contents: sessionTimeout: @@ -375,10 +367,8 @@ passwords: name: passwords label: Passwords method: POST - action: /xapi/siteConfig/batch + url: /xapi/siteConfig contentType: json - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig contents: passwordComplexity: kind: panel.input.text @@ -469,10 +459,8 @@ csrf: name: csrf label: CSRF method: POST - action: /xapi/siteConfig/batch + url: /xapi/siteConfig contentType: json - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig contents: enableCsrfToken: kind: panel.input.checkbox @@ -489,11 +477,9 @@ securityServices: kind: panel.form name: securityServices label: Security Services - action: /xapi/siteConfig/batch + url: /xapi/siteConfig method: POST contentType: json - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig contents: securityServicesFeatureDefault: kind: panel.input.text @@ -519,10 +505,8 @@ securityServices: emailServerSettings: kind: panel.form method: POST - action: /xapi/notifications/batchMail contentType: json - load: XNAT.data.notifications - refresh: /xapi/notifications + url: /xapi/notifications name: emailServerSettings label: Mail Server Settings contents: @@ -582,15 +566,12 @@ notifications: kind: panel.form name: notifications label: Notifications - action: /xapi/notifications/batch + url: /xapi/notifications method: POST contentType: json - load: XNAT.data.notifications - refresh: /xapi/notifications contents: helpContactInfo: kind: panel.input.email - name: ":notifications.helpContactInfo" label: "Help Contact Info" # value: "!? XNAT.data.notifications['notifications.helpContactInfo'] || XNAT.data.siteConfig.adminEmail" @@ -600,19 +581,16 @@ notifications: emailMessageUserRegistration: kind: panel.textarea - name: ":notifications.emailMessageUserRegistration" label: "User Registration" code: html description: "Text of message emailed to users upon registration. Link for email validation is auto-populated." emailMessageForgotUsernameRequest: kind: panel.textarea - name: ":notifications.emailMessageForgotUsernameRequest" label: "Forgot Username Request" code: html description: "Text of message emailed to users upon lost username request." emailMessageForgotPasswordReset: kind: panel.textarea - name: ":notifications.emailMessageForgotPasswordReset" label: "Password Reset" code: html description: "Text of message emailed to users upon lost password reset. Link for password reset is auto-populated" @@ -624,28 +602,24 @@ notifications: # notifyAdminUserRegistration: # kind: panel.input.checkbox # id: notifyAdminUserRegistration -# name: notifications.notifyAdminUserRegistration ## value: "?? XNAT:data:siteConfig:notifications.notifyAdminUserRegistration" # label: "User Registration" # description: "Whether to cc admin user on new user emails. Requires valid admin email address." # notifyAdminPipelineEmails: # kind: panel.input.checkbox # id: notifyAdminPipelineEmails -# name: notifications.notifyAdminPipelineEmails ## value: "?? XNAT:data:siteConfig:notifications.notifyAdminPipelineEmails" # label: "Pipeline Emails" # description: "Whether to cc admin user on pipeline processing submit. Requires valid admin email address." # notifyAdminProjectAccessRequest: # kind: panel.input.checkbox # id: notifyAdminProjectAccessRequest -# name: notifications.notifyAdminProjectAccessRequest ## value: "?? XNAT:data:siteConfig:notifications.notifyAdminProjectAccessRequest" # label: "Project Access Request" # description: "Whether to cc admin user on user project access request. Requires valid admin email address." # notifyAdminSessionTransfer: # kind: panel.input.checkbox # id: notifyAdminSessionTransfer -# name: notifications.notifyAdminProjectOnSessionTransfer ## value: "?? XNAT:data:siteConfig:notifications.notifyAdminProjectOnSessionTransfer" # label: "Session Transfer" # description: "Whether to cc admin user on session transfer by user. Requires valid admin email address." @@ -656,28 +630,29 @@ notifications: emailRecipientErrorMessages: kind: panel.input.email - name: ":notifications.emailRecipientErrorMessages" label: "Error Messages" description: "What email address(es) should receive error emails. Separate multiple email addresses with commas. If empty, emails will be sent to the site administrator email address." value: "!? XNAT.data.notifications['notifications.emailRecipientErrorMessages'] || XNAT.data.siteConfig.adminEmail" emailRecipientIssueReports: kind: panel.input.email - name: ":notifications.emailRecipientIssueReports" label: "Issue Reports" description: "What email address(es) should receive issue reports. Separate multiple email addresses with commas. If empty, emails will be sent to the site administrator email address." value: "!? XNAT.data.notifications['notifications.emailRecipientIssueReports'] || XNAT.data.siteConfig.adminEmail" emailRecipientNewUserAlert: kind: panel.input.email - name: ":notifications.emailRecipientNewUserAlert" label: "New User Alert" description: "What email address(es) should receive New User Registration emails. Separate multiple email addresses with commas. If empty, emails will be sent to the site administrator email address." value: "!? XNAT.data.notifications['notifications.emailRecipientNewUserAlert'] || XNAT.data.siteConfig.adminEmail" emailRecipientUpdate: kind: panel.input.email - name: ":notifications.emailRecipientUpdate" label: "Updates" description: "What email address(es) should receive update emails. Separate multiple email addresses with commas. If empty, emails will be sent to the site administrator email address." value: "!? XNAT.data.notifications['notifications.emailRecipientUpdate'] || XNAT.data.siteConfig.adminEmail" + copyAdminOnNotifications: + kind: panel.input.checkbox + name: copyAdminOnNotifications + label: "Copy Administrator on Notifications?" + description: "Indicates whether the primary administrator should receive a copy of error, issue, new user, and update notifications if the administrator is not one of the configured recipients." otherSubhead: kind: panel.subhead @@ -694,7 +669,7 @@ themeManagement: kind: panel.form name: themeManagement label: Theme Management - action: /xapi/theme + url: /xapi/theme contents: themeScript: tag: script|src=/scripts/xnat/admin/themeManagement.js @@ -736,10 +711,8 @@ authenticationMethods: name: authenticationMethods label: User Authentication Methods method: POST - action: /xapi/siteConfig/batch + url: /xapi/siteConfig contentType: json - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig contents: xnatInternal: kind: panel.input.checkbox @@ -759,10 +732,8 @@ genericAuthenticationProvider: name: genericAuthenticationProvider label: Generic Authentication Provider method: POST - action: /xapi/siteConfig/batch + url: /xapi/siteConfig contentType: json - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig contents: providerDbName: kind: panel.input.text @@ -782,10 +753,8 @@ ldapAuthentication: name: ldapAuthenticationProvider label: LDAP Authentication Provider method: POST - action: /xapi/siteConfig/batch + url: /xapi/siteConfig contentType: json - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig contents: ldapName: kind: panel.input.text @@ -837,9 +806,8 @@ registrationOptions: kind: panel.form name: registrationOptions label: Registration Options + url: /xapi/siteConfig method: POST - action: /xapi/siteConfig/batch - load: XNAT.data.siteConfig contentType: json contents: requireEmailVerificationToRegister: @@ -889,9 +857,7 @@ manageDataTypes: label: Manage Data Types method: POST contentType: json - action: /xapi/siteConfig/batch - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig + url: /xapi/siteConfig contents: displayNameForGenericImageSessionSingular: kind: panel.input.text @@ -908,9 +874,7 @@ sessionBuilder: label: "Session Builder" method: POST contentType: json - action: /xapi/siteConfig/batch - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig + url: /xapi/siteConfig contents: sessionXmlRebuilderRepeat: kind: panel.input.number @@ -939,9 +903,7 @@ anonymization: label: "Anonymization Script (Site Wide)" method: POST contentType: json - action: /xapi/siteConfig/batch - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig + url: /xapi/siteConfig contents: enableSitewideAnonymizationScript: kind: panel.input.checkbox @@ -961,9 +923,7 @@ seriesImportFilter: label: "Series Import Filter (Site Wide)" method: POST contentType: json - action: /xapi/siteConfig/batch - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig + url: /xapi/siteConfig contents: enableSitewideSeriesImportFilter: kind: panel.input.checkbox @@ -996,9 +956,7 @@ petTracers: label: "Pet Tracers (Site Wide)" method: POST contentType: json - action: /xapi/siteConfig/batch - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig + url: /xapi/siteConfig contents: sitewidePetTracers: kind: panel.textarea @@ -1014,9 +972,7 @@ petMr: label: "Separate PET-MR? (Site Wide)" method: POST contentType: json - action: /xapi/siteConfig/batch - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig + url: /xapi/siteConfig contents: petMr: kind: panel.select.single @@ -1036,9 +992,7 @@ sessionUploadMethod: label: "Session Upload Method" method: POST contentType: json - action: /xapi/siteConfig/batch - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig + url: /xapi/siteConfig contents: # selectUploadMethod: # kind: panel.select.single @@ -1134,9 +1088,7 @@ fileSystem: label: File System method: POST contentType: json - action: /xapi/siteConfig/batch - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig + url: /xapi/siteConfig contents: ${archivePath} ${cachePath} @@ -1154,8 +1106,7 @@ automationSettings: label: Automation method: POST contentType: json - action: /xapi/automation - load: /xapi/automation + url: /xapi/automation contents: internalScriptingEnabled: kind: panel.input.checkbox @@ -1170,9 +1121,7 @@ misc: footer: false method: POST contentType: json - action: /xapi/siteConfig/batch - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig + url: /xapi/siteConfig contents: scanTypeMapping: kind: panel.input.checkbox @@ -1353,9 +1302,8 @@ siteSetupSiteInfo: label: Site Information footer: false method: POST - action: /xapi/siteConfig/batch + url: /xapi/siteConfig contentType: json - load: /xapi/siteConfig contents: ${siteId} ${siteUrl} @@ -1368,9 +1316,7 @@ dataStorage: footer: false method: POST contentType: json - action: /xapi/siteConfig/batch - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig + url: /xapi/siteConfig contents: ${archivePath} ${prearchivePath} diff --git a/src/main/webapp/scripts/xnat/app/siteSetup.js b/src/main/webapp/scripts/xnat/app/siteSetup.js index e17966d6f4c73ef52de064ae39bf410f594e65dc..b3fbf46505b69e7c4e2ea9d3c1d1482a8e3e1d50 100644 --- a/src/main/webapp/scripts/xnat/app/siteSetup.js +++ b/src/main/webapp/scripts/xnat/app/siteSetup.js @@ -181,7 +181,7 @@ var XNAT = getObject(XNAT); function initialize(){ XNAT.xhr.postJSON({ - url: XNAT.url.rootUrl('/xapi/siteConfig/batch'), + url: XNAT.url.rootUrl('/xapi/siteConfig'), data: JSON.stringify({initialized:true}), success: function(){ xmodal.loading.close('#multi-save'); diff --git a/src/main/webapp/scripts/xnat/ui/panel.js b/src/main/webapp/scripts/xnat/ui/panel.js index 6a5a9dfb2797bfb2e39116eb23e87e941427aac2..bcb57930c4209b4c80e4ebb84ea4b2816d41891d 100644 --- a/src/main/webapp/scripts/xnat/ui/panel.js +++ b/src/main/webapp/scripts/xnat/ui/panel.js @@ -93,7 +93,7 @@ var XNAT = getObject(XNAT || {}); // Do nothing } } - } + } } /** @@ -168,6 +168,7 @@ var XNAT = getObject(XNAT || {}); opts.element = opts.element || opts.config || {}; opts.title = opts.title || opts.label || opts.header; opts.name = opts.name || opts.element.name || opts.id || opts.element.id || randomID('form-', false); + opts.action = opts.action || opts.url; // data-* attributes to add to panel addDataObjects(opts, { @@ -274,6 +275,8 @@ var XNAT = getObject(XNAT || {}); obj = cloneObject(obj); + obj.load = obj.load || obj.url; + // need a form to put the data into! // and a 'load' property too if (!form || !obj.load) { diff --git a/src/main/webapp/setup/site-setup.yaml b/src/main/webapp/setup/site-setup.yaml index 59957877e9cd97c631e1c6b0dffddab9c044b51d..239e2a19c8e1490e47f843b547bc532636342713 100644 --- a/src/main/webapp/setup/site-setup.yaml +++ b/src/main/webapp/setup/site-setup.yaml @@ -23,10 +23,9 @@ siteSetup: label: Site Information footer: false method: POST - action: /xapi/siteConfig/batch + url: /xapi/siteConfig contentType: json load: XNAT.data.siteConfig - refresh: /xapi/siteConfig contents: siteId: @@ -71,9 +70,8 @@ siteSetup: # header: false # footer: false # method: POST -# action: /xapi/notifications/batchMail +# url: /xapi/notifications # contentType: json -# load: /xapi/notifications # contents: # adminEmail: # tag: input.disabled | disabled, type=hidden, data-value-from=#site-admin-email, name=adminEmail @@ -98,10 +96,8 @@ siteSetup: label: Data Storage footer: false method: POST - action: /xapi/siteConfig/batch + url: /xapi/siteConfig contentType: json - load: XNAT.data.siteConfig - refresh: /xapi/siteConfig contents: archivePath: @@ -160,9 +156,8 @@ siteSetup: label: SMTP Server Settings footer: false method: POST - action: /xapi/notifications/batchMail contentType: json - load: /xapi/notifications + url: /xapi/notifications contents: host: @@ -221,9 +216,8 @@ siteSetup: label: Miscellaneous Settings footer: false method: POST - action: /xapi/siteConfig/batch + url: /xapi/siteConfig contentType: json - load: XNAT.data.siteConfig contents: requireLogin: @@ -248,4 +242,4 @@ siteSetup: id: enableCsrfToken name: enableCsrfToken label: Require CSRF Token? - description: Should this site require the use of a token to prevent CSRF attacks on POST, PUT, and DELETEs? \ No newline at end of file + description: Should this site require the use of a token to prevent CSRF attacks on POST, PUT, and DELETEs?