diff --git a/PKG-INFO b/PKG-INFO index cbf97da8..01ce6dad 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -1,10 +1,10 @@ Metadata-Version: 1.0 Name: swh.web -Version: 0.0.153 +Version: 0.0.154 Summary: Software Heritage Web UI Home-page: https://forge.softwareheritage.org/diffusion/DWUI/ Author: Software Heritage developers Author-email: swh-devel@inria.fr License: UNKNOWN Description: UNKNOWN Platform: UNKNOWN diff --git a/swh.web.egg-info/PKG-INFO b/swh.web.egg-info/PKG-INFO index cbf97da8..01ce6dad 100644 --- a/swh.web.egg-info/PKG-INFO +++ b/swh.web.egg-info/PKG-INFO @@ -1,10 +1,10 @@ Metadata-Version: 1.0 Name: swh.web -Version: 0.0.153 +Version: 0.0.154 Summary: Software Heritage Web UI Home-page: https://forge.softwareheritage.org/diffusion/DWUI/ Author: Software Heritage developers Author-email: swh-devel@inria.fr License: UNKNOWN Description: UNKNOWN Platform: UNKNOWN diff --git a/swh.web.egg-info/SOURCES.txt b/swh.web.egg-info/SOURCES.txt index c3ecbc0a..95a1dc2f 100644 --- a/swh.web.egg-info/SOURCES.txt +++ b/swh.web.egg-info/SOURCES.txt @@ -1,364 +1,365 @@ .gitignore AUTHORS CONTRIBUTORS LICENSE MANIFEST.in Makefile Makefile.local README.md package-lock.json package.json requirements-swh.txt requirements.txt setup.py version.txt yarn.lock debian/changelog debian/compat debian/control debian/copyright debian/postinst debian/rules debian/source/format docs/.gitignore docs/Makefile docs/conf.py docs/developers-info.rst docs/index.rst docs/uri-scheme-api-content.rst docs/uri-scheme-api-directory.rst docs/uri-scheme-api-identifiers.rst docs/uri-scheme-api-origin.rst docs/uri-scheme-api-person.rst docs/uri-scheme-api-release.rst docs/uri-scheme-api-revision.rst docs/uri-scheme-api-snapshot.rst docs/uri-scheme-api-stat.rst docs/uri-scheme-api-vault.rst docs/uri-scheme-api.rst docs/uri-scheme-browse-content.rst docs/uri-scheme-browse-directory.rst docs/uri-scheme-browse-origin.rst docs/uri-scheme-browse-person.rst docs/uri-scheme-browse-release.rst docs/uri-scheme-browse-revision.rst docs/uri-scheme-browse-snapshot.rst docs/uri-scheme-browse.rst docs/uri-scheme-identifiers.rst docs/_static/.placeholder docs/_templates/.placeholder swh/__init__.py swh.web.egg-info/PKG-INFO swh.web.egg-info/SOURCES.txt swh.web.egg-info/dependency_links.txt swh.web.egg-info/requires.txt swh.web.egg-info/top_level.txt swh/web/__init__.py swh/web/config.py swh/web/doc_config.py swh/web/manage.py swh/web/urls.py swh/web/wsgi.py swh/web/admin/__init__.py swh/web/admin/adminurls.py swh/web/admin/origin_save.py swh/web/admin/urls.py swh/web/api/__init__.py swh/web/api/apidoc.py swh/web/api/apiresponse.py swh/web/api/apiurls.py swh/web/api/renderers.py swh/web/api/urls.py swh/web/api/utils.py swh/web/api/views/__init__.py swh/web/api/views/content.py swh/web/api/views/directory.py swh/web/api/views/entity.py swh/web/api/views/identifiers.py swh/web/api/views/origin.py swh/web/api/views/origin_save.py swh/web/api/views/person.py swh/web/api/views/release.py swh/web/api/views/revision.py swh/web/api/views/snapshot.py swh/web/api/views/stat.py swh/web/api/views/utils.py swh/web/api/views/vault.py swh/web/assets/config/.bootstraprc swh/web/assets/config/.eslintrc swh/web/assets/config/bootstrap-pre-customize.scss swh/web/assets/config/webpack.config.development.js swh/web/assets/config/webpack.config.production.js swh/web/assets/config/webpack-plugins/remove-source-map-url-webpack-plugin.js swh/web/assets/src/bundles/admin/index.js swh/web/assets/src/bundles/admin/origin-save.js swh/web/assets/src/bundles/browse/breadcrumbs.css swh/web/assets/src/bundles/browse/browse-utils.js swh/web/assets/src/bundles/browse/browse.css swh/web/assets/src/bundles/browse/content.css swh/web/assets/src/bundles/browse/index.js swh/web/assets/src/bundles/browse/origin-save.js swh/web/assets/src/bundles/browse/origin-search.js swh/web/assets/src/bundles/browse/snapshot-navigation.css swh/web/assets/src/bundles/browse/snapshot-navigation.js swh/web/assets/src/bundles/browse/swh-ids-utils.js swh/web/assets/src/bundles/origin/index.js swh/web/assets/src/bundles/origin/visits-calendar.js swh/web/assets/src/bundles/origin/visits-histogram.js swh/web/assets/src/bundles/origin/visits-reporting.css swh/web/assets/src/bundles/origin/visits-reporting.js swh/web/assets/src/bundles/revision/diff-utils.js swh/web/assets/src/bundles/revision/index.js swh/web/assets/src/bundles/revision/revision.css swh/web/assets/src/bundles/vault/index.js swh/web/assets/src/bundles/vault/vault-create-tasks.js swh/web/assets/src/bundles/vault/vault-ui.js swh/web/assets/src/bundles/vault/vault.css swh/web/assets/src/bundles/vendors/datatables.css swh/web/assets/src/bundles/vendors/index.js swh/web/assets/src/bundles/webapp/breadcrumbs.css swh/web/assets/src/bundles/webapp/code-highlighting.js swh/web/assets/src/bundles/webapp/index.js swh/web/assets/src/bundles/webapp/markdown-rendering.js swh/web/assets/src/bundles/webapp/pdf-rendering.js swh/web/assets/src/bundles/webapp/webapp-utils.js swh/web/assets/src/bundles/webapp/webapp.css swh/web/assets/src/utils/functions.js swh/web/assets/src/utils/heaps-permute.js swh/web/assets/src/utils/highlightjs.css swh/web/assets/src/utils/highlightjs.js swh/web/assets/src/utils/jquery.tabSlideOut.css swh/web/assets/src/utils/jquery.tabSlideOut.js swh/web/assets/src/utils/showdown.css swh/web/assets/src/utils/showdown.js swh/web/browse/__init__.py swh/web/browse/browseurls.py swh/web/browse/identifiers.py swh/web/browse/urls.py swh/web/browse/utils.py swh/web/browse/views/__init__.py swh/web/browse/views/content.py swh/web/browse/views/directory.py swh/web/browse/views/origin.py swh/web/browse/views/origin_save.py swh/web/browse/views/person.py swh/web/browse/views/release.py swh/web/browse/views/revision.py swh/web/browse/views/snapshot.py swh/web/browse/views/utils/__init__.py swh/web/browse/views/utils/snapshot_context.py swh/web/common/__init__.py swh/web/common/apps.py swh/web/common/converters.py swh/web/common/exc.py swh/web/common/highlightjs.py swh/web/common/middlewares.py swh/web/common/models.py swh/web/common/origin_save.py swh/web/common/query.py swh/web/common/service.py swh/web/common/swh_templatetags.py swh/web/common/throttling.py swh/web/common/urlsindex.py swh/web/common/utils.py swh/web/common/migrations/0001_initial.py swh/web/common/migrations/0002_saveoriginrequest_visit_date.py +swh/web/common/migrations/0003_saveoriginrequest_loading_task_status.py swh/web/common/migrations/__init__.py swh/web/settings/__init__.py swh/web/settings/common.py swh/web/settings/development.py swh/web/settings/production.py swh/web/settings/tests.py swh/web/static/robots.txt swh/web/static/webpack-stats.json -swh/web/static/css/browse.92378aae87894b0d9972.css -swh/web/static/css/browse.92378aae87894b0d9972.css.map +swh/web/static/css/browse.cec637f91d68ef766e5f.css +swh/web/static/css/browse.cec637f91d68ef766e5f.css.map swh/web/static/css/highlightjs.8999b6ccd00337cba3b8.css swh/web/static/css/highlightjs.8999b6ccd00337cba3b8.css.map swh/web/static/css/origin.c9b9c6c34c7967dc9329.css swh/web/static/css/origin.c9b9c6c34c7967dc9329.css.map swh/web/static/css/revision.fb503b9a29a646435e5d.css swh/web/static/css/revision.fb503b9a29a646435e5d.css.map swh/web/static/css/showdown.5000791dba563908850c.css swh/web/static/css/showdown.5000791dba563908850c.css.map swh/web/static/css/vault.154f0be768ca9bac8b6c.css swh/web/static/css/vault.154f0be768ca9bac8b6c.css.map swh/web/static/css/vendors.2694d5473acd0a553474.css swh/web/static/css/vendors.2694d5473acd0a553474.css.map swh/web/static/css/webapp.97895616b93bddb8d6b1.css swh/web/static/css/webapp.97895616b93bddb8d6b1.css.map swh/web/static/fonts/alegreya-latin-400.woff swh/web/static/fonts/alegreya-latin-400.woff2 swh/web/static/fonts/alegreya-latin-400italic.woff swh/web/static/fonts/alegreya-latin-400italic.woff2 swh/web/static/fonts/alegreya-latin-500.woff swh/web/static/fonts/alegreya-latin-500.woff2 swh/web/static/fonts/alegreya-latin-500italic.woff swh/web/static/fonts/alegreya-latin-500italic.woff2 swh/web/static/fonts/alegreya-latin-700.woff swh/web/static/fonts/alegreya-latin-700.woff2 swh/web/static/fonts/alegreya-latin-700italic.woff swh/web/static/fonts/alegreya-latin-700italic.woff2 swh/web/static/fonts/alegreya-latin-800.woff swh/web/static/fonts/alegreya-latin-800.woff2 swh/web/static/fonts/alegreya-latin-800italic.woff swh/web/static/fonts/alegreya-latin-800italic.woff2 swh/web/static/fonts/alegreya-latin-900.woff swh/web/static/fonts/alegreya-latin-900.woff2 swh/web/static/fonts/alegreya-latin-900italic.woff swh/web/static/fonts/alegreya-latin-900italic.woff2 swh/web/static/fonts/alegreya-sans-latin-100.woff swh/web/static/fonts/alegreya-sans-latin-100.woff2 swh/web/static/fonts/alegreya-sans-latin-100italic.woff swh/web/static/fonts/alegreya-sans-latin-100italic.woff2 swh/web/static/fonts/alegreya-sans-latin-300.woff swh/web/static/fonts/alegreya-sans-latin-300.woff2 swh/web/static/fonts/alegreya-sans-latin-300italic.woff swh/web/static/fonts/alegreya-sans-latin-300italic.woff2 swh/web/static/fonts/alegreya-sans-latin-400.woff swh/web/static/fonts/alegreya-sans-latin-400.woff2 swh/web/static/fonts/alegreya-sans-latin-400italic.woff swh/web/static/fonts/alegreya-sans-latin-400italic.woff2 swh/web/static/fonts/alegreya-sans-latin-500.woff swh/web/static/fonts/alegreya-sans-latin-500.woff2 swh/web/static/fonts/alegreya-sans-latin-500italic.woff swh/web/static/fonts/alegreya-sans-latin-500italic.woff2 swh/web/static/fonts/alegreya-sans-latin-700.woff swh/web/static/fonts/alegreya-sans-latin-700.woff2 swh/web/static/fonts/alegreya-sans-latin-700italic.woff swh/web/static/fonts/alegreya-sans-latin-700italic.woff2 swh/web/static/fonts/alegreya-sans-latin-800.woff swh/web/static/fonts/alegreya-sans-latin-800.woff2 swh/web/static/fonts/alegreya-sans-latin-800italic.woff swh/web/static/fonts/alegreya-sans-latin-800italic.woff2 swh/web/static/fonts/alegreya-sans-latin-900.woff swh/web/static/fonts/alegreya-sans-latin-900.woff2 swh/web/static/fonts/alegreya-sans-latin-900italic.woff swh/web/static/fonts/alegreya-sans-latin-900italic.woff2 swh/web/static/fonts/fontawesome-webfont.eot swh/web/static/fonts/fontawesome-webfont.svg swh/web/static/fonts/fontawesome-webfont.ttf swh/web/static/fonts/fontawesome-webfont.woff swh/web/static/fonts/fontawesome-webfont.woff2 swh/web/static/fonts/octicons.eot swh/web/static/fonts/octicons.svg swh/web/static/fonts/octicons.ttf swh/web/static/fonts/octicons.woff swh/web/static/fonts/octicons.woff2 swh/web/static/img/arrow-up-small.png swh/web/static/img/swh-api.png swh/web/static/img/swh-browse.png swh/web/static/img/swh-logo.png swh/web/static/img/swh-logo.svg swh/web/static/img/swh-spinner-small.gif swh/web/static/img/swh-spinner.gif swh/web/static/img/swh-vault.png swh/web/static/img/icons/swh-logo-32x32.png swh/web/static/img/icons/swh-logo-archive-180x180.png swh/web/static/img/icons/swh-logo-archive-192x192.png swh/web/static/img/icons/swh-logo-archive-270x270.png swh/web/static/js/admin.a1e42404ef1ac75a42f4.js swh/web/static/js/admin.a1e42404ef1ac75a42f4.js.map -swh/web/static/js/browse.92378aae87894b0d9972.js -swh/web/static/js/browse.92378aae87894b0d9972.js.map +swh/web/static/js/browse.cec637f91d68ef766e5f.js +swh/web/static/js/browse.cec637f91d68ef766e5f.js.map swh/web/static/js/highlightjs.8999b6ccd00337cba3b8.js swh/web/static/js/highlightjs.8999b6ccd00337cba3b8.js.map swh/web/static/js/origin.c9b9c6c34c7967dc9329.js swh/web/static/js/origin.c9b9c6c34c7967dc9329.js.map swh/web/static/js/pdf.worker.min.js swh/web/static/js/pdfjs.a916084c8aca9b766bd3.js swh/web/static/js/pdfjs.a916084c8aca9b766bd3.js.map swh/web/static/js/revision.fb503b9a29a646435e5d.js swh/web/static/js/revision.fb503b9a29a646435e5d.js.map swh/web/static/js/showdown.5000791dba563908850c.js swh/web/static/js/showdown.5000791dba563908850c.js.map swh/web/static/js/vault.154f0be768ca9bac8b6c.js swh/web/static/js/vault.154f0be768ca9bac8b6c.js.map swh/web/static/js/vendors.2694d5473acd0a553474.js swh/web/static/js/vendors.2694d5473acd0a553474.js.map swh/web/static/js/webapp.97895616b93bddb8d6b1.js swh/web/static/js/webapp.97895616b93bddb8d6b1.js.map swh/web/templates/error.html swh/web/templates/homepage.html swh/web/templates/layout.html swh/web/templates/login.html swh/web/templates/logout.html swh/web/templates/admin/origin-save.html swh/web/templates/api/api.html swh/web/templates/api/apidoc.html swh/web/templates/api/endpoints.html swh/web/templates/browse/branches.html swh/web/templates/browse/browse.html swh/web/templates/browse/content.html swh/web/templates/browse/directory.html swh/web/templates/browse/help.html swh/web/templates/browse/layout.html swh/web/templates/browse/origin-save.html swh/web/templates/browse/origin-visits.html swh/web/templates/browse/person.html swh/web/templates/browse/release.html swh/web/templates/browse/releases.html swh/web/templates/browse/revision-log.html swh/web/templates/browse/revision.html swh/web/templates/browse/search.html swh/web/templates/browse/vault-ui.html swh/web/templates/includes/apidoc-header.html swh/web/templates/includes/apidoc-header.md swh/web/templates/includes/breadcrumbs.html swh/web/templates/includes/content-display.html swh/web/templates/includes/directory-display.html swh/web/templates/includes/global-modals.html swh/web/templates/includes/http-error.html swh/web/templates/includes/readme-display.html swh/web/templates/includes/show-metadata.html swh/web/templates/includes/show-swh-ids.html swh/web/templates/includes/snapshot-context.html swh/web/templates/includes/top-navigation.html swh/web/templates/includes/vault-create-tasks.html swh/web/tests/__init__.py swh/web/tests/testcase.py swh/web/tests/admin/__init__.py swh/web/tests/admin/test_origin_save.py swh/web/tests/api/__init__.py swh/web/tests/api/test_api_lookup.py swh/web/tests/api/test_apidoc.py swh/web/tests/api/test_apiresponse.py swh/web/tests/api/test_utils.py swh/web/tests/api/views/__init__.py swh/web/tests/api/views/test_content.py swh/web/tests/api/views/test_directory.py swh/web/tests/api/views/test_entity.py swh/web/tests/api/views/test_identifiers.py swh/web/tests/api/views/test_origin.py swh/web/tests/api/views/test_origin_save.py swh/web/tests/api/views/test_person.py swh/web/tests/api/views/test_release.py swh/web/tests/api/views/test_revision.py swh/web/tests/api/views/test_stat.py swh/web/tests/api/views/test_vault.py swh/web/tests/browse/__init__.py swh/web/tests/browse/test_utils.py swh/web/tests/browse/views/__init__.py swh/web/tests/browse/views/test_content.py swh/web/tests/browse/views/test_directory.py swh/web/tests/browse/views/test_identifiers.py swh/web/tests/browse/views/test_origin.py swh/web/tests/browse/views/test_person.py swh/web/tests/browse/views/test_release.py swh/web/tests/browse/views/test_revision.py swh/web/tests/browse/views/data/__init__.py swh/web/tests/browse/views/data/content_test_data.py swh/web/tests/browse/views/data/directory_test_data.py swh/web/tests/browse/views/data/iso-8859-1_encoded_content swh/web/tests/browse/views/data/origin_test_data.py swh/web/tests/browse/views/data/release_test_data.py swh/web/tests/browse/views/data/revision_test_data.py swh/web/tests/browse/views/data/swh-logo.png swh/web/tests/common/__init__.py swh/web/tests/common/test_converters.py swh/web/tests/common/test_highlightjs.py swh/web/tests/common/test_query.py swh/web/tests/common/test_service.py swh/web/tests/common/test_templatetags.py swh/web/tests/common/test_throttling.py swh/web/tests/common/test_utils.py \ No newline at end of file diff --git a/swh/web/assets/src/bundles/browse/origin-save.js b/swh/web/assets/src/bundles/browse/origin-save.js index 19133cf4..8f6cfc48 100644 --- a/swh/web/assets/src/bundles/browse/origin-save.js +++ b/swh/web/assets/src/bundles/browse/origin-save.js @@ -1,178 +1,187 @@ /** * 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(() => { fetch(Urls.browse_origin_save_types_list()) .then(response => response.json()) .then(data => { for (let originType of data) { $('#swh-input-origin-type').append(``); } }); 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 `${data}`; } 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 `${data}`; } return data; } } ], scrollY: '50vh', scrollCollapse: true, order: [[0, 'desc']] }); setInterval(() => { saveRequestsTable.ajax.reload(null, false); }, 5000); $('#swh-origin-save-requests-list-tab').on('shown.bs.tab', () => { saveRequestsTable.draw(); }); $('#swh-save-origin-form').submit(event => { event.preventDefault(); event.stopPropagation(); 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.'); } 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.'); } grecaptcha.reset(); }) .catch(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.'); } 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(); + 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.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) { - validUrl = isGitRepoUrl(input.value, 'gitlab.com'); + 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/assets/src/bundles/browse/origin-search.js b/swh/web/assets/src/bundles/browse/origin-search.js index aaa3036c..6c7df1b3 100644 --- a/swh/web/assets/src/bundles/browse/origin-search.js +++ b/swh/web/assets/src/bundles/browse/origin-search.js @@ -1,223 +1,223 @@ /** * 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 {heapsPermute} from 'utils/heaps-permute'; import {handleFetchError} from 'utils/functions'; let originPatterns; let perPage = 20; let limit = perPage * 10; let offset = 0; let currentData = null; let inSearch = false; function fixTableRowsStyle() { setTimeout(() => { $('#origin-search-results tbody tr').removeAttr('style'); }); } function clearOriginSearchResultsTable() { $('#origin-search-results tbody tr').remove(); } function populateOriginSearchResultsTable(data, offset) { let localOffset = offset % limit; if (data.length > 0) { $('#swh-origin-search-results').show(); $('#swh-no-result').hide(); clearOriginSearchResultsTable(); let table = $('#origin-search-results tbody'); for (let i = localOffset; i < localOffset + perPage && i < data.length; ++i) { let elem = data[i]; let tableRow = '
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:
git
, for origins using Git.hg
, for origins using Mercurialsvn
, for origins using SubversionOnce submitted, your save request can either be:
Once a save request has been accepted, you can follow its current status in the submitted save requests list.
Request date | Origin type | Origin url | Request status | Save task status |
---|
Searching origins ...
You can jump directly to the endpoint index , which lists all available API functionalities, or read on for more general information about the API.
The Software Heritage project harvests publicly available source code by tracking software distribution channels such as version control systems, tarball releases, and distribution packages.
All retrieved source code and related metadata are stored in the Software Heritage archive, that is conceptually a Merkle DAG. All nodes in the graph are content-addressable, i.e., their node identifiers are computed by hashing their content and, transitively, that of all nodes reachable from them; and no node or edge is ever removed from the graph: the Software Heritage archive is an append-only data structure.
The following types of objects (i.e., graph nodes) can be found in the Software Heritage archive (for more information see the Software Heritage glossary):
The current version of the API is v1.
Warning: this version of the API is not to be considered stable yet. Non-backward compatible changes might happen even without changing the API version number.
API access is over HTTPS.
All API endpoints are rooted at https://archive.softwareheritage.org/api/1/.
Data is sent and received as JSON by default.
Example:
from the command line:
curl -i https://archive.softwareheritage.org/api/1/stat/counters/
The response format can be overridden using the
Accept
request header. In particular,
Accept: text/html
(that web browsers send by default) requests HTML pretty-printing, whereas
Accept: application/yaml
requests YAML-encoded responses.
Example:
from the command line:
curl -i -H 'Accept: application/yaml' https://archive.softwareheritage.org/api/1/stat/counters/
Some API endpoints can be tweaked by passing optional parameters. For GET requests, optional parameters can be passed as an HTTP query string.
The optional parameter
fields
is accepted by all endpoints that return dictionaries and can be used to restrict the list of fields returned
by the API, in case you are not interested in all of them. By default, all available fields are returned.
Example:
from the command line:
curl https://archive.softwareheritage.org/api/1/stat/counters/?fields=content,directory,revision
While API endpoints will return different kinds of errors depending on their own semantics, some error patterns are common across all endpoints.
Sending malformed data, including syntactically incorrect object identifiers, will result in a
400 Bad Request
HTTP response. Example:
from the command line:
curl -i https://archive.softwareheritage.org/api/1/content/deadbeef/
Requesting non existent resources will result in a
404 Not Found
HTTP response. Example:
from the command line:
curl -i https://archive.softwareheritage.org/api/1/content/04740277a81c5be6c16f6c9da488ca073b770d7f/
Unavailability of the underlying storage backend will result in a
503 Service Unavailable
HTTP response.
Requests that might potentially return many items will be paginated.
Page size is set to a default (usually: 10 items), but might be overridden with the
per_page
query parameter up to a maximum (usually: 50 items). Example:
curl https://archive.softwareheritage.org/api/1/origin/1/visits/?per_page=2
To navigate through paginated results, a
Link
HTTP response header is available to link the current result page to the next one. Example:
curl -i https://archive.softwareheritage.org/api/1/origin/1/visits/?per_page=2 | grep ^Link:
Link: </api/1/origin/1/visits/?last_visit=2&per_page=2>; rel="next",
Due to limited resource availability on the back end side, API usage is currently rate limited. Furthermore, as API usage is currently entirely anonymous (i.e., without any authentication), API "users" are currently identified by their origin IP address.
Three HTTP response fields will inform you about the current state of limits that apply to your current rate limiting bucket:
X-RateLimit-Limit
: maximum number of permitted requests per hourX-RateLimit-Remaining
: number of permitted requests remaining before the next resetX-RateLimit-Reset
: the time (expressed in
Unix time seconds) at which the current rate limiting will expire, resetting to a fresh
X-RateLimit-Limit
Example:
curl -i https://archive.softwareheritage.org/api/1/stat/counters/ | grep ^X-RateLimit
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 54
X-RateLimit-Reset: 1485794532
\ No newline at end of file
diff --git a/swh/web/templates/layout.html b/swh/web/templates/layout.html
index 2bac2cd4..981f3d79 100644
--- a/swh/web/templates/layout.html
+++ b/swh/web/templates/layout.html
@@ -1,175 +1,175 @@
{% comment %}
Copyright (C) 2015-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 %}
{% load static %}
{% load render_bundle from webpack_loader %}