From 6d4fbb377f6e2e86a2caa6bb3cb14173614f2860 Mon Sep 17 00:00:00 2001 From: ian-xnatworks Date: Tue, 9 Jun 2026 23:45:55 -0400 Subject: [PATCH 1/6] PLUGINS-234 First pass of connection type management system. --- .../components/XsyncSitePreferencesBean.java | 35 +++++- .../xsync/pojo/XsyncSitePreferencesPojo.java | 11 +- .../xapi/XsyncPreferencesController.java | 47 +++++-- .../admin/xsyncConnectionManager.js | 116 ++++++++++++++++++ .../admin/xsyncWhitelistManager.js | 2 +- .../xnat-plugins/xsyncPlugin/xsync-config.js | 22 +++- .../xsync-setupProjectPreference.js | 105 ++++++++++++++++ .../xsync-plugin/project-settings.yaml | 9 +- .../spawner/xsync-plugin/site-settings.yaml | 35 +++++- 9 files changed, 359 insertions(+), 23 deletions(-) create mode 100644 src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncConnectionManager.js create mode 100644 src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-setupProjectPreference.js diff --git a/src/main/java/org/nrg/xsync/components/XsyncSitePreferencesBean.java b/src/main/java/org/nrg/xsync/components/XsyncSitePreferencesBean.java index 1dc783b..2791906 100644 --- a/src/main/java/org/nrg/xsync/components/XsyncSitePreferencesBean.java +++ b/src/main/java/org/nrg/xsync/components/XsyncSitePreferencesBean.java @@ -104,6 +104,31 @@ public void setXsyncWhitelistEnabled(boolean xsyncWhitelistEnabled) { } } + @NrgPreference(defaultValue = "true") + public boolean getHttpsEnabled() { + return getBooleanValue("httpsEnabled"); + } + + public void setHttpsEnabled(boolean httpsEnabled) { + try { + set(String.valueOf(httpsEnabled), "httpsEnabled"); + } catch (InvalidPreferenceName invalidPreferenceName) { + _log.error("Invalid preference name: httpsEnabled"); + } + } + + @NrgPreference(defaultValue = "false") + public boolean getAsperaEnabled() { + return getBooleanValue("asperaEnabled"); + } + + public void setAsperaEnabled(boolean asperaEnabled) { + try { + set(String.valueOf(asperaEnabled), "asperaEnabled"); + } catch (InvalidPreferenceName invalidPreferenceName) { + _log.error("Invalid preference name: asperaEnabled"); + } + } /** * Sets the Max. Total Uncompressed File Size @@ -297,6 +322,12 @@ public void update(final XsyncSitePreferencesPojo xsyncSitePreferencesPojo) thro if (null != xsyncSitePreferencesPojo.getXsyncWhitelistEnabled()) { this.setXsyncWhitelistEnabled(xsyncSitePreferencesPojo.getXsyncWhitelistEnabled()); } + if (null != xsyncSitePreferencesPojo.getHttpsEnabled()) { + this.setHttpsEnabled(xsyncSitePreferencesPojo.getHttpsEnabled()); + } + if (null != xsyncSitePreferencesPojo.getAsperaEnabled()) { + this.setAsperaEnabled(xsyncSitePreferencesPojo.getAsperaEnabled()); + } } public XsyncSitePreferencesPojo toPojo() { @@ -305,7 +336,9 @@ public XsyncSitePreferencesPojo toPojo() { getSyncRetryInterval(), getSyncRetryCount(), getSyncMaxUncompressedZipFileSize(), - getXsyncWhitelistEnabled() + getXsyncWhitelistEnabled(), + getHttpsEnabled(), + getAsperaEnabled() ); } diff --git a/src/main/java/org/nrg/xsync/pojo/XsyncSitePreferencesPojo.java b/src/main/java/org/nrg/xsync/pojo/XsyncSitePreferencesPojo.java index ace49a5..5685faf 100644 --- a/src/main/java/org/nrg/xsync/pojo/XsyncSitePreferencesPojo.java +++ b/src/main/java/org/nrg/xsync/pojo/XsyncSitePreferencesPojo.java @@ -15,17 +15,24 @@ public XsyncSitePreferencesPojo(final String tokenRefreshInterval, final String syncRetryInterval, final String syncRetryCount, final String syncMaxUncompressedZipFileSize, - final Boolean xsyncWhitelistEnabled) { + final Boolean xsyncWhitelistEnabled, + final Boolean httpsEnabled, + final Boolean asperaEnabled) { this.tokenRefreshInterval = tokenRefreshInterval; this.syncRetryInterval = syncRetryInterval; this.syncRetryCount = syncRetryCount; this.syncMaxUncompressedZipFileSize = syncMaxUncompressedZipFileSize; this.xsyncWhitelistEnabled = xsyncWhitelistEnabled; + this.httpsEnabled = httpsEnabled; + this.asperaEnabled = asperaEnabled; + } private String tokenRefreshInterval; private String syncRetryInterval; private String syncRetryCount; private String syncMaxUncompressedZipFileSize; - private Boolean xsyncWhitelistEnabled; + private Boolean xsyncWhitelistEnabled; + private Boolean httpsEnabled; + private Boolean asperaEnabled; } diff --git a/src/main/java/org/nrg/xsync/xapi/XsyncPreferencesController.java b/src/main/java/org/nrg/xsync/xapi/XsyncPreferencesController.java index db0253f..a4440bf 100644 --- a/src/main/java/org/nrg/xsync/xapi/XsyncPreferencesController.java +++ b/src/main/java/org/nrg/xsync/xapi/XsyncPreferencesController.java @@ -45,7 +45,7 @@ */ @XapiRestController -@Api(description = "XSync Preferences API") +@Api("XSync Preferences API") @SuppressWarnings("unused") public class XsyncPreferencesController extends AbstractXapiRestController { @@ -79,7 +79,6 @@ public void setPreferences(@RequestBody XsyncSitePreferencesPojo xsyncSitePrefer * * @return the preferences */ - @SuppressWarnings("deprecation") @XapiRequestMapping(value = "xsyncSitePreferences", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE }, restrictTo = AccessLevel.Admin) @ApiOperation(value = "Gets the XSync site preferences", response = XsyncSitePreferencesPojo.class) @@ -128,6 +127,34 @@ public ResponseEntity getAsperaPreferences() throws NrgServ return new ResponseEntity<>(new AsperaSitePrefsInfo(asperaSitePrefs), HttpStatus.OK); } + @XapiRequestMapping(value = "xsyncProjectPreferences/httpsEnabled", method = + RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + @ApiOperation(value = "Checks whether Https connection is enabled on the site level.") + @ApiResponses({ @ApiResponse(code = 200, message = "Https enabled returned."), + @ApiResponse(code = 500, message = "Unexpected error") }) + public ResponseEntity getHttpsEnabled() { + return new ResponseEntity<>(prefs.getHttpsEnabled(), HttpStatus.OK); + } + + @XapiRequestMapping(value = "xsyncProjectPreferences/asperaEnabled", method = + RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + @ApiOperation(value = "Checks whether Aspera is enabled on the site level.") + @ApiResponses({ @ApiResponse(code = 200, message = "Aspera enabled returned."), + @ApiResponse(code = 500, message = "Unexpected error") }) + public ResponseEntity getAsperaEnabled() { + return new ResponseEntity<>(prefs.getAsperaEnabled(), HttpStatus.OK); + } + + @XapiRequestMapping(value = "xsyncProjectPreferences/project/{projectId}/asperaEnabled", method = + RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE, restrictTo = AccessLevel.Read) + @ApiOperation(value = "Checks whether Aspera is enabled for project.") + @ApiResponses({ @ApiResponse(code = 200, message = "Aspera enabled returned."), + @ApiResponse(code = 500, message = "Unexpected error") }) + public ResponseEntity getProjectAsperaEnabled(@PathVariable("projectId") final String projectId) { + final AsperaProjectPrefsInfo prefsInfo = new AsperaProjectPrefsInfo(asperaProjectPrefs, projectId); + return new ResponseEntity<>(prefsInfo.getAsperaEnabled(), HttpStatus.OK); + } + /** * Sets the preferences. * @@ -150,7 +177,7 @@ public ResponseEntity setAsperaProjectPreferences(@PathVariable("project asperaProjectPrefs.setSshPort(projectId, asperaPrefs.getSshPort()); asperaProjectPrefs.setUdpPort(projectId, asperaPrefs.getUdpPort()); } catch (Exception exception) { - _logger.error("ERROR: Error setting preferences: " + ExceptionUtils.getFullStackTrace(exception)); + _logger.error("ERROR: Error setting preferences: {}", ExceptionUtils.getFullStackTrace(exception)); return new ResponseEntity<>("XSync preferences assignment failed ", HttpStatus.INTERNAL_SERVER_ERROR); } return new ResponseEntity<>("XSync preferences set", HttpStatus.OK); @@ -170,12 +197,12 @@ public ResponseEntity getAsperaProjectPreferences( @PathVariable("projectId") final String projectId) throws NrgServiceException { final AsperaProjectPrefsInfo prefsInfo = new AsperaProjectPrefsInfo(asperaProjectPrefs, projectId); // Get site defaults, if project settings have not been configured - if ((prefsInfo.getAsperaNodeUrl() == null || prefsInfo.getAsperaNodeUrl().length() < 1) - && (prefsInfo.getAsperaNodeUser() == null || prefsInfo.getAsperaNodeUser().length() < 1) - && (asperaSitePrefs.getAsperaNodeUrl() != null || asperaSitePrefs.getAsperaNodeUrl().length() > 0) - && (asperaSitePrefs.getAsperaNodeUser() != null || asperaSitePrefs.getAsperaNodeUser().length() > 0)) { - _logger.warn("WARNING: Project Aspera preferences not found for project " + projectId + - ". Returning site preferences instead for project preference call."); + if ((prefsInfo.getAsperaNodeUrl() == null || prefsInfo.getAsperaNodeUrl().isEmpty()) + && (prefsInfo.getAsperaNodeUser() == null || prefsInfo.getAsperaNodeUser().isEmpty()) + && (asperaSitePrefs.getAsperaNodeUrl() != null || !asperaSitePrefs.getAsperaNodeUrl().isEmpty()) + && (asperaSitePrefs.getAsperaNodeUser() != null || !asperaSitePrefs.getAsperaNodeUser().isEmpty())) { + _logger.warn("WARNING: Project Aspera preferences not found for project {}. " + + "Returning site preferences instead for project preference call.", projectId); prefsInfo.setAsperaEnabled(false); prefsInfo.setAsperaNodeUrl(asperaSitePrefs.getAsperaNodeUrl()); prefsInfo.setAsperaNodeUser(asperaSitePrefs.getAsperaNodeUser()); @@ -190,7 +217,7 @@ public ResponseEntity getAsperaProjectPreferences( } @XapiRequestMapping(value = "xsyncSitePreferences/whitelistSites", method = RequestMethod.GET, produces = { - MediaType.APPLICATION_JSON_VALUE }, restrictTo = AccessLevel.Admin) + MediaType.APPLICATION_JSON_VALUE }, restrictTo = AccessLevel.Read) @ApiOperation(value = "Get the whitelist of sites allowed for syncing") @ApiResponses({ @ApiResponse(code = 200, message = "Xsync whitelist sites retrieved."), @ApiResponse(code = 500, message = "Unexpected error") }) diff --git a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncConnectionManager.js b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncConnectionManager.js new file mode 100644 index 0000000..3b6b8dc --- /dev/null +++ b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncConnectionManager.js @@ -0,0 +1,116 @@ +/* + * web: xsyncConnectionManager.js + * XNAT http://www.xnat.org + * Copyright (c) 2005-2017, Washington University School of Medicine and Howard Hughes Medical Institute + * All Rights Reserved + * + * Released under the Simplified BSD. + */ + +/*! + * Manage the backend connection by which Xsync transfers will be made. + */ + +console.log('xsyncConnectionManager.js'); + +var XNAT = getObject(XNAT || {}); +XNAT.plugin = getObject(XNAT.plugin || {}); +XNAT.plugin.xsync = getObject(XNAT.plugin.xsync || {}); + +(function(factory){ + if (typeof define === 'function' && define.amd) { + define(factory); + } + else if (typeof exports === 'object') { + module.exports = factory(); + } + else { + return factory(); + } +}(function() { + + var restUrl = XNAT.url.restUrl; + var xsyncConnectionManager; + XNAT.plugin.xsync.xsyncConnectionManager = xsyncConnectionManager = getObject(XNAT.plugin.xsync.xsyncConnectionManager || {}); + + $(document).on('change','#https-enabled', function(){ + xsyncConnectionManager.toggleHttpsEnabled($(this).val()); + }); + + $(document).on('change','#aspera-enabled', function(){ + xsyncConnectionManager.toggleAsperaEnabled($(this).val()); + }); + + xsyncConnectionManager.toggleHttpsEnabled = function(enabled) { + let inputPrefs = {}; + if (enabled === "true") { + inputPrefs['httpsEnabled'] = true; + } else { + inputPrefs['httpsEnabled'] = false; + } + + xsyncConnectionManager.postSitePreferencesUpdate(inputPrefs, 'https'); + } + + xsyncConnectionManager.toggleAsperaEnabled = function(enabled) { + let inputPrefs = {}; + if (enabled === "true") { + inputPrefs['asperaEnabled'] = true; + } else { + inputPrefs['asperaEnabled'] = false; + inputPrefs['httpsEnabled'] = true; + } + + xsyncConnectionManager.postSitePreferencesUpdate(inputPrefs, 'aspera'); + if ($('#aspera-enabled').val() === 'false') { + $("#https-enabled").parent().parent().parent().parent().addClass('disabled'); + $("#https-enabled").prop('disabled', true); + } else { + $("#https-enabled").parent().parent().parent().parent().removeClass('disabled'); + $("#https-enabled").prop('disabled', false); + } + } + + xsyncConnectionManager.postSitePreferencesUpdate = function(inputPrefs, preferenceName) { + XNAT.xhr.post({ + url: restUrl('/xapi/xsyncSitePreferences/'), + async: false, + contentType: 'application/json', + data: JSON.stringify(inputPrefs), + success: function () { + console.log('Updated aspera ' + inputPrefs + ' preference.'); + }, + fail: function (e) { + XNAT.ui.banner.top(2000, 'Could not update ' + inputPrefs + ' enabled preference: ' + e.responseText, 'error'); + } + }); + } + + xsyncConnectionManager.init = function() { + XNAT.xhr.get({ + url: restUrl('/xapi/xsyncSitePreferences/'), + async: false, + success: function (data) { + let httpsEnabled = data['httpsEnabled']; + let asperaEnabled = data['asperaEnabled']; + if (httpsEnabled == true) { + $('#https-enabled').prop("checked",true); + } + if (asperaEnabled == true) { + $('#aspera-enabled').prop("checked",true); + } else { + $("#https-enabled").parent().parent().parent().parent().addClass('disabled'); + $("#https-enabled").prop('disabled', true); + } + }, + fail: function (e) { + XNAT.ui.banner.top(2000, 'Could not retrieve connection information: ' + e.responseText, 'error'); + } + }); + } + + $(document).ready(function () { + xsyncConnectionManager.init(); + }) + +})); \ No newline at end of file diff --git a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncWhitelistManager.js b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncWhitelistManager.js index 7a0ad1c..bc7acf4 100644 --- a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncWhitelistManager.js +++ b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncWhitelistManager.js @@ -37,7 +37,7 @@ XNAT.plugin.xsync = getObject(XNAT.plugin.xsync || {}); xsyncWhitelistManager.toggleWhitelistSwitch = function(enabled) { let $whitelistTableDiv = $('div#xsync-whitelist-table'); - let inputPrefs = {} + let inputPrefs = {}; if (enabled === "true") { inputPrefs['xsyncWhitelistEnabled'] = true; $whitelistTableDiv.empty().append(xsyncWhitelistManager.table()); diff --git a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-config.js b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-config.js index 976dd3f..580e18a 100644 --- a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-config.js +++ b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-config.js @@ -65,6 +65,8 @@ if (typeof XSYNC.credentialsConfig === 'undefined') { XSYNC.xsyncConfig.configuration.subject_assessors.sync_type = 'none'; XSYNC.xsyncConfig.configuration.imaging_sessions.sync_type = 'all'; // XSYNC.xsyncConfig.configuration.imaging_sessions.xsi_types.types_list = ['xnat:mrSessionData']; + + XSYNC.xsyncConfig.isAsperaEnabled = false; }; XSYNC.xsyncConfig.initialConfig = function(){ @@ -542,6 +544,16 @@ if (typeof XSYNC.credentialsConfig === 'undefined') { //////////////////// function configPanel() { + XNAT.xhr.get({ + url: restUrl('/xapi/xsyncProjectPreferences/project/' + XNAT.data.context.project + '/asperaEnabled/'), + async: false, + success: function (data) { + XSYNC.xsyncConfig.isAsperaEnabled = data; + }, + fail: function (e) { + XNAT.ui.banner.top(2000, 'Could not retrieve aspera information: ' + e.responseText, 'error'); + } + }); XNAT.xhr.get({ url: restUrl('/xapi/xsyncSitePreferences/'), async: false, @@ -720,9 +732,13 @@ if (typeof XSYNC.credentialsConfig === 'undefined') { /////////////////////////// function aspera() { - return { - tag: "div.message.bold", - content: "NOTICE: Aspera transfers are now supported, if your destination site supports them. Please see project settings, in the actions menu, to configure Aspera settings." + if (XSYNC.xsyncConfig.isAsperaEnabled === true) { + return { + tag: "div.message.bold", + content: "NOTICE: Aspera transfers are now supported, if your destination site supports them. Please see project settings, in the actions menu, to configure Aspera settings." + } + } else { + return ''; } } diff --git a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-setupProjectPreference.js b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-setupProjectPreference.js new file mode 100644 index 0000000..63bf0cc --- /dev/null +++ b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-setupProjectPreference.js @@ -0,0 +1,105 @@ +console.log('xsync-setupProjectPreference.js'); + +var XNAT = getObject(XNAT || {}); +XNAT.plugin = getObject(XNAT.plugin || {}); +XNAT.plugin.xsync = getObject(XNAT.plugin.xsync || {}); + +(function(factory) { + if (typeof define === 'function' && define.amd) { + define(factory); + } + else if (typeof exports === 'object') { + module.exports = factory(); + } + else { + return factory(); + } +}(function() { + var restUrl = XNAT.url.restUrl; + + var xsyncProjectPreferenceManager; + XNAT.plugin.xsync.xsyncProjectPreferenceManager = xsyncProjectPreferenceManager = getObject(XNAT.plugin.xsync.xsyncProjectPreferenceManager || {}); + + $(document).on('change','#aspera-enabled', function(){ + xsyncProjectPreferenceManager.toggleEnabledElements($(this).val()); + }); + + $('#aspera-panel').find('.btn.save').click(function(){ + xsyncProjectPreferenceManager.submitSettings(); + }); + + xsyncProjectPreferenceManager.toggleEnabledElements = function(enabled) { + var $active_pane = $('#aspera-panel'); + + if (enabled === 'true') { + $active_pane.find("input[type='text']").parent().parent().removeClass('hidden'); + } else { + $active_pane.find("input[type='text']").parent().parent().addClass('hidden') + } + } + +// xsyncProjectPreferenceManager.validateSingleField = function(inputField, required, integer) { +// let elementValue = element.val(); +// +// let valid = true +// if (required) { +// if (elementValue.trim()===''){ +// XNAT.app.context.validation+=name + " is a required field.
"; +// valid = false; +// } +// } +// +// if (integer) { +// var temp = elementValue.trim().replace(/\s+/g, ""); +// if (temp !== "" && !Number.isInteger(Number(temp))) { +// XNAT.app.context.validation += name + " must be a valid integer.
"; +// valid = false; +// } +// } +// +// if (elementType === "input") { +// if (valid){ +// element.css("border-color", ""); +// } else{ +// element.css("border-color", "red"); +// } +// } +// +// return elementValue; +// } + +// xsyncProjectPreferenceManager.validateNecessaryFields = function() { +// node_url = xsyncProjectPreferenceManager.validateSingleField($('#aspera-node-url'), true, false); +// node_url = xsyncProjectPreferenceManager.validateSingleField($('#aspera-node-user'), true, false); +// node_url = xsyncProjectPreferenceManager.validateSingleField($('#aspera-node-url'), true, false); +// node_url = xsyncProjectPreferenceManager.validateSingleField($('#aspera-node-url'), true, false); +// } + + xsyncProjectPreferenceManager.submitSettings = function() { +// let isValidPreferences = xsyncProjectPreferenceManager.validateNecessaryFields(); + } + + xsyncProjectPreferenceManager.init = function() { + XNAT.xhr.get({ + url: restUrl('/xapi/xsyncProjectPreferences/project/' + XNAT.data.context.project + '/asperaEnabled/'), + async: false, + success: function (data) { + let enabled = data; + xsyncProjectPreferenceManager.isAsperaEnabled = true; + if (enabled == true) { + $('#aspera-panel').find('.switchbox.panel-switchbox').children("input").prop("checked",true); + } + xsyncProjectPreferenceManager.toggleEnabledElements($('#aspera-enabled').val()); + }, + fail: function (e) { + XNAT.ui.banner.top(2000, 'Could not retrieve aspera information: ' + e.responseText, 'error'); + } + }); + xsyncProjectPreferenceManager.toggleEnabledElements($('#aspera-enabled').val()); + } + + $(document).ready(function () { + xsyncProjectPreferenceManager.init(); + }) + +})); \ No newline at end of file diff --git a/src/main/resources/META-INF/xnat/spawner/xsync-plugin/project-settings.yaml b/src/main/resources/META-INF/xnat/spawner/xsync-plugin/project-settings.yaml index 94753f8..1b277d0 100644 --- a/src/main/resources/META-INF/xnat/spawner/xsync-plugin/project-settings.yaml +++ b/src/main/resources/META-INF/xnat/spawner/xsync-plugin/project-settings.yaml @@ -18,14 +18,13 @@ projectSettings: kind: panel.form name: asperaPanel label: XSync Aspera Settings - method: POST - url: /xapi/xsyncProjectPreferences/project/{{XNAT.data.projectID}}/aspera - contentType: application/json +# method: POST +# url: /xapi/xsyncProjectPreferences/project/{{XNAT.data.projectID}}/aspera +# contentType: application/json contents: asperaEnabled: kind: panel.input.switchbox name: asperaEnabled - value: true label: Enable Aspera Transfers? onText: Enabled offText: Disabled @@ -78,3 +77,5 @@ projectSettings: placeholder: 33001 description: > The remote server's UDP port + asperaSettingsScript: + tag: script|src="~/scripts/xnat-plugins/xsyncPlugin/xsync-setupProjectPreference.js" diff --git a/src/main/resources/META-INF/xnat/spawner/xsync-plugin/site-settings.yaml b/src/main/resources/META-INF/xnat/spawner/xsync-plugin/site-settings.yaml index 6d464f1..b9d61f5 100644 --- a/src/main/resources/META-INF/xnat/spawner/xsync-plugin/site-settings.yaml +++ b/src/main/resources/META-INF/xnat/spawner/xsync-plugin/site-settings.yaml @@ -8,11 +8,42 @@ siteSettings: tabGroups: xsyncConfig: XSync Site Level Configuration contents: + connectionManagement: + kind: tab + label: Connection Management + group: xsyncConfig + active: true + contents: + connectionManagementPanel: + kind: panel.form + name: connectionManagementPanel + label: Connection Management + footer: false + contents: + httpsEnabled: + kind: panel.input.switchbox + name: httpsEnabled + label: Enable HTTPS Transfers? + onText: Enabled + offText: Disabled + description: > + Use HTTPS for transfers? This is the default configuration. To turn off this setting, another method of transfers must be turned on. + asperaEnabled: + kind: panel.input.switchbox + name: asperaEnabled + label: Enable Aspera Transfers? + onText: Enabled + offText: Disabled + description: > + Use Aspera for transfers? This requires a valid Aspera server to receive files. + xsyncConnectionManagerScript: + tag: script|src="~/scripts/xnat-plugins/xsyncPlugin/admin/xsyncConnectionManager.js" + remoteTokenRefresh: kind: tab label: Remote Token group: xsyncConfig - active: true + active: false contents: remoteTokenRefreshPanel: kind: panel.form @@ -133,7 +164,7 @@ siteSettings: settings may be useful if one of your destination sites supports Aspera-based XSync sends and multiple projects will connect to the same Aspera server, as these will become the default settings for project connections. Please note, however, that - XSync Aspera settings must be configured and enabled for each project. + XSync Aspera settings must be configured and enabled for each project. asperaNodeUrl: kind: panel.input.text name: asperaNodeUrl From b87a3639aa2769f37473af42bc318eb8204f1910 Mon Sep 17 00:00:00 2001 From: ian-xnatworks Date: Wed, 10 Jun 2026 00:13:46 -0400 Subject: [PATCH 2/6] Fixing permissions checking. --- .../org/nrg/xsync/xapi/XsyncPreferencesController.java | 9 +++++++++ .../scripts/xnat-plugins/xsyncPlugin/xsync-config.js | 7 +++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/nrg/xsync/xapi/XsyncPreferencesController.java b/src/main/java/org/nrg/xsync/xapi/XsyncPreferencesController.java index a4440bf..e5faa67 100644 --- a/src/main/java/org/nrg/xsync/xapi/XsyncPreferencesController.java +++ b/src/main/java/org/nrg/xsync/xapi/XsyncPreferencesController.java @@ -216,6 +216,15 @@ public ResponseEntity getAsperaProjectPreferences( return new ResponseEntity<>(prefsInfo, HttpStatus.OK); } + @XapiRequestMapping(value = "xsyncProjectPreferences/whitelistEnabled", method = + RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + @ApiOperation(value = "Checks whether site whitelist is enabled on the site level.") + @ApiResponses({ @ApiResponse(code = 200, message = "Site whitelist enabled returned."), + @ApiResponse(code = 500, message = "Unexpected error") }) + public ResponseEntity getWhitelistEnabled() { + return new ResponseEntity<>(prefs.getXsyncWhitelistEnabled(), HttpStatus.OK); + } + @XapiRequestMapping(value = "xsyncSitePreferences/whitelistSites", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE }, restrictTo = AccessLevel.Read) @ApiOperation(value = "Get the whitelist of sites allowed for syncing") diff --git a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-config.js b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-config.js index 580e18a..5a9e1ac 100644 --- a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-config.js +++ b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-config.js @@ -555,12 +555,11 @@ if (typeof XSYNC.credentialsConfig === 'undefined') { } }); XNAT.xhr.get({ - url: restUrl('/xapi/xsyncSitePreferences/'), + url: restUrl('/xapi/xsyncProjectPreferences/whitelistEnabled/'), async: false, success: function (data) { - let enabled = data['xsyncWhitelistEnabled']; - XSYNC.xsyncConfig.isWhitelistEnabledBackend = enabled; - if (enabled == true) { + XSYNC.xsyncConfig.isWhitelistEnabledBackend = data; + if (XSYNC.xsyncConfig.isWhitelistEnabledBackend == true) { XNAT.xhr.get({ url: restUrl('/xapi/xsyncSitePreferences/whitelistSites/'), async: false, From 2bddb55c627258745761671fc5cfb67303193f7f Mon Sep 17 00:00:00 2001 From: ian-xnatworks Date: Wed, 10 Jun 2026 19:51:10 -0400 Subject: [PATCH 3/6] PLUGINS-235 removing aspera references when setting not turned on. --- .../xsync/xapi/XsyncPreferencesController.java | 4 ++-- .../xsyncPlugin/admin/xsyncConnectionManager.js | 2 ++ .../xnat-plugins/xsyncPlugin/xsync-config.js | 17 ++++++++++++++--- .../xsyncPlugin/xsync-setupProjectPreference.js | 15 +++++++++++++++ 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/nrg/xsync/xapi/XsyncPreferencesController.java b/src/main/java/org/nrg/xsync/xapi/XsyncPreferencesController.java index e5faa67..76457f8 100644 --- a/src/main/java/org/nrg/xsync/xapi/XsyncPreferencesController.java +++ b/src/main/java/org/nrg/xsync/xapi/XsyncPreferencesController.java @@ -127,7 +127,7 @@ public ResponseEntity getAsperaPreferences() throws NrgServ return new ResponseEntity<>(new AsperaSitePrefsInfo(asperaSitePrefs), HttpStatus.OK); } - @XapiRequestMapping(value = "xsyncProjectPreferences/httpsEnabled", method = + @XapiRequestMapping(value = "xsyncSitePreferences/httpsEnabled", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) @ApiOperation(value = "Checks whether Https connection is enabled on the site level.") @ApiResponses({ @ApiResponse(code = 200, message = "Https enabled returned."), @@ -136,7 +136,7 @@ public ResponseEntity getHttpsEnabled() { return new ResponseEntity<>(prefs.getHttpsEnabled(), HttpStatus.OK); } - @XapiRequestMapping(value = "xsyncProjectPreferences/asperaEnabled", method = + @XapiRequestMapping(value = "xsyncSitePreferences/asperaEnabled", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) @ApiOperation(value = "Checks whether Aspera is enabled on the site level.") @ApiResponses({ @ApiResponse(code = 200, message = "Aspera enabled returned."), diff --git a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncConnectionManager.js b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncConnectionManager.js index 3b6b8dc..a2cc257 100644 --- a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncConnectionManager.js +++ b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncConnectionManager.js @@ -65,9 +65,11 @@ XNAT.plugin.xsync = getObject(XNAT.plugin.xsync || {}); if ($('#aspera-enabled').val() === 'false') { $("#https-enabled").parent().parent().parent().parent().addClass('disabled'); $("#https-enabled").prop('disabled', true); + $("a[title='Aspera Server Defaults']").parent().addClass('hidden'); } else { $("#https-enabled").parent().parent().parent().parent().removeClass('disabled'); $("#https-enabled").prop('disabled', false); + $("a[title='Aspera Server Defaults']").parent().removeClass('hidden'); } } diff --git a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-config.js b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-config.js index 5a9e1ac..ca5e7a6 100644 --- a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-config.js +++ b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-config.js @@ -66,7 +66,8 @@ if (typeof XSYNC.credentialsConfig === 'undefined') { XSYNC.xsyncConfig.configuration.imaging_sessions.sync_type = 'all'; // XSYNC.xsyncConfig.configuration.imaging_sessions.xsi_types.types_list = ['xnat:mrSessionData']; - XSYNC.xsyncConfig.isAsperaEnabled = false; + XSYNC.xsyncConfig.isProjectAsperaEnabled = false; + XSYNC.xsyncConfig.isSiteWideAsperaEnabled = false; }; XSYNC.xsyncConfig.initialConfig = function(){ @@ -544,11 +545,21 @@ if (typeof XSYNC.credentialsConfig === 'undefined') { //////////////////// function configPanel() { + XNAT.xhr.get({ + url: restUrl('/xapi/xsyncSitePreferences/asperaEnabled/'), + async: false, + success: function (data) { + XSYNC.xsyncConfig.isSiteWideAsperaEnabled = data; + }, + fail: function (e) { + XNAT.ui.banner.top(2000, 'Could not retrieve aspera information: ' + e.responseText, 'error'); + } + }); XNAT.xhr.get({ url: restUrl('/xapi/xsyncProjectPreferences/project/' + XNAT.data.context.project + '/asperaEnabled/'), async: false, success: function (data) { - XSYNC.xsyncConfig.isAsperaEnabled = data; + XSYNC.xsyncConfig.isProjectAsperaEnabled = data; }, fail: function (e) { XNAT.ui.banner.top(2000, 'Could not retrieve aspera information: ' + e.responseText, 'error'); @@ -731,7 +742,7 @@ if (typeof XSYNC.credentialsConfig === 'undefined') { /////////////////////////// function aspera() { - if (XSYNC.xsyncConfig.isAsperaEnabled === true) { + if (XSYNC.xsyncConfig.isProjectAsperaEnabled === true && XSYNC.xsyncConfig.isSiteWideAsperaEnabled) { return { tag: "div.message.bold", content: "NOTICE: Aspera transfers are now supported, if your destination site supports them. Please see project settings, in the actions menu, to configure Aspera settings." diff --git a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-setupProjectPreference.js b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-setupProjectPreference.js index 63bf0cc..396e40e 100644 --- a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-setupProjectPreference.js +++ b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-setupProjectPreference.js @@ -80,6 +80,21 @@ XNAT.plugin.xsync = getObject(XNAT.plugin.xsync || {}); } xsyncProjectPreferenceManager.init = function() { + XNAT.xhr.get({ + url: restUrl('/xapi/xsyncSitePreferences/asperaEnabled/'), + async: false, + success: function (data) { + xsyncProjectPreferenceManager.siteWideAsperaEnabled = data; + if (xsyncProjectPreferenceManager.siteWideAsperaEnabled == true) { + $("#xsync-config").removeClass('hidden'); + } else { + $("#xsync-config").addClass('hidden'); + } + }, + fail: function (e) { + XNAT.ui.banner.top(2000, 'Could not retrieve aspera information: ' + e.responseText, 'error'); + } + }); XNAT.xhr.get({ url: restUrl('/xapi/xsyncProjectPreferences/project/' + XNAT.data.context.project + '/asperaEnabled/'), async: false, From 0243a4941328f6e3ecbea0cf4cdbf4267a02b622 Mon Sep 17 00:00:00 2001 From: ian-xnatworks Date: Wed, 10 Jun 2026 21:19:12 -0400 Subject: [PATCH 4/6] Fixed a couple of minor bugs. --- .../xnat-plugins/xsyncPlugin/admin/xsyncConnectionManager.js | 5 +++-- .../xnat-plugins/xsyncPlugin/admin/xsyncWhitelistManager.js | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncConnectionManager.js b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncConnectionManager.js index a2cc257..d98675e 100644 --- a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncConnectionManager.js +++ b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncConnectionManager.js @@ -80,10 +80,11 @@ XNAT.plugin.xsync = getObject(XNAT.plugin.xsync || {}); contentType: 'application/json', data: JSON.stringify(inputPrefs), success: function () { - console.log('Updated aspera ' + inputPrefs + ' preference.'); + console.log('Updated ' + preferenceName + ' preference.'); + XNAT.ui.banner.top(2000, 'Updated ' + preferenceName + ' enabled preference.', 'success'); }, fail: function (e) { - XNAT.ui.banner.top(2000, 'Could not update ' + inputPrefs + ' enabled preference: ' + e.responseText, 'error'); + XNAT.ui.banner.top(2000, 'Could not update ' + preferenceName + ' enabled preference: ' + e.responseText, 'error'); } }); } diff --git a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncWhitelistManager.js b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncWhitelistManager.js index bc7acf4..af2a3ed 100644 --- a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncWhitelistManager.js +++ b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncWhitelistManager.js @@ -126,7 +126,7 @@ XNAT.plugin.xsync = getObject(XNAT.plugin.xsync || {}); form.id = 'form'; form.appendChild(spawn('div|class="warning"',{'style': {visibility: 'hidden'}, 'id': 'warning'})); - form.appendChild(createInputElement('Site Id', 'site_id_input', item.id, 'text', 'The unique identifier for the site.')); + form.appendChild(createInputElement('Site Id', 'site_id_input', item.siteId, 'text', 'The unique identifier for the site.')); form.appendChild(createInputElement('Site Name', 'site_name_input', item.siteName, 'text', 'The name given to the site so that it is clearly identifiable to users.')); form.appendChild(createInputElement('Site Url', 'site_url_input', item.siteUrl, 'text', 'The url of the site.')); let options = ['CLINICAL', 'RESEARCH', 'PUBLIC'] From 57609d73dff47bf5dd555fa221756dc951aa0121 Mon Sep 17 00:00:00 2001 From: ian-xnatworks Date: Thu, 11 Jun 2026 13:12:07 -0400 Subject: [PATCH 5/6] Re-adding Aspera setup and integrating with new system. --- .../xsync-setupProjectPreference.js | 45 ------------------- .../xsync-plugin/project-settings.yaml | 6 +-- 2 files changed, 3 insertions(+), 48 deletions(-) diff --git a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-setupProjectPreference.js b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-setupProjectPreference.js index 396e40e..e856568 100644 --- a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-setupProjectPreference.js +++ b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/xsync-setupProjectPreference.js @@ -24,10 +24,6 @@ XNAT.plugin.xsync = getObject(XNAT.plugin.xsync || {}); xsyncProjectPreferenceManager.toggleEnabledElements($(this).val()); }); - $('#aspera-panel').find('.btn.save').click(function(){ - xsyncProjectPreferenceManager.submitSettings(); - }); - xsyncProjectPreferenceManager.toggleEnabledElements = function(enabled) { var $active_pane = $('#aspera-panel'); @@ -38,47 +34,6 @@ XNAT.plugin.xsync = getObject(XNAT.plugin.xsync || {}); } } -// xsyncProjectPreferenceManager.validateSingleField = function(inputField, required, integer) { -// let elementValue = element.val(); -// -// let valid = true -// if (required) { -// if (elementValue.trim()===''){ -// XNAT.app.context.validation+=name + " is a required field.
"; -// valid = false; -// } -// } -// -// if (integer) { -// var temp = elementValue.trim().replace(/\s+/g, ""); -// if (temp !== "" && !Number.isInteger(Number(temp))) { -// XNAT.app.context.validation += name + " must be a valid integer.
"; -// valid = false; -// } -// } -// -// if (elementType === "input") { -// if (valid){ -// element.css("border-color", ""); -// } else{ -// element.css("border-color", "red"); -// } -// } -// -// return elementValue; -// } - -// xsyncProjectPreferenceManager.validateNecessaryFields = function() { -// node_url = xsyncProjectPreferenceManager.validateSingleField($('#aspera-node-url'), true, false); -// node_url = xsyncProjectPreferenceManager.validateSingleField($('#aspera-node-user'), true, false); -// node_url = xsyncProjectPreferenceManager.validateSingleField($('#aspera-node-url'), true, false); -// node_url = xsyncProjectPreferenceManager.validateSingleField($('#aspera-node-url'), true, false); -// } - - xsyncProjectPreferenceManager.submitSettings = function() { -// let isValidPreferences = xsyncProjectPreferenceManager.validateNecessaryFields(); - } - xsyncProjectPreferenceManager.init = function() { XNAT.xhr.get({ url: restUrl('/xapi/xsyncSitePreferences/asperaEnabled/'), diff --git a/src/main/resources/META-INF/xnat/spawner/xsync-plugin/project-settings.yaml b/src/main/resources/META-INF/xnat/spawner/xsync-plugin/project-settings.yaml index 1b277d0..26d1aa4 100644 --- a/src/main/resources/META-INF/xnat/spawner/xsync-plugin/project-settings.yaml +++ b/src/main/resources/META-INF/xnat/spawner/xsync-plugin/project-settings.yaml @@ -18,9 +18,9 @@ projectSettings: kind: panel.form name: asperaPanel label: XSync Aspera Settings -# method: POST -# url: /xapi/xsyncProjectPreferences/project/{{XNAT.data.projectID}}/aspera -# contentType: application/json + method: POST + url: /xapi/xsyncProjectPreferences/project/{{XNAT.data.projectID}}/aspera + contentType: application/json contents: asperaEnabled: kind: panel.input.switchbox From bdbdcfb33a384f3a8a5a7ceaff4162fa701e030f Mon Sep 17 00:00:00 2001 From: ian-xnatworks Date: Thu, 11 Jun 2026 13:20:32 -0400 Subject: [PATCH 6/6] Fixing small issue with removing site defaults tab when aspera turned off. --- .../xnat-plugins/xsyncPlugin/admin/xsyncConnectionManager.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncConnectionManager.js b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncConnectionManager.js index d98675e..a9b2d7b 100644 --- a/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncConnectionManager.js +++ b/src/main/resources/META-INF/resources/scripts/xnat-plugins/xsyncPlugin/admin/xsyncConnectionManager.js @@ -104,6 +104,7 @@ XNAT.plugin.xsync = getObject(XNAT.plugin.xsync || {}); } else { $("#https-enabled").parent().parent().parent().parent().addClass('disabled'); $("#https-enabled").prop('disabled', true); + $("a[title='Aspera Server Defaults']").parent().addClass('hidden'); } }, fail: function (e) {