diff --git a/assets/src/bundles/save/index.js b/assets/src/bundles/save/index.js --- a/assets/src/bundles/save/index.js +++ b/assets/src/bundles/save/index.js @@ -5,7 +5,8 @@ * See top-level LICENSE file for more information */ -import {csrfPost, handleFetchError, isGitRepoUrl, htmlAlert, removeUrlFragment} from 'utils/functions'; +import {csrfPost, handleFetchError, isGitRepoUrl, htmlAlert, removeUrlFragment, + getCanonicalOriginURL} from 'utils/functions'; import {swhSpinnerSrc} from 'utils/constants'; import artifactFormRowTemplate from './artifact-form-row.ejs'; @@ -281,7 +282,7 @@ true ); - $('#swh-save-origin-form').submit(event => { + $('#swh-save-origin-form').submit(async event => { event.preventDefault(); event.stopPropagation(); $('.alert').alert('close'); @@ -290,6 +291,8 @@ let originType = $('#swh-input-visit-type').val(); let originUrl = $('#swh-input-origin-url').val(); + originUrl = await getCanonicalOriginURL(originUrl); + // read the extra inputs for the 'archives' type let extraData = {}; if (originType === 'archives') { diff --git a/assets/src/utils/functions.js b/assets/src/utils/functions.js --- a/assets/src/utils/functions.js +++ b/assets/src/utils/functions.js @@ -97,3 +97,28 @@ return response.ok && response.status === 200; // Success response represents an archived origin } } + +export async function getCanonicalOriginURL(originUrl) { + let originUrlLower = originUrl.toLowerCase(); + // github.com URL processing + const ghUrlRegex = /^http[s]*:\/\/github.com\//; + if (originUrlLower.match(ghUrlRegex)) { + // remove trailing .git + if (originUrlLower.endsWith('.git')) { + originUrlLower = originUrlLower.slice(0, -4); + } + // remove trailing slash + if (originUrlLower.endsWith('/')) { + originUrlLower = originUrlLower.slice(0, -1); + } + // extract {owner}/{repo} + const ownerRepo = originUrlLower.replace(ghUrlRegex, ''); + // fetch canonical URL from github Web API + const ghApiResponse = await fetch(`https://api.github.com/repos/${ownerRepo}`); + if (ghApiResponse.ok && ghApiResponse.status === 200) { + const ghApiResponseData = await ghApiResponse.json(); + return ghApiResponseData.html_url; + } + } + return originUrl; +} diff --git a/cypress/integration/origin-save.spec.js b/cypress/integration/origin-save.spec.js --- a/cypress/integration/origin-save.spec.js +++ b/cypress/integration/origin-save.spec.js @@ -664,4 +664,48 @@ .should('have.value', artifact2Version); }); + it('should use canonical URL for github repository to save', function() { + const ownerRepo = 'BIC-MNI/mni_autoreg'; + const canonicalOriginUrl = 'https://github.com/BIC-MNI/mni_autoreg'; + + // stub call to github Web API fetching canonical repo URL + cy.intercept(`https://api.github.com/repos/${ownerRepo.toLowerCase()}`, (req) => { + req.reply({html_url: canonicalOriginUrl}); + }).as('ghWebApiRequest'); + + // stub save request creation with canonical URL of github repo + cy.intercept('POST', this.Urls.api_1_save_origin('git', canonicalOriginUrl), (req) => { + req.reply(genOriginSaveResponse({ + visitType: 'git', + saveRequestStatus: 'accepted', + originUrl: canonicalOriginUrl, + saveRequestDate: new Date(), + saveTaskStatus: 'not yet scheduled', + visitDate: null, + visitStatus: null + })); + }).as('saveRequest'); + + for (let originUrl of ['https://github.com/BiC-MnI/MnI_AuToReG', + 'https://github.com/BiC-MnI/MnI_AuToReG.git', + 'https://github.com/BiC-MnI/MnI_AuToReG/']) { + + // enter non canonical URL of github repo + cy.get('#swh-input-origin-url') + .clear() + .type(originUrl); + + // submit form + cy.get('#swh-save-origin-form') + .submit(); + + // submission should be successful + cy.wait('@ghWebApiRequest') + .wait('@saveRequest').then(() => { + checkAlertVisible('success', saveCodeMsg['success']); + }); + } + + }); + });