Page MenuHomeSoftware Heritage

No OneTemporary

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 534d2fa6..c7e6c020 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,56 +1,57 @@
exclude: "^swh/web/tests/resources/"
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.1.0
hooks:
- id: trailing-whitespace
+ exclude: '.eml$'
- id: check-json
- id: check-yaml
- repo: https://gitlab.com/pycqa/flake8
rev: 4.0.1
hooks:
- id: flake8
- repo: https://github.com/codespell-project/codespell
rev: v2.1.0
hooks:
- id: codespell
name: Check source code spelling
exclude: >
(?x)^(
cypress/integration/directory.spec.js|
yarn.lock|
package.json
)$
args: [-L edn]
stages: [commit]
- id: codespell
name: Check commit message spelling
stages: [commit-msg]
- repo: local
hooks:
- id: mypy
name: mypy
entry: env DJANGO_SETTINGS_MODULE=swh.web.settings.development mypy
args: [swh]
pass_filenames: false
language: system
types: [python]
- id: eslint
name: eslint
entry: node_modules/.bin/eslint -c assets/config/.eslintrc
language: system
types: [javascript]
- repo: https://github.com/PyCQA/isort
rev: 5.10.1
hooks:
- id: isort
- repo: https://github.com/python/black
rev: 19.10b0
hooks:
- id: black
diff --git a/MANIFEST.in b/MANIFEST.in
index 1e16964a..ea19ad89 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,13 +1,14 @@
include pytest.ini
include README.md
include requirements*.txt
include tox.ini
include version.txt
recursive-include swh py.typed
recursive-include assets *
recursive-include swh/web/templates *
recursive-include swh/web/tests/resources *
+recursive-include swh/web/tests/inbound_email/resources *.eml
include package.json
include yarn.lock
diff --git a/PKG-INFO b/PKG-INFO
index 3beeb4c1..120a2158 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,206 +1,206 @@
Metadata-Version: 2.1
Name: swh.web
-Version: 0.0.379
+Version: 0.0.380
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
Project-URL: Bug Reports, https://forge.softwareheritage.org/maniphest
Project-URL: Funding, https://www.softwareheritage.org/donate
Project-URL: Source, https://forge.softwareheritage.org/source/swh-web
Project-URL: Documentation, https://docs.softwareheritage.org/devel/swh-web/
Platform: UNKNOWN
Classifier: Programming Language :: Python :: 3
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
Classifier: Operating System :: OS Independent
Classifier: Development Status :: 5 - Production/Stable
Classifier: Framework :: Django
Requires-Python: >=3.7
Description-Content-Type: text/markdown
Provides-Extra: testing
License-File: LICENSE
License-File: AUTHORS
# swh-web
This repository holds the development of Software Heritage web applications:
* swh-web API (https://archive.softwareheritage.org/api): enables to query the
content of the archive through HTTP requests and get responses in JSON or
YAML.
* swh-web browse (https://archive.softwareheritage.org/browse): graphical
interface that eases the navigation in the archive.
Documentation about how to use these components but also the details of their
URI schemes can be found in the docs folder. The produced HTML documentation
can be read and browsed at
https://docs.softwareheritage.org/devel/swh-web/index.html.
## Technical details
Those applications are powered by:
* [Django Web Framework](https://www.djangoproject.com/) on the backend side
with the following extensions enabled:
* [django-rest-framework](http://www.django-rest-framework.org/)
* [django-webpack-loader](https://github.com/owais/django-webpack-loader)
* [django-js-reverse](http://django-js-reverse.readthedocs.io/en/latest/)
* [webpack](https://webpack.js.org/) on the frontend side for better static
assets management, including:
* assets dependencies management and retrieval through
[yarn](https://yarnpkg.com/en/)
* linting of custom javascript code (through [eslint](https://eslint.org/))
and stylesheets (through [stylelint](https://stylelint.io/))
* use of [es6](http://es6-features.org) syntax and advanced javascript
feature like [async/await](https://javascript.info/async-await) or
[fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
thanks to [babel](https://babeljs.io/) (es6 to es5 transpiler and
polyfills provider)
* assets minification (using [terser](https://github.com/terser-js/terser)
and [cssnano](http://cssnano.co/)) but also dead code elimination for
production use
## How to build, run and test
### Backend requirements
First you will need [Python 3](https://www.python.org) and a complete [swh
development
environment](https://forge.softwareheritage.org/source/swh-environment/)
installed.
To run the backend, you need to have the following [Python 3
modules](requirements.txt) installed.
To run the backend tests, the following [Python 3
modules](requirements-test.txt) are also required to be installed.
One easy way to install them is to use the `pip` tool:
```
$ pip install -r requirements.txt -r requirements-test.txt
```
### Frontend requirements
To compile the frontend assets, you need to have
[nodejs](https://nodejs.org/en/) >= 12.0.0 and [yarn](https://yarnpkg.com/en/)
installed. If you are on Debian, you can easily install an up to date nodejs
from the
[nodesource](https://github.com/nodesource/distributions/blob/master/README.md)
repository.
Packages for yarn can be installed by following [these
instructions](https://yarnpkg.com/en/docs/install#debian-stable).
Alternatively, you can install yarn with `npm install yarn`, and add
`YARN=node_modules/yarn/bin/yarn` as argument whenever you run `make`.
Please note that the static assets bundles generated by webpack are not stored
in the git repository. Follow the instructions below in order to generate them
in order to be able to run the frontend part of the web applications.
### Make targets to execute the applications
Below is the list of available make targets that can be executed from the root
directory of swh-web in order to build and/or execute the web applications
under various configurations:
* **run-django-webpack-devserver**: Compile and serve not optimized (without
mignification and dead code elimination) frontend static assets using
[webpack-dev-server](https://github.com/webpack/webpack-dev-server) and run
django server with development settings. This is the recommended target to
use when developing swh-web as it enables automatic reloading of backend and
frontend part of the applications when modifying source files (*.py, *.js,
*.css, *.html).
* **run-django-webpack-dev**: Compile not optimized (no minification, no dead
code elimination) frontend static assets using webpack and run django server
with development settings. This is the recommended target when one only wants
to develop the backend side of the application.
* **run-django-webpack-prod**: Compile optimized (with minification and dead
code elimination) frontend static assets using webpack and run django server
with production settings. This is useful to test the applications in
production mode (with the difference that static assets are served by
django). Production settings notably enable advanced django caching and you
will need to have [memcached](https://memcached.org/) installed for that
feature to work.
* **run-django-server-dev**: Run the django server with development settings
but without compiling frontend static assets through webpack.
* **run-django-server-prod**: Run the django server with production settings
but without compiling frontend static assets through webpack.
* **run-gunicorn-server**: Run the web applications with production settings in
a [gunicorn](http://gunicorn.org/) worker as they will be in real production
environment.
Once one of these targets executed, the web applications can be executed by
pointing your browser to http://localhost:5004.
### Make targets to test the applications
Some make targets are also available to easily execute the backend and frontend
tests of the Software Heritage web applications.
The backend tests are powered by the
[pytest](https://docs.pytest.org/en/latest/) and
[hypothesis](https://hypothesis.readthedocs.io/en/latest/) frameworks while the
frontend ones rely on the use of the [cypress](https://www.cypress.io/) tool.
Below is the exhaustive list of those targets:
* **test**: execute the backend tests using a fast hypothesis profile (only one
input example will be provided for each test)
* **test-full**: execute the backend tests using a slower hypothesis profile
(one hundred of input examples will be provided for each test which helps
spotting possible bugs)
* **test-frontend**: execute the frontend tests using cypress in headless mode
but with some slow test suites disabled
* **test-frontend-full**: execute the frontend tests using cypress in headless
mode with all test suites enabled
* **test-frontend-ui**: execute the frontend tests using the cypress GUI but
with some slow test suites disabled
* **test-frontend-full-ui**: execute the frontend tests using the cypress GUI
with all test suites enabled
### Yarn targets
Below is a list of available yarn targets in order to only execute the frontend
static assets compilation (no web server will be executed):
* **build-dev**: compile not optimized (without mignification and dead code
elimination) frontend static assets and store the results in the
`swh/web/static` folder.
* **build**: compile optimized (with mignification and dead code elimination)
frontend static assets and store the results in the `swh/web/static` folder.
**The build target must be executed prior performing the Debian packaging of
swh-web** in order for the package to contain the optimized assets dedicated to
production environment.
To execute these targets, issue the following command:
```
$ yarn <target_name>
```
diff --git a/requirements-test.txt b/requirements-test.txt
index 7818d678..551c3920 100644
--- a/requirements-test.txt
+++ b/requirements-test.txt
@@ -1,19 +1,19 @@
decorator # dependency of swh.core[http]
djangorestframework-stubs
django-stubs
django-test-migrations
hypothesis
-pytest < 7.0.0 # v7.0.0 removed _pytest.tmpdir.TempdirFactory, which is used by some of the pytest plugins we use
+pytest
pytest-django
pytest-mock
pytest-postgresql < 4.0.0
requests-mock != 1.9.0, != 1.9.1
swh.core[http] >= 0.0.95
swh.loader.git >= 0.8.0
swh-scheduler[testing] >= 0.5.0
swh.storage >= 0.1.1
types-chardet
types-docutils
types-psycopg2
types-pyyaml
types-requests
diff --git a/static/webpack-stats.json b/static/webpack-stats.json
index 6a881ce6..10587305 100644
--- a/static/webpack-stats.json
+++ b/static/webpack-stats.json
@@ -1,805 +1,805 @@
{
"status": "done",
"assets": {
- "img/thirdParty/chosen-sprite.png": {
- "name": "img/thirdParty/chosen-sprite.png",
- "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/img/thirdParty/chosen-sprite.png",
- "publicPath": "/static/img/thirdParty/chosen-sprite.png"
- },
"img/thirdParty/chosen-sprite@2x.png": {
"name": "img/thirdParty/chosen-sprite@2x.png",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/img/thirdParty/chosen-sprite@2x.png",
"publicPath": "/static/img/thirdParty/chosen-sprite@2x.png"
},
- "fonts/materialdesignicons-webfont.eot?v=6.6.96": {
- "name": "fonts/materialdesignicons-webfont.eot?v=6.6.96",
- "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/materialdesignicons-webfont.eot",
- "publicPath": "/static/fonts/materialdesignicons-webfont.eot?v=6.6.96"
- },
- "fonts/materialdesignicons-webfont.eot": {
- "name": "fonts/materialdesignicons-webfont.eot",
- "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/materialdesignicons-webfont.eot",
- "publicPath": "/static/fonts/materialdesignicons-webfont.eot"
+ "img/thirdParty/chosen-sprite.png": {
+ "name": "img/thirdParty/chosen-sprite.png",
+ "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/img/thirdParty/chosen-sprite.png",
+ "publicPath": "/static/img/thirdParty/chosen-sprite.png"
},
"fonts/materialdesignicons-webfont.woff2?v=6.6.96": {
"name": "fonts/materialdesignicons-webfont.woff2?v=6.6.96",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/materialdesignicons-webfont.woff2",
"publicPath": "/static/fonts/materialdesignicons-webfont.woff2?v=6.6.96"
},
"fonts/materialdesignicons-webfont.woff?v=6.6.96": {
"name": "fonts/materialdesignicons-webfont.woff?v=6.6.96",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/materialdesignicons-webfont.woff",
"publicPath": "/static/fonts/materialdesignicons-webfont.woff?v=6.6.96"
},
+ "fonts/materialdesignicons-webfont.eot?v=6.6.96": {
+ "name": "fonts/materialdesignicons-webfont.eot?v=6.6.96",
+ "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/materialdesignicons-webfont.eot",
+ "publicPath": "/static/fonts/materialdesignicons-webfont.eot?v=6.6.96"
+ },
+ "fonts/materialdesignicons-webfont.eot": {
+ "name": "fonts/materialdesignicons-webfont.eot",
+ "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/materialdesignicons-webfont.eot",
+ "publicPath": "/static/fonts/materialdesignicons-webfont.eot"
+ },
"fonts/materialdesignicons-webfont.ttf?v=6.6.96": {
"name": "fonts/materialdesignicons-webfont.ttf?v=6.6.96",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/materialdesignicons-webfont.ttf",
"publicPath": "/static/fonts/materialdesignicons-webfont.ttf?v=6.6.96"
},
"fonts/alegreya-latin-400.woff2": {
"name": "fonts/alegreya-latin-400.woff2",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-400.woff2",
"publicPath": "/static/fonts/alegreya-latin-400.woff2"
},
"fonts/alegreya-latin-400.woff": {
"name": "fonts/alegreya-latin-400.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-400.woff",
"publicPath": "/static/fonts/alegreya-latin-400.woff"
},
"fonts/alegreya-latin-400italic.woff2": {
"name": "fonts/alegreya-latin-400italic.woff2",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-400italic.woff2",
"publicPath": "/static/fonts/alegreya-latin-400italic.woff2"
},
- "fonts/alegreya-latin-500italic.woff2": {
- "name": "fonts/alegreya-latin-500italic.woff2",
- "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-500italic.woff2",
- "publicPath": "/static/fonts/alegreya-latin-500italic.woff2"
- },
"fonts/alegreya-latin-400italic.woff": {
"name": "fonts/alegreya-latin-400italic.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-400italic.woff",
"publicPath": "/static/fonts/alegreya-latin-400italic.woff"
},
+ "fonts/alegreya-latin-500.woff2": {
+ "name": "fonts/alegreya-latin-500.woff2",
+ "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-500.woff2",
+ "publicPath": "/static/fonts/alegreya-latin-500.woff2"
+ },
"fonts/alegreya-latin-500.woff": {
"name": "fonts/alegreya-latin-500.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-500.woff",
"publicPath": "/static/fonts/alegreya-latin-500.woff"
},
- "fonts/alegreya-latin-500.woff2": {
- "name": "fonts/alegreya-latin-500.woff2",
- "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-500.woff2",
- "publicPath": "/static/fonts/alegreya-latin-500.woff2"
+ "fonts/alegreya-latin-500italic.woff2": {
+ "name": "fonts/alegreya-latin-500italic.woff2",
+ "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-500italic.woff2",
+ "publicPath": "/static/fonts/alegreya-latin-500italic.woff2"
},
"fonts/alegreya-latin-500italic.woff": {
"name": "fonts/alegreya-latin-500italic.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-500italic.woff",
"publicPath": "/static/fonts/alegreya-latin-500italic.woff"
},
"fonts/alegreya-latin-700.woff2": {
"name": "fonts/alegreya-latin-700.woff2",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-700.woff2",
"publicPath": "/static/fonts/alegreya-latin-700.woff2"
},
"fonts/alegreya-latin-700.woff": {
"name": "fonts/alegreya-latin-700.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-700.woff",
"publicPath": "/static/fonts/alegreya-latin-700.woff"
},
"fonts/alegreya-latin-700italic.woff2": {
"name": "fonts/alegreya-latin-700italic.woff2",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-700italic.woff2",
"publicPath": "/static/fonts/alegreya-latin-700italic.woff2"
},
"fonts/alegreya-latin-700italic.woff": {
"name": "fonts/alegreya-latin-700italic.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-700italic.woff",
"publicPath": "/static/fonts/alegreya-latin-700italic.woff"
},
- "fonts/alegreya-latin-800.woff2": {
- "name": "fonts/alegreya-latin-800.woff2",
- "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-800.woff2",
- "publicPath": "/static/fonts/alegreya-latin-800.woff2"
- },
"fonts/alegreya-latin-800.woff": {
"name": "fonts/alegreya-latin-800.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-800.woff",
"publicPath": "/static/fonts/alegreya-latin-800.woff"
},
+ "fonts/alegreya-latin-800.woff2": {
+ "name": "fonts/alegreya-latin-800.woff2",
+ "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-800.woff2",
+ "publicPath": "/static/fonts/alegreya-latin-800.woff2"
+ },
"fonts/alegreya-latin-800italic.woff2": {
"name": "fonts/alegreya-latin-800italic.woff2",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-800italic.woff2",
"publicPath": "/static/fonts/alegreya-latin-800italic.woff2"
},
"fonts/alegreya-latin-800italic.woff": {
"name": "fonts/alegreya-latin-800italic.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-800italic.woff",
"publicPath": "/static/fonts/alegreya-latin-800italic.woff"
},
"fonts/alegreya-latin-900.woff2": {
"name": "fonts/alegreya-latin-900.woff2",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-900.woff2",
"publicPath": "/static/fonts/alegreya-latin-900.woff2"
},
"fonts/alegreya-latin-900.woff": {
"name": "fonts/alegreya-latin-900.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-900.woff",
"publicPath": "/static/fonts/alegreya-latin-900.woff"
},
"fonts/alegreya-latin-900italic.woff2": {
"name": "fonts/alegreya-latin-900italic.woff2",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-900italic.woff2",
"publicPath": "/static/fonts/alegreya-latin-900italic.woff2"
},
"fonts/alegreya-latin-900italic.woff": {
"name": "fonts/alegreya-latin-900italic.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-latin-900italic.woff",
"publicPath": "/static/fonts/alegreya-latin-900italic.woff"
},
"fonts/alegreya-sans-latin-100.woff2": {
"name": "fonts/alegreya-sans-latin-100.woff2",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-100.woff2",
"publicPath": "/static/fonts/alegreya-sans-latin-100.woff2"
},
"fonts/alegreya-sans-latin-100.woff": {
"name": "fonts/alegreya-sans-latin-100.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-100.woff",
"publicPath": "/static/fonts/alegreya-sans-latin-100.woff"
},
"fonts/alegreya-sans-latin-100italic.woff2": {
"name": "fonts/alegreya-sans-latin-100italic.woff2",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-100italic.woff2",
"publicPath": "/static/fonts/alegreya-sans-latin-100italic.woff2"
},
"fonts/alegreya-sans-latin-100italic.woff": {
"name": "fonts/alegreya-sans-latin-100italic.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-100italic.woff",
"publicPath": "/static/fonts/alegreya-sans-latin-100italic.woff"
},
"fonts/alegreya-sans-latin-300.woff2": {
"name": "fonts/alegreya-sans-latin-300.woff2",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-300.woff2",
"publicPath": "/static/fonts/alegreya-sans-latin-300.woff2"
},
- "fonts/alegreya-sans-latin-300italic.woff2": {
- "name": "fonts/alegreya-sans-latin-300italic.woff2",
- "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-300italic.woff2",
- "publicPath": "/static/fonts/alegreya-sans-latin-300italic.woff2"
- },
"fonts/alegreya-sans-latin-300.woff": {
"name": "fonts/alegreya-sans-latin-300.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-300.woff",
"publicPath": "/static/fonts/alegreya-sans-latin-300.woff"
},
+ "fonts/alegreya-sans-latin-300italic.woff2": {
+ "name": "fonts/alegreya-sans-latin-300italic.woff2",
+ "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-300italic.woff2",
+ "publicPath": "/static/fonts/alegreya-sans-latin-300italic.woff2"
+ },
"fonts/alegreya-sans-latin-300italic.woff": {
"name": "fonts/alegreya-sans-latin-300italic.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-300italic.woff",
"publicPath": "/static/fonts/alegreya-sans-latin-300italic.woff"
},
"fonts/alegreya-sans-latin-400.woff2": {
"name": "fonts/alegreya-sans-latin-400.woff2",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-400.woff2",
"publicPath": "/static/fonts/alegreya-sans-latin-400.woff2"
},
"fonts/alegreya-sans-latin-400.woff": {
"name": "fonts/alegreya-sans-latin-400.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-400.woff",
"publicPath": "/static/fonts/alegreya-sans-latin-400.woff"
},
"fonts/alegreya-sans-latin-400italic.woff2": {
"name": "fonts/alegreya-sans-latin-400italic.woff2",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-400italic.woff2",
"publicPath": "/static/fonts/alegreya-sans-latin-400italic.woff2"
},
"fonts/alegreya-sans-latin-400italic.woff": {
"name": "fonts/alegreya-sans-latin-400italic.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-400italic.woff",
"publicPath": "/static/fonts/alegreya-sans-latin-400italic.woff"
},
"fonts/alegreya-sans-latin-500.woff2": {
"name": "fonts/alegreya-sans-latin-500.woff2",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-500.woff2",
"publicPath": "/static/fonts/alegreya-sans-latin-500.woff2"
},
- "fonts/alegreya-sans-latin-500italic.woff2": {
- "name": "fonts/alegreya-sans-latin-500italic.woff2",
- "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-500italic.woff2",
- "publicPath": "/static/fonts/alegreya-sans-latin-500italic.woff2"
- },
"fonts/alegreya-sans-latin-500.woff": {
"name": "fonts/alegreya-sans-latin-500.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-500.woff",
"publicPath": "/static/fonts/alegreya-sans-latin-500.woff"
},
+ "fonts/alegreya-sans-latin-500italic.woff2": {
+ "name": "fonts/alegreya-sans-latin-500italic.woff2",
+ "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-500italic.woff2",
+ "publicPath": "/static/fonts/alegreya-sans-latin-500italic.woff2"
+ },
"fonts/alegreya-sans-latin-500italic.woff": {
"name": "fonts/alegreya-sans-latin-500italic.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-500italic.woff",
"publicPath": "/static/fonts/alegreya-sans-latin-500italic.woff"
},
- "fonts/alegreya-sans-latin-700.woff": {
- "name": "fonts/alegreya-sans-latin-700.woff",
- "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-700.woff",
- "publicPath": "/static/fonts/alegreya-sans-latin-700.woff"
- },
"fonts/alegreya-sans-latin-700.woff2": {
"name": "fonts/alegreya-sans-latin-700.woff2",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-700.woff2",
"publicPath": "/static/fonts/alegreya-sans-latin-700.woff2"
},
+ "fonts/alegreya-sans-latin-700.woff": {
+ "name": "fonts/alegreya-sans-latin-700.woff",
+ "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-700.woff",
+ "publicPath": "/static/fonts/alegreya-sans-latin-700.woff"
+ },
"fonts/alegreya-sans-latin-700italic.woff2": {
"name": "fonts/alegreya-sans-latin-700italic.woff2",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-700italic.woff2",
"publicPath": "/static/fonts/alegreya-sans-latin-700italic.woff2"
},
- "fonts/alegreya-sans-latin-800.woff2": {
- "name": "fonts/alegreya-sans-latin-800.woff2",
- "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-800.woff2",
- "publicPath": "/static/fonts/alegreya-sans-latin-800.woff2"
- },
"fonts/alegreya-sans-latin-700italic.woff": {
"name": "fonts/alegreya-sans-latin-700italic.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-700italic.woff",
"publicPath": "/static/fonts/alegreya-sans-latin-700italic.woff"
},
+ "fonts/alegreya-sans-latin-800.woff2": {
+ "name": "fonts/alegreya-sans-latin-800.woff2",
+ "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-800.woff2",
+ "publicPath": "/static/fonts/alegreya-sans-latin-800.woff2"
+ },
"fonts/alegreya-sans-latin-800.woff": {
"name": "fonts/alegreya-sans-latin-800.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-800.woff",
"publicPath": "/static/fonts/alegreya-sans-latin-800.woff"
},
+ "fonts/alegreya-sans-latin-800italic.woff2": {
+ "name": "fonts/alegreya-sans-latin-800italic.woff2",
+ "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-800italic.woff2",
+ "publicPath": "/static/fonts/alegreya-sans-latin-800italic.woff2"
+ },
"fonts/alegreya-sans-latin-800italic.woff": {
"name": "fonts/alegreya-sans-latin-800italic.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-800italic.woff",
"publicPath": "/static/fonts/alegreya-sans-latin-800italic.woff"
},
"fonts/alegreya-sans-latin-900.woff2": {
"name": "fonts/alegreya-sans-latin-900.woff2",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-900.woff2",
"publicPath": "/static/fonts/alegreya-sans-latin-900.woff2"
},
- "fonts/alegreya-sans-latin-800italic.woff2": {
- "name": "fonts/alegreya-sans-latin-800italic.woff2",
- "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-800italic.woff2",
- "publicPath": "/static/fonts/alegreya-sans-latin-800italic.woff2"
- },
"fonts/alegreya-sans-latin-900.woff": {
"name": "fonts/alegreya-sans-latin-900.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-900.woff",
"publicPath": "/static/fonts/alegreya-sans-latin-900.woff"
},
"fonts/alegreya-sans-latin-900italic.woff2": {
"name": "fonts/alegreya-sans-latin-900italic.woff2",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-900italic.woff2",
"publicPath": "/static/fonts/alegreya-sans-latin-900italic.woff2"
},
"fonts/alegreya-sans-latin-900italic.woff": {
"name": "fonts/alegreya-sans-latin-900italic.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/alegreya-sans-latin-900italic.woff",
"publicPath": "/static/fonts/alegreya-sans-latin-900italic.woff"
},
+ "js/pdf.worker.min.js": {
+ "name": "js/pdf.worker.min.js",
+ "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/pdf.worker.min.js",
+ "publicPath": "/static/js/pdf.worker.min.js"
+ },
"fonts/MathJax_AMS-Regular.woff": {
"name": "fonts/MathJax_AMS-Regular.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_AMS-Regular.woff",
"publicPath": "/static/fonts/MathJax_AMS-Regular.woff"
},
"fonts/MathJax_Calligraphic-Bold.woff": {
"name": "fonts/MathJax_Calligraphic-Bold.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_Calligraphic-Bold.woff",
"publicPath": "/static/fonts/MathJax_Calligraphic-Bold.woff"
},
"fonts/MathJax_Calligraphic-Regular.woff": {
"name": "fonts/MathJax_Calligraphic-Regular.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_Calligraphic-Regular.woff",
"publicPath": "/static/fonts/MathJax_Calligraphic-Regular.woff"
},
"fonts/MathJax_Fraktur-Bold.woff": {
"name": "fonts/MathJax_Fraktur-Bold.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_Fraktur-Bold.woff",
"publicPath": "/static/fonts/MathJax_Fraktur-Bold.woff"
},
"fonts/MathJax_Fraktur-Regular.woff": {
"name": "fonts/MathJax_Fraktur-Regular.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_Fraktur-Regular.woff",
"publicPath": "/static/fonts/MathJax_Fraktur-Regular.woff"
},
"fonts/MathJax_Main-Bold.woff": {
"name": "fonts/MathJax_Main-Bold.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_Main-Bold.woff",
"publicPath": "/static/fonts/MathJax_Main-Bold.woff"
},
"fonts/MathJax_Main-Italic.woff": {
"name": "fonts/MathJax_Main-Italic.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_Main-Italic.woff",
"publicPath": "/static/fonts/MathJax_Main-Italic.woff"
},
"fonts/MathJax_Main-Regular.woff": {
"name": "fonts/MathJax_Main-Regular.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_Main-Regular.woff",
"publicPath": "/static/fonts/MathJax_Main-Regular.woff"
},
"fonts/MathJax_Math-BoldItalic.woff": {
"name": "fonts/MathJax_Math-BoldItalic.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_Math-BoldItalic.woff",
"publicPath": "/static/fonts/MathJax_Math-BoldItalic.woff"
},
"fonts/MathJax_Math-Italic.woff": {
"name": "fonts/MathJax_Math-Italic.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_Math-Italic.woff",
"publicPath": "/static/fonts/MathJax_Math-Italic.woff"
},
"fonts/MathJax_Math-Regular.woff": {
"name": "fonts/MathJax_Math-Regular.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_Math-Regular.woff",
"publicPath": "/static/fonts/MathJax_Math-Regular.woff"
},
"fonts/MathJax_SansSerif-Bold.woff": {
"name": "fonts/MathJax_SansSerif-Bold.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_SansSerif-Bold.woff",
"publicPath": "/static/fonts/MathJax_SansSerif-Bold.woff"
},
"fonts/MathJax_SansSerif-Italic.woff": {
"name": "fonts/MathJax_SansSerif-Italic.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_SansSerif-Italic.woff",
"publicPath": "/static/fonts/MathJax_SansSerif-Italic.woff"
},
"fonts/MathJax_SansSerif-Regular.woff": {
"name": "fonts/MathJax_SansSerif-Regular.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_SansSerif-Regular.woff",
"publicPath": "/static/fonts/MathJax_SansSerif-Regular.woff"
},
"fonts/MathJax_Script-Regular.woff": {
"name": "fonts/MathJax_Script-Regular.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_Script-Regular.woff",
"publicPath": "/static/fonts/MathJax_Script-Regular.woff"
},
"fonts/MathJax_Size1-Regular.woff": {
"name": "fonts/MathJax_Size1-Regular.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_Size1-Regular.woff",
"publicPath": "/static/fonts/MathJax_Size1-Regular.woff"
},
"fonts/MathJax_Size2-Regular.woff": {
"name": "fonts/MathJax_Size2-Regular.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_Size2-Regular.woff",
"publicPath": "/static/fonts/MathJax_Size2-Regular.woff"
},
"fonts/MathJax_Size3-Regular.woff": {
"name": "fonts/MathJax_Size3-Regular.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_Size3-Regular.woff",
"publicPath": "/static/fonts/MathJax_Size3-Regular.woff"
},
"fonts/MathJax_Size4-Regular.woff": {
"name": "fonts/MathJax_Size4-Regular.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_Size4-Regular.woff",
"publicPath": "/static/fonts/MathJax_Size4-Regular.woff"
},
"fonts/MathJax_Typewriter-Regular.woff": {
"name": "fonts/MathJax_Typewriter-Regular.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_Typewriter-Regular.woff",
"publicPath": "/static/fonts/MathJax_Typewriter-Regular.woff"
},
"fonts/MathJax_Vector-Bold.woff": {
"name": "fonts/MathJax_Vector-Bold.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_Vector-Bold.woff",
"publicPath": "/static/fonts/MathJax_Vector-Bold.woff"
},
"fonts/MathJax_Vector-Regular.woff": {
"name": "fonts/MathJax_Vector-Regular.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_Vector-Regular.woff",
"publicPath": "/static/fonts/MathJax_Vector-Regular.woff"
},
"fonts/MathJax_Zero.woff": {
"name": "fonts/MathJax_Zero.woff",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/fonts/MathJax_Zero.woff",
"publicPath": "/static/fonts/MathJax_Zero.woff"
},
- "js/pdf.worker.min.js": {
- "name": "js/pdf.worker.min.js",
- "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/pdf.worker.min.js",
- "publicPath": "/static/js/pdf.worker.min.js"
- },
"robots.txt": {
"name": "robots.txt",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/robots.txt",
"publicPath": "/static/robots.txt"
},
"js/pdf.worker.min.js.LICENSE.txt": {
"name": "js/pdf.worker.min.js.LICENSE.txt",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/pdf.worker.min.js.LICENSE.txt",
"publicPath": "/static/js/pdf.worker.min.js.LICENSE.txt"
},
"js/add_forge.bcbbc1be5ab34eede65c.js.LICENSE.txt": {
"name": "js/add_forge.bcbbc1be5ab34eede65c.js.LICENSE.txt",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/add_forge.bcbbc1be5ab34eede65c.js.LICENSE.txt",
"publicPath": "/static/js/add_forge.bcbbc1be5ab34eede65c.js.LICENSE.txt"
},
"js/admin.e1bdd6f126d315dc57e6.js.LICENSE.txt": {
"name": "js/admin.e1bdd6f126d315dc57e6.js.LICENSE.txt",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/admin.e1bdd6f126d315dc57e6.js.LICENSE.txt",
"publicPath": "/static/js/admin.e1bdd6f126d315dc57e6.js.LICENSE.txt"
},
"js/auth.7a6ba4612115126f9b59.js.LICENSE.txt": {
"name": "js/auth.7a6ba4612115126f9b59.js.LICENSE.txt",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/auth.7a6ba4612115126f9b59.js.LICENSE.txt",
"publicPath": "/static/js/auth.7a6ba4612115126f9b59.js.LICENSE.txt"
},
"js/browse.89ce9f7581cb4a43fa54.js.LICENSE.txt": {
"name": "js/browse.89ce9f7581cb4a43fa54.js.LICENSE.txt",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/browse.89ce9f7581cb4a43fa54.js.LICENSE.txt",
"publicPath": "/static/js/browse.89ce9f7581cb4a43fa54.js.LICENSE.txt"
},
"js/guided_tour.6fdb762b8416936b3c84.js.LICENSE.txt": {
"name": "js/guided_tour.6fdb762b8416936b3c84.js.LICENSE.txt",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/guided_tour.6fdb762b8416936b3c84.js.LICENSE.txt",
"publicPath": "/static/js/guided_tour.6fdb762b8416936b3c84.js.LICENSE.txt"
},
"js/highlightjs.ccd71c93a63af0249728.js.LICENSE.txt": {
"name": "js/highlightjs.ccd71c93a63af0249728.js.LICENSE.txt",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/highlightjs.ccd71c93a63af0249728.js.LICENSE.txt",
"publicPath": "/static/js/highlightjs.ccd71c93a63af0249728.js.LICENSE.txt"
},
"js/revision.530bd3980955c9cce3fb.js.LICENSE.txt": {
"name": "js/revision.530bd3980955c9cce3fb.js.LICENSE.txt",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/revision.530bd3980955c9cce3fb.js.LICENSE.txt",
"publicPath": "/static/js/revision.530bd3980955c9cce3fb.js.LICENSE.txt"
},
"js/save.78a0e5b182ba60ef8cba.js.LICENSE.txt": {
"name": "js/save.78a0e5b182ba60ef8cba.js.LICENSE.txt",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/save.78a0e5b182ba60ef8cba.js.LICENSE.txt",
"publicPath": "/static/js/save.78a0e5b182ba60ef8cba.js.LICENSE.txt"
},
"js/showdown.b448e42a34c43d6a7de5.js.LICENSE.txt": {
"name": "js/showdown.b448e42a34c43d6a7de5.js.LICENSE.txt",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/showdown.b448e42a34c43d6a7de5.js.LICENSE.txt",
"publicPath": "/static/js/showdown.b448e42a34c43d6a7de5.js.LICENSE.txt"
},
"js/vault.e2e8f042b9c742390872.js.LICENSE.txt": {
"name": "js/vault.e2e8f042b9c742390872.js.LICENSE.txt",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/vault.e2e8f042b9c742390872.js.LICENSE.txt",
"publicPath": "/static/js/vault.e2e8f042b9c742390872.js.LICENSE.txt"
},
"js/vendors.4d86327911239b43ce67.js.LICENSE.txt": {
"name": "js/vendors.4d86327911239b43ce67.js.LICENSE.txt",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/vendors.4d86327911239b43ce67.js.LICENSE.txt",
"publicPath": "/static/js/vendors.4d86327911239b43ce67.js.LICENSE.txt"
},
"js/webapp.ec1d7512d2628f39df9b.js.LICENSE.txt": {
"name": "js/webapp.ec1d7512d2628f39df9b.js.LICENSE.txt",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/webapp.ec1d7512d2628f39df9b.js.LICENSE.txt",
"publicPath": "/static/js/webapp.ec1d7512d2628f39df9b.js.LICENSE.txt"
},
"css/add_forge.737aa359fb467b5670bc.css": {
"name": "css/add_forge.737aa359fb467b5670bc.css",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/add_forge.737aa359fb467b5670bc.css",
"publicPath": "/static/css/add_forge.737aa359fb467b5670bc.css"
},
"js/add_forge.bcbbc1be5ab34eede65c.js": {
"name": "js/add_forge.bcbbc1be5ab34eede65c.js",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/add_forge.bcbbc1be5ab34eede65c.js",
"publicPath": "/static/js/add_forge.bcbbc1be5ab34eede65c.js"
},
"js/admin.e1bdd6f126d315dc57e6.js": {
"name": "js/admin.e1bdd6f126d315dc57e6.js",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/admin.e1bdd6f126d315dc57e6.js",
"publicPath": "/static/js/admin.e1bdd6f126d315dc57e6.js"
},
"css/auth.0336a94c2c02b4b2a4f4.css": {
"name": "css/auth.0336a94c2c02b4b2a4f4.css",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/auth.0336a94c2c02b4b2a4f4.css",
"publicPath": "/static/css/auth.0336a94c2c02b4b2a4f4.css"
},
"js/auth.7a6ba4612115126f9b59.js": {
"name": "js/auth.7a6ba4612115126f9b59.js",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/auth.7a6ba4612115126f9b59.js",
"publicPath": "/static/js/auth.7a6ba4612115126f9b59.js"
},
"css/browse.6315ef52ed73df532bed.css": {
"name": "css/browse.6315ef52ed73df532bed.css",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/browse.6315ef52ed73df532bed.css",
"publicPath": "/static/css/browse.6315ef52ed73df532bed.css"
},
"js/browse.89ce9f7581cb4a43fa54.js": {
"name": "js/browse.89ce9f7581cb4a43fa54.js",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/browse.89ce9f7581cb4a43fa54.js",
"publicPath": "/static/js/browse.89ce9f7581cb4a43fa54.js"
},
"css/guided_tour.00d493abd76b55df7e25.css": {
"name": "css/guided_tour.00d493abd76b55df7e25.css",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/guided_tour.00d493abd76b55df7e25.css",
"publicPath": "/static/css/guided_tour.00d493abd76b55df7e25.css"
},
"js/guided_tour.6fdb762b8416936b3c84.js": {
"name": "js/guided_tour.6fdb762b8416936b3c84.js",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/guided_tour.6fdb762b8416936b3c84.js",
"publicPath": "/static/js/guided_tour.6fdb762b8416936b3c84.js"
},
"css/origin.5b45e9e6e54fd51ee886.css": {
"name": "css/origin.5b45e9e6e54fd51ee886.css",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/origin.5b45e9e6e54fd51ee886.css",
"publicPath": "/static/css/origin.5b45e9e6e54fd51ee886.css"
},
"js/origin.751694c0f651d0e204de.js": {
"name": "js/origin.751694c0f651d0e204de.js",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/origin.751694c0f651d0e204de.js",
"publicPath": "/static/js/origin.751694c0f651d0e204de.js"
},
"css/revision.5ddd36d69e1760bfa29d.css": {
"name": "css/revision.5ddd36d69e1760bfa29d.css",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/revision.5ddd36d69e1760bfa29d.css",
"publicPath": "/static/css/revision.5ddd36d69e1760bfa29d.css"
},
"js/revision.530bd3980955c9cce3fb.js": {
"name": "js/revision.530bd3980955c9cce3fb.js",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/revision.530bd3980955c9cce3fb.js",
"publicPath": "/static/js/revision.530bd3980955c9cce3fb.js"
},
"js/save.78a0e5b182ba60ef8cba.js": {
"name": "js/save.78a0e5b182ba60ef8cba.js",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/save.78a0e5b182ba60ef8cba.js",
"publicPath": "/static/js/save.78a0e5b182ba60ef8cba.js"
},
"css/vault.25fc5883f848b48ffa5b.css": {
"name": "css/vault.25fc5883f848b48ffa5b.css",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/vault.25fc5883f848b48ffa5b.css",
"publicPath": "/static/css/vault.25fc5883f848b48ffa5b.css"
},
"js/vault.e2e8f042b9c742390872.js": {
"name": "js/vault.e2e8f042b9c742390872.js",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/vault.e2e8f042b9c742390872.js",
"publicPath": "/static/js/vault.e2e8f042b9c742390872.js"
},
"css/vendors.e9b3239bd4aa43cec2c2.css": {
"name": "css/vendors.e9b3239bd4aa43cec2c2.css",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/vendors.e9b3239bd4aa43cec2c2.css",
"publicPath": "/static/css/vendors.e9b3239bd4aa43cec2c2.css"
},
"js/vendors.4d86327911239b43ce67.js": {
"name": "js/vendors.4d86327911239b43ce67.js",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/vendors.4d86327911239b43ce67.js",
"publicPath": "/static/js/vendors.4d86327911239b43ce67.js"
},
"css/webapp.dd439fd586ffe21d20dc.css": {
"name": "css/webapp.dd439fd586ffe21d20dc.css",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/webapp.dd439fd586ffe21d20dc.css",
"publicPath": "/static/css/webapp.dd439fd586ffe21d20dc.css"
},
"js/webapp.ec1d7512d2628f39df9b.js": {
"name": "js/webapp.ec1d7512d2628f39df9b.js",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/webapp.ec1d7512d2628f39df9b.js",
"publicPath": "/static/js/webapp.ec1d7512d2628f39df9b.js"
},
"js/d3.f989183a810fb9dbb086.js": {
"name": "js/d3.f989183a810fb9dbb086.js",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/d3.f989183a810fb9dbb086.js",
"publicPath": "/static/js/d3.f989183a810fb9dbb086.js"
},
"css/highlightjs.ae43064ab38a65a04d81.css": {
"name": "css/highlightjs.ae43064ab38a65a04d81.css",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/highlightjs.ae43064ab38a65a04d81.css",
"publicPath": "/static/css/highlightjs.ae43064ab38a65a04d81.css"
},
"js/highlightjs.ccd71c93a63af0249728.js": {
"name": "js/highlightjs.ccd71c93a63af0249728.js",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/highlightjs.ccd71c93a63af0249728.js",
"publicPath": "/static/js/highlightjs.ccd71c93a63af0249728.js"
},
"css/showdown.426fbf6a7a6653fd4cbb.css": {
"name": "css/showdown.426fbf6a7a6653fd4cbb.css",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/showdown.426fbf6a7a6653fd4cbb.css",
"publicPath": "/static/css/showdown.426fbf6a7a6653fd4cbb.css"
},
"js/showdown.b448e42a34c43d6a7de5.js": {
"name": "js/showdown.b448e42a34c43d6a7de5.js",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/showdown.b448e42a34c43d6a7de5.js",
"publicPath": "/static/js/showdown.b448e42a34c43d6a7de5.js"
},
"css/org.6851b70c924e28f6bf51.css": {
"name": "css/org.6851b70c924e28f6bf51.css",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/org.6851b70c924e28f6bf51.css",
"publicPath": "/static/css/org.6851b70c924e28f6bf51.css"
},
"js/org.9adc9a39a210c2fb4be0.js": {
"name": "js/org.9adc9a39a210c2fb4be0.js",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/org.9adc9a39a210c2fb4be0.js",
"publicPath": "/static/js/org.9adc9a39a210c2fb4be0.js"
},
"js/pdfjs.7fa499e22fea56527058.js": {
"name": "js/pdfjs.7fa499e22fea56527058.js",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/pdfjs.7fa499e22fea56527058.js",
"publicPath": "/static/js/pdfjs.7fa499e22fea56527058.js"
},
"js/mathjax.a0046af7afe82fd10728.js": {
"name": "js/mathjax.a0046af7afe82fd10728.js",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/mathjax.a0046af7afe82fd10728.js",
"publicPath": "/static/js/mathjax.a0046af7afe82fd10728.js"
},
"css/add_forge.737aa359fb467b5670bc.css.map": {
"name": "css/add_forge.737aa359fb467b5670bc.css.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/add_forge.737aa359fb467b5670bc.css.map",
"publicPath": "/static/css/add_forge.737aa359fb467b5670bc.css.map"
},
+ "css/auth.0336a94c2c02b4b2a4f4.css.map": {
+ "name": "css/auth.0336a94c2c02b4b2a4f4.css.map",
+ "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/auth.0336a94c2c02b4b2a4f4.css.map",
+ "publicPath": "/static/css/auth.0336a94c2c02b4b2a4f4.css.map"
+ },
"css/guided_tour.00d493abd76b55df7e25.css.map": {
"name": "css/guided_tour.00d493abd76b55df7e25.css.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/guided_tour.00d493abd76b55df7e25.css.map",
"publicPath": "/static/css/guided_tour.00d493abd76b55df7e25.css.map"
},
"css/origin.5b45e9e6e54fd51ee886.css.map": {
"name": "css/origin.5b45e9e6e54fd51ee886.css.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/origin.5b45e9e6e54fd51ee886.css.map",
"publicPath": "/static/css/origin.5b45e9e6e54fd51ee886.css.map"
},
+ "css/browse.6315ef52ed73df532bed.css.map": {
+ "name": "css/browse.6315ef52ed73df532bed.css.map",
+ "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/browse.6315ef52ed73df532bed.css.map",
+ "publicPath": "/static/css/browse.6315ef52ed73df532bed.css.map"
+ },
"css/revision.5ddd36d69e1760bfa29d.css.map": {
"name": "css/revision.5ddd36d69e1760bfa29d.css.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/revision.5ddd36d69e1760bfa29d.css.map",
"publicPath": "/static/css/revision.5ddd36d69e1760bfa29d.css.map"
},
"css/vault.25fc5883f848b48ffa5b.css.map": {
"name": "css/vault.25fc5883f848b48ffa5b.css.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/vault.25fc5883f848b48ffa5b.css.map",
"publicPath": "/static/css/vault.25fc5883f848b48ffa5b.css.map"
},
- "css/auth.0336a94c2c02b4b2a4f4.css.map": {
- "name": "css/auth.0336a94c2c02b4b2a4f4.css.map",
- "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/auth.0336a94c2c02b4b2a4f4.css.map",
- "publicPath": "/static/css/auth.0336a94c2c02b4b2a4f4.css.map"
- },
"css/vendors.e9b3239bd4aa43cec2c2.css.map": {
"name": "css/vendors.e9b3239bd4aa43cec2c2.css.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/vendors.e9b3239bd4aa43cec2c2.css.map",
"publicPath": "/static/css/vendors.e9b3239bd4aa43cec2c2.css.map"
},
- "css/browse.6315ef52ed73df532bed.css.map": {
- "name": "css/browse.6315ef52ed73df532bed.css.map",
- "path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/browse.6315ef52ed73df532bed.css.map",
- "publicPath": "/static/css/browse.6315ef52ed73df532bed.css.map"
- },
"css/webapp.dd439fd586ffe21d20dc.css.map": {
"name": "css/webapp.dd439fd586ffe21d20dc.css.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/webapp.dd439fd586ffe21d20dc.css.map",
"publicPath": "/static/css/webapp.dd439fd586ffe21d20dc.css.map"
},
"css/highlightjs.ae43064ab38a65a04d81.css.map": {
"name": "css/highlightjs.ae43064ab38a65a04d81.css.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/highlightjs.ae43064ab38a65a04d81.css.map",
"publicPath": "/static/css/highlightjs.ae43064ab38a65a04d81.css.map"
},
"css/showdown.426fbf6a7a6653fd4cbb.css.map": {
"name": "css/showdown.426fbf6a7a6653fd4cbb.css.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/showdown.426fbf6a7a6653fd4cbb.css.map",
"publicPath": "/static/css/showdown.426fbf6a7a6653fd4cbb.css.map"
},
"css/org.6851b70c924e28f6bf51.css.map": {
"name": "css/org.6851b70c924e28f6bf51.css.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/css/org.6851b70c924e28f6bf51.css.map",
"publicPath": "/static/css/org.6851b70c924e28f6bf51.css.map"
},
"js/add_forge.bcbbc1be5ab34eede65c.js.map": {
"name": "js/add_forge.bcbbc1be5ab34eede65c.js.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/add_forge.bcbbc1be5ab34eede65c.js.map",
"publicPath": "/static/js/add_forge.bcbbc1be5ab34eede65c.js.map"
},
"js/admin.e1bdd6f126d315dc57e6.js.map": {
"name": "js/admin.e1bdd6f126d315dc57e6.js.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/admin.e1bdd6f126d315dc57e6.js.map",
"publicPath": "/static/js/admin.e1bdd6f126d315dc57e6.js.map"
},
"js/auth.7a6ba4612115126f9b59.js.map": {
"name": "js/auth.7a6ba4612115126f9b59.js.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/auth.7a6ba4612115126f9b59.js.map",
"publicPath": "/static/js/auth.7a6ba4612115126f9b59.js.map"
},
"js/browse.89ce9f7581cb4a43fa54.js.map": {
"name": "js/browse.89ce9f7581cb4a43fa54.js.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/browse.89ce9f7581cb4a43fa54.js.map",
"publicPath": "/static/js/browse.89ce9f7581cb4a43fa54.js.map"
},
"js/guided_tour.6fdb762b8416936b3c84.js.map": {
"name": "js/guided_tour.6fdb762b8416936b3c84.js.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/guided_tour.6fdb762b8416936b3c84.js.map",
"publicPath": "/static/js/guided_tour.6fdb762b8416936b3c84.js.map"
},
"js/origin.751694c0f651d0e204de.js.map": {
"name": "js/origin.751694c0f651d0e204de.js.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/origin.751694c0f651d0e204de.js.map",
"publicPath": "/static/js/origin.751694c0f651d0e204de.js.map"
},
"js/revision.530bd3980955c9cce3fb.js.map": {
"name": "js/revision.530bd3980955c9cce3fb.js.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/revision.530bd3980955c9cce3fb.js.map",
"publicPath": "/static/js/revision.530bd3980955c9cce3fb.js.map"
},
"js/save.78a0e5b182ba60ef8cba.js.map": {
"name": "js/save.78a0e5b182ba60ef8cba.js.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/save.78a0e5b182ba60ef8cba.js.map",
"publicPath": "/static/js/save.78a0e5b182ba60ef8cba.js.map"
},
"js/vault.e2e8f042b9c742390872.js.map": {
"name": "js/vault.e2e8f042b9c742390872.js.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/vault.e2e8f042b9c742390872.js.map",
"publicPath": "/static/js/vault.e2e8f042b9c742390872.js.map"
},
"js/vendors.4d86327911239b43ce67.js.map": {
"name": "js/vendors.4d86327911239b43ce67.js.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/vendors.4d86327911239b43ce67.js.map",
"publicPath": "/static/js/vendors.4d86327911239b43ce67.js.map"
},
"js/webapp.ec1d7512d2628f39df9b.js.map": {
"name": "js/webapp.ec1d7512d2628f39df9b.js.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/webapp.ec1d7512d2628f39df9b.js.map",
"publicPath": "/static/js/webapp.ec1d7512d2628f39df9b.js.map"
},
"js/d3.f989183a810fb9dbb086.js.map": {
"name": "js/d3.f989183a810fb9dbb086.js.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/d3.f989183a810fb9dbb086.js.map",
"publicPath": "/static/js/d3.f989183a810fb9dbb086.js.map"
},
"js/highlightjs.ccd71c93a63af0249728.js.map": {
"name": "js/highlightjs.ccd71c93a63af0249728.js.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/highlightjs.ccd71c93a63af0249728.js.map",
"publicPath": "/static/js/highlightjs.ccd71c93a63af0249728.js.map"
},
"js/showdown.b448e42a34c43d6a7de5.js.map": {
"name": "js/showdown.b448e42a34c43d6a7de5.js.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/showdown.b448e42a34c43d6a7de5.js.map",
"publicPath": "/static/js/showdown.b448e42a34c43d6a7de5.js.map"
},
"js/org.9adc9a39a210c2fb4be0.js.map": {
"name": "js/org.9adc9a39a210c2fb4be0.js.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/org.9adc9a39a210c2fb4be0.js.map",
"publicPath": "/static/js/org.9adc9a39a210c2fb4be0.js.map"
},
"js/pdfjs.7fa499e22fea56527058.js.map": {
"name": "js/pdfjs.7fa499e22fea56527058.js.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/pdfjs.7fa499e22fea56527058.js.map",
"publicPath": "/static/js/pdfjs.7fa499e22fea56527058.js.map"
},
"js/mathjax.a0046af7afe82fd10728.js.map": {
"name": "js/mathjax.a0046af7afe82fd10728.js.map",
"path": "/var/lib/jenkins/workspace/DWAPPS/pypi-upload/static/js/mathjax.a0046af7afe82fd10728.js.map",
"publicPath": "/static/js/mathjax.a0046af7afe82fd10728.js.map"
}
},
"chunks": {
"add_forge": [
"css/add_forge.737aa359fb467b5670bc.css",
"js/add_forge.bcbbc1be5ab34eede65c.js"
],
"admin": [
"js/admin.e1bdd6f126d315dc57e6.js"
],
"auth": [
"css/auth.0336a94c2c02b4b2a4f4.css",
"js/auth.7a6ba4612115126f9b59.js"
],
"browse": [
"css/browse.6315ef52ed73df532bed.css",
"js/browse.89ce9f7581cb4a43fa54.js"
],
"guided_tour": [
"css/guided_tour.00d493abd76b55df7e25.css",
"js/guided_tour.6fdb762b8416936b3c84.js"
],
"origin": [
"css/origin.5b45e9e6e54fd51ee886.css",
"js/origin.751694c0f651d0e204de.js"
],
"revision": [
"css/revision.5ddd36d69e1760bfa29d.css",
"js/revision.530bd3980955c9cce3fb.js"
],
"save": [
"js/save.78a0e5b182ba60ef8cba.js"
],
"vault": [
"css/vault.25fc5883f848b48ffa5b.css",
"js/vault.e2e8f042b9c742390872.js"
],
"vendors": [
"css/vendors.e9b3239bd4aa43cec2c2.css",
"js/vendors.4d86327911239b43ce67.js"
],
"webapp": [
"css/webapp.dd439fd586ffe21d20dc.css",
"js/webapp.ec1d7512d2628f39df9b.js"
]
},
"publicPath": "/static/"
}
\ No newline at end of file
diff --git a/swh.web.egg-info/PKG-INFO b/swh.web.egg-info/PKG-INFO
index 3beeb4c1..120a2158 100644
--- a/swh.web.egg-info/PKG-INFO
+++ b/swh.web.egg-info/PKG-INFO
@@ -1,206 +1,206 @@
Metadata-Version: 2.1
Name: swh.web
-Version: 0.0.379
+Version: 0.0.380
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
Project-URL: Bug Reports, https://forge.softwareheritage.org/maniphest
Project-URL: Funding, https://www.softwareheritage.org/donate
Project-URL: Source, https://forge.softwareheritage.org/source/swh-web
Project-URL: Documentation, https://docs.softwareheritage.org/devel/swh-web/
Platform: UNKNOWN
Classifier: Programming Language :: Python :: 3
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
Classifier: Operating System :: OS Independent
Classifier: Development Status :: 5 - Production/Stable
Classifier: Framework :: Django
Requires-Python: >=3.7
Description-Content-Type: text/markdown
Provides-Extra: testing
License-File: LICENSE
License-File: AUTHORS
# swh-web
This repository holds the development of Software Heritage web applications:
* swh-web API (https://archive.softwareheritage.org/api): enables to query the
content of the archive through HTTP requests and get responses in JSON or
YAML.
* swh-web browse (https://archive.softwareheritage.org/browse): graphical
interface that eases the navigation in the archive.
Documentation about how to use these components but also the details of their
URI schemes can be found in the docs folder. The produced HTML documentation
can be read and browsed at
https://docs.softwareheritage.org/devel/swh-web/index.html.
## Technical details
Those applications are powered by:
* [Django Web Framework](https://www.djangoproject.com/) on the backend side
with the following extensions enabled:
* [django-rest-framework](http://www.django-rest-framework.org/)
* [django-webpack-loader](https://github.com/owais/django-webpack-loader)
* [django-js-reverse](http://django-js-reverse.readthedocs.io/en/latest/)
* [webpack](https://webpack.js.org/) on the frontend side for better static
assets management, including:
* assets dependencies management and retrieval through
[yarn](https://yarnpkg.com/en/)
* linting of custom javascript code (through [eslint](https://eslint.org/))
and stylesheets (through [stylelint](https://stylelint.io/))
* use of [es6](http://es6-features.org) syntax and advanced javascript
feature like [async/await](https://javascript.info/async-await) or
[fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
thanks to [babel](https://babeljs.io/) (es6 to es5 transpiler and
polyfills provider)
* assets minification (using [terser](https://github.com/terser-js/terser)
and [cssnano](http://cssnano.co/)) but also dead code elimination for
production use
## How to build, run and test
### Backend requirements
First you will need [Python 3](https://www.python.org) and a complete [swh
development
environment](https://forge.softwareheritage.org/source/swh-environment/)
installed.
To run the backend, you need to have the following [Python 3
modules](requirements.txt) installed.
To run the backend tests, the following [Python 3
modules](requirements-test.txt) are also required to be installed.
One easy way to install them is to use the `pip` tool:
```
$ pip install -r requirements.txt -r requirements-test.txt
```
### Frontend requirements
To compile the frontend assets, you need to have
[nodejs](https://nodejs.org/en/) >= 12.0.0 and [yarn](https://yarnpkg.com/en/)
installed. If you are on Debian, you can easily install an up to date nodejs
from the
[nodesource](https://github.com/nodesource/distributions/blob/master/README.md)
repository.
Packages for yarn can be installed by following [these
instructions](https://yarnpkg.com/en/docs/install#debian-stable).
Alternatively, you can install yarn with `npm install yarn`, and add
`YARN=node_modules/yarn/bin/yarn` as argument whenever you run `make`.
Please note that the static assets bundles generated by webpack are not stored
in the git repository. Follow the instructions below in order to generate them
in order to be able to run the frontend part of the web applications.
### Make targets to execute the applications
Below is the list of available make targets that can be executed from the root
directory of swh-web in order to build and/or execute the web applications
under various configurations:
* **run-django-webpack-devserver**: Compile and serve not optimized (without
mignification and dead code elimination) frontend static assets using
[webpack-dev-server](https://github.com/webpack/webpack-dev-server) and run
django server with development settings. This is the recommended target to
use when developing swh-web as it enables automatic reloading of backend and
frontend part of the applications when modifying source files (*.py, *.js,
*.css, *.html).
* **run-django-webpack-dev**: Compile not optimized (no minification, no dead
code elimination) frontend static assets using webpack and run django server
with development settings. This is the recommended target when one only wants
to develop the backend side of the application.
* **run-django-webpack-prod**: Compile optimized (with minification and dead
code elimination) frontend static assets using webpack and run django server
with production settings. This is useful to test the applications in
production mode (with the difference that static assets are served by
django). Production settings notably enable advanced django caching and you
will need to have [memcached](https://memcached.org/) installed for that
feature to work.
* **run-django-server-dev**: Run the django server with development settings
but without compiling frontend static assets through webpack.
* **run-django-server-prod**: Run the django server with production settings
but without compiling frontend static assets through webpack.
* **run-gunicorn-server**: Run the web applications with production settings in
a [gunicorn](http://gunicorn.org/) worker as they will be in real production
environment.
Once one of these targets executed, the web applications can be executed by
pointing your browser to http://localhost:5004.
### Make targets to test the applications
Some make targets are also available to easily execute the backend and frontend
tests of the Software Heritage web applications.
The backend tests are powered by the
[pytest](https://docs.pytest.org/en/latest/) and
[hypothesis](https://hypothesis.readthedocs.io/en/latest/) frameworks while the
frontend ones rely on the use of the [cypress](https://www.cypress.io/) tool.
Below is the exhaustive list of those targets:
* **test**: execute the backend tests using a fast hypothesis profile (only one
input example will be provided for each test)
* **test-full**: execute the backend tests using a slower hypothesis profile
(one hundred of input examples will be provided for each test which helps
spotting possible bugs)
* **test-frontend**: execute the frontend tests using cypress in headless mode
but with some slow test suites disabled
* **test-frontend-full**: execute the frontend tests using cypress in headless
mode with all test suites enabled
* **test-frontend-ui**: execute the frontend tests using the cypress GUI but
with some slow test suites disabled
* **test-frontend-full-ui**: execute the frontend tests using the cypress GUI
with all test suites enabled
### Yarn targets
Below is a list of available yarn targets in order to only execute the frontend
static assets compilation (no web server will be executed):
* **build-dev**: compile not optimized (without mignification and dead code
elimination) frontend static assets and store the results in the
`swh/web/static` folder.
* **build**: compile optimized (with mignification and dead code elimination)
frontend static assets and store the results in the `swh/web/static` folder.
**The build target must be executed prior performing the Debian packaging of
swh-web** in order for the package to contain the optimized assets dedicated to
production environment.
To execute these targets, issue the following command:
```
$ yarn <target_name>
```
diff --git a/swh.web.egg-info/SOURCES.txt b/swh.web.egg-info/SOURCES.txt
index 61d8c425..b66be8c1 100644
--- a/swh.web.egg-info/SOURCES.txt
+++ b/swh.web.egg-info/SOURCES.txt
@@ -1,2038 +1,2044 @@
.gitignore
.pre-commit-config.yaml
AUTHORS
CODE_OF_CONDUCT.md
CONTRIBUTORS
LICENSE
MANIFEST.in
Makefile
Makefile.local
README.md
conftest.py
cypress.json
mypy.ini
package.json
pyproject.toml
pytest.ini
requirements-swh.txt
requirements-test.txt
requirements.txt
setup.cfg
setup.py
tox.ini
yarn.lock
assets/config/.bootstraprc
assets/config/.eslintignore
assets/config/.eslintrc
assets/config/bootstrap-pre-customize.scss
assets/config/webpack.config.development.js
assets/config/webpack.config.production.js
assets/config/webpack-plugins/dump-highlightjs-languages-data-plugin.js
assets/config/webpack-plugins/fix-swh-source-maps-webpack-plugin.js
assets/config/webpack-plugins/generate-weblabels-webpack-plugin/README.md
assets/config/webpack-plugins/generate-weblabels-webpack-plugin/index.js
assets/config/webpack-plugins/generate-weblabels-webpack-plugin/jslicenses.ejs
assets/config/webpack-plugins/generate-weblabels-webpack-plugin/plugin-options-schema.json
assets/config/webpack-plugins/generate-weblabels-webpack-plugin/spdx-licenses-mapping.js
assets/src/bundles/add_forge/add-forge.css
assets/src/bundles/add_forge/add-request-history-item.ejs
assets/src/bundles/add_forge/create-request.js
assets/src/bundles/add_forge/forge-admin-email.ejs
assets/src/bundles/add_forge/index.js
assets/src/bundles/add_forge/moderation-dashboard.js
assets/src/bundles/add_forge/request-dashboard.js
assets/src/bundles/admin/deposit.js
assets/src/bundles/admin/index.js
assets/src/bundles/admin/mailmap-form.ejs
assets/src/bundles/admin/mailmap.js
assets/src/bundles/admin/origin-save.js
assets/src/bundles/auth/auth.css
assets/src/bundles/auth/index.js
assets/src/bundles/browse/breadcrumbs.css
assets/src/bundles/browse/browse-utils.js
assets/src/bundles/browse/browse.css
assets/src/bundles/browse/content.css
assets/src/bundles/browse/index.js
assets/src/bundles/browse/origin-search.js
assets/src/bundles/browse/snapshot-navigation.css
assets/src/bundles/browse/snapshot-navigation.js
assets/src/bundles/browse/swhid-utils.js
assets/src/bundles/guided_tour/guided-tour-steps.yaml
assets/src/bundles/guided_tour/index.js
assets/src/bundles/guided_tour/swh-introjs.css
assets/src/bundles/origin/index.js
assets/src/bundles/origin/utils.js
assets/src/bundles/origin/visits-calendar.js
assets/src/bundles/origin/visits-histogram.js
assets/src/bundles/origin/visits-reporting.css
assets/src/bundles/origin/visits-reporting.js
assets/src/bundles/revision/diff-panel.ejs
assets/src/bundles/revision/diff-utils.js
assets/src/bundles/revision/index.js
assets/src/bundles/revision/log-utils.js
assets/src/bundles/revision/revision.css
assets/src/bundles/save/artifact-form-row.ejs
assets/src/bundles/save/index.js
assets/src/bundles/vault/index.js
assets/src/bundles/vault/vault-create-tasks.js
assets/src/bundles/vault/vault-table-row.ejs
assets/src/bundles/vault/vault-ui.js
assets/src/bundles/vault/vault.css
assets/src/bundles/vendors/datatables.css
assets/src/bundles/vendors/elementsfrompoint-polyfill.js
assets/src/bundles/vendors/index.js
assets/src/bundles/webapp/badges.js
assets/src/bundles/webapp/breadcrumbs.css
assets/src/bundles/webapp/code-highlighting.js
assets/src/bundles/webapp/coverage.css
assets/src/bundles/webapp/history-counters.css
assets/src/bundles/webapp/history-counters.js
assets/src/bundles/webapp/iframes.js
assets/src/bundles/webapp/index.js
assets/src/bundles/webapp/math-typesetting.js
assets/src/bundles/webapp/notebook-rendering.js
assets/src/bundles/webapp/notebook.css
assets/src/bundles/webapp/pdf-rendering.js
assets/src/bundles/webapp/readme-rendering.js
assets/src/bundles/webapp/sentry.js
assets/src/bundles/webapp/status-widget.css
assets/src/bundles/webapp/status-widget.js
assets/src/bundles/webapp/webapp-utils.js
assets/src/bundles/webapp/webapp.css
assets/src/bundles/webapp/xss-filtering.js
assets/src/thirdparty/jquery.tabSlideOut/LICENSE
assets/src/thirdparty/jquery.tabSlideOut/jquery.tabSlideOut.css
assets/src/thirdparty/jquery.tabSlideOut/jquery.tabSlideOut.js
assets/src/utils/constants.js
assets/src/utils/d3.js
assets/src/utils/functions.js
assets/src/utils/highlightjs.css
assets/src/utils/highlightjs.js
assets/src/utils/hljs-swh-theme.css
assets/src/utils/mathjax.js
assets/src/utils/org.css
assets/src/utils/org.js
assets/src/utils/requests-filter-checkbox.ejs
assets/src/utils/scrolling.js
assets/src/utils/showdown.css
assets/src/utils/showdown.js
cypress/fixtures/add-forge-now-requests.json
cypress/fixtures/example.json
cypress/fixtures/origin-save.json
cypress/fixtures/save-task-info.json
cypress/fixtures/swh_1_dir_cd19126d815470b28919d64b2a8e6a3e37f900dd.tar.gz
cypress/fixtures/swh_1_rev_1c480a4573d2a003fc2630c21c2b25829de49972.git.tar
cypress/integration/add-forge-now-request-create.spec.js
cypress/integration/add-forge-now-request-dashboard.spec.js
cypress/integration/add-forge-now-requests-moderation.spec.js
cypress/integration/admin.spec.js
cypress/integration/api-tokens.spec.js
cypress/integration/back-to-top.spec.js
cypress/integration/code-highlighting.spec.js
cypress/integration/content-display.spec.js
cypress/integration/content-rendering.spec.js
cypress/integration/deposit-admin.spec.js
cypress/integration/directory.spec.js
cypress/integration/errors.spec.js
cypress/integration/guided-tour.spec.js
cypress/integration/home.spec.js
cypress/integration/language-select.spec.js
cypress/integration/layout.spec.js
cypress/integration/mailmap.spec.js
cypress/integration/origin-browse.spec.js
cypress/integration/origin-save.spec.js
cypress/integration/origin-search.spec.js
cypress/integration/origin-visits.spec.js
cypress/integration/persistent-identifiers.spec.js
cypress/integration/revision-diff.spec.js
cypress/integration/sidebar.spec.js
cypress/integration/vault.spec.js
cypress/plugins/index.js
cypress/support/index.js
cypress/utils/index.js
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-graph.rst
docs/uri-scheme-api-identifiers.rst
docs/uri-scheme-api-origin.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-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/uri-scheme-misc.rst
docs/_static/.placeholder
docs/_templates/.placeholder
static/robots.txt
static/webpack-stats.json
static/css/add_forge.737aa359fb467b5670bc.css
static/css/add_forge.737aa359fb467b5670bc.css.map
static/css/auth.0336a94c2c02b4b2a4f4.css
static/css/auth.0336a94c2c02b4b2a4f4.css.map
static/css/browse.6315ef52ed73df532bed.css
static/css/browse.6315ef52ed73df532bed.css.map
static/css/guided_tour.00d493abd76b55df7e25.css
static/css/guided_tour.00d493abd76b55df7e25.css.map
static/css/highlightjs.ae43064ab38a65a04d81.css
static/css/highlightjs.ae43064ab38a65a04d81.css.map
static/css/org.6851b70c924e28f6bf51.css
static/css/org.6851b70c924e28f6bf51.css.map
static/css/origin.5b45e9e6e54fd51ee886.css
static/css/origin.5b45e9e6e54fd51ee886.css.map
static/css/revision.5ddd36d69e1760bfa29d.css
static/css/revision.5ddd36d69e1760bfa29d.css.map
static/css/showdown.426fbf6a7a6653fd4cbb.css
static/css/showdown.426fbf6a7a6653fd4cbb.css.map
static/css/vault.25fc5883f848b48ffa5b.css
static/css/vault.25fc5883f848b48ffa5b.css.map
static/css/vendors.e9b3239bd4aa43cec2c2.css
static/css/vendors.e9b3239bd4aa43cec2c2.css.map
static/css/webapp.dd439fd586ffe21d20dc.css
static/css/webapp.dd439fd586ffe21d20dc.css.map
static/fonts/MathJax_AMS-Regular.woff
static/fonts/MathJax_Calligraphic-Bold.woff
static/fonts/MathJax_Calligraphic-Regular.woff
static/fonts/MathJax_Fraktur-Bold.woff
static/fonts/MathJax_Fraktur-Regular.woff
static/fonts/MathJax_Main-Bold.woff
static/fonts/MathJax_Main-Italic.woff
static/fonts/MathJax_Main-Regular.woff
static/fonts/MathJax_Math-BoldItalic.woff
static/fonts/MathJax_Math-Italic.woff
static/fonts/MathJax_Math-Regular.woff
static/fonts/MathJax_SansSerif-Bold.woff
static/fonts/MathJax_SansSerif-Italic.woff
static/fonts/MathJax_SansSerif-Regular.woff
static/fonts/MathJax_Script-Regular.woff
static/fonts/MathJax_Size1-Regular.woff
static/fonts/MathJax_Size2-Regular.woff
static/fonts/MathJax_Size3-Regular.woff
static/fonts/MathJax_Size4-Regular.woff
static/fonts/MathJax_Typewriter-Regular.woff
static/fonts/MathJax_Vector-Bold.woff
static/fonts/MathJax_Vector-Regular.woff
static/fonts/MathJax_Zero.woff
static/fonts/alegreya-latin-400.woff
static/fonts/alegreya-latin-400.woff2
static/fonts/alegreya-latin-400italic.woff
static/fonts/alegreya-latin-400italic.woff2
static/fonts/alegreya-latin-500.woff
static/fonts/alegreya-latin-500.woff2
static/fonts/alegreya-latin-500italic.woff
static/fonts/alegreya-latin-500italic.woff2
static/fonts/alegreya-latin-700.woff
static/fonts/alegreya-latin-700.woff2
static/fonts/alegreya-latin-700italic.woff
static/fonts/alegreya-latin-700italic.woff2
static/fonts/alegreya-latin-800.woff
static/fonts/alegreya-latin-800.woff2
static/fonts/alegreya-latin-800italic.woff
static/fonts/alegreya-latin-800italic.woff2
static/fonts/alegreya-latin-900.woff
static/fonts/alegreya-latin-900.woff2
static/fonts/alegreya-latin-900italic.woff
static/fonts/alegreya-latin-900italic.woff2
static/fonts/alegreya-sans-latin-100.woff
static/fonts/alegreya-sans-latin-100.woff2
static/fonts/alegreya-sans-latin-100italic.woff
static/fonts/alegreya-sans-latin-100italic.woff2
static/fonts/alegreya-sans-latin-300.woff
static/fonts/alegreya-sans-latin-300.woff2
static/fonts/alegreya-sans-latin-300italic.woff
static/fonts/alegreya-sans-latin-300italic.woff2
static/fonts/alegreya-sans-latin-400.woff
static/fonts/alegreya-sans-latin-400.woff2
static/fonts/alegreya-sans-latin-400italic.woff
static/fonts/alegreya-sans-latin-400italic.woff2
static/fonts/alegreya-sans-latin-500.woff
static/fonts/alegreya-sans-latin-500.woff2
static/fonts/alegreya-sans-latin-500italic.woff
static/fonts/alegreya-sans-latin-500italic.woff2
static/fonts/alegreya-sans-latin-700.woff
static/fonts/alegreya-sans-latin-700.woff2
static/fonts/alegreya-sans-latin-700italic.woff
static/fonts/alegreya-sans-latin-700italic.woff2
static/fonts/alegreya-sans-latin-800.woff
static/fonts/alegreya-sans-latin-800.woff2
static/fonts/alegreya-sans-latin-800italic.woff
static/fonts/alegreya-sans-latin-800italic.woff2
static/fonts/alegreya-sans-latin-900.woff
static/fonts/alegreya-sans-latin-900.woff2
static/fonts/alegreya-sans-latin-900italic.woff
static/fonts/alegreya-sans-latin-900italic.woff2
static/fonts/materialdesignicons-webfont.eot
static/fonts/materialdesignicons-webfont.ttf
static/fonts/materialdesignicons-webfont.woff
static/fonts/materialdesignicons-webfont.woff2
static/img/arrow-up-small.png
static/img/swh-donor.png
static/img/swh-logo-white.svg
static/img/swh-logo.png
static/img/swh-logo.svg
static/img/swh-spinner-small.gif
static/img/swh-spinner.gif
static/img/swh-vault.png
static/img/icons/swh-logo-32x32.png
static/img/icons/swh-logo-archive-180x180.png
static/img/icons/swh-logo-archive-192x192.png
static/img/icons/swh-logo-archive-270x270.png
static/img/logos/bitbucket.png
static/img/logos/cgit.png
static/img/logos/cran.png
static/img/logos/debian.png
static/img/logos/elife.png
static/img/logos/gitea.png
static/img/logos/github.png
static/img/logos/gitlab.png
static/img/logos/gitorious.png
static/img/logos/gnu.png
static/img/logos/googlecode.png
static/img/logos/guix.png
static/img/logos/hal.png
static/img/logos/heptapod.png
static/img/logos/inria.jpg
static/img/logos/ipol.png
static/img/logos/launchpad.png
static/img/logos/nixos.png
static/img/logos/npm.png
static/img/logos/opam.png
static/img/logos/phabricator.png
static/img/logos/pypi.png
static/img/logos/sourceforge.png
static/img/thirdParty/chosen-sprite.png
static/img/thirdParty/chosen-sprite@2x.png
static/js/add_forge.bcbbc1be5ab34eede65c.js
static/js/add_forge.bcbbc1be5ab34eede65c.js.LICENSE.txt
static/js/add_forge.bcbbc1be5ab34eede65c.js.map
static/js/admin.e1bdd6f126d315dc57e6.js
static/js/admin.e1bdd6f126d315dc57e6.js.LICENSE.txt
static/js/admin.e1bdd6f126d315dc57e6.js.map
static/js/auth.7a6ba4612115126f9b59.js
static/js/auth.7a6ba4612115126f9b59.js.LICENSE.txt
static/js/auth.7a6ba4612115126f9b59.js.map
static/js/browse.89ce9f7581cb4a43fa54.js
static/js/browse.89ce9f7581cb4a43fa54.js.LICENSE.txt
static/js/browse.89ce9f7581cb4a43fa54.js.map
static/js/d3.f989183a810fb9dbb086.js
static/js/d3.f989183a810fb9dbb086.js.map
static/js/guided_tour.6fdb762b8416936b3c84.js
static/js/guided_tour.6fdb762b8416936b3c84.js.LICENSE.txt
static/js/guided_tour.6fdb762b8416936b3c84.js.map
static/js/highlightjs.ccd71c93a63af0249728.js
static/js/highlightjs.ccd71c93a63af0249728.js.LICENSE.txt
static/js/highlightjs.ccd71c93a63af0249728.js.map
static/js/mathjax.a0046af7afe82fd10728.js
static/js/mathjax.a0046af7afe82fd10728.js.map
static/js/org.9adc9a39a210c2fb4be0.js
static/js/org.9adc9a39a210c2fb4be0.js.map
static/js/origin.751694c0f651d0e204de.js
static/js/origin.751694c0f651d0e204de.js.map
static/js/pdf.worker.min.js
static/js/pdf.worker.min.js.LICENSE.txt
static/js/pdfjs.7fa499e22fea56527058.js
static/js/pdfjs.7fa499e22fea56527058.js.map
static/js/revision.530bd3980955c9cce3fb.js
static/js/revision.530bd3980955c9cce3fb.js.LICENSE.txt
static/js/revision.530bd3980955c9cce3fb.js.map
static/js/save.78a0e5b182ba60ef8cba.js
static/js/save.78a0e5b182ba60ef8cba.js.LICENSE.txt
static/js/save.78a0e5b182ba60ef8cba.js.map
static/js/showdown.b448e42a34c43d6a7de5.js
static/js/showdown.b448e42a34c43d6a7de5.js.LICENSE.txt
static/js/showdown.b448e42a34c43d6a7de5.js.map
static/js/vault.e2e8f042b9c742390872.js
static/js/vault.e2e8f042b9c742390872.js.LICENSE.txt
static/js/vault.e2e8f042b9c742390872.js.map
static/js/vendors.4d86327911239b43ce67.js
static/js/vendors.4d86327911239b43ce67.js.LICENSE.txt
static/js/vendors.4d86327911239b43ce67.js.map
static/js/webapp.ec1d7512d2628f39df9b.js
static/js/webapp.ec1d7512d2628f39df9b.js.LICENSE.txt
static/js/webapp.ec1d7512d2628f39df9b.js.map
static/json/highlightjs-languages.json
static/jssources/LICENSE.txt
static/jssources/jslicenses.json
static/jssources/@babel/runtime/LICENSE.txt
static/jssources/@babel/runtime/helpers/esm/asyncToGenerator.js
static/jssources/@babel/runtime/helpers/esm/inherits.js
static/jssources/@babel/runtime/helpers/esm/setPrototypeOf.js
static/jssources/@babel/runtime/regenerator/index.js
static/jssources/@sentry/browser/LICENSE.txt
static/jssources/@sentry/browser/esm/backend.js
static/jssources/@sentry/browser/esm/client.js
static/jssources/@sentry/browser/esm/eventbuilder.js
static/jssources/@sentry/browser/esm/helpers.js
static/jssources/@sentry/browser/esm/sdk.js
static/jssources/@sentry/browser/esm/stack-parsers.js
static/jssources/@sentry/browser/esm/integrations/breadcrumbs.js
static/jssources/@sentry/browser/esm/integrations/dedupe.js
static/jssources/@sentry/browser/esm/integrations/globalhandlers.js
static/jssources/@sentry/browser/esm/integrations/linkederrors.js
static/jssources/@sentry/browser/esm/integrations/trycatch.js
static/jssources/@sentry/browser/esm/integrations/useragent.js
static/jssources/@sentry/browser/esm/transports/base.js
static/jssources/@sentry/browser/esm/transports/fetch.js
static/jssources/@sentry/browser/esm/transports/new-fetch.js
static/jssources/@sentry/browser/esm/transports/new-xhr.js
static/jssources/@sentry/browser/esm/transports/utils.js
static/jssources/@sentry/browser/esm/transports/xhr.js
static/jssources/@sentry/core/LICENSE.txt
static/jssources/@sentry/core/esm/api.js
static/jssources/@sentry/core/esm/basebackend.js
static/jssources/@sentry/core/esm/baseclient.js
static/jssources/@sentry/core/esm/integration.js
static/jssources/@sentry/core/esm/request.js
static/jssources/@sentry/core/esm/sdk.js
static/jssources/@sentry/core/esm/version.js
static/jssources/@sentry/core/esm/integrations/functiontostring.js
static/jssources/@sentry/core/esm/integrations/inboundfilters.js
static/jssources/@sentry/core/esm/transports/base.js
static/jssources/@sentry/core/esm/transports/noop.js
static/jssources/@sentry/hub/LICENSE.txt
static/jssources/@sentry/hub/esm/hub.js
static/jssources/@sentry/hub/esm/scope.js
static/jssources/@sentry/hub/esm/session.js
static/jssources/@sentry/minimal/LICENSE.txt
static/jssources/@sentry/minimal/esm/index.js
static/jssources/@sentry/types/LICENSE.txt
static/jssources/@sentry/types/esm/severity.js
static/jssources/@sentry/utils/LICENSE.txt
static/jssources/@sentry/utils/esm/async.js
static/jssources/@sentry/utils/esm/browser.js
static/jssources/@sentry/utils/esm/clientreport.js
static/jssources/@sentry/utils/esm/dsn.js
static/jssources/@sentry/utils/esm/enums.js
static/jssources/@sentry/utils/esm/env.js
static/jssources/@sentry/utils/esm/envelope.js
static/jssources/@sentry/utils/esm/error.js
static/jssources/@sentry/utils/esm/global.js
static/jssources/@sentry/utils/esm/instrument.js
static/jssources/@sentry/utils/esm/is.js
static/jssources/@sentry/utils/esm/logger.js
static/jssources/@sentry/utils/esm/memo.js
static/jssources/@sentry/utils/esm/misc.js
static/jssources/@sentry/utils/esm/node.js
static/jssources/@sentry/utils/esm/normalize.js
static/jssources/@sentry/utils/esm/object.js
static/jssources/@sentry/utils/esm/polyfill.js
static/jssources/@sentry/utils/esm/promisebuffer.js
static/jssources/@sentry/utils/esm/ratelimit.js
static/jssources/@sentry/utils/esm/severity.js
static/jssources/@sentry/utils/esm/stacktrace.js
static/jssources/@sentry/utils/esm/status.js
static/jssources/@sentry/utils/esm/string.js
static/jssources/@sentry/utils/esm/supports.js
static/jssources/@sentry/utils/esm/syncpromise.js
static/jssources/@sentry/utils/esm/time.js
static/jssources/admin-lte/LICENSE.txt
static/jssources/admin-lte/dist/js/adminlte.js
static/jssources/ansi_up/LICENSE.txt
static/jssources/ansi_up/ansi_up.js
static/jssources/assets/src/bundles/add_forge/add-request-history-item.ejs
static/jssources/assets/src/bundles/add_forge/create-request.js
static/jssources/assets/src/bundles/add_forge/forge-admin-email.ejs
static/jssources/assets/src/bundles/add_forge/index.js
static/jssources/assets/src/bundles/add_forge/moderation-dashboard.js
static/jssources/assets/src/bundles/add_forge/request-dashboard.js
static/jssources/assets/src/bundles/admin/deposit.js
static/jssources/assets/src/bundles/admin/index.js
static/jssources/assets/src/bundles/admin/mailmap-form.ejs
static/jssources/assets/src/bundles/admin/mailmap.js
static/jssources/assets/src/bundles/admin/origin-save.js
static/jssources/assets/src/bundles/auth/index.js
static/jssources/assets/src/bundles/browse/browse-utils.js
static/jssources/assets/src/bundles/browse/index.js
static/jssources/assets/src/bundles/browse/origin-search.js
static/jssources/assets/src/bundles/browse/snapshot-navigation.js
static/jssources/assets/src/bundles/browse/swhid-utils.js
static/jssources/assets/src/bundles/guided_tour/index.js
static/jssources/assets/src/bundles/origin/index.js
static/jssources/assets/src/bundles/origin/utils.js
static/jssources/assets/src/bundles/origin/visits-calendar.js
static/jssources/assets/src/bundles/origin/visits-histogram.js
static/jssources/assets/src/bundles/origin/visits-reporting.js
static/jssources/assets/src/bundles/revision/diff-panel.ejs
static/jssources/assets/src/bundles/revision/diff-utils.js
static/jssources/assets/src/bundles/revision/index.js
static/jssources/assets/src/bundles/revision/log-utils.js
static/jssources/assets/src/bundles/save/artifact-form-row.ejs
static/jssources/assets/src/bundles/save/index.js
static/jssources/assets/src/bundles/vault/index.js
static/jssources/assets/src/bundles/vault/vault-create-tasks.js
static/jssources/assets/src/bundles/vault/vault-table-row.ejs
static/jssources/assets/src/bundles/vault/vault-ui.js
static/jssources/assets/src/bundles/vendors/elementsfrompoint-polyfill.js
static/jssources/assets/src/bundles/vendors/index.js
static/jssources/assets/src/bundles/webapp/badges.js
static/jssources/assets/src/bundles/webapp/code-highlighting.js
static/jssources/assets/src/bundles/webapp/history-counters.js
static/jssources/assets/src/bundles/webapp/iframes.js
static/jssources/assets/src/bundles/webapp/index.js
static/jssources/assets/src/bundles/webapp/math-typesetting.js
static/jssources/assets/src/bundles/webapp/notebook-rendering.js
static/jssources/assets/src/bundles/webapp/pdf-rendering.js
static/jssources/assets/src/bundles/webapp/readme-rendering.js
static/jssources/assets/src/bundles/webapp/sentry.js
static/jssources/assets/src/bundles/webapp/status-widget.js
static/jssources/assets/src/bundles/webapp/webapp-utils.js
static/jssources/assets/src/bundles/webapp/xss-filtering.js
static/jssources/assets/src/thirdparty/jquery.tabSlideOut/LICENSE.txt
static/jssources/assets/src/thirdparty/jquery.tabSlideOut/jquery.tabSlideOut.js
static/jssources/assets/src/utils/constants.js
static/jssources/assets/src/utils/d3.js
static/jssources/assets/src/utils/functions.js
static/jssources/assets/src/utils/highlightjs.js
static/jssources/assets/src/utils/mathjax.js
static/jssources/assets/src/utils/org.js
static/jssources/assets/src/utils/requests-filter-checkbox.ejs
static/jssources/assets/src/utils/scrolling.js
static/jssources/assets/src/utils/showdown.js
static/jssources/bootstrap/LICENSE.txt
static/jssources/bootstrap/js/dist/alert.js
static/jssources/bootstrap/js/dist/button.js
static/jssources/bootstrap/js/dist/carousel.js
static/jssources/bootstrap/js/dist/collapse.js
static/jssources/bootstrap/js/dist/dropdown.js
static/jssources/bootstrap/js/dist/modal.js
static/jssources/bootstrap/js/dist/popover.js
static/jssources/bootstrap/js/dist/scrollspy.js
static/jssources/bootstrap/js/dist/tab.js
static/jssources/bootstrap/js/dist/tooltip.js
static/jssources/bootstrap/js/dist/util.js
static/jssources/chosen-js/LICENSE.md
static/jssources/chosen-js/chosen.jquery.js
static/jssources/clipboard/LICENSE.txt
static/jssources/clipboard/dist/clipboard.js
static/jssources/core-js/LICENSE.txt
static/jssources/core-js/internals/a-callable.js
static/jssources/core-js/internals/a-constructor.js
static/jssources/core-js/internals/a-possible-prototype.js
static/jssources/core-js/internals/add-to-unscopables.js
static/jssources/core-js/internals/advance-string-index.js
static/jssources/core-js/internals/an-instance.js
static/jssources/core-js/internals/an-object.js
static/jssources/core-js/internals/array-buffer-native.js
static/jssources/core-js/internals/array-buffer-non-extensible.js
static/jssources/core-js/internals/array-buffer-view-core.js
static/jssources/core-js/internals/array-buffer.js
static/jssources/core-js/internals/array-copy-within.js
static/jssources/core-js/internals/array-fill.js
static/jssources/core-js/internals/array-for-each.js
static/jssources/core-js/internals/array-from-constructor-and-list.js
static/jssources/core-js/internals/array-from.js
static/jssources/core-js/internals/array-includes.js
static/jssources/core-js/internals/array-iteration.js
static/jssources/core-js/internals/array-last-index-of.js
static/jssources/core-js/internals/array-method-has-species-support.js
static/jssources/core-js/internals/array-method-is-strict.js
static/jssources/core-js/internals/array-reduce.js
static/jssources/core-js/internals/array-slice-simple.js
static/jssources/core-js/internals/array-slice.js
static/jssources/core-js/internals/array-sort.js
static/jssources/core-js/internals/array-species-constructor.js
static/jssources/core-js/internals/array-species-create.js
static/jssources/core-js/internals/base64-map.js
static/jssources/core-js/internals/call-with-safe-iteration-closing.js
static/jssources/core-js/internals/check-correctness-of-iteration.js
static/jssources/core-js/internals/classof-raw.js
static/jssources/core-js/internals/classof.js
static/jssources/core-js/internals/clear-error-stack.js
static/jssources/core-js/internals/collection-strong.js
static/jssources/core-js/internals/collection-weak.js
static/jssources/core-js/internals/collection.js
static/jssources/core-js/internals/copy-constructor-properties.js
static/jssources/core-js/internals/correct-is-regexp-logic.js
static/jssources/core-js/internals/correct-prototype-getter.js
static/jssources/core-js/internals/create-html.js
static/jssources/core-js/internals/create-iterator-constructor.js
static/jssources/core-js/internals/create-non-enumerable-property.js
static/jssources/core-js/internals/create-property-descriptor.js
static/jssources/core-js/internals/create-property.js
static/jssources/core-js/internals/date-to-iso-string.js
static/jssources/core-js/internals/date-to-primitive.js
static/jssources/core-js/internals/define-iterator.js
static/jssources/core-js/internals/define-well-known-symbol.js
static/jssources/core-js/internals/descriptors.js
static/jssources/core-js/internals/document-create-element.js
static/jssources/core-js/internals/dom-exception-constants.js
static/jssources/core-js/internals/dom-iterables.js
static/jssources/core-js/internals/dom-token-list-prototype.js
static/jssources/core-js/internals/engine-ff-version.js
static/jssources/core-js/internals/engine-is-browser.js
static/jssources/core-js/internals/engine-is-ie-or-edge.js
static/jssources/core-js/internals/engine-is-ios-pebble.js
static/jssources/core-js/internals/engine-is-ios.js
static/jssources/core-js/internals/engine-is-node.js
static/jssources/core-js/internals/engine-is-webos-webkit.js
static/jssources/core-js/internals/engine-user-agent.js
static/jssources/core-js/internals/engine-v8-version.js
static/jssources/core-js/internals/engine-webkit-version.js
static/jssources/core-js/internals/enum-bug-keys.js
static/jssources/core-js/internals/error-stack-installable.js
static/jssources/core-js/internals/error-to-string.js
static/jssources/core-js/internals/export.js
static/jssources/core-js/internals/fails.js
static/jssources/core-js/internals/fix-regexp-well-known-symbol-logic.js
static/jssources/core-js/internals/flatten-into-array.js
static/jssources/core-js/internals/freezing.js
static/jssources/core-js/internals/function-apply.js
static/jssources/core-js/internals/function-bind-context.js
static/jssources/core-js/internals/function-bind-native.js
static/jssources/core-js/internals/function-bind.js
static/jssources/core-js/internals/function-call.js
static/jssources/core-js/internals/function-name.js
static/jssources/core-js/internals/function-uncurry-this.js
static/jssources/core-js/internals/get-built-in.js
static/jssources/core-js/internals/get-iterator-method.js
static/jssources/core-js/internals/get-iterator.js
static/jssources/core-js/internals/get-method.js
static/jssources/core-js/internals/get-substitution.js
static/jssources/core-js/internals/global.js
static/jssources/core-js/internals/has-own-property.js
static/jssources/core-js/internals/hidden-keys.js
static/jssources/core-js/internals/host-report-errors.js
static/jssources/core-js/internals/html.js
static/jssources/core-js/internals/ie8-dom-define.js
static/jssources/core-js/internals/ieee754.js
static/jssources/core-js/internals/indexed-object.js
static/jssources/core-js/internals/inherit-if-required.js
static/jssources/core-js/internals/inspect-source.js
static/jssources/core-js/internals/install-error-cause.js
static/jssources/core-js/internals/internal-metadata.js
static/jssources/core-js/internals/internal-state.js
static/jssources/core-js/internals/is-array-iterator-method.js
static/jssources/core-js/internals/is-array.js
static/jssources/core-js/internals/is-callable.js
static/jssources/core-js/internals/is-constructor.js
static/jssources/core-js/internals/is-data-descriptor.js
static/jssources/core-js/internals/is-forced.js
static/jssources/core-js/internals/is-integral-number.js
static/jssources/core-js/internals/is-object.js
static/jssources/core-js/internals/is-pure.js
static/jssources/core-js/internals/is-regexp.js
static/jssources/core-js/internals/is-symbol.js
static/jssources/core-js/internals/iterate.js
static/jssources/core-js/internals/iterator-close.js
static/jssources/core-js/internals/iterators-core.js
static/jssources/core-js/internals/iterators.js
static/jssources/core-js/internals/length-of-array-like.js
static/jssources/core-js/internals/math-expm1.js
static/jssources/core-js/internals/math-fround.js
static/jssources/core-js/internals/math-log10.js
static/jssources/core-js/internals/math-log1p.js
static/jssources/core-js/internals/math-sign.js
static/jssources/core-js/internals/microtask.js
static/jssources/core-js/internals/native-promise-constructor.js
static/jssources/core-js/internals/native-symbol.js
static/jssources/core-js/internals/native-url.js
static/jssources/core-js/internals/native-weak-map.js
static/jssources/core-js/internals/new-promise-capability.js
static/jssources/core-js/internals/normalize-string-argument.js
static/jssources/core-js/internals/not-a-regexp.js
static/jssources/core-js/internals/number-is-finite.js
static/jssources/core-js/internals/number-parse-float.js
static/jssources/core-js/internals/number-parse-int.js
static/jssources/core-js/internals/object-assign.js
static/jssources/core-js/internals/object-create.js
static/jssources/core-js/internals/object-define-properties.js
static/jssources/core-js/internals/object-define-property.js
static/jssources/core-js/internals/object-get-own-property-descriptor.js
static/jssources/core-js/internals/object-get-own-property-names-external.js
static/jssources/core-js/internals/object-get-own-property-names.js
static/jssources/core-js/internals/object-get-own-property-symbols.js
static/jssources/core-js/internals/object-get-prototype-of.js
static/jssources/core-js/internals/object-is-extensible.js
static/jssources/core-js/internals/object-is-prototype-of.js
static/jssources/core-js/internals/object-keys-internal.js
static/jssources/core-js/internals/object-keys.js
static/jssources/core-js/internals/object-property-is-enumerable.js
static/jssources/core-js/internals/object-prototype-accessors-forced.js
static/jssources/core-js/internals/object-set-prototype-of.js
static/jssources/core-js/internals/object-to-array.js
static/jssources/core-js/internals/object-to-string.js
static/jssources/core-js/internals/ordinary-to-primitive.js
static/jssources/core-js/internals/own-keys.js
static/jssources/core-js/internals/path.js
static/jssources/core-js/internals/perform.js
static/jssources/core-js/internals/promise-resolve.js
static/jssources/core-js/internals/queue.js
static/jssources/core-js/internals/redefine-all.js
static/jssources/core-js/internals/redefine.js
static/jssources/core-js/internals/regexp-exec-abstract.js
static/jssources/core-js/internals/regexp-exec.js
static/jssources/core-js/internals/regexp-flags.js
static/jssources/core-js/internals/regexp-sticky-helpers.js
static/jssources/core-js/internals/regexp-unsupported-dot-all.js
static/jssources/core-js/internals/regexp-unsupported-ncg.js
static/jssources/core-js/internals/require-object-coercible.js
static/jssources/core-js/internals/same-value.js
static/jssources/core-js/internals/set-global.js
static/jssources/core-js/internals/set-species.js
static/jssources/core-js/internals/set-to-string-tag.js
static/jssources/core-js/internals/shared-key.js
static/jssources/core-js/internals/shared-store.js
static/jssources/core-js/internals/shared.js
static/jssources/core-js/internals/species-constructor.js
static/jssources/core-js/internals/string-html-forced.js
static/jssources/core-js/internals/string-multibyte.js
static/jssources/core-js/internals/string-pad-webkit-bug.js
static/jssources/core-js/internals/string-pad.js
static/jssources/core-js/internals/string-punycode-to-ascii.js
static/jssources/core-js/internals/string-repeat.js
static/jssources/core-js/internals/string-trim-forced.js
static/jssources/core-js/internals/string-trim.js
static/jssources/core-js/internals/task.js
static/jssources/core-js/internals/this-number-value.js
static/jssources/core-js/internals/to-absolute-index.js
static/jssources/core-js/internals/to-index.js
static/jssources/core-js/internals/to-indexed-object.js
static/jssources/core-js/internals/to-integer-or-infinity.js
static/jssources/core-js/internals/to-length.js
static/jssources/core-js/internals/to-object.js
static/jssources/core-js/internals/to-offset.js
static/jssources/core-js/internals/to-positive-integer.js
static/jssources/core-js/internals/to-primitive.js
static/jssources/core-js/internals/to-property-key.js
static/jssources/core-js/internals/to-string-tag-support.js
static/jssources/core-js/internals/to-string.js
static/jssources/core-js/internals/try-node-require.js
static/jssources/core-js/internals/try-to-string.js
static/jssources/core-js/internals/typed-array-constructor.js
static/jssources/core-js/internals/typed-array-constructors-require-wrappers.js
static/jssources/core-js/internals/typed-array-from-species-and-list.js
static/jssources/core-js/internals/typed-array-from.js
static/jssources/core-js/internals/typed-array-species-constructor.js
static/jssources/core-js/internals/uid.js
static/jssources/core-js/internals/use-symbol-as-uid.js
static/jssources/core-js/internals/v8-prototype-define-bug.js
static/jssources/core-js/internals/validate-arguments-length.js
static/jssources/core-js/internals/well-known-symbol-wrapped.js
static/jssources/core-js/internals/well-known-symbol.js
static/jssources/core-js/internals/whitespaces.js
static/jssources/core-js/internals/wrap-error-constructor-with-cause.js
static/jssources/core-js/modules/es.aggregate-error.cause.js
static/jssources/core-js/modules/es.aggregate-error.js
static/jssources/core-js/modules/es.array-buffer.constructor.js
static/jssources/core-js/modules/es.array-buffer.is-view.js
static/jssources/core-js/modules/es.array-buffer.slice.js
static/jssources/core-js/modules/es.array.at.js
static/jssources/core-js/modules/es.array.concat.js
static/jssources/core-js/modules/es.array.copy-within.js
static/jssources/core-js/modules/es.array.every.js
static/jssources/core-js/modules/es.array.fill.js
static/jssources/core-js/modules/es.array.filter.js
static/jssources/core-js/modules/es.array.find-index.js
static/jssources/core-js/modules/es.array.find.js
static/jssources/core-js/modules/es.array.flat-map.js
static/jssources/core-js/modules/es.array.flat.js
static/jssources/core-js/modules/es.array.for-each.js
static/jssources/core-js/modules/es.array.from.js
static/jssources/core-js/modules/es.array.includes.js
static/jssources/core-js/modules/es.array.index-of.js
static/jssources/core-js/modules/es.array.is-array.js
static/jssources/core-js/modules/es.array.iterator.js
static/jssources/core-js/modules/es.array.join.js
static/jssources/core-js/modules/es.array.last-index-of.js
static/jssources/core-js/modules/es.array.map.js
static/jssources/core-js/modules/es.array.of.js
static/jssources/core-js/modules/es.array.reduce-right.js
static/jssources/core-js/modules/es.array.reduce.js
static/jssources/core-js/modules/es.array.reverse.js
static/jssources/core-js/modules/es.array.slice.js
static/jssources/core-js/modules/es.array.some.js
static/jssources/core-js/modules/es.array.sort.js
static/jssources/core-js/modules/es.array.species.js
static/jssources/core-js/modules/es.array.splice.js
static/jssources/core-js/modules/es.array.unscopables.flat-map.js
static/jssources/core-js/modules/es.array.unscopables.flat.js
static/jssources/core-js/modules/es.data-view.js
static/jssources/core-js/modules/es.date.get-year.js
static/jssources/core-js/modules/es.date.now.js
static/jssources/core-js/modules/es.date.set-year.js
static/jssources/core-js/modules/es.date.to-gmt-string.js
static/jssources/core-js/modules/es.date.to-iso-string.js
static/jssources/core-js/modules/es.date.to-json.js
static/jssources/core-js/modules/es.date.to-primitive.js
static/jssources/core-js/modules/es.date.to-string.js
static/jssources/core-js/modules/es.error.cause.js
static/jssources/core-js/modules/es.error.to-string.js
static/jssources/core-js/modules/es.escape.js
static/jssources/core-js/modules/es.function.bind.js
static/jssources/core-js/modules/es.function.has-instance.js
static/jssources/core-js/modules/es.function.name.js
static/jssources/core-js/modules/es.global-this.js
static/jssources/core-js/modules/es.json.stringify.js
static/jssources/core-js/modules/es.json.to-string-tag.js
static/jssources/core-js/modules/es.map.js
static/jssources/core-js/modules/es.math.acosh.js
static/jssources/core-js/modules/es.math.asinh.js
static/jssources/core-js/modules/es.math.atanh.js
static/jssources/core-js/modules/es.math.cbrt.js
static/jssources/core-js/modules/es.math.clz32.js
static/jssources/core-js/modules/es.math.cosh.js
static/jssources/core-js/modules/es.math.expm1.js
static/jssources/core-js/modules/es.math.fround.js
static/jssources/core-js/modules/es.math.hypot.js
static/jssources/core-js/modules/es.math.imul.js
static/jssources/core-js/modules/es.math.log10.js
static/jssources/core-js/modules/es.math.log1p.js
static/jssources/core-js/modules/es.math.log2.js
static/jssources/core-js/modules/es.math.sign.js
static/jssources/core-js/modules/es.math.sinh.js
static/jssources/core-js/modules/es.math.tanh.js
static/jssources/core-js/modules/es.math.to-string-tag.js
static/jssources/core-js/modules/es.math.trunc.js
static/jssources/core-js/modules/es.number.constructor.js
static/jssources/core-js/modules/es.number.epsilon.js
static/jssources/core-js/modules/es.number.is-finite.js
static/jssources/core-js/modules/es.number.is-integer.js
static/jssources/core-js/modules/es.number.is-nan.js
static/jssources/core-js/modules/es.number.is-safe-integer.js
static/jssources/core-js/modules/es.number.max-safe-integer.js
static/jssources/core-js/modules/es.number.min-safe-integer.js
static/jssources/core-js/modules/es.number.parse-float.js
static/jssources/core-js/modules/es.number.parse-int.js
static/jssources/core-js/modules/es.number.to-exponential.js
static/jssources/core-js/modules/es.number.to-fixed.js
static/jssources/core-js/modules/es.number.to-precision.js
static/jssources/core-js/modules/es.object.assign.js
static/jssources/core-js/modules/es.object.create.js
static/jssources/core-js/modules/es.object.define-getter.js
static/jssources/core-js/modules/es.object.define-properties.js
static/jssources/core-js/modules/es.object.define-property.js
static/jssources/core-js/modules/es.object.define-setter.js
static/jssources/core-js/modules/es.object.entries.js
static/jssources/core-js/modules/es.object.freeze.js
static/jssources/core-js/modules/es.object.from-entries.js
static/jssources/core-js/modules/es.object.get-own-property-descriptor.js
static/jssources/core-js/modules/es.object.get-own-property-descriptors.js
static/jssources/core-js/modules/es.object.get-own-property-names.js
static/jssources/core-js/modules/es.object.get-prototype-of.js
static/jssources/core-js/modules/es.object.has-own.js
static/jssources/core-js/modules/es.object.is-extensible.js
static/jssources/core-js/modules/es.object.is-frozen.js
static/jssources/core-js/modules/es.object.is-sealed.js
static/jssources/core-js/modules/es.object.is.js
static/jssources/core-js/modules/es.object.keys.js
static/jssources/core-js/modules/es.object.lookup-getter.js
static/jssources/core-js/modules/es.object.lookup-setter.js
static/jssources/core-js/modules/es.object.prevent-extensions.js
static/jssources/core-js/modules/es.object.seal.js
static/jssources/core-js/modules/es.object.set-prototype-of.js
static/jssources/core-js/modules/es.object.to-string.js
static/jssources/core-js/modules/es.object.values.js
static/jssources/core-js/modules/es.parse-float.js
static/jssources/core-js/modules/es.parse-int.js
static/jssources/core-js/modules/es.promise.all-settled.js
static/jssources/core-js/modules/es.promise.any.js
static/jssources/core-js/modules/es.promise.finally.js
static/jssources/core-js/modules/es.promise.js
static/jssources/core-js/modules/es.reflect.apply.js
static/jssources/core-js/modules/es.reflect.construct.js
static/jssources/core-js/modules/es.reflect.define-property.js
static/jssources/core-js/modules/es.reflect.delete-property.js
static/jssources/core-js/modules/es.reflect.get-own-property-descriptor.js
static/jssources/core-js/modules/es.reflect.get-prototype-of.js
static/jssources/core-js/modules/es.reflect.get.js
static/jssources/core-js/modules/es.reflect.has.js
static/jssources/core-js/modules/es.reflect.is-extensible.js
static/jssources/core-js/modules/es.reflect.own-keys.js
static/jssources/core-js/modules/es.reflect.prevent-extensions.js
static/jssources/core-js/modules/es.reflect.set-prototype-of.js
static/jssources/core-js/modules/es.reflect.set.js
static/jssources/core-js/modules/es.reflect.to-string-tag.js
static/jssources/core-js/modules/es.regexp.constructor.js
static/jssources/core-js/modules/es.regexp.dot-all.js
static/jssources/core-js/modules/es.regexp.exec.js
static/jssources/core-js/modules/es.regexp.flags.js
static/jssources/core-js/modules/es.regexp.sticky.js
static/jssources/core-js/modules/es.regexp.test.js
static/jssources/core-js/modules/es.regexp.to-string.js
static/jssources/core-js/modules/es.set.js
static/jssources/core-js/modules/es.string.anchor.js
static/jssources/core-js/modules/es.string.at-alternative.js
static/jssources/core-js/modules/es.string.big.js
static/jssources/core-js/modules/es.string.blink.js
static/jssources/core-js/modules/es.string.bold.js
static/jssources/core-js/modules/es.string.code-point-at.js
static/jssources/core-js/modules/es.string.ends-with.js
static/jssources/core-js/modules/es.string.fixed.js
static/jssources/core-js/modules/es.string.fontcolor.js
static/jssources/core-js/modules/es.string.fontsize.js
static/jssources/core-js/modules/es.string.from-code-point.js
static/jssources/core-js/modules/es.string.includes.js
static/jssources/core-js/modules/es.string.italics.js
static/jssources/core-js/modules/es.string.iterator.js
static/jssources/core-js/modules/es.string.link.js
static/jssources/core-js/modules/es.string.match-all.js
static/jssources/core-js/modules/es.string.match.js
static/jssources/core-js/modules/es.string.pad-end.js
static/jssources/core-js/modules/es.string.pad-start.js
static/jssources/core-js/modules/es.string.raw.js
static/jssources/core-js/modules/es.string.repeat.js
static/jssources/core-js/modules/es.string.replace-all.js
static/jssources/core-js/modules/es.string.replace.js
static/jssources/core-js/modules/es.string.search.js
static/jssources/core-js/modules/es.string.small.js
static/jssources/core-js/modules/es.string.split.js
static/jssources/core-js/modules/es.string.starts-with.js
static/jssources/core-js/modules/es.string.strike.js
static/jssources/core-js/modules/es.string.sub.js
static/jssources/core-js/modules/es.string.substr.js
static/jssources/core-js/modules/es.string.sup.js
static/jssources/core-js/modules/es.string.trim-end.js
static/jssources/core-js/modules/es.string.trim-start.js
static/jssources/core-js/modules/es.string.trim.js
static/jssources/core-js/modules/es.symbol.async-iterator.js
static/jssources/core-js/modules/es.symbol.description.js
static/jssources/core-js/modules/es.symbol.has-instance.js
static/jssources/core-js/modules/es.symbol.is-concat-spreadable.js
static/jssources/core-js/modules/es.symbol.iterator.js
static/jssources/core-js/modules/es.symbol.js
static/jssources/core-js/modules/es.symbol.match-all.js
static/jssources/core-js/modules/es.symbol.match.js
static/jssources/core-js/modules/es.symbol.replace.js
static/jssources/core-js/modules/es.symbol.search.js
static/jssources/core-js/modules/es.symbol.species.js
static/jssources/core-js/modules/es.symbol.split.js
static/jssources/core-js/modules/es.symbol.to-primitive.js
static/jssources/core-js/modules/es.symbol.to-string-tag.js
static/jssources/core-js/modules/es.symbol.unscopables.js
static/jssources/core-js/modules/es.typed-array.at.js
static/jssources/core-js/modules/es.typed-array.copy-within.js
static/jssources/core-js/modules/es.typed-array.every.js
static/jssources/core-js/modules/es.typed-array.fill.js
static/jssources/core-js/modules/es.typed-array.filter.js
static/jssources/core-js/modules/es.typed-array.find-index.js
static/jssources/core-js/modules/es.typed-array.find.js
static/jssources/core-js/modules/es.typed-array.float32-array.js
static/jssources/core-js/modules/es.typed-array.float64-array.js
static/jssources/core-js/modules/es.typed-array.for-each.js
static/jssources/core-js/modules/es.typed-array.from.js
static/jssources/core-js/modules/es.typed-array.includes.js
static/jssources/core-js/modules/es.typed-array.index-of.js
static/jssources/core-js/modules/es.typed-array.int16-array.js
static/jssources/core-js/modules/es.typed-array.int32-array.js
static/jssources/core-js/modules/es.typed-array.int8-array.js
static/jssources/core-js/modules/es.typed-array.iterator.js
static/jssources/core-js/modules/es.typed-array.join.js
static/jssources/core-js/modules/es.typed-array.last-index-of.js
static/jssources/core-js/modules/es.typed-array.map.js
static/jssources/core-js/modules/es.typed-array.of.js
static/jssources/core-js/modules/es.typed-array.reduce-right.js
static/jssources/core-js/modules/es.typed-array.reduce.js
static/jssources/core-js/modules/es.typed-array.reverse.js
static/jssources/core-js/modules/es.typed-array.set.js
static/jssources/core-js/modules/es.typed-array.slice.js
static/jssources/core-js/modules/es.typed-array.some.js
static/jssources/core-js/modules/es.typed-array.sort.js
static/jssources/core-js/modules/es.typed-array.subarray.js
static/jssources/core-js/modules/es.typed-array.to-locale-string.js
static/jssources/core-js/modules/es.typed-array.to-string.js
static/jssources/core-js/modules/es.typed-array.uint16-array.js
static/jssources/core-js/modules/es.typed-array.uint32-array.js
static/jssources/core-js/modules/es.typed-array.uint8-array.js
static/jssources/core-js/modules/es.typed-array.uint8-clamped-array.js
static/jssources/core-js/modules/es.unescape.js
static/jssources/core-js/modules/es.weak-map.js
static/jssources/core-js/modules/es.weak-set.js
static/jssources/core-js/modules/web.atob.js
static/jssources/core-js/modules/web.btoa.js
static/jssources/core-js/modules/web.dom-collections.for-each.js
static/jssources/core-js/modules/web.dom-collections.iterator.js
static/jssources/core-js/modules/web.dom-exception.constructor.js
static/jssources/core-js/modules/web.dom-exception.stack.js
static/jssources/core-js/modules/web.dom-exception.to-string-tag.js
static/jssources/core-js/modules/web.immediate.js
static/jssources/core-js/modules/web.queue-microtask.js
static/jssources/core-js/modules/web.structured-clone.js
static/jssources/core-js/modules/web.timers.js
static/jssources/core-js/modules/web.url-search-params.js
static/jssources/core-js/modules/web.url.js
static/jssources/core-js/modules/web.url.to-json.js
static/jssources/core-js/stable/index.js
static/jssources/d3-array/LICENSE.txt
static/jssources/d3-array/src/array.js
static/jssources/d3-array/src/ascending.js
static/jssources/d3-array/src/bin.js
static/jssources/d3-array/src/bisect.js
static/jssources/d3-array/src/bisector.js
static/jssources/d3-array/src/constant.js
static/jssources/d3-array/src/count.js
static/jssources/d3-array/src/cross.js
static/jssources/d3-array/src/cumsum.js
static/jssources/d3-array/src/descending.js
static/jssources/d3-array/src/deviation.js
static/jssources/d3-array/src/difference.js
static/jssources/d3-array/src/disjoint.js
static/jssources/d3-array/src/every.js
static/jssources/d3-array/src/extent.js
static/jssources/d3-array/src/filter.js
static/jssources/d3-array/src/fsum.js
static/jssources/d3-array/src/greatest.js
static/jssources/d3-array/src/greatestIndex.js
static/jssources/d3-array/src/group.js
static/jssources/d3-array/src/groupSort.js
static/jssources/d3-array/src/identity.js
static/jssources/d3-array/src/index.js
static/jssources/d3-array/src/intersection.js
static/jssources/d3-array/src/least.js
static/jssources/d3-array/src/leastIndex.js
static/jssources/d3-array/src/map.js
static/jssources/d3-array/src/max.js
static/jssources/d3-array/src/maxIndex.js
static/jssources/d3-array/src/mean.js
static/jssources/d3-array/src/median.js
static/jssources/d3-array/src/merge.js
static/jssources/d3-array/src/min.js
static/jssources/d3-array/src/minIndex.js
static/jssources/d3-array/src/mode.js
static/jssources/d3-array/src/nice.js
static/jssources/d3-array/src/number.js
static/jssources/d3-array/src/pairs.js
static/jssources/d3-array/src/permute.js
static/jssources/d3-array/src/quantile.js
static/jssources/d3-array/src/quickselect.js
static/jssources/d3-array/src/range.js
static/jssources/d3-array/src/reduce.js
static/jssources/d3-array/src/reverse.js
static/jssources/d3-array/src/scan.js
static/jssources/d3-array/src/set.js
static/jssources/d3-array/src/shuffle.js
static/jssources/d3-array/src/some.js
static/jssources/d3-array/src/sort.js
static/jssources/d3-array/src/subset.js
static/jssources/d3-array/src/sum.js
static/jssources/d3-array/src/superset.js
static/jssources/d3-array/src/ticks.js
static/jssources/d3-array/src/transpose.js
static/jssources/d3-array/src/union.js
static/jssources/d3-array/src/variance.js
static/jssources/d3-array/src/zip.js
static/jssources/d3-array/src/threshold/freedmanDiaconis.js
static/jssources/d3-array/src/threshold/scott.js
static/jssources/d3-array/src/threshold/sturges.js
static/jssources/d3-axis/LICENSE.txt
static/jssources/d3-axis/src/axis.js
static/jssources/d3-axis/src/identity.js
static/jssources/d3-axis/src/index.js
static/jssources/d3-color/LICENSE.txt
static/jssources/d3-color/src/color.js
static/jssources/d3-color/src/define.js
static/jssources/d3-dispatch/LICENSE.txt
static/jssources/d3-dispatch/src/dispatch.js
static/jssources/d3-ease/LICENSE.txt
static/jssources/d3-ease/src/cubic.js
static/jssources/d3-format/LICENSE.txt
static/jssources/d3-format/src/defaultLocale.js
static/jssources/d3-format/src/exponent.js
static/jssources/d3-format/src/formatDecimal.js
static/jssources/d3-format/src/formatGroup.js
static/jssources/d3-format/src/formatNumerals.js
static/jssources/d3-format/src/formatPrefixAuto.js
static/jssources/d3-format/src/formatRounded.js
static/jssources/d3-format/src/formatSpecifier.js
static/jssources/d3-format/src/formatTrim.js
static/jssources/d3-format/src/formatTypes.js
static/jssources/d3-format/src/identity.js
static/jssources/d3-format/src/index.js
static/jssources/d3-format/src/locale.js
static/jssources/d3-format/src/precisionFixed.js
static/jssources/d3-format/src/precisionPrefix.js
static/jssources/d3-format/src/precisionRound.js
static/jssources/d3-interpolate/LICENSE.txt
static/jssources/d3-interpolate/src/array.js
static/jssources/d3-interpolate/src/basis.js
static/jssources/d3-interpolate/src/basisClosed.js
static/jssources/d3-interpolate/src/color.js
static/jssources/d3-interpolate/src/constant.js
static/jssources/d3-interpolate/src/date.js
static/jssources/d3-interpolate/src/number.js
static/jssources/d3-interpolate/src/numberArray.js
static/jssources/d3-interpolate/src/object.js
static/jssources/d3-interpolate/src/piecewise.js
static/jssources/d3-interpolate/src/rgb.js
static/jssources/d3-interpolate/src/round.js
static/jssources/d3-interpolate/src/string.js
static/jssources/d3-interpolate/src/value.js
static/jssources/d3-interpolate/src/transform/decompose.js
static/jssources/d3-interpolate/src/transform/index.js
static/jssources/d3-interpolate/src/transform/parse.js
static/jssources/d3-path/LICENSE.txt
static/jssources/d3-path/src/path.js
static/jssources/d3-scale/LICENSE.txt
static/jssources/d3-scale/src/band.js
static/jssources/d3-scale/src/constant.js
static/jssources/d3-scale/src/continuous.js
static/jssources/d3-scale/src/diverging.js
static/jssources/d3-scale/src/identity.js
static/jssources/d3-scale/src/index.js
static/jssources/d3-scale/src/init.js
static/jssources/d3-scale/src/linear.js
static/jssources/d3-scale/src/log.js
static/jssources/d3-scale/src/nice.js
static/jssources/d3-scale/src/number.js
static/jssources/d3-scale/src/ordinal.js
static/jssources/d3-scale/src/pow.js
static/jssources/d3-scale/src/quantile.js
static/jssources/d3-scale/src/quantize.js
static/jssources/d3-scale/src/radial.js
static/jssources/d3-scale/src/sequential.js
static/jssources/d3-scale/src/sequentialQuantile.js
static/jssources/d3-scale/src/symlog.js
static/jssources/d3-scale/src/threshold.js
static/jssources/d3-scale/src/tickFormat.js
static/jssources/d3-scale/src/time.js
static/jssources/d3-scale/src/utcTime.js
static/jssources/d3-selection/LICENSE.txt
static/jssources/d3-selection/src/array.js
static/jssources/d3-selection/src/constant.js
static/jssources/d3-selection/src/create.js
static/jssources/d3-selection/src/creator.js
static/jssources/d3-selection/src/index.js
static/jssources/d3-selection/src/local.js
static/jssources/d3-selection/src/matcher.js
static/jssources/d3-selection/src/namespace.js
static/jssources/d3-selection/src/namespaces.js
static/jssources/d3-selection/src/pointer.js
static/jssources/d3-selection/src/pointers.js
static/jssources/d3-selection/src/select.js
static/jssources/d3-selection/src/selectAll.js
static/jssources/d3-selection/src/selector.js
static/jssources/d3-selection/src/selectorAll.js
static/jssources/d3-selection/src/sourceEvent.js
static/jssources/d3-selection/src/window.js
static/jssources/d3-selection/src/selection/append.js
static/jssources/d3-selection/src/selection/attr.js
static/jssources/d3-selection/src/selection/call.js
static/jssources/d3-selection/src/selection/classed.js
static/jssources/d3-selection/src/selection/clone.js
static/jssources/d3-selection/src/selection/data.js
static/jssources/d3-selection/src/selection/datum.js
static/jssources/d3-selection/src/selection/dispatch.js
static/jssources/d3-selection/src/selection/each.js
static/jssources/d3-selection/src/selection/empty.js
static/jssources/d3-selection/src/selection/enter.js
static/jssources/d3-selection/src/selection/exit.js
static/jssources/d3-selection/src/selection/filter.js
static/jssources/d3-selection/src/selection/html.js
static/jssources/d3-selection/src/selection/index.js
static/jssources/d3-selection/src/selection/insert.js
static/jssources/d3-selection/src/selection/iterator.js
static/jssources/d3-selection/src/selection/join.js
static/jssources/d3-selection/src/selection/lower.js
static/jssources/d3-selection/src/selection/merge.js
static/jssources/d3-selection/src/selection/node.js
static/jssources/d3-selection/src/selection/nodes.js
static/jssources/d3-selection/src/selection/on.js
static/jssources/d3-selection/src/selection/order.js
static/jssources/d3-selection/src/selection/property.js
static/jssources/d3-selection/src/selection/raise.js
static/jssources/d3-selection/src/selection/remove.js
static/jssources/d3-selection/src/selection/select.js
static/jssources/d3-selection/src/selection/selectAll.js
static/jssources/d3-selection/src/selection/selectChild.js
static/jssources/d3-selection/src/selection/selectChildren.js
static/jssources/d3-selection/src/selection/size.js
static/jssources/d3-selection/src/selection/sort.js
static/jssources/d3-selection/src/selection/sparse.js
static/jssources/d3-selection/src/selection/style.js
static/jssources/d3-selection/src/selection/text.js
static/jssources/d3-shape/LICENSE.txt
static/jssources/d3-shape/src/arc.js
static/jssources/d3-shape/src/area.js
static/jssources/d3-shape/src/areaRadial.js
static/jssources/d3-shape/src/array.js
static/jssources/d3-shape/src/constant.js
static/jssources/d3-shape/src/descending.js
static/jssources/d3-shape/src/identity.js
static/jssources/d3-shape/src/index.js
static/jssources/d3-shape/src/line.js
static/jssources/d3-shape/src/lineRadial.js
static/jssources/d3-shape/src/math.js
static/jssources/d3-shape/src/noop.js
static/jssources/d3-shape/src/pie.js
static/jssources/d3-shape/src/point.js
static/jssources/d3-shape/src/pointRadial.js
static/jssources/d3-shape/src/stack.js
static/jssources/d3-shape/src/symbol.js
static/jssources/d3-shape/src/curve/basis.js
static/jssources/d3-shape/src/curve/basisClosed.js
static/jssources/d3-shape/src/curve/basisOpen.js
static/jssources/d3-shape/src/curve/bump.js
static/jssources/d3-shape/src/curve/bundle.js
static/jssources/d3-shape/src/curve/cardinal.js
static/jssources/d3-shape/src/curve/cardinalClosed.js
static/jssources/d3-shape/src/curve/cardinalOpen.js
static/jssources/d3-shape/src/curve/catmullRom.js
static/jssources/d3-shape/src/curve/catmullRomClosed.js
static/jssources/d3-shape/src/curve/catmullRomOpen.js
static/jssources/d3-shape/src/curve/linear.js
static/jssources/d3-shape/src/curve/linearClosed.js
static/jssources/d3-shape/src/curve/monotone.js
static/jssources/d3-shape/src/curve/natural.js
static/jssources/d3-shape/src/curve/radial.js
static/jssources/d3-shape/src/curve/step.js
static/jssources/d3-shape/src/link/index.js
static/jssources/d3-shape/src/offset/diverging.js
static/jssources/d3-shape/src/offset/expand.js
static/jssources/d3-shape/src/offset/none.js
static/jssources/d3-shape/src/offset/silhouette.js
static/jssources/d3-shape/src/offset/wiggle.js
static/jssources/d3-shape/src/order/appearance.js
static/jssources/d3-shape/src/order/ascending.js
static/jssources/d3-shape/src/order/descending.js
static/jssources/d3-shape/src/order/insideOut.js
static/jssources/d3-shape/src/order/none.js
static/jssources/d3-shape/src/order/reverse.js
static/jssources/d3-shape/src/symbol/circle.js
static/jssources/d3-shape/src/symbol/cross.js
static/jssources/d3-shape/src/symbol/diamond.js
static/jssources/d3-shape/src/symbol/square.js
static/jssources/d3-shape/src/symbol/star.js
static/jssources/d3-shape/src/symbol/triangle.js
static/jssources/d3-shape/src/symbol/wye.js
static/jssources/d3-time/LICENSE.txt
static/jssources/d3-time-format/LICENSE.txt
static/jssources/d3-time-format/src/defaultLocale.js
static/jssources/d3-time-format/src/index.js
static/jssources/d3-time-format/src/isoFormat.js
static/jssources/d3-time-format/src/isoParse.js
static/jssources/d3-time-format/src/locale.js
static/jssources/d3-time/src/day.js
static/jssources/d3-time/src/duration.js
static/jssources/d3-time/src/hour.js
static/jssources/d3-time/src/index.js
static/jssources/d3-time/src/interval.js
static/jssources/d3-time/src/millisecond.js
static/jssources/d3-time/src/minute.js
static/jssources/d3-time/src/month.js
static/jssources/d3-time/src/second.js
static/jssources/d3-time/src/ticks.js
static/jssources/d3-time/src/utcDay.js
static/jssources/d3-time/src/utcHour.js
static/jssources/d3-time/src/utcMinute.js
static/jssources/d3-time/src/utcMonth.js
static/jssources/d3-time/src/utcWeek.js
static/jssources/d3-time/src/utcYear.js
static/jssources/d3-time/src/week.js
static/jssources/d3-time/src/year.js
static/jssources/d3-timer/LICENSE.txt
static/jssources/d3-timer/src/timeout.js
static/jssources/d3-timer/src/timer.js
static/jssources/d3-transition/LICENSE.txt
static/jssources/d3-transition/src/active.js
static/jssources/d3-transition/src/index.js
static/jssources/d3-transition/src/interrupt.js
static/jssources/d3-transition/src/selection/index.js
static/jssources/d3-transition/src/selection/interrupt.js
static/jssources/d3-transition/src/selection/transition.js
static/jssources/d3-transition/src/transition/attr.js
static/jssources/d3-transition/src/transition/attrTween.js
static/jssources/d3-transition/src/transition/delay.js
static/jssources/d3-transition/src/transition/duration.js
static/jssources/d3-transition/src/transition/ease.js
static/jssources/d3-transition/src/transition/easeVarying.js
static/jssources/d3-transition/src/transition/end.js
static/jssources/d3-transition/src/transition/filter.js
static/jssources/d3-transition/src/transition/index.js
static/jssources/d3-transition/src/transition/interpolate.js
static/jssources/d3-transition/src/transition/merge.js
static/jssources/d3-transition/src/transition/on.js
static/jssources/d3-transition/src/transition/remove.js
static/jssources/d3-transition/src/transition/schedule.js
static/jssources/d3-transition/src/transition/select.js
static/jssources/d3-transition/src/transition/selectAll.js
static/jssources/d3-transition/src/transition/selection.js
static/jssources/d3-transition/src/transition/style.js
static/jssources/d3-transition/src/transition/styleTween.js
static/jssources/d3-transition/src/transition/text.js
static/jssources/d3-transition/src/transition/textTween.js
static/jssources/d3-transition/src/transition/transition.js
static/jssources/d3-transition/src/transition/tween.js
static/jssources/datatables.net/License.txt
static/jssources/datatables.net-bs4/License.txt
static/jssources/datatables.net-bs4/js/dataTables.bootstrap4.js
static/jssources/datatables.net/js/jquery.dataTables.js
static/jssources/dompurify/LICENSE.txt
static/jssources/dompurify/dist/purify.js
static/jssources/email-validator/LICENSE.txt
static/jssources/email-validator/index.js
static/jssources/expose-loader/LICENSE.txt
static/jssources/expose-loader/dist/runtime/getGlobalThis.js
static/jssources/he/LICENSE-MIT.txt.txt
static/jssources/he/he.js
static/jssources/hex-rgb/index.js
static/jssources/hex-rgb/license.txt
static/jssources/highlight.js/LICENSE.txt
static/jssources/highlight.js/es/index.js
static/jssources/highlight.js/lib/core.js
static/jssources/highlight.js/lib/index.js
static/jssources/highlight.js/lib/languages/1c.js
static/jssources/highlight.js/lib/languages/abnf.js
static/jssources/highlight.js/lib/languages/accesslog.js
static/jssources/highlight.js/lib/languages/actionscript.js
static/jssources/highlight.js/lib/languages/ada.js
static/jssources/highlight.js/lib/languages/angelscript.js
static/jssources/highlight.js/lib/languages/apache.js
static/jssources/highlight.js/lib/languages/applescript.js
static/jssources/highlight.js/lib/languages/arcade.js
static/jssources/highlight.js/lib/languages/arduino.js
static/jssources/highlight.js/lib/languages/armasm.js
static/jssources/highlight.js/lib/languages/asciidoc.js
static/jssources/highlight.js/lib/languages/aspectj.js
static/jssources/highlight.js/lib/languages/autohotkey.js
static/jssources/highlight.js/lib/languages/autoit.js
static/jssources/highlight.js/lib/languages/avrasm.js
static/jssources/highlight.js/lib/languages/awk.js
static/jssources/highlight.js/lib/languages/axapta.js
static/jssources/highlight.js/lib/languages/bash.js
static/jssources/highlight.js/lib/languages/basic.js
static/jssources/highlight.js/lib/languages/bnf.js
static/jssources/highlight.js/lib/languages/brainfuck.js
static/jssources/highlight.js/lib/languages/c.js
static/jssources/highlight.js/lib/languages/cal.js
static/jssources/highlight.js/lib/languages/capnproto.js
static/jssources/highlight.js/lib/languages/ceylon.js
static/jssources/highlight.js/lib/languages/clean.js
static/jssources/highlight.js/lib/languages/clojure-repl.js
static/jssources/highlight.js/lib/languages/clojure.js
static/jssources/highlight.js/lib/languages/cmake.js
static/jssources/highlight.js/lib/languages/coffeescript.js
static/jssources/highlight.js/lib/languages/coq.js
static/jssources/highlight.js/lib/languages/cos.js
static/jssources/highlight.js/lib/languages/cpp.js
static/jssources/highlight.js/lib/languages/crmsh.js
static/jssources/highlight.js/lib/languages/crystal.js
static/jssources/highlight.js/lib/languages/csharp.js
static/jssources/highlight.js/lib/languages/csp.js
static/jssources/highlight.js/lib/languages/css.js
static/jssources/highlight.js/lib/languages/d.js
static/jssources/highlight.js/lib/languages/dart.js
static/jssources/highlight.js/lib/languages/delphi.js
static/jssources/highlight.js/lib/languages/diff.js
static/jssources/highlight.js/lib/languages/django.js
static/jssources/highlight.js/lib/languages/dns.js
static/jssources/highlight.js/lib/languages/dockerfile.js
static/jssources/highlight.js/lib/languages/dos.js
static/jssources/highlight.js/lib/languages/dsconfig.js
static/jssources/highlight.js/lib/languages/dts.js
static/jssources/highlight.js/lib/languages/dust.js
static/jssources/highlight.js/lib/languages/ebnf.js
static/jssources/highlight.js/lib/languages/elixir.js
static/jssources/highlight.js/lib/languages/elm.js
static/jssources/highlight.js/lib/languages/erb.js
static/jssources/highlight.js/lib/languages/erlang-repl.js
static/jssources/highlight.js/lib/languages/erlang.js
static/jssources/highlight.js/lib/languages/excel.js
static/jssources/highlight.js/lib/languages/fix.js
static/jssources/highlight.js/lib/languages/flix.js
static/jssources/highlight.js/lib/languages/fortran.js
static/jssources/highlight.js/lib/languages/fsharp.js
static/jssources/highlight.js/lib/languages/gams.js
static/jssources/highlight.js/lib/languages/gauss.js
static/jssources/highlight.js/lib/languages/gcode.js
static/jssources/highlight.js/lib/languages/gherkin.js
static/jssources/highlight.js/lib/languages/glsl.js
static/jssources/highlight.js/lib/languages/gml.js
static/jssources/highlight.js/lib/languages/go.js
static/jssources/highlight.js/lib/languages/golo.js
static/jssources/highlight.js/lib/languages/gradle.js
static/jssources/highlight.js/lib/languages/graphql.js
static/jssources/highlight.js/lib/languages/groovy.js
static/jssources/highlight.js/lib/languages/haml.js
static/jssources/highlight.js/lib/languages/handlebars.js
static/jssources/highlight.js/lib/languages/haskell.js
static/jssources/highlight.js/lib/languages/haxe.js
static/jssources/highlight.js/lib/languages/hsp.js
static/jssources/highlight.js/lib/languages/http.js
static/jssources/highlight.js/lib/languages/hy.js
static/jssources/highlight.js/lib/languages/inform7.js
static/jssources/highlight.js/lib/languages/ini.js
static/jssources/highlight.js/lib/languages/irpf90.js
static/jssources/highlight.js/lib/languages/isbl.js
static/jssources/highlight.js/lib/languages/java.js
static/jssources/highlight.js/lib/languages/javascript.js
static/jssources/highlight.js/lib/languages/jboss-cli.js
static/jssources/highlight.js/lib/languages/json.js
static/jssources/highlight.js/lib/languages/julia-repl.js
static/jssources/highlight.js/lib/languages/julia.js
static/jssources/highlight.js/lib/languages/kotlin.js
static/jssources/highlight.js/lib/languages/lasso.js
static/jssources/highlight.js/lib/languages/latex.js
static/jssources/highlight.js/lib/languages/ldif.js
static/jssources/highlight.js/lib/languages/leaf.js
static/jssources/highlight.js/lib/languages/less.js
static/jssources/highlight.js/lib/languages/lisp.js
static/jssources/highlight.js/lib/languages/livecodeserver.js
static/jssources/highlight.js/lib/languages/livescript.js
static/jssources/highlight.js/lib/languages/llvm.js
static/jssources/highlight.js/lib/languages/lsl.js
static/jssources/highlight.js/lib/languages/lua.js
static/jssources/highlight.js/lib/languages/makefile.js
static/jssources/highlight.js/lib/languages/markdown.js
static/jssources/highlight.js/lib/languages/mathematica.js
static/jssources/highlight.js/lib/languages/matlab.js
static/jssources/highlight.js/lib/languages/maxima.js
static/jssources/highlight.js/lib/languages/mel.js
static/jssources/highlight.js/lib/languages/mercury.js
static/jssources/highlight.js/lib/languages/mipsasm.js
static/jssources/highlight.js/lib/languages/mizar.js
static/jssources/highlight.js/lib/languages/mojolicious.js
static/jssources/highlight.js/lib/languages/monkey.js
static/jssources/highlight.js/lib/languages/moonscript.js
static/jssources/highlight.js/lib/languages/n1ql.js
static/jssources/highlight.js/lib/languages/nestedtext.js
static/jssources/highlight.js/lib/languages/nginx.js
static/jssources/highlight.js/lib/languages/nim.js
static/jssources/highlight.js/lib/languages/nix.js
static/jssources/highlight.js/lib/languages/node-repl.js
static/jssources/highlight.js/lib/languages/nsis.js
static/jssources/highlight.js/lib/languages/objectivec.js
static/jssources/highlight.js/lib/languages/ocaml.js
static/jssources/highlight.js/lib/languages/openscad.js
static/jssources/highlight.js/lib/languages/oxygene.js
static/jssources/highlight.js/lib/languages/parser3.js
static/jssources/highlight.js/lib/languages/perl.js
static/jssources/highlight.js/lib/languages/pf.js
static/jssources/highlight.js/lib/languages/pgsql.js
static/jssources/highlight.js/lib/languages/php-template.js
static/jssources/highlight.js/lib/languages/php.js
static/jssources/highlight.js/lib/languages/plaintext.js
static/jssources/highlight.js/lib/languages/pony.js
static/jssources/highlight.js/lib/languages/powershell.js
static/jssources/highlight.js/lib/languages/processing.js
static/jssources/highlight.js/lib/languages/profile.js
static/jssources/highlight.js/lib/languages/prolog.js
static/jssources/highlight.js/lib/languages/properties.js
static/jssources/highlight.js/lib/languages/protobuf.js
static/jssources/highlight.js/lib/languages/puppet.js
static/jssources/highlight.js/lib/languages/purebasic.js
static/jssources/highlight.js/lib/languages/python-repl.js
static/jssources/highlight.js/lib/languages/python.js
static/jssources/highlight.js/lib/languages/q.js
static/jssources/highlight.js/lib/languages/qml.js
static/jssources/highlight.js/lib/languages/r.js
static/jssources/highlight.js/lib/languages/reasonml.js
static/jssources/highlight.js/lib/languages/rib.js
static/jssources/highlight.js/lib/languages/roboconf.js
static/jssources/highlight.js/lib/languages/routeros.js
static/jssources/highlight.js/lib/languages/rsl.js
static/jssources/highlight.js/lib/languages/ruby.js
static/jssources/highlight.js/lib/languages/ruleslanguage.js
static/jssources/highlight.js/lib/languages/rust.js
static/jssources/highlight.js/lib/languages/sas.js
static/jssources/highlight.js/lib/languages/scala.js
static/jssources/highlight.js/lib/languages/scheme.js
static/jssources/highlight.js/lib/languages/scilab.js
static/jssources/highlight.js/lib/languages/scss.js
static/jssources/highlight.js/lib/languages/shell.js
static/jssources/highlight.js/lib/languages/smali.js
static/jssources/highlight.js/lib/languages/smalltalk.js
static/jssources/highlight.js/lib/languages/sml.js
static/jssources/highlight.js/lib/languages/sqf.js
static/jssources/highlight.js/lib/languages/sql.js
static/jssources/highlight.js/lib/languages/stan.js
static/jssources/highlight.js/lib/languages/stata.js
static/jssources/highlight.js/lib/languages/step21.js
static/jssources/highlight.js/lib/languages/stylus.js
static/jssources/highlight.js/lib/languages/subunit.js
static/jssources/highlight.js/lib/languages/swift.js
static/jssources/highlight.js/lib/languages/taggerscript.js
static/jssources/highlight.js/lib/languages/tap.js
static/jssources/highlight.js/lib/languages/tcl.js
static/jssources/highlight.js/lib/languages/thrift.js
static/jssources/highlight.js/lib/languages/tp.js
static/jssources/highlight.js/lib/languages/twig.js
static/jssources/highlight.js/lib/languages/typescript.js
static/jssources/highlight.js/lib/languages/vala.js
static/jssources/highlight.js/lib/languages/vbnet.js
static/jssources/highlight.js/lib/languages/vbscript-html.js
static/jssources/highlight.js/lib/languages/vbscript.js
static/jssources/highlight.js/lib/languages/verilog.js
static/jssources/highlight.js/lib/languages/vhdl.js
static/jssources/highlight.js/lib/languages/vim.js
static/jssources/highlight.js/lib/languages/wasm.js
static/jssources/highlight.js/lib/languages/wren.js
static/jssources/highlight.js/lib/languages/x86asm.js
static/jssources/highlight.js/lib/languages/xl.js
static/jssources/highlight.js/lib/languages/xml.js
static/jssources/highlight.js/lib/languages/xquery.js
static/jssources/highlight.js/lib/languages/yaml.js
static/jssources/highlight.js/lib/languages/zephir.js
static/jssources/highlightjs-4d/LICENSE.txt
static/jssources/highlightjs-4d/dist/4d.min.js
static/jssources/highlightjs-alan/LICENSE.txt
static/jssources/highlightjs-alan/dist/alan.min.js
static/jssources/highlightjs-blade/LICENSE.txt
static/jssources/highlightjs-blade/dist/blade.min.js
static/jssources/highlightjs-chaos/LICENSE.txt
static/jssources/highlightjs-chaos/dist/chaos.min.js
static/jssources/highlightjs-chapel/LICENSE.txt
static/jssources/highlightjs-chapel/dist/chapel.min.js
static/jssources/highlightjs-cpcdos/LICENSE.txt
static/jssources/highlightjs-cpcdos/dist/cpc-highlight.min.js
static/jssources/highlightjs-cshtml-razor/LICENSE.txt
static/jssources/highlightjs-cshtml-razor/dist/cshtml-razor.min.js
static/jssources/highlightjs-cypher/LICENSE.txt
static/jssources/highlightjs-cypher/dist/cypher.min.js
static/jssources/highlightjs-dafny/LICENSE.txt
static/jssources/highlightjs-dafny/dist/dafny.min.js
static/jssources/highlightjs-dylan/LICENSE.txt
static/jssources/highlightjs-dylan/dist/dylan.min.js
static/jssources/highlightjs-eta/dist/eta.min.js
static/jssources/highlightjs-extempore/LICENSE.txt
static/jssources/highlightjs-extempore/dist/extempore.min.js
static/jssources/highlightjs-gdscript/LICENSE.txt
static/jssources/highlightjs-gdscript/dist/gdscript.min.js
static/jssources/highlightjs-gf/LICENSE.txt
static/jssources/highlightjs-gf/dist/gf.min.js
static/jssources/highlightjs-gsql/dist/gsql.min.js
static/jssources/highlightjs-hlsl/LICENSE.txt
static/jssources/highlightjs-hlsl/dist/hlsl.min.js
static/jssources/highlightjs-jolie/LICENSE.txt
static/jssources/highlightjs-jolie/dist/jolie.min.js
static/jssources/highlightjs-lean/LICENSE.txt
static/jssources/highlightjs-lean/src/lean.js
static/jssources/highlightjs-line-numbers.js/LICENSE.txt
static/jssources/highlightjs-line-numbers.js/src/highlightjs-line-numbers.js
static/jssources/highlightjs-lox/LICENSE.md
static/jssources/highlightjs-lox/dist/es/lox.mjs
static/jssources/highlightjs-mirc/LICENSE.txt
static/jssources/highlightjs-mirc/mirc.js
static/jssources/highlightjs-modelica/LICENSE.txt
static/jssources/highlightjs-modelica/modelica.js
static/jssources/highlightjs-never/LICENSE.txt
static/jssources/highlightjs-never/dist/never.min.js
static/jssources/highlightjs-octave/LICENSE.txt
static/jssources/highlightjs-octave/dist/highlightjs-octave.cjs.js
static/jssources/highlightjs-oz/LICENSE.txt
static/jssources/highlightjs-oz/dist/oz.min.js
static/jssources/highlightjs-qsharp/dist/qsharp.min.js
static/jssources/highlightjs-redbol/LICENSE.txt
static/jssources/highlightjs-redbol/dist/redbol.min.js
static/jssources/highlightjs-robot/LICENSE.txt
static/jssources/highlightjs-robot/robot.js
static/jssources/highlightjs-robots-txt/LICENSE.txt
static/jssources/highlightjs-robots-txt/dist/robots-txt.min.js
static/jssources/highlightjs-rpm-specfile/LICENSE.txt
static/jssources/highlightjs-rpm-specfile/rpm-specfile.js
static/jssources/highlightjs-sap-abap/LICENSE.txt
static/jssources/highlightjs-sap-abap/dist/abap.min.js
static/jssources/highlightjs-solidity/LICENSE.txt
static/jssources/highlightjs-solidity/dist/solidity.min.js
static/jssources/highlightjs-svelte/LICENSE.txt
static/jssources/highlightjs-svelte/dist/svelte.min.js
static/jssources/highlightjs-terraform/LICENSE.txt
static/jssources/highlightjs-terraform/terraform.js
static/jssources/highlightjs-xsharp/LICENSE.txt
static/jssources/highlightjs-xsharp/dist/xsharp.min.js
static/jssources/highlightjs-zenscript/LICENSE.txt
static/jssources/highlightjs-zenscript/dist/zenscript.min.js
static/jssources/highlightjs-zig/LICENSE.txt
static/jssources/highlightjs-zig/dist/zig.min.js
static/jssources/hightlightjs-papyrus/LICENSE.txt
static/jssources/hightlightjs-papyrus/dist/papyrus.min.js
static/jssources/html-encoder-decoder/LICENSE.txt
static/jssources/html-encoder-decoder/lib/index.js
static/jssources/iframe-resizer/LICENSE.txt
static/jssources/iframe-resizer/index.js
static/jssources/iframe-resizer/js/iframeResizer.contentWindow.js
static/jssources/iframe-resizer/js/iframeResizer.js
static/jssources/iframe-resizer/js/index.js
static/jssources/internmap/LICENSE.txt
static/jssources/internmap/src/index.js
static/jssources/intro.js/intro.module.js
static/jssources/intro.js/license.md
static/jssources/iterate-object/LICENSE.txt
static/jssources/iterate-object/lib/index.js
static/jssources/jquery/LICENSE.txt
static/jssources/jquery/dist/jquery.js
static/jssources/js-cookie/LICENSE.txt
static/jssources/js-cookie/dist/js.cookie.mjs
static/jssources/js-year-calendar/LICENSE.txt
static/jssources/js-year-calendar/dist/js-year-calendar.js
static/jssources/mathjax/LICENSE.txt
static/jssources/mathjax/es5/tex-mml-chtml.js
static/jssources/notebookjs/LICENSE.txt
static/jssources/notebookjs/notebook.js
static/jssources/object-fit-images/license.txt
static/jssources/object-fit-images/dist/ofi.common-js.js
static/jssources/org/LICENSE.txt
static/jssources/org/lib/org.js
static/jssources/org/lib/org/lexer.js
static/jssources/org/lib/org/node.js
static/jssources/org/lib/org/parser.js
static/jssources/org/lib/org/stream.js
static/jssources/org/lib/org/converter/converter.js
static/jssources/org/lib/org/converter/html.js
static/jssources/pdfjs-dist/LICENSE.txt
static/jssources/pdfjs-dist/build/pdf.js
static/jssources/pdfjs-dist/build/pdf.worker.js
static/jssources/popper.js/dist/esm/popper.js
static/jssources/regenerator-runtime/LICENSE.txt
static/jssources/regenerator-runtime/runtime.js
static/jssources/regex-escape/LICENSE.txt
static/jssources/regex-escape/lib/index.js
static/jssources/script-loader/LICENSE.txt
static/jssources/script-loader/addScript.js
static/jssources/showdown/LICENSE.txt
static/jssources/showdown/dist/showdown.js
static/jssources/tslib/LICENSE.txt
static/jssources/tslib/tslib.es6.js
static/jssources/waypoints/licenses.txt.txt
static/jssources/waypoints/lib/jquery.waypoints.js
static/jssources/whatwg-fetch/LICENSE.txt
static/jssources/whatwg-fetch/dist/fetch.umd.js
static/xml/swh-opensearch.xml
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/gunicorn_config.py
swh/web/manage.py
swh/web/py.typed
swh/web/urls.py
swh/web/add_forge_now/__init__.py
swh/web/add_forge_now/apps.py
swh/web/add_forge_now/models.py
swh/web/add_forge_now/views.py
swh/web/add_forge_now/migrations/0001_initial.py
swh/web/add_forge_now/migrations/0002_authorized_null_comment.py
swh/web/add_forge_now/migrations/0003_request_submitter_forward_username.py
swh/web/add_forge_now/migrations/0004_rename_tables.py
swh/web/add_forge_now/migrations/__init__.py
swh/web/admin/__init__.py
swh/web/admin/add_forge_now.py
swh/web/admin/adminurls.py
swh/web/admin/deposit.py
swh/web/admin/mailmap.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/throttling.py
swh/web/api/urls.py
swh/web/api/utils.py
swh/web/api/views/__init__.py
swh/web/api/views/add_forge_now.py
swh/web/api/views/content.py
swh/web/api/views/directory.py
swh/web/api/views/graph.py
swh/web/api/views/identifiers.py
swh/web/api/views/metadata.py
swh/web/api/views/origin.py
swh/web/api/views/origin_save.py
swh/web/api/views/ping.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/auth/__init__.py
swh/web/auth/apps.py
swh/web/auth/mailmap.py
swh/web/auth/models.py
swh/web/auth/utils.py
swh/web/auth/views.py
swh/web/auth/management/__init__.py
swh/web/auth/management/commands/__init__.py
swh/web/auth/management/commands/sync_mailmaps.py
swh/web/auth/migrations/0001_initial.py
swh/web/auth/migrations/0002_remove_stored_tokens.py
swh/web/auth/migrations/0003_delete_oidcuser.py
swh/web/auth/migrations/0004_usermailmap.py
swh/web/auth/migrations/0005_usermailmapevent.py
swh/web/auth/migrations/0006_fix_mailmap_admin_user_id.py
swh/web/auth/migrations/__init__.py
swh/web/browse/__init__.py
swh/web/browse/browseurls.py
swh/web/browse/identifiers.py
swh/web/browse/snapshot_context.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/release.py
swh/web/browse/views/revision.py
swh/web/browse/views/snapshot.py
swh/web/common/__init__.py
swh/web/common/apps.py
swh/web/common/archive.py
swh/web/common/converters.py
swh/web/common/exc.py
swh/web/common/highlightjs.py
swh/web/common/identifiers.py
swh/web/common/middlewares.py
swh/web/common/models.py
swh/web/common/origin_save.py
swh/web/common/origin_visits.py
swh/web/common/query.py
swh/web/common/swh_templatetags.py
swh/web/common/typing.py
swh/web/common/urlsindex.py
swh/web/common/utils.py
swh/web/common/management/__init__.py
swh/web/common/management/commands/__init__.py
swh/web/common/management/commands/refresh_savecodenow_statuses.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/0004_auto_20190204_1324.py
swh/web/common/migrations/0005_remove_duplicated_authorized_origins.py
swh/web/common/migrations/0006_rename_origin_type.py
swh/web/common/migrations/0007_save_request_task_status_fix_typo.py
swh/web/common/migrations/0008_save-code-now_indexes_20210106_1327.py
swh/web/common/migrations/0009_saveoriginrequest_visit_status.py
swh/web/common/migrations/0010_saveoriginrequest_user_id.py
swh/web/common/migrations/0011_saveoriginrequest_user_ids.py
swh/web/common/migrations/0012_saveoriginrequest_note.py
swh/web/common/migrations/__init__.py
swh/web/inbound_email/__init__.py
swh/web/inbound_email/apps.py
swh/web/inbound_email/signals.py
swh/web/inbound_email/utils.py
swh/web/inbound_email/management/__init__.py
swh/web/inbound_email/management/commands/__init__.py
swh/web/inbound_email/management/commands/process_inbound_email.py
swh/web/misc/__init__.py
swh/web/misc/badges.py
swh/web/misc/coverage.py
swh/web/misc/fundraising.py
swh/web/misc/iframe.py
swh/web/misc/metrics.py
swh/web/misc/origin_save.py
swh/web/misc/urls.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/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/add_forge_now/common.html
swh/web/templates/add_forge_now/creation_form.html
swh/web/templates/add_forge_now/help.html
swh/web/templates/add_forge_now/list.html
swh/web/templates/add_forge_now/request-dashboard.html
swh/web/templates/add_forge_now/requests-moderation.html
swh/web/templates/admin/deposit.html
swh/web/templates/admin/mailmap.html
swh/web/templates/admin/origin-save/common.html
swh/web/templates/admin/origin-save/filters.html
swh/web/templates/admin/origin-save/requests.html
swh/web/templates/api/api.html
swh/web/templates/api/apidoc.html
swh/web/templates/api/endpoints.html
swh/web/templates/auth/profile.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-visits.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/branch-search.html
swh/web/templates/includes/breadcrumbs.html
swh/web/templates/includes/content-display.html
swh/web/templates/includes/directory-display.html
swh/web/templates/includes/empty-snapshot.html
swh/web/templates/includes/global-modals.html
swh/web/templates/includes/http-error.html
swh/web/templates/includes/origin-search-form.html
swh/web/templates/includes/readme-display.html
swh/web/templates/includes/revision-info.html
swh/web/templates/includes/show-metadata.html
swh/web/templates/includes/show-swhids.html
swh/web/templates/includes/snapshot-context.html
swh/web/templates/includes/take-new-snapshot.html
swh/web/templates/includes/top-navigation.html
swh/web/templates/includes/vault-common.html
swh/web/templates/includes/vault-create-tasks.html
swh/web/templates/misc/coverage.html
swh/web/templates/misc/fundraising-banner.html
swh/web/templates/misc/iframe.html
swh/web/templates/misc/jslicenses.html
swh/web/templates/misc/origin-save-help.html
swh/web/templates/misc/origin-save-list.html
swh/web/templates/misc/origin-save.html
swh/web/tests/__init__.py
swh/web/tests/conftest.py
swh/web/tests/create_test_admin.py
swh/web/tests/create_test_users.py
swh/web/tests/data.py
swh/web/tests/django_asserts.py
swh/web/tests/random_fixtures_test.py
swh/web/tests/strategies.py
swh/web/tests/test_config.py
swh/web/tests/test_create_users.py
swh/web/tests/test_gunicorn_config.py
swh/web/tests/test_migrations.py
swh/web/tests/test_random_fixtures.py
swh/web/tests/test_templates.py
swh/web/tests/test_urls.py
swh/web/tests/utils.py
swh/web/tests/views.py
swh/web/tests/add_forge_now/test_migration.py
swh/web/tests/add_forge_now/test_models.py
swh/web/tests/add_forge_now/test_views.py
swh/web/tests/admin/__init__.py
swh/web/tests/admin/test_deposit.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_apiurls.py
swh/web/tests/api/test_throttling.py
swh/web/tests/api/test_utils.py
swh/web/tests/api/views/__init__.py
swh/web/tests/api/views/test_add_forge_now.py
swh/web/tests/api/views/test_content.py
swh/web/tests/api/views/test_directory.py
swh/web/tests/api/views/test_graph.py
swh/web/tests/api/views/test_identifiers.py
swh/web/tests/api/views/test_metadata.py
swh/web/tests/api/views/test_origin.py
swh/web/tests/api/views/test_origin_save.py
swh/web/tests/api/views/test_ping.py
swh/web/tests/api/views/test_release.py
swh/web/tests/api/views/test_revision.py
swh/web/tests/api/views/test_snapshot.py
swh/web/tests/api/views/test_stat.py
swh/web/tests/api/views/test_vault.py
swh/web/tests/api/views/utils.py
swh/web/tests/auth/__init__.py
swh/web/tests/auth/test_mailmap.py
swh/web/tests/auth/test_migrations.py
swh/web/tests/auth/test_utils.py
swh/web/tests/auth/test_views.py
swh/web/tests/browse/__init__.py
swh/web/tests/browse/test_snapshot_context.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_release.py
swh/web/tests/browse/views/test_revision.py
swh/web/tests/browse/views/test_snapshot.py
swh/web/tests/common/__init__.py
swh/web/tests/common/test_archive.py
swh/web/tests/common/test_converters.py
swh/web/tests/common/test_django_command.py
swh/web/tests/common/test_highlightjs.py
swh/web/tests/common/test_identifiers.py
swh/web/tests/common/test_middlewares.py
swh/web/tests/common/test_origin_save.py
swh/web/tests/common/test_origin_visits.py
swh/web/tests/common/test_query.py
swh/web/tests/common/test_templatetags.py
swh/web/tests/common/test_utils.py
+swh/web/tests/inbound_email/__init__.py
swh/web/tests/inbound_email/test_management_command.py
swh/web/tests/inbound_email/test_utils.py
+swh/web/tests/inbound_email/resources/__init__.py
+swh/web/tests/inbound_email/resources/multipart.eml
+swh/web/tests/inbound_email/resources/multipart_html_only.eml
+swh/web/tests/inbound_email/resources/multipart_text_only.eml
+swh/web/tests/inbound_email/resources/plaintext.eml
swh/web/tests/misc/__init__.py
swh/web/tests/misc/test_badges.py
swh/web/tests/misc/test_coverage.py
swh/web/tests/misc/test_fundraising.py
swh/web/tests/misc/test_iframe.py
swh/web/tests/misc/test_metrics.py
swh/web/tests/misc/test_origin_save.py
swh/web/tests/resources/contents/code/LICENSE
swh/web/tests/resources/contents/code/extensions/test.R
swh/web/tests/resources/contents/code/extensions/test.abnf
swh/web/tests/resources/contents/code/extensions/test.adb
swh/web/tests/resources/contents/code/extensions/test.adoc
swh/web/tests/resources/contents/code/extensions/test.ahk
swh/web/tests/resources/contents/code/extensions/test.aj
swh/web/tests/resources/contents/code/extensions/test.applescript
swh/web/tests/resources/contents/code/extensions/test.as
swh/web/tests/resources/contents/code/extensions/test.au3
swh/web/tests/resources/contents/code/extensions/test.awk
swh/web/tests/resources/contents/code/extensions/test.bas
swh/web/tests/resources/contents/code/extensions/test.bat
swh/web/tests/resources/contents/code/extensions/test.bf
swh/web/tests/resources/contents/code/extensions/test.bnf
swh/web/tests/resources/contents/code/extensions/test.bsl
swh/web/tests/resources/contents/code/extensions/test.cal
swh/web/tests/resources/contents/code/extensions/test.capnp
swh/web/tests/resources/contents/code/extensions/test.ceylon
swh/web/tests/resources/contents/code/extensions/test.clj
swh/web/tests/resources/contents/code/extensions/test.cls
swh/web/tests/resources/contents/code/extensions/test.cmake
swh/web/tests/resources/contents/code/extensions/test.coffee
swh/web/tests/resources/contents/code/extensions/test.cpp
swh/web/tests/resources/contents/code/extensions/test.cr
swh/web/tests/resources/contents/code/extensions/test.cs
swh/web/tests/resources/contents/code/extensions/test.css
swh/web/tests/resources/contents/code/extensions/test.d
swh/web/tests/resources/contents/code/extensions/test.dart
swh/web/tests/resources/contents/code/extensions/test.dcl
swh/web/tests/resources/contents/code/extensions/test.dfm
swh/web/tests/resources/contents/code/extensions/test.diff
swh/web/tests/resources/contents/code/extensions/test.do
swh/web/tests/resources/contents/code/extensions/test.dts
swh/web/tests/resources/contents/code/extensions/test.dust
swh/web/tests/resources/contents/code/extensions/test.ebnf
swh/web/tests/resources/contents/code/extensions/test.elm
swh/web/tests/resources/contents/code/extensions/test.ep
swh/web/tests/resources/contents/code/extensions/test.erb
swh/web/tests/resources/contents/code/extensions/test.erl
swh/web/tests/resources/contents/code/extensions/test.ex
swh/web/tests/resources/contents/code/extensions/test.f90
swh/web/tests/resources/contents/code/extensions/test.feature
swh/web/tests/resources/contents/code/extensions/test.flix
swh/web/tests/resources/contents/code/extensions/test.fs
swh/web/tests/resources/contents/code/extensions/test.gcode
swh/web/tests/resources/contents/code/extensions/test.glsl
swh/web/tests/resources/contents/code/extensions/test.gml
swh/web/tests/resources/contents/code/extensions/test.gms
swh/web/tests/resources/contents/code/extensions/test.go
swh/web/tests/resources/contents/code/extensions/test.golo
swh/web/tests/resources/contents/code/extensions/test.gradle
swh/web/tests/resources/contents/code/extensions/test.groovy
swh/web/tests/resources/contents/code/extensions/test.gss
swh/web/tests/resources/contents/code/extensions/test.haml
swh/web/tests/resources/contents/code/extensions/test.hbs
swh/web/tests/resources/contents/code/extensions/test.hs
swh/web/tests/resources/contents/code/extensions/test.hsp
swh/web/tests/resources/contents/code/extensions/test.html
swh/web/tests/resources/contents/code/extensions/test.hx
swh/web/tests/resources/contents/code/extensions/test.hy
swh/web/tests/resources/contents/code/extensions/test.ini
swh/web/tests/resources/contents/code/extensions/test.ino
swh/web/tests/resources/contents/code/extensions/test.java
swh/web/tests/resources/contents/code/extensions/test.jl
swh/web/tests/resources/contents/code/extensions/test.js
swh/web/tests/resources/contents/code/extensions/test.json
swh/web/tests/resources/contents/code/extensions/test.kt
swh/web/tests/resources/contents/code/extensions/test.lasso
swh/web/tests/resources/contents/code/extensions/test.lc
swh/web/tests/resources/contents/code/extensions/test.ldif
swh/web/tests/resources/contents/code/extensions/test.leaf
swh/web/tests/resources/contents/code/extensions/test.less
swh/web/tests/resources/contents/code/extensions/test.lisp
swh/web/tests/resources/contents/code/extensions/test.ll
swh/web/tests/resources/contents/code/extensions/test.ls
swh/web/tests/resources/contents/code/extensions/test.lsl
swh/web/tests/resources/contents/code/extensions/test.lua
swh/web/tests/resources/contents/code/extensions/test.m
swh/web/tests/resources/contents/code/extensions/test.md
swh/web/tests/resources/contents/code/extensions/test.mel
swh/web/tests/resources/contents/code/extensions/test.mk
swh/web/tests/resources/contents/code/extensions/test.ml
swh/web/tests/resources/contents/code/extensions/test.moon
swh/web/tests/resources/contents/code/extensions/test.nim
swh/web/tests/resources/contents/code/extensions/test.nix
swh/web/tests/resources/contents/code/extensions/test.nsi
swh/web/tests/resources/contents/code/extensions/test.p
swh/web/tests/resources/contents/code/extensions/test.pbi
swh/web/tests/resources/contents/code/extensions/test.pde
swh/web/tests/resources/contents/code/extensions/test.php
swh/web/tests/resources/contents/code/extensions/test.pl
swh/web/tests/resources/contents/code/extensions/test.pony
swh/web/tests/resources/contents/code/extensions/test.pp
swh/web/tests/resources/contents/code/extensions/test.properties
swh/web/tests/resources/contents/code/extensions/test.proto
swh/web/tests/resources/contents/code/extensions/test.ps1
swh/web/tests/resources/contents/code/extensions/test.py
swh/web/tests/resources/contents/code/extensions/test.q
swh/web/tests/resources/contents/code/extensions/test.qml
swh/web/tests/resources/contents/code/extensions/test.rb
swh/web/tests/resources/contents/code/extensions/test.re
swh/web/tests/resources/contents/code/extensions/test.rib
swh/web/tests/resources/contents/code/extensions/test.rs
swh/web/tests/resources/contents/code/extensions/test.rsc
swh/web/tests/resources/contents/code/extensions/test.s
swh/web/tests/resources/contents/code/extensions/test.sas
swh/web/tests/resources/contents/code/extensions/test.scad
swh/web/tests/resources/contents/code/extensions/test.scala
swh/web/tests/resources/contents/code/extensions/test.sci
swh/web/tests/resources/contents/code/extensions/test.scm
swh/web/tests/resources/contents/code/extensions/test.scss
swh/web/tests/resources/contents/code/extensions/test.sh
swh/web/tests/resources/contents/code/extensions/test.sl
swh/web/tests/resources/contents/code/extensions/test.smali
swh/web/tests/resources/contents/code/extensions/test.sml
swh/web/tests/resources/contents/code/extensions/test.sqf
swh/web/tests/resources/contents/code/extensions/test.st
swh/web/tests/resources/contents/code/extensions/test.stan
swh/web/tests/resources/contents/code/extensions/test.styl
swh/web/tests/resources/contents/code/extensions/test.subunit
swh/web/tests/resources/contents/code/extensions/test.swift
swh/web/tests/resources/contents/code/extensions/test.tap
swh/web/tests/resources/contents/code/extensions/test.tcl
swh/web/tests/resources/contents/code/extensions/test.tex
swh/web/tests/resources/contents/code/extensions/test.thrift
swh/web/tests/resources/contents/code/extensions/test.ts
swh/web/tests/resources/contents/code/extensions/test.v
swh/web/tests/resources/contents/code/extensions/test.vala
swh/web/tests/resources/contents/code/extensions/test.vb
swh/web/tests/resources/contents/code/extensions/test.vbs
swh/web/tests/resources/contents/code/extensions/test.vhd
swh/web/tests/resources/contents/code/extensions/test.vim
swh/web/tests/resources/contents/code/extensions/test.wl
swh/web/tests/resources/contents/code/extensions/test.xml
swh/web/tests/resources/contents/code/extensions/test.xqy
swh/web/tests/resources/contents/code/extensions/test.yml
swh/web/tests/resources/contents/code/extensions/test.zep
swh/web/tests/resources/contents/code/filenames/.htaccess
swh/web/tests/resources/contents/code/filenames/CMakeLists.txt
swh/web/tests/resources/contents/code/filenames/Dockerfile
swh/web/tests/resources/contents/code/filenames/Makefile
swh/web/tests/resources/contents/code/filenames/access.log
swh/web/tests/resources/contents/code/filenames/httpd.conf
swh/web/tests/resources/contents/code/filenames/nginx.conf
swh/web/tests/resources/contents/code/filenames/nginx.log
swh/web/tests/resources/contents/code/filenames/pf.conf
swh/web/tests/resources/contents/code/filenames/resolv.conf
swh/web/tests/resources/contents/other/extensions/bash-cheatsheet.pdf
swh/web/tests/resources/contents/other/extensions/public.gpg
swh/web/tests/resources/contents/other/extensions/swh-logo.jpeg
swh/web/tests/resources/contents/other/extensions/swh-logo.png
swh/web/tests/resources/contents/other/extensions/swh-logo.webp
swh/web/tests/resources/contents/other/extensions/swh-spinner.gif
swh/web/tests/resources/contents/other/extensions/word2vec.ipynb
swh/web/tests/resources/deposit/raw-metadata-add-to-origin.xml
swh/web/tests/resources/deposit/raw-metadata-create-origin.xml
swh/web/tests/resources/deposit/raw-metadata-no-swh.xml
swh/web/tests/resources/deposit/raw-metadata-provenance.xml
swh/web/tests/resources/http_esnode1.internal.softwareheritage.org/swh_workers-*__search
swh/web/tests/resources/repos/highlightjs-line-numbers.js.zip
swh/web/tests/resources/repos/highlightjs-line-numbers.js_visit2.zip
swh/web/tests/resources/repos/libtess2.zip
swh/web/tests/resources/repos/repo_with_submodules.tgz
\ No newline at end of file
diff --git a/swh.web.egg-info/requires.txt b/swh.web.egg-info/requires.txt
index e103f418..47fe7924 100644
--- a/swh.web.egg-info/requires.txt
+++ b/swh.web.egg-info/requires.txt
@@ -1,52 +1,52 @@
beautifulsoup4
chardet
cryptography
django<3
django-cors-headers
django-js-reverse
djangorestframework
django-webpack-loader
docutils
htmlmin
iso8601
lxml
prometheus-client
pybadges>=2.2.1
pygments
python-magic>=0.4.0
python-memcached
pyyaml
requests
sentry-sdk
typing-extensions
psycopg2<2.9
swh.auth[django]>=0.5.3
swh.core>=0.0.95
swh.counters>=0.5.1
swh.indexer>=0.4.1
swh.model>=2.6.3
swh.scheduler>=0.7.0
swh.search>=0.2.0
swh.storage>=0.31.0
swh.vault>=1.0.0
[testing]
decorator
djangorestframework-stubs
django-stubs
django-test-migrations
hypothesis
-pytest<7.0.0
+pytest
pytest-django
pytest-mock
pytest-postgresql<4.0.0
requests-mock!=1.9.0,!=1.9.1
swh.core[http]>=0.0.95
swh.loader.git>=0.8.0
swh-scheduler[testing]>=0.5.0
swh.storage>=0.1.1
types-chardet
types-docutils
types-psycopg2
types-pyyaml
types-requests
diff --git a/swh/web/common/utils.py b/swh/web/common/utils.py
index 098bbad1..da65d01b 100644
--- a/swh/web/common/utils.py
+++ b/swh/web/common/utils.py
@@ -1,549 +1,549 @@
# Copyright (C) 2017-2022 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
from datetime import datetime, timezone
import os
import re
from typing import Any, Dict, List, Optional
import urllib.parse
from xml.etree import ElementTree
from bs4 import BeautifulSoup
from docutils.core import publish_parts
import docutils.parsers.rst
import docutils.utils
from docutils.writers.html5_polyglot import HTMLTranslator, Writer
from iso8601 import ParseError, parse_date
from pkg_resources import get_distribution
from prometheus_client.registry import CollectorRegistry
import requests
from requests.auth import HTTPBasicAuth
from django.core.cache import cache
from django.http import HttpRequest, QueryDict
from django.shortcuts import redirect
from django.urls import resolve
from django.urls import reverse as django_reverse
from swh.web.auth.utils import (
ADD_FORGE_MODERATOR_PERMISSION,
ADMIN_LIST_DEPOSIT_PERMISSION,
MAILMAP_ADMIN_PERMISSION,
)
from swh.web.common.exc import BadInputExc
from swh.web.common.typing import QueryParameters
from swh.web.config import SWH_WEB_SERVER_NAME, get_config, search
SWH_WEB_METRICS_REGISTRY = CollectorRegistry(auto_describe=True)
swh_object_icons = {
"alias": "mdi mdi-star",
"branch": "mdi mdi-source-branch",
"branches": "mdi mdi-source-branch",
"content": "mdi mdi-file-document",
"cnt": "mdi mdi-file-document",
"directory": "mdi mdi-folder",
"dir": "mdi mdi-folder",
"origin": "mdi mdi-source-repository",
"ori": "mdi mdi-source-repository",
"person": "mdi mdi-account",
"revisions history": "mdi mdi-history",
"release": "mdi mdi-tag",
"rel": "mdi mdi-tag",
"releases": "mdi mdi-tag",
"revision": "mdi mdi-rotate-90 mdi-source-commit",
"rev": "mdi mdi-rotate-90 mdi-source-commit",
"snapshot": "mdi mdi-camera",
"snp": "mdi mdi-camera",
"visits": "mdi mdi-calendar-month",
}
def reverse(
viewname: str,
url_args: Optional[Dict[str, Any]] = None,
query_params: Optional[QueryParameters] = None,
current_app: Optional[str] = None,
urlconf: Optional[str] = None,
request: Optional[HttpRequest] = None,
) -> str:
"""An override of django reverse function supporting query parameters.
Args:
viewname: the name of the django view from which to compute a url
url_args: dictionary of url arguments indexed by their names
query_params: dictionary of query parameters to append to the
reversed url
current_app: the name of the django app tighten to the view
urlconf: url configuration module
request: build an absolute URI if provided
Returns:
str: the url of the requested view with processed arguments and
query parameters
"""
if url_args:
url_args = {k: v for k, v in url_args.items() if v is not None}
url = django_reverse(
viewname, urlconf=urlconf, kwargs=url_args, current_app=current_app
)
if query_params:
query_params = {k: v for k, v in query_params.items() if v is not None}
if query_params and len(query_params) > 0:
query_dict = QueryDict("", mutable=True)
for k in sorted(query_params.keys()):
query_dict[k] = query_params[k]
url += "?" + query_dict.urlencode(safe="/;:")
if request is not None:
url = request.build_absolute_uri(url)
return url
def datetime_to_utc(date):
"""Returns datetime in UTC without timezone info
Args:
date (datetime.datetime): input datetime with timezone info
Returns:
datetime.datetime: datetime in UTC without timezone info
"""
if date.tzinfo and date.tzinfo != timezone.utc:
return date.astimezone(tz=timezone.utc)
else:
return date
def parse_iso8601_date_to_utc(iso_date: str) -> datetime:
"""Given an ISO 8601 datetime string, parse the result as UTC datetime.
Returns:
a timezone-aware datetime representing the parsed date
Raises:
swh.web.common.exc.BadInputExc: provided date does not respect ISO 8601 format
Samples:
- 2016-01-12
- 2016-01-12T09:19:12+0100
- 2007-01-14T20:34:22Z
"""
try:
date = parse_date(iso_date)
return datetime_to_utc(date)
except ParseError as e:
raise BadInputExc(e)
def shorten_path(path):
"""Shorten the given path: for each hash present, only return the first
8 characters followed by an ellipsis"""
sha256_re = r"([0-9a-f]{8})[0-9a-z]{56}"
sha1_re = r"([0-9a-f]{8})[0-9a-f]{32}"
ret = re.sub(sha256_re, r"\1...", path)
return re.sub(sha1_re, r"\1...", ret)
def format_utc_iso_date(iso_date, fmt="%d %B %Y, %H:%M UTC"):
"""Turns a string representation of an ISO 8601 datetime string
to UTC and format it into a more human readable one.
For instance, from the following input
string: '2017-05-04T13:27:13+02:00' the following one
is returned: '04 May 2017, 11:27 UTC'.
Custom format string may also be provided
as parameter
Args:
iso_date (str): a string representation of an ISO 8601 date
fmt (str): optional date formatting string
Returns:
str: a formatted string representation of the input iso date
"""
if not iso_date:
return iso_date
date = parse_iso8601_date_to_utc(iso_date)
return date.strftime(fmt)
def gen_path_info(path):
"""Function to generate path data navigation for use
with a breadcrumb in the swh web ui.
For instance, from a path /folder1/folder2/folder3,
it returns the following list::
[{'name': 'folder1', 'path': 'folder1'},
{'name': 'folder2', 'path': 'folder1/folder2'},
{'name': 'folder3', 'path': 'folder1/folder2/folder3'}]
Args:
path: a filesystem path
Returns:
list: a list of path data for navigation as illustrated above.
"""
path_info = []
if path:
sub_paths = path.strip("/").split("/")
path_from_root = ""
for p in sub_paths:
path_from_root += "/" + p
path_info.append({"name": p, "path": path_from_root.strip("/")})
return path_info
def parse_rst(text, report_level=2):
"""
Parse a reStructuredText string with docutils.
Args:
text (str): string with reStructuredText markups in it
report_level (int): level of docutils report messages to print
(1 info 2 warning 3 error 4 severe 5 none)
Returns:
docutils.nodes.document: a parsed docutils document
"""
parser = docutils.parsers.rst.Parser()
components = (docutils.parsers.rst.Parser,)
settings = docutils.frontend.OptionParser(
components=components
).get_default_values()
settings.report_level = report_level
document = docutils.utils.new_document("rst-doc", settings=settings)
parser.parse(text, document)
return document
def get_client_ip(request):
"""
Return the client IP address from an incoming HTTP request.
Args:
request (django.http.HttpRequest): the incoming HTTP request
Returns:
str: The client IP address
"""
x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
if x_forwarded_for:
ip = x_forwarded_for.split(",")[0]
else:
ip = request.META.get("REMOTE_ADDR")
return ip
def is_swh_web_development(request: HttpRequest) -> bool:
"""Indicate if we are running a development version of swh-web.
"""
site_base_url = request.build_absolute_uri("/")
return any(
host in site_base_url for host in ("localhost", "127.0.0.1", "testserver")
)
def is_swh_web_staging(request: HttpRequest) -> bool:
"""Indicate if we are running a staging version of swh-web.
"""
config = get_config()
site_base_url = request.build_absolute_uri("/")
return any(
server_name in site_base_url for server_name in config["staging_server_names"]
)
def is_swh_web_production(request: HttpRequest) -> bool:
"""Indicate if we are running the public production version of swh-web.
"""
return SWH_WEB_SERVER_NAME in request.build_absolute_uri("/")
browsers_supported_image_mimes = set(
[
"image/gif",
"image/png",
"image/jpeg",
"image/bmp",
"image/webp",
"image/svg",
"image/svg+xml",
]
)
def context_processor(request):
"""
Django context processor used to inject variables
in all swh-web templates.
"""
config = get_config()
if (
hasattr(request, "user")
and request.user.is_authenticated
and not hasattr(request.user, "backend")
):
# To avoid django.template.base.VariableDoesNotExist errors
# when rendering templates when standard Django user is logged in.
request.user.backend = "django.contrib.auth.backends.ModelBackend"
return {
"swh_object_icons": swh_object_icons,
"available_languages": None,
"swh_client_config": config["client_config"],
"oidc_enabled": bool(config["keycloak"]["server_url"]),
"browsers_supported_image_mimes": browsers_supported_image_mimes,
"keycloak": config["keycloak"],
"site_base_url": request.build_absolute_uri("/"),
"DJANGO_SETTINGS_MODULE": os.environ["DJANGO_SETTINGS_MODULE"],
"status": config["status"],
"swh_web_dev": is_swh_web_development(request),
"swh_web_staging": is_swh_web_staging(request),
"swh_web_version": get_distribution("swh.web").version,
"iframe_mode": False,
"ADMIN_LIST_DEPOSIT_PERMISSION": ADMIN_LIST_DEPOSIT_PERMISSION,
"ADD_FORGE_MODERATOR_PERMISSION": ADD_FORGE_MODERATOR_PERMISSION,
"FEATURES": get_config()["features"],
"MAILMAP_ADMIN_PERMISSION": MAILMAP_ADMIN_PERMISSION,
}
def resolve_branch_alias(
snapshot: Dict[str, Any], branch: Optional[Dict[str, Any]]
) -> Optional[Dict[str, Any]]:
"""
Resolve branch alias in snapshot content.
Args:
snapshot: a full snapshot content
branch: a branch alias contained in the snapshot
Returns:
The real snapshot branch that got aliased.
"""
while branch and branch["target_type"] == "alias":
if branch["target"] in snapshot["branches"]:
branch = snapshot["branches"][branch["target"]]
else:
from swh.web.common import archive
snp = archive.lookup_snapshot(
snapshot["id"], branches_from=branch["target"], branches_count=1
)
if snp and branch["target"] in snp["branches"]:
branch = snp["branches"][branch["target"]]
else:
branch = None
return branch
class _NoHeaderHTMLTranslator(HTMLTranslator):
"""
Docutils translator subclass to customize the generation of HTML
from reST-formatted docstrings
"""
def __init__(self, document):
super().__init__(document)
self.body_prefix = []
self.body_suffix = []
_HTML_WRITER = Writer()
_HTML_WRITER.translator_class = _NoHeaderHTMLTranslator
def rst_to_html(rst: str) -> str:
"""
Convert reStructuredText document into HTML.
Args:
rst: A string containing a reStructuredText document
Returns:
Body content of the produced HTML conversion.
"""
settings = {
"initial_header_level": 2,
"halt_level": 4,
"traceback": True,
"file_insertion_enabled": False,
"raw_enabled": False,
}
pp = publish_parts(rst, writer=_HTML_WRITER, settings_overrides=settings)
return f'<div class="swh-rst">{pp["html_body"]}</div>'
def prettify_html(html: str) -> str:
"""
Prettify an HTML document.
Args:
html: Input HTML document
Returns:
The prettified HTML document
"""
return BeautifulSoup(html, "lxml").prettify()
def _deposits_list_url(
deposits_list_base_url: str, page_size: int, username: Optional[str]
) -> str:
params = {"page_size": str(page_size)}
if username is not None:
params["username"] = username
return f"{deposits_list_base_url}?{urllib.parse.urlencode(params)}"
def get_deposits_list(username: Optional[str] = None) -> List[Dict[str, Any]]:
"""Return the list of software deposits using swh-deposit API
"""
config = get_config()["deposit"]
deposits_list_base_url = config["private_api_url"] + "deposits"
deposits_list_auth = HTTPBasicAuth(
config["private_api_user"], config["private_api_password"]
)
deposits_list_url = _deposits_list_url(
deposits_list_base_url, page_size=1, username=username
)
nb_deposits = requests.get(
deposits_list_url, auth=deposits_list_auth, timeout=30
).json()["count"]
cache_key = f"swh-deposit-list-{username}"
deposits_data = cache.get(cache_key)
if not deposits_data or deposits_data["count"] != nb_deposits:
deposits_list_url = _deposits_list_url(
deposits_list_base_url, page_size=nb_deposits, username=username
)
deposits_data = requests.get(
deposits_list_url, auth=deposits_list_auth, timeout=30,
).json()
cache.set(cache_key, deposits_data)
return deposits_data["results"]
def get_deposit_raw_metadata(deposit_id: int) -> Optional[str]:
cache_key = f"swh-deposit-raw-metadata-{deposit_id}"
metadata = cache.get(cache_key)
if metadata is None:
config = get_config()["deposit"]
url = f"{config['private_api_url']}/{deposit_id}/meta"
- metadata = requests.get(url).json()["metadata_raw"]
+ metadata = requests.get(url).json()["raw_metadata"]
cache.set(cache_key, metadata)
return metadata
def origin_visit_types() -> List[str]:
"""Return the exhaustive list of visit types for origins
ingested into the archive.
"""
try:
return sorted(search().visit_types_count().keys())
except Exception:
return []
def redirect_to_new_route(request, new_route, permanent=True):
"""Redirect a request to another route with url args and query parameters
eg: /origin/<url:url-val>/log?path=test can be redirected as
/log?url=<url-val>&path=test. This can be used to deprecate routes
"""
request_path = resolve(request.path_info)
args = {**request_path.kwargs, **request.GET.dict()}
return redirect(reverse(new_route, query_params=args), permanent=permanent,)
NAMESPACES = {
"swh": "https://www.softwareheritage.org/schema/2018/deposit",
"schema": "http://schema.org/",
}
def parse_swh_metadata_provenance(raw_metadata: str) -> Optional[str]:
"""Parse swh metadata-provenance out of the raw metadata deposit. If found, returns the
value, None otherwise.
.. code-block:: xml
<swh:deposit>
<swh:metadata-provenance>
<schema:url>https://example.org/metadata/url</schema:url>
</swh:metadata-provenance>
</swh:deposit>
Args:
raw_metadata: raw metadata out of deposits received
Returns:
Either the metadata provenance url if any or None otherwise
"""
metadata = ElementTree.fromstring(raw_metadata)
url = metadata.findtext(
"swh:deposit/swh:metadata-provenance/schema:url", namespaces=NAMESPACES,
)
return url or None
def parse_swh_deposit_origin(raw_metadata: str) -> Optional[str]:
"""Parses <swh:add_to_origin> and <swh:create_origin> from metadata document,
if any. They are mutually exclusive and tested as such in the deposit.
.. code-block:: xml
<swh:deposit>
<swh:create_origin>
<swh:origin url='https://example.org/repo/software123/'/>
</swh:reference>
</swh:deposit>
.. code-block:: xml
<swh:deposit>
<swh:add_to_origin>
<swh:origin url='https://example.org/repo/software123/'/>
</swh:add_to_origin>
</swh:deposit>
Returns:
The one not null if any, None otherwise
"""
metadata = ElementTree.fromstring(raw_metadata)
for origin_tag in ["create_origin", "add_to_origin"]:
elt = metadata.find(
f"swh:deposit/swh:{origin_tag}/swh:origin[@url]", namespaces=NAMESPACES
)
if elt is not None:
return elt.attrib["url"]
return None
def has_add_forge_now_permission(user) -> bool:
"""Is a user considered an add-forge-now moderator?
Returns
True if a user is staff or has add forge now moderator permission
"""
return user.is_staff or user.has_perm(ADD_FORGE_MODERATOR_PERMISSION)
diff --git a/swh/web/inbound_email/utils.py b/swh/web/inbound_email/utils.py
index b469e40f..9a210626 100644
--- a/swh/web/inbound_email/utils.py
+++ b/swh/web/inbound_email/utils.py
@@ -1,80 +1,204 @@
# Copyright (C) 2022 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
from dataclasses import dataclass
from email.headerregistry import Address
from email.message import EmailMessage
-from typing import List, Optional
+import logging
+from typing import List, Optional, Set
+
+from django.core.signing import Signer
+from django.utils.crypto import constant_time_compare
+
+logger = logging.getLogger(__name__)
def extract_recipients(message: EmailMessage) -> List[Address]:
"""Extract a list of recipients of the `message`.
This uses the ``To`` and ``Cc`` fields.
"""
ret = []
for header_name in ("to", "cc"):
for header in message.get_all(header_name, []):
ret.extend(header.addresses)
return ret
@dataclass
class AddressMatch:
"""Data related to a recipient match"""
recipient: Address
"""The original recipient that matched the expected address"""
extension: Optional[str]
"""The parsed +-extension of the matched recipient address"""
def single_recipient_matches(
recipient: Address, address: str
) -> Optional[AddressMatch]:
"""Check whether a single address matches the provided base address.
The match is case-insensitive, which is not really RFC-compliant but is consistent
with what most people would expect.
This function supports "+-addressing", where the local part of the email address is
appended with a `+`.
"""
parsed_address = Address(addr_spec=address.lower())
if recipient.domain.lower() != parsed_address.domain:
return None
base_username, _, extension = recipient.username.partition("+")
if base_username.lower() != parsed_address.username:
return None
return AddressMatch(recipient=recipient, extension=extension or None)
def recipient_matches(message: EmailMessage, address: str) -> List[AddressMatch]:
"""Check whether any of the message recipients match the given address.
The match is case-insensitive, which is not really RFC-compliant but matches what
most people would expect.
This function supports "+-addressing", where the local part of the email address is
appended with a `+`.
"""
ret = []
for recipient in extract_recipients(message):
match = single_recipient_matches(recipient, address)
if match:
ret.append(match)
return ret
+
+
+ADDRESS_SIGNER_SEP = "."
+"""Separator for email address signatures"""
+
+
+def get_address_signer(salt: str) -> Signer:
+ """Get a signer for the given seed"""
+ return Signer(salt=salt, sep=ADDRESS_SIGNER_SEP)
+
+
+def get_address_for_pk(salt: str, base_address: str, pk: int) -> str:
+ """Get the email address that will be able to receive messages to be logged in
+ this request."""
+ if "@" not in base_address:
+ raise ValueError("Base address needs to contain an @")
+
+ username, domain = base_address.split("@")
+
+ extension = get_address_signer(salt).sign(str(pk))
+
+ return f"{username}+{extension}@{domain}"
+
+
+def get_pk_from_extension(salt: str, extension: str) -> int:
+ """Retrieve the primary key for the given inbound address extension.
+
+ We reimplement `Signer.unsign`, because the extension can be casemapped at any
+ point in the email chain (even though email is, theoretically, case sensitive),
+ so we have to compare lowercase versions of both the extension and the
+ signature...
+
+ Raises ValueError if the signature couldn't be verified.
+
+ """
+
+ value, signature = extension.rsplit(ADDRESS_SIGNER_SEP, 1)
+ expected_signature = get_address_signer(salt).signature(value)
+ if not constant_time_compare(signature.lower(), expected_signature.lower()):
+ raise ValueError(f"Invalid signature for extension {extension}")
+
+ return int(value)
+
+
+def get_pks_from_message(
+ salt: str, base_address: str, message: EmailMessage
+) -> Set[int]:
+ """Retrieve the set of primary keys that were successfully decoded from the
+ recipients of the ``message`` matching ``base_address``.
+
+ This uses :func:`recipient_matches` to retrieve all the recipient addresses matching
+ ``base_address``, then :func:`get_pk_from_extension` to decode the primary key and
+ verify the signature for every extension. To generate relevant email addresses, use
+ :func:`get_address_for_pk` with the same ``base_address`` and ``salt``.
+
+ Returns:
+ the set of primary keys that were successfully decoded from the recipients of the
+ ``message``
+
+ """
+ ret: Set[int] = set()
+
+ for match in recipient_matches(message, base_address):
+ extension = match.extension
+ if extension is None:
+ logger.debug(
+ "Recipient address %s cannot be matched to a request, ignoring",
+ match.recipient.addr_spec,
+ )
+ continue
+
+ try:
+ ret.add(get_pk_from_extension(salt, extension))
+ except ValueError:
+ logger.debug(
+ "Recipient address %s failed validation", match.recipient.addr_spec
+ )
+ continue
+
+ return ret
+
+
+def get_message_plaintext(message: EmailMessage) -> Optional[bytes]:
+ """Get the plaintext body for a given message, if any such part exists. If only a html
+ part exists, return that instead.
+
+ If there are multiple, ambiguous plain text or html parts in the message, this
+ function will return the largest of them.
+
+ """
+ if not message.is_multipart():
+ single_part = message.get_payload(decode=True).rstrip(b"\n")
+ return single_part or None
+
+ text_parts: List[bytes] = []
+ fallback_parts: List[bytes] = []
+
+ for part in message.walk():
+ content_type = part.get_content_type()
+ content_disposition = str(part.get("Content-Disposition"))
+ if "attachment" in content_disposition:
+ continue
+ if content_type == "text/plain":
+ current_part = part.get_payload(decode=True).rstrip(b"\n")
+ if current_part:
+ text_parts.append(current_part)
+ elif not text_parts and content_type == "text/html":
+ current_part = part.get_payload(decode=True).rstrip(b"\n")
+ if current_part:
+ fallback_parts.append(current_part)
+
+ if text_parts:
+ return max(text_parts, key=len)
+
+ if fallback_parts:
+ return max(fallback_parts, key=len)
+
+ return None
diff --git a/swh/web/tests/inbound_email/__init__.py b/swh/web/tests/inbound_email/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/swh/web/tests/inbound_email/resources/__init__.py b/swh/web/tests/inbound_email/resources/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/swh/web/tests/inbound_email/resources/multipart.eml b/swh/web/tests/inbound_email/resources/multipart.eml
new file mode 100644
index 00000000..b148efe4
--- /dev/null
+++ b/swh/web/tests/inbound_email/resources/multipart.eml
@@ -0,0 +1,24 @@
+Return-Path: <test@example.com>
+X-Mailer: MessagingEngine.com Webmail Interface
+User-Agent: Cyrus-JMAP/3.7.0-alpha0-382-g88b93171a9-fm-20220330.001-g88b93171
+Mime-Version: 1.0
+Message-Id: <c78f8ea4-6dc7-4604-b0b1-be1f4aecdc7f@www.fastmail.com>
+Date: Mon, 04 Apr 2022 17:10:00 +0200
+From: "Test User" <test@example.com>
+To: test@example.com
+Subject: Multipart email
+Content-Type: multipart/alternative;
+ boundary=67575b1b68b24603a2d00f02e032c975
+
+--67575b1b68b24603a2d00f02e032c975
+Content-Type: text/plain
+
+*Multipart email.*
+
+--
+Test User
+--67575b1b68b24603a2d00f02e032c975
+Content-Type: text/html
+
+<!DOCTYPE html><html><head><title></title><style type="text/css">p.MsoNormal,p.MsoNoSpacing{margin:0}</style></head><body><div><b>Multipart email.</b><br></div><div><br></div><div>--&nbsp;<br></div><div>Test User<br></div></body></html>
+--67575b1b68b24603a2d00f02e032c975--
diff --git a/swh/web/tests/inbound_email/resources/multipart_html_only.eml b/swh/web/tests/inbound_email/resources/multipart_html_only.eml
new file mode 100644
index 00000000..664d39b5
--- /dev/null
+++ b/swh/web/tests/inbound_email/resources/multipart_html_only.eml
@@ -0,0 +1,21 @@
+Return-Path: <test@example.com>
+X-Mailer: MessagingEngine.com Webmail Interface
+User-Agent: Cyrus-JMAP/3.7.0-alpha0-382-g88b93171a9-fm-20220330.001-g88b93171
+Mime-Version: 1.0
+Message-Id: <c78f8ea4-6dc7-4604-b0b1-be1f4aecdc7f@www.fastmail.com>
+Date: Mon, 04 Apr 2022 17:10:00 +0200
+From: "Test User" <test@example.com>
+To: test@example.com
+Subject: Multipart email
+Content-Type: multipart/alternative;
+ boundary=67575b1b68b24603a2d00f02e032c975
+
+--67575b1b68b24603a2d00f02e032c975
+Content-Type: text/html
+
+<!DOCTYPE html><html><head><title></title></head><body><div><b>Multipart email (short html part).</b><br></div><div><br></div><div>--&nbsp;<br></div><div>Test User<br></div></body></html>
+--67575b1b68b24603a2d00f02e032c975
+Content-Type: text/html
+
+<!DOCTYPE html><html><head><title></title></head><body><div><b>Multipart email (a much longer html part).</b><br></div><div><br></div><div>--&nbsp;<br></div><div>Test User<br></div></body></html>
+--67575b1b68b24603a2d00f02e032c975--
diff --git a/swh/web/tests/inbound_email/resources/multipart_text_only.eml b/swh/web/tests/inbound_email/resources/multipart_text_only.eml
new file mode 100644
index 00000000..9430e013
--- /dev/null
+++ b/swh/web/tests/inbound_email/resources/multipart_text_only.eml
@@ -0,0 +1,27 @@
+Return-Path: <test@example.com>
+X-Mailer: MessagingEngine.com Webmail Interface
+User-Agent: Cyrus-JMAP/3.7.0-alpha0-382-g88b93171a9-fm-20220330.001-g88b93171
+Mime-Version: 1.0
+Message-Id: <c78f8ea4-6dc7-4604-b0b1-be1f4aecdc7f@www.fastmail.com>
+Date: Mon, 04 Apr 2022 17:10:00 +0200
+From: "Test User" <test@example.com>
+To: test@example.com
+Subject: Multipart email
+Content-Type: multipart/alternative;
+ boundary=67575b1b68b24603a2d00f02e032c975
+
+--67575b1b68b24603a2d00f02e032c975
+Content-Type: text/plain
+
+*Multipart email.*
+
+--
+Test User
+--67575b1b68b24603a2d00f02e032c975
+Content-Type: text/plain
+
+*Multipart email, but a longer text part.*
+
+--
+Test User
+--67575b1b68b24603a2d00f02e032c975--
diff --git a/swh/web/tests/inbound_email/resources/plaintext.eml b/swh/web/tests/inbound_email/resources/plaintext.eml
new file mode 100644
index 00000000..77588407
--- /dev/null
+++ b/swh/web/tests/inbound_email/resources/plaintext.eml
@@ -0,0 +1,15 @@
+Return-Path: <test@example.com>
+X-Mailer: MessagingEngine.com Webmail Interface
+User-Agent: Cyrus-JMAP/3.7.0-alpha0-382-g88b93171a9-fm-20220330.001-g88b93171
+Mime-Version: 1.0
+Message-Id: <21e17bca-d6a7-40fb-bab8-5dadd939835b@www.fastmail.com>
+Date: Mon, 04 Apr 2022 17:08:04 +0200
+From: "Test User" <test@example.com>
+To: test@example.com
+Subject: Plain text email
+Content-Type: text/plain
+
+Plain text email.
+
+--
+Test User
diff --git a/swh/web/tests/inbound_email/test_utils.py b/swh/web/tests/inbound_email/test_utils.py
index 83af934c..9a1ed6e5 100644
--- a/swh/web/tests/inbound_email/test_utils.py
+++ b/swh/web/tests/inbound_email/test_utils.py
@@ -1,132 +1,298 @@
# Copyright (C) 2022 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 email
from email.headerregistry import Address
from email.message import EmailMessage
+import email.policy
+from importlib.resources import open_binary
+from typing import List
+
+import pytest
from swh.web.inbound_email import utils
def test_extract_recipients():
message = EmailMessage()
assert utils.extract_recipients(message) == []
message["To"] = "Test Recipient <test-recipient@example.com>"
assert utils.extract_recipients(message) == [
Address(display_name="Test Recipient", addr_spec="test-recipient@example.com")
]
message["Cc"] = (
"test-recipient-2@example.com, "
"Another Test Recipient <test-recipient-3@example.com>"
)
assert utils.extract_recipients(message) == [
Address(display_name="Test Recipient", addr_spec="test-recipient@example.com"),
Address(addr_spec="test-recipient-2@example.com"),
Address(
display_name="Another Test Recipient",
addr_spec="test-recipient-3@example.com",
),
]
del message["To"]
assert utils.extract_recipients(message) == [
Address(addr_spec="test-recipient-2@example.com"),
Address(
display_name="Another Test Recipient",
addr_spec="test-recipient-3@example.com",
),
]
def test_single_recipient_matches():
assert (
utils.single_recipient_matches(
Address(addr_spec="test@example.com"), "match@example.com"
)
is None
)
assert utils.single_recipient_matches(
Address(addr_spec="match@example.com"), "match@example.com"
) == utils.AddressMatch(
recipient=Address(addr_spec="match@example.com"), extension=None
)
assert utils.single_recipient_matches(
Address(addr_spec="MaTch+12345AbC@exaMple.Com"), "match@example.com"
) == utils.AddressMatch(
recipient=Address(addr_spec="MaTch+12345AbC@exaMple.Com"), extension="12345AbC"
)
def test_recipient_matches():
message = EmailMessage()
assert utils.recipient_matches(message, "match@example.com") == []
message = EmailMessage()
message["to"] = "nomatch@example.com"
assert utils.recipient_matches(message, "match@example.com") == []
message = EmailMessage()
message["to"] = "match@example.com"
assert utils.recipient_matches(message, "match@example.com") == [
utils.AddressMatch(
recipient=Address(addr_spec="match@example.com"), extension=None
)
]
message = EmailMessage()
message["to"] = "match+extension@example.com"
assert utils.recipient_matches(message, "match@example.com") == [
utils.AddressMatch(
recipient=Address(addr_spec="match+extension@example.com"),
extension="extension",
)
]
message = EmailMessage()
message["to"] = "match+weird+plussed+extension@example.com"
assert utils.recipient_matches(message, "match@example.com") == [
utils.AddressMatch(
recipient=Address(addr_spec="match+weird+plussed+extension@example.com"),
extension="weird+plussed+extension",
)
]
message = EmailMessage()
message["to"] = "nomatch@example.com"
message["cc"] = ", ".join(
(
"match@example.com",
"match@notamatch.example.com",
"Another Match <match+extension@example.com>",
)
)
assert utils.recipient_matches(message, "match@example.com") == [
utils.AddressMatch(
recipient=Address(addr_spec="match@example.com"), extension=None,
),
utils.AddressMatch(
recipient=Address(
display_name="Another Match", addr_spec="match+extension@example.com"
),
extension="extension",
),
]
def test_recipient_matches_casemapping():
message = EmailMessage()
message["to"] = "match@example.com"
assert utils.recipient_matches(message, "Match@Example.Com")
assert utils.recipient_matches(message, "match@example.com")
message = EmailMessage()
message["to"] = "Match+weirdCaseMapping@Example.Com"
matches = utils.recipient_matches(message, "match@example.com")
assert matches
assert matches[0].extension == "weirdCaseMapping"
+
+
+def test_get_address_for_pk():
+ salt = "test_salt"
+ pks = [1, 10, 1000]
+ base_address = "base@example.com"
+
+ addresses = {
+ pk: utils.get_address_for_pk(salt=salt, base_address=base_address, pk=pk)
+ for pk in pks
+ }
+
+ assert len(set(addresses.values())) == len(addresses)
+
+ for pk, address in addresses.items():
+ localpart, _, domain = address.partition("@")
+ base_localpart, _, extension = localpart.partition("+")
+ assert domain == "example.com"
+ assert base_localpart == "base"
+ assert extension.startswith(f"{pk}.")
+
+
+def test_get_address_for_pk_salt():
+ pk = 1000
+ base_address = "base@example.com"
+ addresses = [
+ utils.get_address_for_pk(salt=salt, base_address=base_address, pk=pk)
+ for salt in ["salt1", "salt2"]
+ ]
+
+ assert len(addresses) == len(set(addresses))
+
+
+def test_get_pks_from_message():
+ salt = "test_salt"
+ pks = [1, 10, 1000]
+ base_address = "base@example.com"
+
+ addresses = {
+ pk: utils.get_address_for_pk(salt=salt, base_address=base_address, pk=pk)
+ for pk in pks
+ }
+
+ message = EmailMessage()
+ message["To"] = "test@example.com"
+
+ assert utils.get_pks_from_message(salt, base_address, message) == set()
+
+ message = EmailMessage()
+ message["To"] = f"Test Address <{addresses[1]}>"
+
+ assert utils.get_pks_from_message(salt, base_address, message) == {1}
+
+ message = EmailMessage()
+ message["To"] = f"Test Address <{addresses[1]}>"
+ message["Cc"] = ", ".join(
+ [
+ f"Test Address <{addresses[1]}>",
+ f"Another Test Address <{addresses[10].lower()}>",
+ "A Third Address <irrelevant@example.com>",
+ ]
+ )
+
+ assert utils.get_pks_from_message(salt, base_address, message) == {1, 10}
+
+
+def test_get_pks_from_message_logging(caplog):
+ salt = "test_salt"
+ pks = [1, 10, 1000]
+ base_address = "base@example.com"
+
+ addresses = {
+ pk: utils.get_address_for_pk(salt=salt, base_address=base_address, pk=pk)
+ for pk in pks
+ }
+
+ message = EmailMessage()
+ message["To"] = f"Test Address <{base_address}>"
+
+ assert utils.get_pks_from_message(salt, base_address, message) == set()
+
+ relevant_records = [
+ record
+ for record in caplog.records
+ if record.name == "swh.web.inbound_email.utils"
+ ]
+ assert len(relevant_records) == 1
+ assert relevant_records[0].levelname == "DEBUG"
+ assert (
+ f"{base_address} cannot be matched to a request"
+ in relevant_records[0].getMessage()
+ )
+
+ # Replace the signature with "mangle{signature}"
+ mangled_address = addresses[1].replace(".", ".mangle", 1)
+
+ message = EmailMessage()
+ message["To"] = f"Test Address <{mangled_address}>"
+
+ assert utils.get_pks_from_message(salt, base_address, message) == set()
+
+ relevant_records = [
+ record
+ for record in caplog.records
+ if record.name == "swh.web.inbound_email.utils"
+ ]
+ assert len(relevant_records) == 2
+ assert relevant_records[0].levelname == "DEBUG"
+ assert relevant_records[1].levelname == "DEBUG"
+
+ assert f"{mangled_address} failed" in relevant_records[1].getMessage()
+
+
+@pytest.mark.parametrize(
+ "filename,expected_parts,expected_absent",
+ (
+ pytest.param(
+ "plaintext.eml",
+ [b"Plain text email.\n\n-- \nTest User"],
+ [],
+ id="plaintext",
+ ),
+ pytest.param(
+ "multipart.eml",
+ [b"*Multipart email.*\n\n-- \nTest User"],
+ [],
+ id="multipart",
+ ),
+ pytest.param(
+ "multipart_html_only.eml",
+ [b"<html>", b"<b>Multipart email (a much longer html part).</b>"],
+ [b"<b>Multipart email (short html part)</b>"],
+ id="multipart_html_only",
+ ),
+ pytest.param(
+ "multipart_text_only.eml",
+ [b"*Multipart email, but a longer text part.*\n\n--\nTest User"],
+ [],
+ id="multipart_text_only",
+ ),
+ ),
+)
+def test_get_message_plaintext(
+ filename: str, expected_parts: List[bytes], expected_absent: List[bytes]
+):
+ with open_binary("swh.web.tests.inbound_email.resources", filename) as f:
+ message = email.message_from_binary_file(f, policy=email.policy.default)
+
+ assert isinstance(message, EmailMessage)
+
+ plaintext = utils.get_message_plaintext(message)
+ assert plaintext is not None
+
+ if len(expected_parts) == 1:
+ assert plaintext == expected_parts[0]
+ else:
+ for part in expected_parts:
+ assert part in plaintext
+ for part in expected_absent:
+ assert part not in plaintext

File Metadata

Mime Type
text/x-diff
Expires
Jul 4 2025, 9:22 AM (6 w, 17 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3336658

Event Timeline