diff --git a/swh/web/assets/src/bundles/browse/origin-save.js b/swh/web/assets/src/bundles/browse/origin-save.js
index e9b4b9b3..73292262 100644
--- a/swh/web/assets/src/bundles/browse/origin-save.js
+++ b/swh/web/assets/src/bundles/browse/origin-save.js
@@ -1,262 +1,267 @@
/**
* Copyright (C) 2018-2019 The Software Heritage developers
* See the AUTHORS file at the top-level directory of this distribution
* License: GNU Affero General Public License version 3, or any later version
* See top-level LICENSE file for more information
*/
import {handleFetchError, csrfPost, isGitRepoUrl, removeUrlFragment} from 'utils/functions';
import {validate} from 'validate.js';
let saveRequestsTable;
function originSaveRequest(originType, originUrl,
acceptedCallback, pendingCallback, errorCallback) {
let addSaveOriginRequestUrl = Urls.browse_origin_save_request(originType, originUrl);
let grecaptchaData = {};
if (swh.webapp.isReCaptchaActivated()) {
grecaptchaData['g-recaptcha-response'] = grecaptcha.getResponse();
}
let headers = {
'Accept': 'application/json',
'Content-Type': 'application/json'
};
let body = JSON.stringify(grecaptchaData);
$('.swh-processing-save-request').css('display', 'block');
csrfPost(addSaveOriginRequestUrl, headers, body)
.then(handleFetchError)
.then(response => response.json())
.then(data => {
$('.swh-processing-save-request').css('display', 'none');
if (data.save_request_status === 'accepted') {
acceptedCallback();
} else {
pendingCallback();
}
if (swh.webapp.isReCaptchaActivated()) {
grecaptcha.reset();
}
})
.catch(response => {
$('.swh-processing-save-request').css('display', 'none');
if (response.status === 403) {
errorCallback();
}
if (swh.webapp.isReCaptchaActivated()) {
grecaptcha.reset();
}
});
}
export function initOriginSave() {
$(document).ready(() => {
- $.fn.dataTable.ext.errMode = 'throw';
+ $.fn.dataTable.ext.errMode = 'none';
fetch(Urls.browse_origin_save_types_list())
.then(response => response.json())
.then(data => {
for (let originType of data) {
$('#swh-input-origin-type').append(`${originType} `);
}
});
- saveRequestsTable = $('#swh-origin-save-requests').DataTable({
- serverSide: true,
- ajax: Urls.browse_origin_save_requests_list('all'),
- columns: [
- {
- data: 'save_request_date',
- name: 'request_date',
- render: (data, type, row) => {
- if (type === 'display') {
- let date = new Date(data);
- return date.toLocaleString();
+ saveRequestsTable = $('#swh-origin-save-requests')
+ .on('error.dt', (e, settings, techNote, message) => {
+ $('#swh-origin-save-request-list-error').text('An error occurred while retrieving the save requests list');
+ console.log(message);
+ })
+ .DataTable({
+ serverSide: true,
+ ajax: Urls.browse_origin_save_requests_list('all'),
+ columns: [
+ {
+ data: 'save_request_date',
+ name: 'request_date',
+ render: (data, type, row) => {
+ if (type === 'display') {
+ let date = new Date(data);
+ return date.toLocaleString();
+ }
+ return data;
}
- return data;
- }
- },
- {
- data: 'origin_type',
- name: 'origin_type'
+ },
+ {
+ data: 'origin_type',
+ name: 'origin_type'
- },
- {
- data: 'origin_url',
- name: 'origin_url',
- render: (data, type, row) => {
- if (type === 'display') {
- return `${data} `;
+ },
+ {
+ data: 'origin_url',
+ name: 'origin_url',
+ render: (data, type, row) => {
+ if (type === 'display') {
+ return `${data} `;
+ }
+ return data;
}
- return data;
- }
- },
- {
- data: 'save_request_status',
- name: 'status'
- },
- {
- data: 'save_task_status',
- name: 'loading_task_status',
- render: (data, type, row) => {
- if (data === 'succeed') {
- let browseOriginUrl = Urls.browse_origin(row.origin_url);
- if (row.visit_date) {
- browseOriginUrl += `visit/${row.visit_date}/`;
+ },
+ {
+ data: 'save_request_status',
+ name: 'status'
+ },
+ {
+ data: 'save_task_status',
+ name: 'loading_task_status',
+ render: (data, type, row) => {
+ if (data === 'succeed') {
+ let browseOriginUrl = Urls.browse_origin(row.origin_url);
+ if (row.visit_date) {
+ browseOriginUrl += `visit/${row.visit_date}/`;
+ }
+ return `${data} `;
}
- return `${data} `;
+ return data;
}
- return data;
}
- }
- ],
- scrollY: '50vh',
- scrollCollapse: true,
- order: [[0, 'desc']]
- });
+ ],
+ scrollY: '50vh',
+ scrollCollapse: true,
+ order: [[0, 'desc']]
+ });
$('#swh-origin-save-requests-list-tab').on('shown.bs.tab', () => {
saveRequestsTable.draw();
window.location.hash = '#requests';
});
$('#swh-origin-save-request-create-tab').on('shown.bs.tab', () => {
removeUrlFragment();
});
let saveRequestAcceptedAlert =
`
The "save code now" request has been accepted and will be processed as soon as possible.
`;
let saveRequestPendingAlert =
`
The "save code now" request has been put in pending state and may be accepted for processing after manual review.
`;
let saveRequestRejectedAlert =
`
The "save code now" request has been rejected because the reCAPTCHA could not be validated or the provided origin url is blacklisted.
`;
$('#swh-save-origin-form').submit(event => {
event.preventDefault();
event.stopPropagation();
$('.alert').alert('close');
if (event.target.checkValidity()) {
$(event.target).removeClass('was-validated');
let originType = $('#swh-input-origin-type').val();
let originUrl = $('#swh-input-origin-url').val();
originSaveRequest(originType, originUrl,
() => $('#swh-origin-save-request-status').html(saveRequestAcceptedAlert),
() => $('#swh-origin-save-request-status').html(saveRequestPendingAlert),
() => {
$('#swh-origin-save-request-status').css('color', 'red');
$('#swh-origin-save-request-status').html(saveRequestRejectedAlert);
});
} else {
$(event.target).addClass('was-validated');
}
});
$('#swh-show-origin-save-requests-list').on('click', (event) => {
event.preventDefault();
$('.nav-tabs a[href="#swh-origin-save-requests-list"]').tab('show');
});
$('#swh-input-origin-url').on('input', function(event) {
let originUrl = $(this).val().trim();
$(this).val(originUrl);
$('#swh-input-origin-type option').each(function() {
let val = $(this).val();
if (val && originUrl.includes(val)) {
$(this).prop('selected', true);
}
});
});
if (window.location.hash === '#requests') {
$('.nav-tabs a[href="#swh-origin-save-requests-list"]').tab('show');
}
});
}
export function validateSaveOriginUrl(input) {
let validUrl = validate({website: input.value}, {
website: {
url: {
schemes: ['http', 'https', 'svn', 'git']
}
}
}) === undefined;
let originType = $('#swh-input-origin-type').val();
if (originType === 'git' && validUrl) {
// additional checks for well known code hosting providers
let githubIdx = input.value.indexOf('://github.com');
let gitlabIdx = input.value.indexOf('://gitlab.');
let gitSfIdx = input.value.indexOf('://git.code.sf.net');
let bitbucketIdx = input.value.indexOf('://bitbucket.org');
if (githubIdx !== -1 && githubIdx <= 5) {
validUrl = isGitRepoUrl(input.value, 'github.com');
} else if (gitlabIdx !== -1 && gitlabIdx <= 5) {
let startIdx = gitlabIdx + 3;
let idx = input.value.indexOf('/', startIdx);
if (idx !== -1) {
let gitlabDomain = input.value.substr(startIdx, idx - startIdx);
// GitLab repo url needs to be suffixed by '.git' in order to be successfully loaded
validUrl = isGitRepoUrl(input.value, gitlabDomain) && input.value.endsWith('.git');
} else {
validUrl = false;
}
} else if (gitSfIdx !== -1 && gitSfIdx <= 5) {
validUrl = isGitRepoUrl(input.value, 'git.code.sf.net/p');
} else if (bitbucketIdx !== -1 && bitbucketIdx <= 5) {
validUrl = isGitRepoUrl(input.value, 'bitbucket.org');
}
}
if (validUrl) {
input.setCustomValidity('');
} else {
input.setCustomValidity('The origin url is not valid or does not reference a code repository');
}
}
export function initTakeNewSnapshot() {
let newSnapshotRequestAcceptedAlert =
`
The "take new snapshot" request has been accepted and will be processed as soon as possible.
`;
let newSnapshotRequestPendingAlert =
`
The "take new snapshot" request has been put in pending state and may be accepted for processing after manual review.
`;
let newSnapshotRequestRejectedAlert =
`
The "take new snapshot" request has been rejected because the reCAPTCHA could not be validated.
`;
$(document).ready(() => {
$('#swh-take-new-snapshot-form').submit(event => {
event.preventDefault();
event.stopPropagation();
let originType = $('#swh-input-origin-type').val();
let originUrl = $('#swh-input-origin-url').val();
originSaveRequest(originType, originUrl,
() => $('#swh-take-new-snapshot-request-status').html(newSnapshotRequestAcceptedAlert),
() => $('#swh-take-new-snapshot-request-status').html(newSnapshotRequestPendingAlert),
() => {
$('#swh-take-new-snapshot-request-status').css('color', 'red');
$('#swh-take-new-snapshot-request-status').html(newSnapshotRequestRejectedAlert);
});
});
});
}
diff --git a/swh/web/templates/browse/origin-save.html b/swh/web/templates/browse/origin-save.html
index 34bcc9eb..7e15e376 100644
--- a/swh/web/templates/browse/origin-save.html
+++ b/swh/web/templates/browse/origin-save.html
@@ -1,133 +1,134 @@
{% extends "./layout.html" %}
{% comment %}
Copyright (C) 2018-2019 The Software Heritage developers
See the AUTHORS file at the top-level directory of this distribution
License: GNU Affero General Public License version 3, or any later version
See top-level LICENSE file for more information
{% endcomment %}
{% load static %}
{% block header %}
{{ block.super }}
{% if grecaptcha_activated %}
{% endif %}
{% endblock %}
{% block navbar-content %}
Save code now
{% endblock %}
{% block browse-content %}
You can contribute to extend the content of the Software Heritage archive by submitting an origin
save request. To do so, fill the required info in the form below:
Origin type: the type of version control system the software origin is using.
Currently, the only supported type is git
, for origins using Git .
Soon, the following origin types will also be available to save into the archive:
Origin url: the url of the remote repository for the software origin.
In order to avoid saving errors from Software Heritage, you should provide the clone/checkout url
as given by the provider hosting the software origin. It can easily be found in the
web interface used to browse the software origin. For instance, if you want to save a git
origin into the archive, you should check that the command $ git clone <origin_url>
does not return an error before submitting a request.
Once submitted, your save request can either be:
accepted: a visit to the provided origin will then be scheduled by Software Heritage in order to
load its content into the archive as soon as possible
rejected: the provided origin url is blacklisted and no visit will be scheduled
put in pending state: a manual review will then be performed in order to determine if the
origin can be safely loaded or not into the archive
Once a save request has been accepted, you can follow its current status in the
submitted save requests list .
Processing "save code now" request ...
Request date
Origin type
Origin url
Request status
Save task status
+
{% endblock %}
\ No newline at end of file