diff --git a/VERSION b/VERSION index 143e8c0..5077e63 100644 --- a/VERSION +++ b/VERSION @@ -5,6 +5,6 @@ # tags with and without build number so operators use the versioned # tag but we always keep a timestamped tag in case a semantic tag gets # replaced accidentally -VER=0.3.0 +VER=0.3.1 TAGS="${VER} ${VER}-$(date -u +"%Y%m%dT%H%M%S")" unset VER diff --git a/build.gradle b/build.gradle index ba25743..756c1ee 100644 --- a/build.gradle +++ b/build.gradle @@ -7,10 +7,13 @@ plugins { // IntelliJ IDEA plugin here to allow integration tests to appear properly in IDEs. id 'idea' + + id 'com.diffplug.spotless' version '6.25.0' + id 'jacoco' } node { - version = '18.18.0' + version = '22.11.0' } repositories { @@ -18,7 +21,6 @@ repositories { mavenCentral() } - dependencies { implementation 'com.opencsv:opencsv:[5.1,6.0)' implementation 'commons-net:commons-net:3.9.0' @@ -53,7 +55,8 @@ war { archiveName 'science-portal.war' } -task buildReactApp(type: NodeTask, dependsOn: 'npmInstall') { +tasks.register('buildReactApp', NodeTask) { + dependsOn 'npmInstall' script = project.file('node_modules/webpack/bin/webpack.js') args = [ '--mode', 'development', diff --git a/public/dev/js/science_portal.js b/public/dev/js/science_portal.js index 62f0370..017f8c6 100644 --- a/public/dev/js/science_portal.js +++ b/public/dev/js/science_portal.js @@ -399,12 +399,21 @@ event.preventDefault() portalCore.clearAjaxAlert(portalCore.pageSections.form) - const _prunedFormData = new FormData(); + const _prunedFormData = new FormData() + const form = event.target - for (let i= 0; i < event.target.length; i++) { - const currentValue = event.target[i]; + for (const currentValue of form) { _prunedFormData.append(currentValue.name, currentValue.value) - console.log(currentValue.name + ": " + currentValue.value) + } + + // This is sent from the Private (Advanced) form + const repositoryHostFieldName = "repositoryHost" + if (_prunedFormData.has(repositoryHostFieldName)) { + const repositoryHost = _prunedFormData.get(repositoryHostFieldName) + const image = `${repositoryHost}/${_prunedFormData.get("image")}` + + _prunedFormData.delete(repositoryHostFieldName) + _prunedFormData.set("image", image) } portalCore.setPageState(portalCore.pageSections.form, "primary", true, '') @@ -454,12 +463,12 @@ request.open("POST", serviceURL) // Request headers can only be set after the request is open. - const secretFieldName = "registryAuthSecret" - const secretHeader = "x-registry-secret" - const usernameHeader = "x-registry-username" + const secretFieldName = "repositoryAuthSecret" + const secretHeader = "x-repository-secret" + const usernameHeader = "x-repository-username" if (sessionData.has(secretFieldName)) { const secret = sessionData.get(secretFieldName) - const username = sessionData.get("registryAuthUsername") + const username = sessionData.get("repositoryAuthUsername") if (secret) { request.setRequestHeader(secretHeader, secret) } diff --git a/public/dev/js/science_portal_core.js b/public/dev/js/science_portal_core.js index 50f6808..34c646c 100644 --- a/public/dev/js/science_portal_core.js +++ b/public/dev/js/science_portal_core.js @@ -20,7 +20,8 @@ userInfoEndpoint: '/science-portal/userinfo', sessionEndpoint: '/science-portal/session', imageEndpoint: '/science-portal/image', - contextEndpoint: '/science-portal/context' + contextEndpoint: '/science-portal/context', + repositoryEndpoint: '/science-portal/repository', } } } @@ -287,6 +288,7 @@ "base": baseURL, "session": `${baseURL}${cadc.web.science.portal.core.sessionEndpoint}`, "context": `${baseURL}${cadc.web.science.portal.core.contextEndpoint}`, + "repositoryHosts": `${baseURL}${cadc.web.science.portal.core.repositoryEndpoint}`, "images": `${baseURL}${cadc.web.science.portal.core.imageEndpoint}` } diff --git a/public/dev/js/science_portal_form.js b/public/dev/js/science_portal_form.js index 52eebc6..ed00e58 100644 --- a/public/dev/js/science_portal_form.js +++ b/public/dev/js/science_portal_form.js @@ -15,6 +15,8 @@ onLoadFormDataError: new jQuery.Event('sciPort:onLoadFormDataError'), onLoadImageDataDone: new jQuery.Event('sciPort:onLoadImageDataDone'), onLoadImageDataError: new jQuery.Event('sciPort:onLoadImageDataError'), + onLoadRepositoryHostsDone: new jQuery.Event('sciPort:onLoadRepositoryHostsDone'), + onLoadRepositoryHostsError: new jQuery.Event('sciPort:onLoadRepositoryHostsError'), onLoadContextDataDone: new jQuery.Event('sciPort:onLoadContextDataDone'), onLoadContextDataError: new jQuery.Event('sciPort:onLoadContextDataError'), } @@ -36,10 +38,11 @@ this._imageData = [] this._contextData = {} this._sessionTypeList = null + this._repositoryHosts = [] this._sessionTypeMap = {} // Used to determine when all the data is collected from the form - // 1 - call for context informtaion + // 1 - call for context information // 2 - n: for calls to get image lists for each type this._ajaxCallCount = 0 @@ -74,13 +77,16 @@ // Set up counter for ajax calls used to load page data // context + image list - _selfPortalForm._ajaxCallCount = 2; + _selfPortalForm._ajaxCallCount = 3; // Start loading context data _selfPortalForm.getContextData() // Start loading container image lists _selfPortalForm.getFullImageList() + + // Obtain the configured repository hosts + _selfPortalForm.getRepositoryHosts() } @@ -191,28 +197,40 @@ } } + function getRepositoryHosts() { + const fullListURL = _selfPortalForm.sessionURLs.repositoryHosts; + Promise.resolve(_getAjaxData(fullListURL)) + .then(function (repositoryHostArray) { + _selfPortalForm._repositoryHosts = _selfPortalForm._repositoryHosts.concat(repositoryHostArray) + _selfPortalForm._ajaxCallCount-- + if (_selfPortalForm._ajaxCallCount === 0) { + trigger(_selfPortalForm, cadc.web.science.portal.form.events.onLoadFormDataDone) + } + }) + .catch(function (message) { + trigger(_selfPortalForm, cadc.web.science.portal.form.events.onLoadRepositoryHostsError, message) + }) + } + function getFormDataForType(sessionType, sessionName) { - var _formData = {} - _formData.contextData = _selfPortalForm._contextData - _formData.imageList= _selfPortalForm.getImageListForType(sessionType) - _formData.types = _selfPortalForm._sessionTypeList - _formData.selectedType = sessionType - _formData.sessionName = sessionName + const _formData = { + contextData: _selfPortalForm._contextData, + imageList: _selfPortalForm.getImageListForType(sessionType), + repositoryHosts: _selfPortalForm._repositoryHosts, + types: _selfPortalForm._sessionTypeList, + selectedType: sessionType, + sessionName: sessionName + } - var tmpMapEntry = _selfPortalForm.getMapEntry(sessionType) + const tmpMapEntry = _selfPortalForm.getMapEntry(sessionType) // Translate list of allowed fields into booleans for variable fields // ie: showRAM and showCores - var showcores = false - if (tmpMapEntry.form_fields.includes("cores")) { - showcores = true - } - var showram = false - if (tmpMapEntry.form_fields.includes("memory")) { - showram = true - } - _formData.formFields = {"showCores": showcores, "showRAM": showram} + const showCores = tmpMapEntry.form_fields.includes("cores") + const showRAM = tmpMapEntry.form_fields.includes("memory") + + _formData.formFields = {"showCores": showCores, "showRAM": showRAM} return _formData } @@ -338,6 +356,7 @@ getCoresArray: getCoresArray, getCoresDefault: getCoresDefault, getFullImageList: getFullImageList, + getRepositoryHosts: getRepositoryHosts, getImageListForType: getImageListForType, getSessionTypeDefault: getSessionTypeDefault, getSessionTypeList: getSessionTypeList, diff --git a/src/main/java/org/opencadc/scienceportal/ApplicationConfiguration.java b/src/main/java/org/opencadc/scienceportal/ApplicationConfiguration.java index 14ed83b..aa38de0 100644 --- a/src/main/java/org/opencadc/scienceportal/ApplicationConfiguration.java +++ b/src/main/java/org/opencadc/scienceportal/ApplicationConfiguration.java @@ -6,28 +6,26 @@ import ca.nrc.cadc.reg.client.LocalAuthority; import ca.nrc.cadc.reg.client.RegistryClient; import ca.nrc.cadc.util.StringUtil; - -import java.io.IOException; -import java.net.URI; -import java.net.URL; -import java.util.Arrays; -import java.util.Date; - -import java.util.NoSuchElementException; -import java.util.Set; import org.apache.commons.configuration2.CombinedConfiguration; import org.apache.commons.configuration2.Configuration; import org.apache.commons.configuration2.PropertiesConfiguration; import org.apache.commons.configuration2.SystemConfiguration; import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder; import org.apache.commons.configuration2.builder.fluent.Parameters; -import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler; import org.apache.commons.configuration2.ex.ConfigurationException; import org.apache.commons.configuration2.tree.MergeCombiner; import org.apache.log4j.Logger; import org.json.JSONObject; import org.opencadc.token.Client; +import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.util.Arrays; +import java.util.Date; +import java.util.NoSuchElementException; +import java.util.Set; + public class ApplicationConfiguration { @@ -35,12 +33,9 @@ public class ApplicationConfiguration { public static final long BUILD_TIME_MS = new Date().getTime(); public static final String FIRST_PARTY_COOKIE_NAME = "__Host-science-portal-auth"; - - private static final Logger LOGGER = Logger.getLogger(ApplicationConfiguration.class); - public static final String DEFAULT_CONFIG_FILE_PATH = System.getProperty("user.home") - + "/config/org.opencadc.science-portal.properties"; - + + "/config/org.opencadc.science-portal.properties"; + private static final Logger LOGGER = Logger.getLogger(ApplicationConfiguration.class); private final Configuration configuration; private final String filePath; @@ -55,7 +50,8 @@ public ApplicationConfiguration() { final Parameters parameters = new Parameters(); final FileBasedConfigurationBuilder builder = - new FileBasedConfigurationBuilder<>(PropertiesConfiguration.class).configure(parameters.properties().setFileName(filePath)); + new FileBasedConfigurationBuilder<>(PropertiesConfiguration.class).configure( + parameters.properties().setFileName(filePath)); try { combinedConfiguration.addConfiguration(builder.getConfiguration()); @@ -89,6 +85,7 @@ public String getTokenCacheURLString() { /** * Expected that the configuration is a forward slash list of tab labels. * Apache Configuration reference + * * @return String array, never null. */ public String[] getTabLabels() { @@ -104,7 +101,8 @@ public String[] getTabLabels() { /** * Pull the /applications header URLs. - * @return JSONObject of header URIs to URLs. + * + * @return JSONObject of header URIs to URLs. */ public JSONObject getHeaderURLs() { final RegistryClient registryClient = new RegistryClient(); @@ -143,7 +141,7 @@ String getStringValue(final String key, final boolean required) { if (required && !StringUtil.hasText(val)) { throw new IllegalStateException("Configuration property " + key + " is missing or invalid at " - + this.filePath); + + this.filePath); } else { return val; } @@ -175,8 +173,8 @@ public String getOIDCScope() { public boolean isOIDCConfigured() { return StringUtil.hasText(getOIDCClientID()) && StringUtil.hasText(getOIDCClientSecret()) - && StringUtil.hasText(getOIDCCallbackURI()) && StringUtil.hasText(getOIDCScope()) - && StringUtil.hasText(getTokenCacheURLString()); + && StringUtil.hasText(getOIDCCallbackURI()) && StringUtil.hasText(getOIDCScope()) + && StringUtil.hasText(getTokenCacheURLString()); } public Client getOIDCClient() throws IOException { diff --git a/src/main/java/org/opencadc/scienceportal/repository/GetAction.java b/src/main/java/org/opencadc/scienceportal/repository/GetAction.java new file mode 100644 index 0000000..de9ef79 --- /dev/null +++ b/src/main/java/org/opencadc/scienceportal/repository/GetAction.java @@ -0,0 +1,95 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2023. (c) 2023. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package org.opencadc.scienceportal.repository; + +import ca.nrc.cadc.auth.AuthMethod; +import ca.nrc.cadc.reg.Standards; +import ca.nrc.cadc.reg.client.RegistryClient; +import org.opencadc.scienceportal.ApplicationConfiguration; +import org.opencadc.scienceportal.SciencePortalAuthGetAction; + +import java.net.URI; +import java.net.URL; + +public class GetAction extends SciencePortalAuthGetAction { + private static final String REGISTRY_ENDPOINT = "/repository"; + + @Override + protected String getEndpoint() { + return GetAction.REGISTRY_ENDPOINT; + } + + @Override + protected URL getAPIURL() { + final ApplicationConfiguration applicationConfiguration = new ApplicationConfiguration(); + final URI apiServiceURI = URI.create(applicationConfiguration.getResourceID()); + final RegistryClient registryClient = new RegistryClient(); + return registryClient.getServiceURL(apiServiceURI, Standards.PROC_SESSIONS_10, AuthMethod.TOKEN); + } +} diff --git a/src/main/java/org/opencadc/scienceportal/session/PostAction.java b/src/main/java/org/opencadc/scienceportal/session/PostAction.java index 2a79067..e914e40 100644 --- a/src/main/java/org/opencadc/scienceportal/session/PostAction.java +++ b/src/main/java/org/opencadc/scienceportal/session/PostAction.java @@ -75,6 +75,10 @@ import ca.nrc.cadc.rest.SyncInput; import ca.nrc.cadc.util.Base64; import ca.nrc.cadc.util.StringUtil; +import org.opencadc.scienceportal.ApplicationConfiguration; +import org.opencadc.scienceportal.SciencePortalAuthAction; + +import javax.security.auth.Subject; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -88,15 +92,12 @@ import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; -import javax.security.auth.Subject; -import org.opencadc.scienceportal.ApplicationConfiguration; -import org.opencadc.scienceportal.SciencePortalAuthAction; public class PostAction extends SciencePortalAuthAction { - private static final String SESSION_ENDPOINT = "/session"; static final String SECRET_REQUEST_HEADER_NAME_TO_SKAHA = "x-skaha-registry-auth"; - static final String REGISTRY_AUTH_SECRET_FROM_BROWSER = "x-registry-secret"; - static final String REGISTRY_AUTH_USERNAME_FROM_BROWSER = "x-registry-username"; + static final String REPOSITORY_AUTH_SECRET_FROM_BROWSER = "x-repository-secret"; + static final String REPOSITORY_AUTH_USERNAME_FROM_BROWSER = "x-repository-username"; + private static final String SESSION_ENDPOINT = "/session"; PostAction(final SyncInput syncInput) { this.syncInput = syncInput; @@ -130,21 +131,23 @@ public void doAction() throws Exception { HttpPost createPostRequest(final URL apiURL) { final Map payload = new HashMap<>(); payload.putAll(syncInput.getParameterNames().stream() - .collect(Collectors.toMap(key -> key, key -> syncInput.getParameter(key) == null ? "" : syncInput.getParameter(key).trim()))); + .collect(Collectors.toMap(key -> key, + key -> syncInput.getParameter(key) == null + ? "" : syncInput.getParameter(key).trim()))); final HttpPost httpPost = new HttpPost(apiURL, payload, false); - final String registrySecret = syncInput.getHeader(PostAction.REGISTRY_AUTH_SECRET_FROM_BROWSER); - final String registryUsername = syncInput.getHeader(PostAction.REGISTRY_AUTH_USERNAME_FROM_BROWSER); + final String repositorySecret = syncInput.getHeader(PostAction.REPOSITORY_AUTH_SECRET_FROM_BROWSER); + final String repositoryUsername = syncInput.getHeader(PostAction.REPOSITORY_AUTH_USERNAME_FROM_BROWSER); - if (StringUtil.hasText(registrySecret)) { - if (StringUtil.hasText(registryUsername)) { + if (StringUtil.hasText(repositorySecret)) { + if (StringUtil.hasText(repositoryUsername)) { httpPost.setRequestProperty(PostAction.SECRET_REQUEST_HEADER_NAME_TO_SKAHA, - Base64.encodeString(registryUsername + ":" + registrySecret)); + Base64.encodeString(repositoryUsername + ":" + repositorySecret)); } else { throw new IllegalArgumentException("Secret specified but no username provided."); } - } else if (StringUtil.hasText(registryUsername)) { + } else if (StringUtil.hasText(repositoryUsername)) { throw new IllegalArgumentException("Username specified but no secret provided."); } diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 94a88c8..9a2377e 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -4,158 +4,162 @@ xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> - Science Portal Web Application - Science Portal Web Application - - - - - - - - - - - - - logControl - ca.nrc.cadc.log.LogControlServlet - - logLevel - info - - - logLevelPackages - - org.opencadc.skaha - ca.nrc.cadc.util - ca.nrc.cadc.rest - ca.nrc.cadc.net - - - - logAccessGroup - ivo://cadc.nrc.ca/gms?CADC - - - groupAuthorizer - ca.nrc.cadc.ac.client.GroupAuthorizer - - 1 - - - - OIDCCallbackServlet - ca.nrc.cadc.rest.RestServlet - - get - org.opencadc.scienceportal.oidc.callback.GetAction - - - - - OIDCLoginServlet - ca.nrc.cadc.rest.RestServlet - - get - org.opencadc.scienceportal.oidc.login.GetAction - - - - - UserInfoServlet - ca.nrc.cadc.rest.RestServlet - - get - org.opencadc.scienceportal.userinfo.GetAction - - - - - SessionServlet - ca.nrc.cadc.rest.RestServlet - - get - org.opencadc.scienceportal.session.GetAction - - - post - org.opencadc.scienceportal.session.PostAction - - - delete - org.opencadc.scienceportal.session.DeleteAction - - - - - ImageServlet - ca.nrc.cadc.rest.RestServlet - - get - org.opencadc.scienceportal.image.GetAction - - - - - ContextServlet - ca.nrc.cadc.rest.RestServlet - - get - org.opencadc.scienceportal.context.GetAction - - - - - - logControl - /logControl - - - - OIDCCallbackServlet - /oidc-callback - - - - OIDCLoginServlet - /oidc-login - - - - UserInfoServlet - /userinfo - - - - SessionServlet - /session/* - - - - ImageServlet - /image - - - - ContextServlet - /context/* - - - - - http://java.sun.com/jsp/jstl/core - /tags/c.tld - - - - http://java.sun.com/jsp/jstl/functions - /tags/fn.tld - - - - - index.jsp - + Science Portal Web Application + Science Portal Web Application + + + logControl + ca.nrc.cadc.log.LogControlServlet + + logLevel + info + + + logLevelPackages + + org.opencadc.skaha + ca.nrc.cadc.util + ca.nrc.cadc.rest + ca.nrc.cadc.net + + + + logAccessGroup + ivo://cadc.nrc.ca/gms?CADC + + + groupAuthorizer + ca.nrc.cadc.ac.client.GroupAuthorizer + + 1 + + + + OIDCCallbackServlet + ca.nrc.cadc.rest.RestServlet + + get + org.opencadc.scienceportal.oidc.callback.GetAction + + + + + OIDCLoginServlet + ca.nrc.cadc.rest.RestServlet + + get + org.opencadc.scienceportal.oidc.login.GetAction + + + + + UserInfoServlet + ca.nrc.cadc.rest.RestServlet + + get + org.opencadc.scienceportal.userinfo.GetAction + + + + + SessionServlet + ca.nrc.cadc.rest.RestServlet + + get + org.opencadc.scienceportal.session.GetAction + + + post + org.opencadc.scienceportal.session.PostAction + + + delete + org.opencadc.scienceportal.session.DeleteAction + + + + + ImageServlet + ca.nrc.cadc.rest.RestServlet + + get + org.opencadc.scienceportal.image.GetAction + + + + + ImageRepositoryServlet + ca.nrc.cadc.rest.RestServlet + + get + org.opencadc.scienceportal.repository.GetAction + + + + + ContextServlet + ca.nrc.cadc.rest.RestServlet + + get + org.opencadc.scienceportal.context.GetAction + + + + + + logControl + /logControl + + + + OIDCCallbackServlet + /oidc-callback + + + + OIDCLoginServlet + /oidc-login + + + + UserInfoServlet + /userinfo + + + + SessionServlet + /session/* + + + + ImageServlet + /image + + + + ImageRepositoryServlet + /repository + + + + ContextServlet + /context/* + + + + + http://java.sun.com/jsp/jstl/core + /tags/c.tld + + + + http://java.sun.com/jsp/jstl/functions + /tags/fn.tld + + + + + index.jsp + \ No newline at end of file diff --git a/src/react/SciencePortalPrivateForm.js b/src/react/SciencePortalPrivateForm.js index 253754c..019dffb 100644 --- a/src/react/SciencePortalPrivateForm.js +++ b/src/react/SciencePortalPrivateForm.js @@ -18,22 +18,26 @@ class SciencePortalPrivateForm extends React.Component { super(props) this.selectedRAM = "" this.selectedCores = "" - this.registryUsername = props.authenticatedUsername && props.authenticatedUsername !== "Login" ? props.authenticatedUsername : "" + this.repositoryUsername = props.authenticatedUsername && props.authenticatedUsername !== "Login" ? props.authenticatedUsername : "" if (typeof props.fData.contextData !== "undefined") { this.selectedRAM = props.fData.contextData.defaultRAM this.selectedCores = props.fData.contextData.defaultCores } + + const repositoryHostArray = props.fData.repositoryHosts + this.state = { - fData:props.fData, + fData: props.fData, selectedRAM: this.selectedRAM, selectedCores: this.selectedCores, - registryUsername: this.registryUsername + repositoryUsername: this.repositoryUsername, + repositoryHost: (repositoryHostArray && repositoryHostArray.length > 0) ? repositoryHostArray[0] : "" } this.handleChange = this.handleChange.bind(this); this.resetForm = this.resetForm.bind(this); this.handleImageChange = this.handleImageChange.bind(this); - this.handleRegistrySecretChange = this.handleRegistrySecretChange.bind(this); - this.handleRegistryUsernameChange = this.handleRegistryUsernameChange.bind(this); + this.handleRepositorySecretChange = this.handleRepositorySecretChange.bind(this); + this.handleRepositoryUsernameChange = this.handleRepositoryUsernameChange.bind(this); } handleChange(event) { @@ -51,15 +55,15 @@ class SciencePortalPrivateForm extends React.Component { }) } - handleRegistryUsernameChange(event) { + handleRepositoryUsernameChange(event) { this.setState({ - registryUsername: event.target.value + repositoryUsername: event.target.value }) } - handleRegistrySecretChange(event) { + handleRepositorySecretChange(event) { this.setState({ - registrySecret: event.target.value + repositorySecret: event.target.value }) } @@ -77,11 +81,13 @@ class SciencePortalPrivateForm extends React.Component { resetForm(event) { event.stopPropagation(); + const formProps = this.props; this.setState({ selectedCores : this.state.fData.contextData.defaultCores, selectedRAM : this.state.fData.contextData.defaultRAM, - registryUsername: props.authenticatedUsername && props.authenticatedUsername !== "Login" ? props.authenticatedUsername : "" + repositoryUsername: formProps.authenticatedUsername && formProps.authenticatedUsername !== "Login" + ? formProps.authenticatedUsername : "" }); this.state.fData.resetHandler(); } @@ -155,6 +161,24 @@ class SciencePortalPrivateForm extends React.Component { } } + const repositoryHostComponent = this.state.fData.repositoryHosts.length > 1 + ? + {this.state.fData.repositoryHosts?.map(mapObj => ( + + ))} + + : + return ( <> {Object.keys(this.state.fData).length !== 0 && @@ -170,10 +194,13 @@ class SciencePortalPrivateForm extends React.Component { {this.renderPopover("Container Image","The full Docker image URI for the session.")} - + + {repositoryHostComponent} + + - registry username - {this.renderPopover("Image registry username","The username for authenticated access to the Image Registry.")} + repository username + {this.renderPopover("Image repository username","The username for authenticated access to the Image Repository.")} - registry secret - {this.renderPopover("Image registry secret","The secret for authenticated access to the Image Registry.")} + repository secret + {this.renderPopover("Image repository secret","The secret for authenticated access to the Image Repository.")} @@ -224,7 +251,7 @@ class SciencePortalPrivateForm extends React.Component { type - {this.renderPopover("Session Type", "Select from the list of supported session types")} + {this.renderPopover("Session Type", "Pick from the list of supported session types")} diff --git a/src/test/java/org/opencadc/scienceportal/session/PostActionTest.java b/src/test/java/org/opencadc/scienceportal/session/PostActionTest.java index 9e5d579..072edd7 100644 --- a/src/test/java/org/opencadc/scienceportal/session/PostActionTest.java +++ b/src/test/java/org/opencadc/scienceportal/session/PostActionTest.java @@ -4,7 +4,7 @@ import ca.nrc.cadc.net.HttpRequestProperty; import ca.nrc.cadc.rest.SyncInput; import ca.nrc.cadc.util.Base64; -import java.net.MalformedURLException; + import java.net.URL; import java.util.HashSet; import java.util.List; @@ -19,8 +19,8 @@ public class PostActionTest { public void createPostRequestMissingUsername() throws Exception { final SyncInput mockSyncInput = Mockito.mock(SyncInput.class); - Mockito.when(mockSyncInput.getHeader(PostAction.REGISTRY_AUTH_SECRET_FROM_BROWSER)).thenReturn("mysecret"); - Mockito.when(mockSyncInput.getHeader(PostAction.REGISTRY_AUTH_USERNAME_FROM_BROWSER)).thenReturn(null); + Mockito.when(mockSyncInput.getHeader(PostAction.REPOSITORY_AUTH_SECRET_FROM_BROWSER)).thenReturn("mysecret"); + Mockito.when(mockSyncInput.getHeader(PostAction.REPOSITORY_AUTH_USERNAME_FROM_BROWSER)).thenReturn(null); final Set parameterNames = new HashSet<>(); parameterNames.add("param1"); @@ -46,8 +46,8 @@ public void createPostRequestMissingUsername() throws Exception { public void createPostRequestMissingSecret() throws Exception { final SyncInput mockSyncInput = Mockito.mock(SyncInput.class); - Mockito.when(mockSyncInput.getHeader(PostAction.REGISTRY_AUTH_SECRET_FROM_BROWSER)).thenReturn(null); - Mockito.when(mockSyncInput.getHeader(PostAction.REGISTRY_AUTH_USERNAME_FROM_BROWSER)).thenReturn("username1"); + Mockito.when(mockSyncInput.getHeader(PostAction.REPOSITORY_AUTH_SECRET_FROM_BROWSER)).thenReturn(null); + Mockito.when(mockSyncInput.getHeader(PostAction.REPOSITORY_AUTH_USERNAME_FROM_BROWSER)).thenReturn("username1"); final Set parameterNames = new HashSet<>(); parameterNames.add("param1"); @@ -73,8 +73,8 @@ public void createPostRequestMissingSecret() throws Exception { public void createPostRequestPrivate() throws Exception { final SyncInput mockSyncInput = Mockito.mock(SyncInput.class); - Mockito.when(mockSyncInput.getHeader(PostAction.REGISTRY_AUTH_SECRET_FROM_BROWSER)).thenReturn("secret1"); - Mockito.when(mockSyncInput.getHeader(PostAction.REGISTRY_AUTH_USERNAME_FROM_BROWSER)).thenReturn("username1"); + Mockito.when(mockSyncInput.getHeader(PostAction.REPOSITORY_AUTH_SECRET_FROM_BROWSER)).thenReturn("secret1"); + Mockito.when(mockSyncInput.getHeader(PostAction.REPOSITORY_AUTH_USERNAME_FROM_BROWSER)).thenReturn("username1"); final Set parameterNames = new HashSet<>(); parameterNames.add("param1");