Page Menu
Home
Software Heritage
Search
Configure Global Search
Log In
Files
F9347251
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
13 KB
Subscribers
None
View Options
diff --git a/swh/web/assets/src/bundles/browse/origin-save.js b/swh/web/assets/src/bundles/browse/origin-save.js
index e4b4da328..b3d392b95 100644
--- a/swh/web/assets/src/bundles/browse/origin-save.js
+++ b/swh/web/assets/src/bundles/browse/origin-save.js
@@ -1,185 +1,197 @@
/**
* Copyright (C) 2018 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} from 'utils/functions';
import {validate} from 'validate.js';
let saveRequestsTable;
export function initOriginSave() {
$(document).ready(() => {
$.fn.dataTable.ext.errMode = 'throw';
fetch(Urls.browse_origin_save_types_list())
.then(response => response.json())
.then(data => {
for (let originType of data) {
$('#swh-input-origin-type').append(`<option value="${originType}">${originType}</option>`);
}
});
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();
}
return data;
}
},
{
data: 'origin_type',
name: 'origin_type'
},
{
data: 'origin_url',
name: 'origin_url',
render: (data, type, row) => {
if (type === 'display') {
return `<a href="${data}">${data}</a>`;
}
return data;
}
},
{
data: 'save_request_status',
name: 'status'
},
{
data: 'save_task_status',
name: 'save_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 `<a href="${browseOriginUrl}">${data}</a>`;
}
return data;
}
}
],
scrollY: '50vh',
scrollCollapse: true,
order: [[0, 'desc']]
});
$('#swh-origin-save-requests-list-tab').on('shown.bs.tab', () => {
saveRequestsTable.draw();
});
+ let saveRequestAcceptedALert =
+ `<div class="alert alert-success" role="alert">
+ The "save code now" request has been accepted and will be processed as soon as possible.
+ </div>`;
+
+ let saveRequestPendingAlert =
+ `<div class="alert alert-warning" role="alert">
+ The "save code now" request has been put in pending state and may be accepted for processing after manual review.
+ </div>`;
+
+ let saveRequestRejectedAlert =
+ `<div class="alert alert-danger" role="alert">
+ The "save code now" request has been rejected because the reCAPTCHA could not be validated or the provided origin url is blacklisted.
+ </div>`;
+
$('#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();
let addSaveOriginRequestUrl = Urls.browse_origin_save_request(originType, originUrl);
let grecaptchaData = {'g-recaptcha-response': grecaptcha.getResponse()};
let headers = {
'Accept': 'application/json',
'Content-Type': 'application/json'
};
let body = JSON.stringify(grecaptchaData);
csrfPost(addSaveOriginRequestUrl, headers, body)
.then(handleFetchError)
.then(response => response.json())
.then(data => {
if (data.save_request_status === 'accepted') {
- $('#swh-origin-save-request-status').css('color', 'green');
- $('#swh-origin-save-request-status').text(
- 'The "save code now" request has been accepted and will be processed as soon as possible.');
+ $('#swh-origin-save-request-status').html(saveRequestAcceptedALert);
} else {
- $('#swh-origin-save-request-status').css('color', '#fecd1b');
- $('#swh-origin-save-request-status').text(
- 'The "save code now" request has been put in pending state and may be accepted for processing after manual review.');
+ $('#swh-origin-save-request-status').html(saveRequestPendingAlert);
}
grecaptcha.reset();
})
.catch(response => {
+ console.log(response);
if (response.status === 403) {
$('#swh-origin-save-request-status').css('color', 'red');
- $('#swh-origin-save-request-status').text(
- 'The "save code now" request has been rejected because the reCAPTCHA could not be validated or the provided origin url is blacklisted.');
+ $('#swh-origin-save-request-status').html(saveRequestRejectedAlert);
}
grecaptcha.reset();
});
} 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);
}
});
});
});
}
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');
}
}
diff --git a/swh/web/templates/browse/origin-save.html b/swh/web/templates/browse/origin-save.html
index e5b22798f..1988b269b 100644
--- a/swh/web/templates/browse/origin-save.html
+++ b/swh/web/templates/browse/origin-save.html
@@ -1,116 +1,116 @@
{% extends "./layout.html" %}
{% comment %}
Copyright (C) 2018 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 %}
{% block header %}
{{ block.super }}
<script src="https://www.google.com/recaptcha/api.js"></script>
{% endblock %}
{% block navbar-content %}
<h4>Save code now</h4>
{% endblock %}
{% block browse-content %}
<ul class="nav nav-tabs" style="padding-left: 5px;">
<li class="nav-item"><a class="nav-link active" data-toggle="tab" id="swh-origin-save-request-create-tab" href="#swh-origin-save-requests-create">Create save request</a></li>
<li class="nav-item"><a class="nav-link" data-toggle="tab" id="swh-origin-save-requests-list-tab" href="#swh-origin-save-requests-list">Browse save requests</a></li>
</ul>
<div class="tab-content">
<div id="swh-origin-save-requests-create" class="tab-pane active">
<p class="mt-3">
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:
</p>
<ul>
<li><b>Origin type:</b> the type of version control system the software origin is using.<br/>
Currently, the only supported type is <code>git</code>, for origins using <a href="https://git-scm.com/">Git</a>.<br/>
Soon, the following origin types will also be available to save into the archive:
<ul>
<li><code>hg</code>, for origins using <a href="https://www.mercurial-scm.org/">Mercurial</a></li>
<li><code>svn</code>, for origins using <a href="https://subversion.apache.org/">Subversion</a></li>
</ul>
</li>
<li><b>Origin url:</b> the url of the remote repository for the software origin.<br/>
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. <br/>It can easily be found in the
web interface used to browse the software origin. <br/>For instance, if you want to save a <code>git</code>
origin into the archive, you should check that the command <code>$ git clone <origin_url></code><br/>
does not return an error before submitting a request.
</li>
</ul>
<p>
Once submitted, your save request can either be:
</p>
<ul>
<li><b>accepted:</b> 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</li>
<li><b>rejected:</b> the provided origin url is blacklisted and no visit will be scheduled</li>
<li>put in <b>pending</b> state: a manual review will then be performed in order to determine if the
origin can be safely loaded or not into the archive</li>
</ul>
<p>
Once a save request has been accepted, you can follow its current status in the
<a id="swh-show-origin-save-requests-list" href="#swh-origin-save-requests-list">submitted save requests list</a>.
</p>
<form id="swh-save-origin-form" class="needs-validation" novalidate>
{% csrf_token %}
<div class="form-row">
<div class="col-md-1"></div>
<div class="form-group col-md-2">
<label for="swh-input-origin-type">Origin type</label>
<select id="swh-input-origin-type" class="form-control" required>
{% comment %} <option selected value="">Choose...</option> {% endcomment %}
</select>
<div class="invalid-feedback">The origin type must be specified</div>
</div>
<div class="form-group col-md-6">
<label for="swh-input-origin-url">Origin url</label>
<input type="text" class="form-control" id="swh-input-origin-url" oninput="swh.browse.validateSaveOriginUrl(this)" required>
<div class="invalid-feedback">The origin url is not valid or does not reference a code repository</div>
</div>
<div class="col-md-2"></div>
</div>
<div class="form-row">
<div class="col-md-2"></div>
<div class="form-group col-md-4">
<div class="g-recaptcha" id="save-origin-recaptcha" data-sitekey="{{ grecaptcha_site_key }}"></div>
</div>
<div class="form-group col-md-1">
<label for="swh-input-origin-save-submit">​</label>
<button type="submit" id="swh-input-origin-save-submit" class="btn btn-default btn-block">Submit</button>
</div>
</div>
</form>
- <p id="swh-origin-save-request-status">
- </p>
+ <div id="swh-origin-save-request-status">
+ </div>
</div>
<div id="swh-origin-save-requests-list" class="tab-pane mt-3">
<table id="swh-origin-save-requests" class="table swh-table swh-table-striped" width="100%">
<thead>
<tr>
<th>Request date</th>
<th>Origin type</th>
<th>Origin url</th>
<th>Request status</th>
<th>Save task status</th>
</tr>
</thead>
</table>
</div>
</div>
<script>
swh.webapp.initPage('origin-save');
swh.browse.initOriginSave();
</script>
{% endblock %}
\ No newline at end of file
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Jul 4, 5:16 PM (3 w, 2 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3293404
Attached To
R65 Staging repository
Event Timeline
Log In to Comment