Page MenuHomeSoftware Heritage

No OneTemporary

diff --git a/swh/web/assets/src/bundles/browse/origin-save.js b/swh/web/assets/src/bundles/browse/origin-save.js
index f12419da..e9b4b9b3 100644
--- a/swh/web/assets/src/bundles/browse/origin-save.js
+++ b/swh/web/assets/src/bundles/browse/origin-save.js
@@ -1,259 +1,262 @@
/**
- * Copyright (C) 2018 The Software Heritage developers
+ * 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';
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: '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 `<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();
window.location.hash = '#requests';
});
$('#swh-origin-save-request-create-tab').on('shown.bs.tab', () => {
removeUrlFragment();
});
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();
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 =
`<div class="alert alert-success" role="alert">
The "take new snapshot" request has been accepted and will be processed as soon as possible.
</div>`;
let newSnapshotRequestPendingAlert =
`<div class="alert alert-warning" role="alert">
The "take new snapshot" request has been put in pending state and may be accepted for processing after manual review.
</div>`;
let newSnapshotRequestRejectedAlert =
`<div class="alert alert-danger" role="alert">
The "take new snapshot" request has been rejected because the reCAPTCHA could not be validated.
</div>`;
$(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 92e233c6..34bcc9eb 100644
--- a/swh/web/templates/browse/origin-save.html
+++ b/swh/web/templates/browse/origin-save.html
@@ -1,127 +1,133 @@
{% extends "./layout.html" %}
{% comment %}
-Copyright (C) 2018 The Software Heritage developers
+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 %}
<script src="https://www.google.com/recaptcha/api.js"></script>
{% endif %}
{% 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 &lt;origin_url&gt;</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">
{% if not grecaptcha_activated %}
<div class="form-group">
<label for="swh-input-origin-save-submit">&#8203;</label>
<button type="submit" id="swh-input-origin-save-submit" class="btn btn-default btn-block">Submit</button>
</div>
{% endif %}
</div>
</div>
{% if grecaptcha_activated %}
<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">&#8203;</label>
<button type="submit" id="swh-input-origin-save-submit" class="btn btn-default btn-block">Submit</button>
</div>
</div>
{% endif %}
</form>
+ <div class="swh-processing-save-request text-center" style="display: none;">
+ <img src="{% static 'img/swh-spinner.gif' %}">
+ <p>Processing "save code now" request ...</p>
+ </div>
<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
diff --git a/swh/web/templates/includes/take-new-snapshot.html b/swh/web/templates/includes/take-new-snapshot.html
index 73ce7936..7fd6b313 100644
--- a/swh/web/templates/includes/take-new-snapshot.html
+++ b/swh/web/templates/includes/take-new-snapshot.html
@@ -1,88 +1,92 @@
{% comment %}
Copyright (C) 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 %}
{% load swh_templatetags %}
{% if snapshot_context and snapshot_context.origin_info and snapshot_context.origin_info.type|origin_type_savable %}
{% if grecaptcha_activated %}
<script src="https://www.google.com/recaptcha/api.js"></script>
{% endif %}
<!-- entry in the Actions menu -->
<div class="dropdown-submenu">
<button class="dropdown-item" type="button" tabindex="-1" data-toggle="modal" data-target="#swh-take-new-snapshot-modal">
<i class="fa fa-camera fa-fw" aria-hidden="true"></i>Take a new snapshot
</button>
</div>
<div class="modal fade" id="swh-take-new-snapshot-modal" tabindex="-1" role="dialog" aria-labelledby="swh-take-new-snapshot-modal-label" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h6 class="modal-title" id="swh-take-new-snapshot-modal-label">Take a new snapshot of a software origin</h6>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>
If the archived software origin currently browsed is not synchronized with its upstream
version (for instance when new commits have been issued), you can explicitely request Software
Heritage to take a new snapshot of it.
<p>
</p>
Use the form below to proceed. Once a request has been submitted and accepted, it will be processed as soon as possible.
You can then check its processing state by visiting this <a href="{% url 'browse-origin-save'%}#requests">dedicated page</a>.
</p>
<form id="swh-take-new-snapshot-form" class="mt-3">
{% csrf_token %}
<div class="form-row">
<div class="form-group col-md-3">
<label for="swh-input-origin-type">Origin type</label>
<input id="swh-input-origin-type" class="form-control" value="{{ snapshot_context.origin_info.type }}" disabled>
</div>
<div class="form-group col-md-9">
<label for="swh-input-origin-url">Origin url</label>
<input type="text" class="form-control" id="swh-input-origin-url" value="{{ snapshot_context.origin_info.url }}" disabled>
</div>
</div>
<div class="form-row">
{% if grecaptcha_activated %}
<div class="form-group col-md-6">
<div class="g-recaptcha" id="swh-take-new-snapshot-recaptcha" data-sitekey="{{ grecaptcha_site_key }}"></div>
</div>
<div class="col-md-3"></div>
<div class="form-group col-md-3">
<label for="swh-take-new-snapshot-submit">&#8203;</label>
<button type="submit" id="swh-take-new-snapshot-save-submit" class="btn btn-default btn-block">Submit</button>
</div>
{% else %}
<div class="col-md-4"></div>
<div class="col-md-4 form-group">
<label for="swh-take-new-snapshot-submit">&#8203;</label>
<button type="submit" id="swh-take-new-snapshot-save-submit" class="btn btn-default btn-block">Submit</button>
</div>
<div class="col-md-4"></div>
{% endif %}
</div>
-
</form>
+ <div class="swh-processing-save-request text-center" style="display: none;">
+ <img src="{% static 'img/swh-spinner.gif' %}">
+ <p>Processing "take a new snapshot" request ...</p>
+ </div>
<div id="swh-take-new-snapshot-request-status">
</div>
</div>
</div>
</div>
</div>
<script>
swh.browse.initTakeNewSnapshot();
</script>
{% endif %}
\ No newline at end of file

File Metadata

Mime Type
text/x-diff
Expires
Mon, Aug 18, 11:27 PM (1 w, 18 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3252518

Event Timeline