* Update devenv

* Added uv for python package management

* Clean up gunicorn config artifacts

* Scaffolded site

* Fixed configuration for 13.0

* Added iform config/theme

* Added agent contracts to allow for more automation of work in repo

* Added a local rebuild command to justfile for development

* Fixed deployment persistence issues

* Site polish and deployment streamlining

* Updated justfile to include production deployment commands

* Fixed deployment bugs

* Fixed local test commands
This commit is contained in:
2026-07-16 12:05:06 +01:00
committed by GitHub
parent 15a179c2bf
commit 413c85096d
76 changed files with 8396 additions and 1143 deletions
+11
View File
@@ -0,0 +1,11 @@
---
description: "Imports the Master AGENTS.md context."
alwaysApply: true
---
# AGENTS.md Integration
- You are working in the I-Form Invenio project.
- ALWAYS prioritize the instructions defined in `AGENTS.md` in the project root.
- If a conflict arises between this local rule and `AGENTS.md`, `AGENTS.md` is
the source of truth.
+17
View File
@@ -0,0 +1,17 @@
---
description: "Strict behavioral guardrails for safety and iteration limits."
alwaysApply: true
---
# Agent Iteration & Safety Guardrails
- **Strict Iteration Limit:** You are permitted a maximum of 3 tool calls to
solve a problem. If tests/linters fail after 3 attempts, you MUST stop
execution, summarize the failure, and wait for human input. Do NOT attempt a
4th fix.
- **No Blind Retries:** If a tool call fails, do NOT immediately retry with the
exact same arguments. Change your approach or ask the user.
- **Destructive Action Halt:** NEVER run `rm -rf`, `git reset --hard`, or drop
database tables without explicit user confirmation.
- **No Git Operations:** Do not use `git` to sync or commit changes unless
explicitly told to. The human is the final QC step.
+17
View File
@@ -0,0 +1,17 @@
---
description: "Core context for the I-Form Invenio RDM repository. Use this when reasoning about architecture, deployment, or advanced manufacturing requirements."
alwaysApply: false
---
# I-Form Invenio Repository Context
- **Goal:** Set up a reliable, customized Invenio instance for the Irish
"I-Form" research institution (advanced manufacturing / Powder Bed Fusion).
- **Scale:** The system must handle extreme volumes of data and remain highly
reconfigurable.
- **Tooling:** `uv` is used for environment/dependency management.
- **Containers:** All changes must be completely OCI compatible. We use podman
locally, but deployment could be Docker or podman.
- **Upstream References:** The packages `invenio-config-iform` and
`invenio-theme-iform` were forked from `invenio-config-tugraz` and
`invenio-theme-tugraz`.
+17
View File
@@ -0,0 +1,17 @@
---
description: "Strict LSP and syntax validation rules."
globs: ["**/*.py"]
alwaysApply: false
---
# Python Validation & Editing Rules
- **Mandatory Planning:** Before modifying any files, you must outline the files
you intend to touch.
- **LSP Checking:** After editing or removing boilerplate, you MUST query the
LSP server (e.g., ruff) to check for broken references, undefined variables,
or unused imports.
- **Zero Warnings:** The file is not considered "clean" until the LSP returns
zero warnings for the section you modified.
- **Revert on Failure:** If your cleanup causes cascading errors in other files,
revert your change and ask the user how they want to proceed.
+13
View File
@@ -0,0 +1,13 @@
---
description: "Workflow for documenting agent actions and handoffs."
alwaysApply: false
---
# Agent Logging & Handoff Protocol
When you complete a major task, fail a task, or require a human handoff, you
must update the following files in the `gemini/` directory: -
**`gemini/history.md`**: Update this living log with your past executions,
discoveries, bug fixes, and system status. - **`gemini/handoff.md`**: If passing
control back to a human or another agent, update this with active problems,
proposed solutions, and immediate next steps.
+1
View File
@@ -0,0 +1 @@
/home/cianh/Storage/Programming/Work_Projects/iform-invenio/.agents/rules/00-master-import.md
+1
View File
@@ -0,0 +1 @@
/home/cianh/Storage/Programming/Work_Projects/iform-invenio/.agents/rules/01-guardrails.md
+1
View File
@@ -0,0 +1 @@
/home/cianh/Storage/Programming/Work_Projects/iform-invenio/.agents/rules/02-project-context.md
+1
View File
@@ -0,0 +1 @@
/home/cianh/Storage/Programming/Work_Projects/iform-invenio/.agents/rules/03-python-validation.md
+1
View File
@@ -0,0 +1 @@
/home/cianh/Storage/Programming/Work_Projects/iform-invenio/.agents/rules/04-logging.md
+1
View File
@@ -47,3 +47,4 @@ versions
secrets.env
.env
agents
+1
View File
@@ -0,0 +1 @@
3.12
+22
View File
@@ -0,0 +1,22 @@
# I-Form Invenio Repository - AGENTS.md
## Project Identity
- **Goal:** Manage a customized Invenio RDM instance for I-Form research.
- **Scale:** High-volume data, extreme reconfigurability.
- **Tech Stack:** Invenio RDM, Python, OCI-compliant (Docker/Podman).
## Core Principles
1. **Human-in-the-Loop:** Do not perform git commits or destructive database
actions without explicit human approval.
2. **Deterministic Tooling:** Always prefer `uv` for environment management.
3. **Safety First:** If a tool/command fails, stop and report. Do not blindly
retry.
4. **Tool Integrity:** Use `sequential-thinking` for planning and `LSP`
(ruff/typescript) for validation.
## Records
- All agent logs must be synced to `agents/history.md`.
- All handoffs must be documented in `agents/handoff.md`.
-10
View File
@@ -1,10 +0,0 @@
FROM ghcr.io/front-matter/invenio-rdm-starter:v12.0.18.0
RUN /opt/invenio/.venv/bin/python -m ensurepip
RUN /opt/invenio/.venv/bin/python -m pip install --upgrade pip
RUN /opt/invenio/.venv/bin/python -m pip install invenio-theme-iform==2025.6.6.4
RUN apt update -y && apt upgrade -y
RUN apt install -y npm
RUN invenio collect --verbose
RUN invenio webpack buildall
# RUN apt remove -y npm && apt autoremove -y
-5
View File
@@ -14,9 +14,4 @@ docker compose up
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Acknowledgements
Thanks to the extremely friendly community of the inveniosoftware discord, and in particular
Martin Fenner and his [alternative invenio deployment](https://github.com/front-matter/invenio-rdm-starter/tree/main) using gunicorn and caddy.
Trying to get this to work via the traditional uwsgi and nginx was a nightmare; one he had
apparently already discovered and worked around.
+52 -52
View File
@@ -3,10 +3,11 @@
"devenv": {
"locked": {
"dir": "src/modules",
"lastModified": 1749416335,
"lastModified": 1782751734,
"narHash": "sha256-shLdS1fYdEQvbp+XzzSDq/pBxKoniU+cqXvDFgmEE70=",
"owner": "cachix",
"repo": "devenv",
"rev": "e8fffc7d61259f27c27b0fbe39a052a604807a2e",
"rev": "26c8d030f9398fb8531a2b19f6b3aaa8b3589b47",
"type": "github"
},
"original": {
@@ -19,10 +20,11 @@
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1747046372,
"lastModified": 1767039857,
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
"type": "github"
},
"original": {
@@ -31,53 +33,16 @@
"type": "github"
}
},
"git-hooks": {
"inputs": {
"flake-compat": "flake-compat",
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1747372754,
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "80479b6ec16fefd9c1db3ea13aeb038c60530f46",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"git-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"nixpkgs": {
"inputs": {
"nixpkgs-src": "nixpkgs-src"
},
"locked": {
"lastModified": 1746807397,
"lastModified": 1782132010,
"narHash": "sha256-ZnAVHdVrotp80iIMm5CSR1fdxPlw7Uwmwxb+O/wsgZ8=",
"owner": "cachix",
"repo": "devenv-nixpkgs",
"rev": "c5208b594838ea8e6cca5997fbf784b7cca1ca90",
"rev": "12866ae2dddbc0ab8b329915f8072bb9c75bde89",
"type": "github"
},
"original": {
@@ -87,17 +52,52 @@
"type": "github"
}
},
"nixpkgs-python": {
"inputs": {
"flake-compat": "flake-compat",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1781070343,
"narHash": "sha256-wXAybU+2LlbXm9cfRDHRPASakq60rLvZBXVT2Ahkj1U=",
"owner": "cachix",
"repo": "nixpkgs-python",
"rev": "23629493653be6df0472a46b1be1d65cbd6df55b",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "nixpkgs-python",
"type": "github"
}
},
"nixpkgs-src": {
"flake": false,
"locked": {
"lastModified": 1781607440,
"narHash": "sha256-rxO+uc/KFbSJp+pgyXRuAX6QlG9hJdnt0BXpEQRXY+U=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "3e41b24abd260e8f71dbe2f5737d24122f972158",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"devenv": "devenv",
"git-hooks": "git-hooks",
"nixpkgs": "nixpkgs",
"pre-commit-hooks": [
"git-hooks"
]
"nixpkgs-python": "nixpkgs-python"
}
}
},
"root": "root",
"version": 7
}
}
+23 -4
View File
@@ -7,15 +7,34 @@
}: {
packages = with pkgs; [
awscli2
bun
cairo
cairomm
git
jq
nodejs
uv
libxcrypt
];
dotenv.enable = true;
languages.javascript.bun = {
enable = true;
install.enable = true;
languages = {
python = {
enable = true;
version = "3.12";
uv.enable = true;
};
javascript.npm = {
enable = true;
install.enable = true;
};
};
env = {
NIX_LD_LIBRARY_PATH = lib.makeLibraryPath (with pkgs; [
cairo
cairomm
]);
NIX_LD = lib.fileContents "${pkgs.stdenv.cc}/nix-support/dynamic-linker";
};
}
+7 -3
View File
@@ -1,4 +1,8 @@
# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json
inputs:
nixpkgs:
url: github:cachix/devenv-nixpkgs/rolling
nixpkgs:
url: github:cachix/devenv-nixpkgs/rolling
nixpkgs-python:
url: github:cachix/nixpkgs-python
inputs:
nixpkgs:
follows: nixpkgs
-188
View File
@@ -1,188 +0,0 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json
services:
caddy:
image: docker.io/library/caddy:latest
depends_on:
- invenio-rdm
networks:
- invenio-network
ports:
- "8080:80"
- "8443:443"
volumes:
- caddy_data:/data
- ./env/${COMPOSE_PROFILES}/caddy:/etc/caddy
restart: unless-stopped
labels:
- "io.containers.autoupdate=registry"
invenio-rdm:
build:
context: .
networks:
- invenio-network
volumes:
- uploaded_data:/opt/invenio/var/instance/data
- archived_data:/opt/invenio/var/instance/archive
- static_files:/opt/invenio/var/instance/static
- ./invenio.cfg:/opt/invenio/var/instance/invenio.cfg
- ./dev_templates:/dev_templates
environment:
- INVENIO_THEME_LOGO
- INVENIO_THEME_FRONTPAGE_TITLE
- INVENIO_THEME_SITENAME
- INVENIO_THEME_FRONTPAGE_SUBTITLE
- INVENIO_THEME_SHOW_FRONTPAGE_INTRO_SECTION
- INVENIO_SECURITY_REGISTERABLE
- INVENIO_SQLALCHEMY_DATABASE_URI=postgresql+psycopg2://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db/${POSTGRES_DB}
- INVENIO_CACHE_TYPE
- INVENIO_CACHE_REDIS_URL
- INVENIO_ACCOUNTS_SESSION_REDIS_URL
- INVENIO_CELERY_RESULT_BACKEND
- INVENIO_RATELIMIT_STORAGE_URI
- INVENIO_COMMUNITIES_IDENTITIES_CACHE_REDIS_URL
- INVENIO_BROKER_URL
- INVENIO_CELERY_BROKER_URL
- INVENIO_WSGI_PROXIES
- INVENIO_SITE_UI_URL
- INVENIO_SITE_API_URL
- INVENIO_DATACITE_ENABLED
- INVENIO_DATACITE_USERNAME
- INVENIO_DATACITE_PASSWORD
- INVENIO_DATACITE_PREFIX
- INVENIO_DATACITE_TEST_MODE
- INVENIO_DATACITE_DATACENTER_SYMBOL
- INVENIO_RDM_ALLOW_METADATA_ONLY_RECORDS
- INVENIO_RDM_ALLOW_RESTRICTED_RECORDS
- INVENIO_RDM_ALLOW_EXTERNAL_DOI_VERSIONING
- INVENIO_RDM_CITATION_STYLES_DEFAULT
- INVENIO_RDM_DEFAULT_CITATION_STYLE
- INVENIO_MAIL_SUPPRESS_SEND
- INVENIO_SECURITY_EMAIL_SENDER
- INVENIO_ACCOUNTS_LOCAL_LOGIN_ENABLED
- INVENIO_ORCID_APP_CREDENTIALS_CONSUMER_KEY=${INVENIO_ORCID_CLIENT_ID}
- INVENIO_ORCID_APP_CREDENTIALS_CONSUMER_SECRET=${INVENIO_ORCID_SECRET}
- INVENIO_GITHUB_APP_CREDENTIALS_CONSUMER_KEY=${INVENIO_GITHUB_CLIENT_ID}
- INVENIO_GITHUB_APP_CREDENTIALS_CONSUMER_SECRET=${INVENIO_GITHUB_SECRET}
- INVENIO_OAISERVER_ID_PREFIX
- INVENIO_FILES_REST_STORAGE_FACTORY
- INVENIO_S3_ENDPOINT_URL
- INVENIO_S3_ACCESS_KEY_ID
- INVENIO_S3_SECRET_ACCESS_KEY
- INVENIO_S3_BUCKET_NAME
- INVENIO_SEARCH_HOSTS
- INVENIO_SEARCH_INDEX_PREFIX
- INVENIO_LOGGING_CONSOLE_LEVEL
- INVENIO_ENV=${COMPOSE_PROFILES}
- FLASK_ENV=${COMPOSE_PROFILES}
- NODE_ENV=${COMPOSE_PROFILES}
- FLASK_DEBUG
depends_on:
search:
condition: service_started
cache:
condition: service_started
db:
condition: service_started
worker:
command: "celery -A invenio_app.celery worker --beat --events --loglevel=WARNING"
build:
context: .
networks:
- invenio-network
volumes:
- uploaded_data:/opt/invenio/var/instance/data
environment:
- INVENIO_MAIL_SUPPRESS_SEND=true
# Passthrough of shared env variables
- INVENIO_SQLALCHEMY_DATABASE_URI=postgresql+psycopg2://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db/${POSTGRES_DB:-inveniordm}
- INVENIO_SEARCH_HOSTS
- INVENIO_SEARCH_INDEX_PREFIX
- INVENIO_CACHE_TYPE
- INVENIO_CACHE_REDIS_URL
- INVENIO_ACCOUNTS_SESSION_REDIS_URL
- INVENIO_CELERY_RESULT_BACKEND
- INVENIO_RATELIMIT_STORAGE_URI
- INVENIO_COMMUNITIES_IDENTITIES_CACHE_REDIS_URL
- INVENIO_BROKER_URL
- INVENIO_CELERY_BROKER_URL
- INVENIO_MAIL_SERVER
- INVENIO_MAIL_PORT
- INVENIO_MAIL_USERNAME
- INVENIO_MAIL_PASSWORD
- INVENIO_MAIL_USE_SSL
- INVENIO_FILES_REST_STORAGE_FACTORY
- INVENIO_S3_ENDPOINT_URL
- INVENIO_S3_ACCESS_KEY_ID
- INVENIO_S3_SECRET_ACCESS_KEY
- INVENIO_S3_BUCKET_NAME
- INVENIO_ENV=${COMPOSE_PROFILES}
- FLASK_ENV=${COMPOSE_PROFILES}
- NODE_ENV=${COMPOSE_PROFILES}
- FLASK_DEBUG
depends_on:
search:
condition: service_started
cache:
condition: service_started
db:
condition: service_started
cache:
image: valkey/valkey:7.2.5-bookworm
networks:
- invenio-network
restart: "unless-stopped"
volumes:
- "valkey_data:/data"
ports:
- "6379:6379"
db:
image: postgres:16.4-bookworm
networks:
- invenio-network
restart: "unless-stopped"
environment:
- POSTGRES_USER
- POSTGRES_PASSWORD
- POSTGRES_DB
volumes:
- "postgres_data:/var/lib/postgresql/data"
ports:
- 5432:5432
search:
image: opensearchproject/opensearch:2.12.0
networks:
- invenio-network
restart: "unless-stopped"
environment:
- OPENSEARCH_INITIAL_ADMIN_PASSWORD
- bootstrap.memory_lock=true
- OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m
- DISABLE_INSTALL_DEMO_CONFIG=true
- DISABLE_SECURITY_PLUGIN=true
- discovery.type=single-node
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
mem_limit: 2g
volumes:
- opensearch_data:/usr/share/opensearch/data
ports:
- "9200:9200"
- "9600:9600"
networks:
invenio-network:
volumes:
app_data:
uploaded_data:
archived_data:
static_files:
postgres_data:
opensearch_data:
valkey_data:
caddy_data:
+1
View File
@@ -74,3 +74,4 @@ INVENIO_LOGGING_CONSOLE_LEVEL=WARNING
INVENIO_THEME_IFORM_PRODUCTION=false
INVENIO_THEME_IFORM_CONTACT_FORM=true
INVENIO_THEME_IFORM_SUPPORT_EMAIL=support@i-form.ie
COMPOSE_FILE=i-form-data-repository/docker-compose.full.yml
+2
View File
@@ -0,0 +1,2 @@
# Ignore local virtualenv (if present)
.venv/
+79
View File
@@ -0,0 +1,79 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
test.db
# Environments
.venv/
# Logs
logs/
# Invenio-cli per machine file
.invenio.private
# S3 default bucket location
data/default/*
data/.minio.sys
# Celery
celerybeat-schedule
# Local testing
local_wheels/*
!local_wheels/.gitkeep
+42
View File
@@ -0,0 +1,42 @@
[cli]
flavour = RDM
logfile = /logs/invenio-cli.log
[cookiecutter]
project_name = I-Form Data Repository
project_shortname = i-form-data-repository
package_name = i_form_data_repository
project_site = repo.i-form.ie
author_name = Cian Hughes
author_email = info@repo.i-form.ie
year = 2025
database = postgresql
search = opensearch2
file_storage = S3
development_tools = yes
site_code = yes
use_reduced_vocabs = no
_template = https://github.com/inveniosoftware/cookiecutter-invenio-rdm.git
_output_dir = /home/cianh/Storage/Programming/Work_Projects/iform-invenio
_repo_dir = /home/cianh/.cookiecutters/cookiecutter-invenio-rdm
_checkout = v13.0
[files]
site = {'tests': {'.gitkeep': 'd4756cdf68d94c670c924f9d57d44718f666e457727701486435b57a97e52c5f'}, '.gitkeep': '7a0ab727bee27863bd144c4c473f832833d8952d56a83e54ad05a9ce9e73404d', 'pyproject.toml': 'e1acd833b38f03f26cc31439246cbeeb82e2edf56c751f28c3247cb44e95caca', 'setup.cfg': 'f6ac996bb751a7b02dfeca5faaca578151bdf4adb9b3ff1825d2443fa41109af', 'i_form_data_repository': {'templates': {'semantic-ui': {'i_form_data_repository': {'.gitkeep': 'd4756cdf68d94c670c924f9d57d44718f666e457727701486435b57a97e52c5f'}}}, '__init__.py': 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', 'views.py': '039927b9ebcf3482b714559dd6fc9455b88a570bc5496af742ac7b23663c9547', 'webpack.py': '96b09a233bee5087e4329023dea3a363632372c100fdb790c6003cd6b04dba03', 'assets': {'semantic-ui': {'js': {'i_form_data_repository': {'.gitkeep': '3253a6fe7fc74a1279fb374e67ffd3383eded63cd28c4877afd77dffc8cc5da4'}}, 'less': {'i_form_data_repository': {'.gitkeep': 'de96a61fec5b6b168bced6dda58bd11e353f618ae9bee45aad9253cb0d6c5617'}}}}}, 'setup.py': '843ac26c38a41abae578250bc0f9419194b320a0f67327d941037a4268f6cfe7'}
dockerfile = 44e5c207cf3e82cddda086f73e6fa5f3bacfc06d11f55a95f954d744a773c605
.dockerignore = 21241bc12cdf4ac5f209d6b191adc8f25eb89af93ce5c4c3f72c86661162d7b5
static = {'images': {'logo-invenio-white.svg': '5af2c7b67a09798cba3d50cc2e811ca9fd2ff73b40d9d2a52a97237b9ed44008', 'invenio-rdm.svg': '50f09b4d83244a69c58f44aa436a3fa097726d9b47fd0e0782ea92d31f854b65'}}
templates = {'.gitkeep': 'd4756cdf68d94c670c924f9d57d44718f666e457727701486435b57a97e52c5f'}
pipfile = be67d4845f38cf90f681c5df8f69696333e302755fa05a2c13b80ce4033a86ac
docker-compose.full.yml = bd48fde383c673b84607e5ab99b01e688db6450e9bba4009ce079815223b51ea
invenio.cfg = f58cc1d00290ff85ad73824005d04fb8c6c42393fbced496fe922bb36a3e7fa3
translations = {'babel.ini': '3fb6bff73460aa031d4f90fc1e1d16235cab84d2385c9831efacb2ce32e5409b'}
docker-compose.yml = b262b784dd6b5f144993319557c4295937d8dece2e92ddef502427517b037954
docker = {'uwsgi': {'uwsgi_rest.ini': 'c36fc5021baf15f375b3b6c825f7753e5d166319c5fe38a85b604391ce5b37b6', 'uwsgi_ui.ini': 'aeb0797a1fadb462e0ed208c979d5152cc58a85958d4de9c4e989637c70b9005'}, 'pgadmin': {'servers.json': '405a1ade1eaf37d99301abb460fe49a9deacda13e5e5f2618cfc99e2e7bbe299'}, 'nginx': {'nginx.conf': '7ba045f9e5c94cbbe96653c0b2fdc0b58951642d488d5fcae1ace3eeca9253c0', 'Dockerfile': '541326766beaba2e8492255c99e11aa76640d71329ceab5bcab1c8d6a979bd5c', 'test.key': '5e8a6cdf7e53ef815148744b275f7f02d5f046b1582f347543caf95c81901092', 'test.crt': '61a088d23224f550806d05e671096375b68c679fad1745145c7d2520397f509b', 'conf.d': {'default.conf': '360a483a89dbea713f4138b8115d06558897f2419afef1347b50cd800ea16ccc'}}}
readme.md = f99f106a4aba1cb7143553c6516017c81a7c10e82bc909d30a6112550f2c4a16
docker-services.yml = f9850f3abddcaa5285e5533502fc334238e111e6db6e66fa1804ec3d57133e7b
app_data = {'vocabularies.yaml': 'e860d2136df803dc05e67c8f1c32bc58aa4bdca348dcc2daf7aaa4aee67ecfbf', 'README.md': 'd58978488626bdeddc791a15a39e341a4ed06f202b84d0c0d4aa9ef49481c6d9', 'vocabularies': {'languages.yaml': 'd3bdb59940e8e6cd2401785ad55733f5fc6a1fb0bb0a2005a8fe4e5148e5f286', 'names.yaml': '6dc80984186ec960bcf53fbb6c482554d0aaf386d345bf82f504fdbd896e5848', 'cc_licences.csv': '19a8bfd2488c7adb90d1dbe1c70f57cf2e0a737cb11814cc814f917072843de7', 'subjects_oecd_fos.yaml': 'eef38714c506d956193c3be17e6004049525d252bf22424f4804dfc1ad46db44'}, 'pages': {'.gitkeep': '22818f8c9f68fb11b7ca893ad1c082f844ae9f691f082d2174e32738d9ae6114'}}
data = {'default': {'.gitkeep': 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'}}
.gitignore = af1182c70588e583daeb35809e6cdfe3408425d438c3ceb282b1f4b8360290e2
assets = {'templates': {'custom_fields': {'.gitkeep': 'd4756cdf68d94c670c924f9d57d44718f666e457727701486435b57a97e52c5f'}, 'search': {'.gitkeep': 'd4756cdf68d94c670c924f9d57d44718f666e457727701486435b57a97e52c5f'}}, 'js': {'invenio_app_rdm': {'overridableRegistry': {'mapping.js': '7fb63c1b801d11f1c1bb9b7d5cad6662ae475210df2bbba6919cda402684590a'}}}, 'less': {'site': {'globals': {'site.variables': 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', 'site.overrides': 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'}}, 'theme.config': 'ee68441b779400585a3a1ed4445ab5727e3a47a09aa708976dd506c0e081f0d8'}}
+51
View File
@@ -0,0 +1,51 @@
# Dockerfile that builds a fully functional image of your app.
#
# This image installs all Python dependencies for your application. It's based
# on Almalinux (https://github.com/inveniosoftware/docker-invenio)
# and includes Pip, Pipenv, Node.js, NPM and some few standard libraries
# Invenio usually needs.
#
# Note: It is important to keep the commands in this file in sync with your
# bootstrap script located in ./scripts/bootstrap.
FROM registry.cern.ch/inveniosoftware/almalinux:1
ENV UV_PYTHON=3.12
ENV PIPENV_VENV_IN_PROJECT=1
COPY site ./site
COPY Pipfile Pipfile.lock ./
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
RUN uv python install ${UV_PYTHON} && \
pipenv install --deploy --python $(uv python find ${UV_PYTHON}) && \
pipenv run pip install "setuptools<70.0.0"
COPY ./docker/uwsgi/ ${INVENIO_INSTANCE_PATH}
COPY ./invenio.cfg ${INVENIO_INSTANCE_PATH}
COPY ./templates/ ${INVENIO_INSTANCE_PATH}/templates/
COPY ./app_data/ ${INVENIO_INSTANCE_PATH}/app_data/
COPY ./translations/ ${INVENIO_INSTANCE_PATH}/translations/
COPY ./ .
RUN curl -fsSL https://rpm.nodesource.com/setup_20.x | bash - && \
dnf install -y nodejs
ARG INSTALL_LOCAL_WHEELS=false
COPY ./local_wheels/ ./local_wheels/
RUN if [ "$INSTALL_LOCAL_WHEELS" = "true" ]; then \
if ls ./local_wheels/invenio_theme_iform*.whl ./local_wheels/invenio_config_iform*.whl 1> /dev/null 2>&1; then \
pipenv run pip install --no-deps --force-reinstall ./local_wheels/invenio_theme_iform*.whl ./local_wheels/invenio_config_iform*.whl; \
fi \
fi
ENV WEBPACKEXT_PROJECT="invenio_assets.webpack:rspack_project"
COPY patch_js_translations.py /opt/invenio/src/patch_js_translations.py
RUN cp -r ./static/. ${INVENIO_INSTANCE_PATH}/static/ && \
cp -r ./assets/. ${INVENIO_INSTANCE_PATH}/assets/ && \
uv run invenio collect --verbose && \
uv run invenio i18n js-translation build --all-packages && \
uv run python patch_js_translations.py && \
npm config set legacy-peer-deps true && \
uv run invenio webpack buildall
ENV PATH="/opt/invenio/src/.venv/bin:$PATH"
+24
View File
@@ -0,0 +1,24 @@
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
check-manifest = ">=0.25"
[packages]
invenio-app-rdm = {extras = ["opensearch2", "s3"], version = ">=13.0.0"}
i-form-data-repository = {editable = true, path="./site"}
invenio-config-iform = "*"
invenio-theme-iform = "*"
uwsgi = ">=2.0"
uwsgitop = ">=0.11"
uwsgi-tools = ">=1.1.1"
nh3 = ">=0.2.24"
[requires]
python_version = "3.12"
[pipenv]
allow_prereleases = false
+5191
View File
File diff suppressed because it is too large Load Diff
+49
View File
@@ -0,0 +1,49 @@
# I-Form Data Repository
Welcome to your InvenioRDM instance.
## Getting started
Run the following commands in order to start your new InvenioRDM instance:
```console
invenio-cli containers start --lock --build --setup
```
The above command first builds the application docker image and afterwards
starts the application and related services (database, Opensearch, Redis
and RabbitMQ). The build and boot process will take some time to complete,
especially the first time as docker images have to be downloaded during the
process.
Once running, visit https://127.0.0.1 in your browser.
**Note**: The server is using a self-signed SSL certificate, so your browser
will issue a warning that you will have to by-pass.
## Overview
Following is an overview of the generated files and folders:
| Name | Description |
|---|---|
| ``Dockerfile`` | Dockerfile used to build your application image. |
| ``Pipfile`` | Python requirements installed via [pipenv](https://pipenv.pypa.io) |
| ``Pipfile.lock`` | Locked requirements (generated on first install). |
| ``app_data`` | Application data such as vocabularies. |
| ``assets`` | Web assets (CSS, JavaScript, LESS, JSX templates) used in the Webpack build. |
| ``docker`` | Example configuration for NGINX and uWSGI. |
| ``docker-compose.full.yml`` | Example of a full infrastructure stack. |
| ``docker-compose.yml`` | Backend services needed for local development. |
| ``docker-services.yml`` | Common services for the Docker Compose files. |
| ``invenio.cfg`` | The Invenio application configuration. |
| ``logs`` | Log files. |
| ``static`` | Static files that need to be served as-is (e.g. images). |
| ``templates`` | Folder for your Jinja templates. |
| ``.invenio`` | Common file used by Invenio-CLI to be version controlled. |
| ``.invenio.private`` | Private file used by Invenio-CLI *not* to be version controlled. |
## Documentation
To learn how to configure, customize, deploy and much more, visit
the [InvenioRDM Documentation](https://inveniordm.docs.cern.ch/).
@@ -0,0 +1,6 @@
# README
Place in this directory the subdirectories containing application data.
For example, you can create the `vocabularies/` folder to hold
your custom controlled vocabularies.
@@ -0,0 +1 @@
# This file exists only to add pages/ folder to git repository.
@@ -0,0 +1,18 @@
subjects:
pid-type: sub
schemes:
- id: FOS
name: Fields of Science and Technology
uri: "http://www.oecd.org/science/inno/38235147.pdf"
data-file: vocabularies/subjects_oecd_fos.yaml
# Minimal example vocabularies
# can be used for quick testing, or a basis for building your own customized vocabularies.
#names:
# pid-type: names
# data-file: vocabularies/names.yaml
#licenses:
# pid-type: lic
# data-file: vocabularies/cc_licences.csv
#languages:
# pid-type: lng
# data-file: vocabularies/languages.yaml
@@ -0,0 +1,37 @@
id;title__en;description__en;icon;tags;props__url;props__scheme;props__osi_approved
cc-by-1.0;Creative Commons Attribution 1.0 Generic;;cc-by-icon;all,data;https://creativecommons.org/licenses/by/1.0/legalcode;spdx;
cc-by-2.0;Creative Commons Attribution 2.0 Generic;;cc-by-icon;all,data;https://creativecommons.org/licenses/by/2.0/legalcode;spdx;
cc-by-2.5;Creative Commons Attribution 2.5 Generic;;cc-by-icon;all,data;https://creativecommons.org/licenses/by/2.5/legalcode;spdx;
cc-by-3.0;Creative Commons Attribution 3.0 Unported;;cc-by-icon;all,data;https://creativecommons.org/licenses/by/3.0/legalcode;spdx;
cc-by-3.0-at;Creative Commons Attribution 3.0 Austria;;cc-by-icon;all,data;https://creativecommons.org/licenses/by/3.0/at/legalcode;spdx;
cc-by-3.0-us;Creative Commons Attribution 3.0 United States;;cc-by-icon;all,data;https://creativecommons.org/licenses/by/3.0/us/legalcode;spdx;
cc-by-4.0;Creative Commons Attribution 4.0 International;The Creative Commons Attribution license allows re-distribution and re-use of a licensed work on the condition that the creator is appropriately credited.;cc-by-icon;recommended,all,data;https://creativecommons.org/licenses/by/4.0/legalcode;spdx;
cc-by-nc-1.0;Creative Commons Attribution Non Commercial 1.0 Generic;;cc-by-nc-icon;all,data;https://creativecommons.org/licenses/by-nc/1.0/legalcode;spdx;
cc-by-nc-2.0;Creative Commons Attribution Non Commercial 2.0 Generic;;cc-by-nc-icon;all,data;https://creativecommons.org/licenses/by-nc/2.0/legalcode;spdx;
cc-by-nc-2.5;Creative Commons Attribution Non Commercial 2.5 Generic;;cc-by-nc-icon;all,data;https://creativecommons.org/licenses/by-nc/2.5/legalcode;spdx;
cc-by-nc-3.0;Creative Commons Attribution Non Commercial 3.0 Unported;;cc-by-nc-icon;all,data;https://creativecommons.org/licenses/by-nc/3.0/legalcode;spdx;
cc-by-nc-4.0;Creative Commons Attribution Non Commercial 4.0 International;;cc-by-nc-icon;all,data;https://creativecommons.org/licenses/by-nc/4.0/legalcode;spdx;
cc-by-nc-nd-1.0;Creative Commons Attribution Non Commercial No Derivatives 1.0 Generic;;cc-by-nc-nd-icon;all,data;https://creativecommons.org/licenses/by-nd-nc/1.0/legalcode;spdx;
cc-by-nc-nd-2.0;Creative Commons Attribution Non Commercial No Derivatives 2.0 Generic;;cc-by-nc-nd-icon;all,data;https://creativecommons.org/licenses/by-nc-nd/2.0/legalcode;spdx;
cc-by-nc-nd-2.5;Creative Commons Attribution Non Commercial No Derivatives 2.5 Generic;;cc-by-nc-nd-icon;all,data;https://creativecommons.org/licenses/by-nc-nd/2.5/legalcode;spdx;
cc-by-nc-nd-3.0;Creative Commons Attribution Non Commercial No Derivatives 3.0 Unported;;cc-by-nc-nd-icon;all,data;https://creativecommons.org/licenses/by-nc-nd/3.0/legalcode;spdx;
cc-by-nc-nd-3.0-igo;Creative Commons Attribution Non Commercial No Derivatives 3.0 IGO;;cc-by-nc-nd-icon;all,data;https://creativecommons.org/licenses/by-nc-nd/3.0/igo/legalcode;spdx;
cc-by-nc-nd-4.0;Creative Commons Attribution Non Commercial No Derivatives 4.0 International;;cc-by-nc-nd-icon;all,data;https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode;spdx;
cc-by-nc-sa-1.0;Creative Commons Attribution Non Commercial Share Alike 1.0 Generic;;cc-by-nc-sa-icon;all,data;https://creativecommons.org/licenses/by-nc-sa/1.0/legalcode;spdx;
cc-by-nc-sa-2.0;Creative Commons Attribution Non Commercial Share Alike 2.0 Generic;;cc-by-nc-sa-icon;all,data;https://creativecommons.org/licenses/by-nc-sa/2.0/legalcode;spdx;
cc-by-nc-sa-2.5;Creative Commons Attribution Non Commercial Share Alike 2.5 Generic;;cc-by-nc-sa-icon;all,data;https://creativecommons.org/licenses/by-nc-sa/2.5/legalcode;spdx;
cc-by-nc-sa-3.0;Creative Commons Attribution Non Commercial Share Alike 3.0 Unported;;cc-by-nc-sa-icon;all,data;https://creativecommons.org/licenses/by-nc-sa/3.0/legalcode;spdx;
cc-by-nc-sa-4.0;Creative Commons Attribution Non Commercial Share Alike 4.0 International;;cc-by-nc-sa-icon;all,data;https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode;spdx;
cc-by-nd-1.0;Creative Commons Attribution No Derivatives 1.0 Generic;;cc-by-nd-icon;all,data;https://creativecommons.org/licenses/by-nd/1.0/legalcode;spdx;
cc-by-nd-2.0;Creative Commons Attribution No Derivatives 2.0 Generic;;cc-by-nd-icon;all,data;https://creativecommons.org/licenses/by-nd/2.0/legalcode;spdx;
cc-by-nd-2.5;Creative Commons Attribution No Derivatives 2.5 Generic;;cc-by-nd-icon;all,data;https://creativecommons.org/licenses/by-nd/2.5/legalcode;spdx;
cc-by-nd-3.0;Creative Commons Attribution No Derivatives 3.0 Unported;;cc-by-nd-icon;all,data;https://creativecommons.org/licenses/by-nd/3.0/legalcode;spdx;
cc-by-nd-4.0;Creative Commons Attribution No Derivatives 4.0 International;;cc-by-nd-icon;all,data;https://creativecommons.org/licenses/by-nd/4.0/legalcode;spdx;
cc-by-sa-1.0;Creative Commons Attribution Share Alike 1.0 Generic;;cc-by-sa-icon;all,data;https://creativecommons.org/licenses/by-sa/1.0/legalcode;spdx;
cc-by-sa-2.0;Creative Commons Attribution Share Alike 2.0 Generic;;cc-by-sa-icon;all,data;https://creativecommons.org/licenses/by-sa/2.0/legalcode;spdx;
cc-by-sa-2.0-uk;Creative Commons Attribution Share Alike 2.0 England and Wales;;;all,data;https://creativecommons.org/licenses/by-sa/2.0/uk/legalcode;spdx;
cc-by-sa-2.5;Creative Commons Attribution Share Alike 2.5 Generic;;cc-by-sa-icon;all,data;https://creativecommons.org/licenses/by-sa/2.5/legalcode;spdx;
cc-by-sa-3.0;Creative Commons Attribution Share Alike 3.0 Unported;;cc-by-sa-icon;all,data;https://creativecommons.org/licenses/by-sa/3.0/legalcode;spdx;
cc-by-sa-3.0-at;Creative Commons Attribution-Share Alike 3.0 Austria;;cc-by-sa-icon;all,data;https://creativecommons.org/licenses/by-sa/3.0/at/legalcode;spdx;
cc-by-sa-4.0;Creative Commons Attribution Share Alike 4.0 International;Permits almost any use subject to providing credit and license notice. Frequently used for media assets and educational materials. The most common license for Open Access scientific publications. Not recommended for software.;cc-by-sa-icon;recommended,all,data;https://creativecommons.org/licenses/by-sa/4.0/legalcode;spdx;
cc-pddc;Creative Commons Public Domain Dedication and Certification;;cc-pddc-icon;all;https://creativecommons.org/licenses/publicdomain/;spdx;
1 id title__en description__en icon tags props__url props__scheme props__osi_approved
2 cc-by-1.0 Creative Commons Attribution 1.0 Generic cc-by-icon all,data https://creativecommons.org/licenses/by/1.0/legalcode spdx
3 cc-by-2.0 Creative Commons Attribution 2.0 Generic cc-by-icon all,data https://creativecommons.org/licenses/by/2.0/legalcode spdx
4 cc-by-2.5 Creative Commons Attribution 2.5 Generic cc-by-icon all,data https://creativecommons.org/licenses/by/2.5/legalcode spdx
5 cc-by-3.0 Creative Commons Attribution 3.0 Unported cc-by-icon all,data https://creativecommons.org/licenses/by/3.0/legalcode spdx
6 cc-by-3.0-at Creative Commons Attribution 3.0 Austria cc-by-icon all,data https://creativecommons.org/licenses/by/3.0/at/legalcode spdx
7 cc-by-3.0-us Creative Commons Attribution 3.0 United States cc-by-icon all,data https://creativecommons.org/licenses/by/3.0/us/legalcode spdx
8 cc-by-4.0 Creative Commons Attribution 4.0 International The Creative Commons Attribution license allows re-distribution and re-use of a licensed work on the condition that the creator is appropriately credited. cc-by-icon recommended,all,data https://creativecommons.org/licenses/by/4.0/legalcode spdx
9 cc-by-nc-1.0 Creative Commons Attribution Non Commercial 1.0 Generic cc-by-nc-icon all,data https://creativecommons.org/licenses/by-nc/1.0/legalcode spdx
10 cc-by-nc-2.0 Creative Commons Attribution Non Commercial 2.0 Generic cc-by-nc-icon all,data https://creativecommons.org/licenses/by-nc/2.0/legalcode spdx
11 cc-by-nc-2.5 Creative Commons Attribution Non Commercial 2.5 Generic cc-by-nc-icon all,data https://creativecommons.org/licenses/by-nc/2.5/legalcode spdx
12 cc-by-nc-3.0 Creative Commons Attribution Non Commercial 3.0 Unported cc-by-nc-icon all,data https://creativecommons.org/licenses/by-nc/3.0/legalcode spdx
13 cc-by-nc-4.0 Creative Commons Attribution Non Commercial 4.0 International cc-by-nc-icon all,data https://creativecommons.org/licenses/by-nc/4.0/legalcode spdx
14 cc-by-nc-nd-1.0 Creative Commons Attribution Non Commercial No Derivatives 1.0 Generic cc-by-nc-nd-icon all,data https://creativecommons.org/licenses/by-nd-nc/1.0/legalcode spdx
15 cc-by-nc-nd-2.0 Creative Commons Attribution Non Commercial No Derivatives 2.0 Generic cc-by-nc-nd-icon all,data https://creativecommons.org/licenses/by-nc-nd/2.0/legalcode spdx
16 cc-by-nc-nd-2.5 Creative Commons Attribution Non Commercial No Derivatives 2.5 Generic cc-by-nc-nd-icon all,data https://creativecommons.org/licenses/by-nc-nd/2.5/legalcode spdx
17 cc-by-nc-nd-3.0 Creative Commons Attribution Non Commercial No Derivatives 3.0 Unported cc-by-nc-nd-icon all,data https://creativecommons.org/licenses/by-nc-nd/3.0/legalcode spdx
18 cc-by-nc-nd-3.0-igo Creative Commons Attribution Non Commercial No Derivatives 3.0 IGO cc-by-nc-nd-icon all,data https://creativecommons.org/licenses/by-nc-nd/3.0/igo/legalcode spdx
19 cc-by-nc-nd-4.0 Creative Commons Attribution Non Commercial No Derivatives 4.0 International cc-by-nc-nd-icon all,data https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode spdx
20 cc-by-nc-sa-1.0 Creative Commons Attribution Non Commercial Share Alike 1.0 Generic cc-by-nc-sa-icon all,data https://creativecommons.org/licenses/by-nc-sa/1.0/legalcode spdx
21 cc-by-nc-sa-2.0 Creative Commons Attribution Non Commercial Share Alike 2.0 Generic cc-by-nc-sa-icon all,data https://creativecommons.org/licenses/by-nc-sa/2.0/legalcode spdx
22 cc-by-nc-sa-2.5 Creative Commons Attribution Non Commercial Share Alike 2.5 Generic cc-by-nc-sa-icon all,data https://creativecommons.org/licenses/by-nc-sa/2.5/legalcode spdx
23 cc-by-nc-sa-3.0 Creative Commons Attribution Non Commercial Share Alike 3.0 Unported cc-by-nc-sa-icon all,data https://creativecommons.org/licenses/by-nc-sa/3.0/legalcode spdx
24 cc-by-nc-sa-4.0 Creative Commons Attribution Non Commercial Share Alike 4.0 International cc-by-nc-sa-icon all,data https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode spdx
25 cc-by-nd-1.0 Creative Commons Attribution No Derivatives 1.0 Generic cc-by-nd-icon all,data https://creativecommons.org/licenses/by-nd/1.0/legalcode spdx
26 cc-by-nd-2.0 Creative Commons Attribution No Derivatives 2.0 Generic cc-by-nd-icon all,data https://creativecommons.org/licenses/by-nd/2.0/legalcode spdx
27 cc-by-nd-2.5 Creative Commons Attribution No Derivatives 2.5 Generic cc-by-nd-icon all,data https://creativecommons.org/licenses/by-nd/2.5/legalcode spdx
28 cc-by-nd-3.0 Creative Commons Attribution No Derivatives 3.0 Unported cc-by-nd-icon all,data https://creativecommons.org/licenses/by-nd/3.0/legalcode spdx
29 cc-by-nd-4.0 Creative Commons Attribution No Derivatives 4.0 International cc-by-nd-icon all,data https://creativecommons.org/licenses/by-nd/4.0/legalcode spdx
30 cc-by-sa-1.0 Creative Commons Attribution Share Alike 1.0 Generic cc-by-sa-icon all,data https://creativecommons.org/licenses/by-sa/1.0/legalcode spdx
31 cc-by-sa-2.0 Creative Commons Attribution Share Alike 2.0 Generic cc-by-sa-icon all,data https://creativecommons.org/licenses/by-sa/2.0/legalcode spdx
32 cc-by-sa-2.0-uk Creative Commons Attribution Share Alike 2.0 England and Wales all,data https://creativecommons.org/licenses/by-sa/2.0/uk/legalcode spdx
33 cc-by-sa-2.5 Creative Commons Attribution Share Alike 2.5 Generic cc-by-sa-icon all,data https://creativecommons.org/licenses/by-sa/2.5/legalcode spdx
34 cc-by-sa-3.0 Creative Commons Attribution Share Alike 3.0 Unported cc-by-sa-icon all,data https://creativecommons.org/licenses/by-sa/3.0/legalcode spdx
35 cc-by-sa-3.0-at Creative Commons Attribution-Share Alike 3.0 Austria cc-by-sa-icon all,data https://creativecommons.org/licenses/by-sa/3.0/at/legalcode spdx
36 cc-by-sa-4.0 Creative Commons Attribution Share Alike 4.0 International Permits almost any use subject to providing credit and license notice. Frequently used for media assets and educational materials. The most common license for Open Access scientific publications. Not recommended for software. cc-by-sa-icon recommended,all,data https://creativecommons.org/licenses/by-sa/4.0/legalcode spdx
37 cc-pddc Creative Commons Public Domain Dedication and Certification cc-pddc-icon all https://creativecommons.org/licenses/publicdomain/ spdx
@@ -0,0 +1,96 @@
- id: ara
props:
alpha_2: ar
tags:
- macrolanguage
- living
title:
en: Arabic
- id: cym
props:
alpha_2: cy
tags:
- individual
- living
title:
en: Welsh
- id: deu
props:
alpha_2: de
tags:
- individual
- living
title:
en: German
- id: eng
props:
alpha_2: en
tags:
- individual
- living
title:
en: English
- id: fra
props:
alpha_2: fr
tags:
- individual
- living
title:
en: French
- id: ita
props:
alpha_2: it
tags:
- individual
- living
title:
en: Italian
- id: nor
props:
alpha_2: 'no'
tags:
- macrolanguage
- living
title:
en: Norwegian
- id: roh
props:
alpha_2: rm
tags:
- individual
- living
title:
en: Romansh
- id: spa
props:
alpha_2: es
tags:
- individual
- living
title:
en: Spanish
- id: tur
props:
alpha_2: tr
tags:
- individual
- living
title:
en: Turkish
- id: aag
props:
alpha_2: ''
tags:
- individual
- living
title:
en: Ambrak
- id: aah
props:
alpha_2: ''
tags:
- individual
- living
title:
en: Abu' Arapesh
@@ -0,0 +1,20 @@
- affiliations:
- name: University of Zurich
- name: Humboldt University of Berlin
- name: Kaiser Wilhelm Institute for Physics
family_name: Einstein
given_name: Albert
id: gnd:118529579
identifiers:
- identifier: gnd:118529579
scheme: gnd
- affiliations:
- name: University of Cambridge
- name: California Institute of Technology
- name: University of Oxford
family_name: Hawking
given_name: Stephen
id: 0000-0002-9079-593X
identifiers:
- identifier: https://orcid.org/0000-0002-9079-593X
scheme: orcid
@@ -0,0 +1,144 @@
- id: "http://www.oecd.org/science/inno/38235147.pdf?1"
scheme: FOS
subject: "Natural sciences"
- id: "http://www.oecd.org/science/inno/38235147.pdf?1.1"
scheme: FOS
subject: "Mathematics"
- id: "http://www.oecd.org/science/inno/38235147.pdf?1.2"
scheme: FOS
subject: "Computer and information sciences"
- id: "http://www.oecd.org/science/inno/38235147.pdf?1.3"
scheme: FOS
subject: "Physical sciences"
- id: "http://www.oecd.org/science/inno/38235147.pdf?1.4"
scheme: FOS
subject: "Chemical sciences"
- id: "http://www.oecd.org/science/inno/38235147.pdf?1.5"
scheme: FOS
subject: "Earth and related environmental sciences"
- id: "http://www.oecd.org/science/inno/38235147.pdf?1.6"
scheme: FOS
subject: "Biological sciences"
- id: "http://www.oecd.org/science/inno/38235147.pdf?1.7"
scheme: FOS
subject: "Other natural sciences"
- id: "http://www.oecd.org/science/inno/38235147.pdf?2"
scheme: FOS
subject: "Engineering and technology"
- id: "http://www.oecd.org/science/inno/38235147.pdf?2.1"
scheme: FOS
subject: "Civil engineering"
- id: "http://www.oecd.org/science/inno/38235147.pdf?2.2"
scheme: FOS
subject: "Electrical engineering, electronic engineering, information engineering"
- id: "http://www.oecd.org/science/inno/38235147.pdf?2.3"
scheme: FOS
subject: "Mechanical engineering"
- id: "http://www.oecd.org/science/inno/38235147.pdf?2.4"
scheme: FOS
subject: "Chemical engineering"
- id: "http://www.oecd.org/science/inno/38235147.pdf?2.5"
scheme: FOS
subject: "Materials engineering"
- id: "http://www.oecd.org/science/inno/38235147.pdf?2.6"
scheme: FOS
subject: "Medical engineering"
- id: "http://www.oecd.org/science/inno/38235147.pdf?2.7"
scheme: FOS
subject: "Environmental engineering"
- id: "http://www.oecd.org/science/inno/38235147.pdf?2.8"
scheme: FOS
subject: "Environmental biotechnology"
- id: "http://www.oecd.org/science/inno/38235147.pdf?2.9"
scheme: FOS
subject: "Industrial biotechnology"
- id: "http://www.oecd.org/science/inno/38235147.pdf?2.10"
scheme: FOS
subject: "Nano technology"
- id: "http://www.oecd.org/science/inno/38235147.pdf?2.11"
scheme: FOS
subject: "Other engineering and technologies"
- id: "http://www.oecd.org/science/inno/38235147.pdf?3"
scheme: FOS
subject: "Medical and health sciences"
- id: "http://www.oecd.org/science/inno/38235147.pdf?3.1"
scheme: FOS
subject: "Basic medicine"
- id: "http://www.oecd.org/science/inno/38235147.pdf?3.2"
scheme: FOS
subject: "Clinical medicine"
- id: "http://www.oecd.org/science/inno/38235147.pdf?3.3"
scheme: FOS
subject: "Health sciences"
- id: "http://www.oecd.org/science/inno/38235147.pdf?3.4"
scheme: FOS
subject: "Health biotechnology"
- id: "http://www.oecd.org/science/inno/38235147.pdf?3.5"
scheme: FOS
subject: "Other medical sciences"
- id: "http://www.oecd.org/science/inno/38235147.pdf?4"
scheme: FOS
subject: "Agricultural sciences"
- id: "http://www.oecd.org/science/inno/38235147.pdf?4.1"
scheme: FOS
subject: "Agriculture, forestry, and fisheries"
- id: "http://www.oecd.org/science/inno/38235147.pdf?4.2"
scheme: FOS
subject: "Animal and dairy science"
- id: "http://www.oecd.org/science/inno/38235147.pdf?4.3"
scheme: FOS
subject: "Veterinary science"
- id: "http://www.oecd.org/science/inno/38235147.pdf?4.4"
scheme: FOS
subject: "Agricultural biotechnology"
- id: "http://www.oecd.org/science/inno/38235147.pdf?4.5"
scheme: FOS
subject: "Other agricultural sciences"
- id: "http://www.oecd.org/science/inno/38235147.pdf?5"
scheme: FOS
subject: "Social science"
- id: "http://www.oecd.org/science/inno/38235147.pdf?5.1"
scheme: FOS
subject: "Psychology"
- id: "http://www.oecd.org/science/inno/38235147.pdf?5.2"
scheme: FOS
subject: "Economics and business"
- id: "http://www.oecd.org/science/inno/38235147.pdf?5.3"
scheme: FOS
subject: "Educational sciences"
- id: "http://www.oecd.org/science/inno/38235147.pdf?5.4"
scheme: FOS
subject: "Sociology"
- id: "http://www.oecd.org/science/inno/38235147.pdf?5.5"
scheme: FOS
subject: "Law"
- id: "http://www.oecd.org/science/inno/38235147.pdf?5.6"
scheme: FOS
subject: "Political science"
- id: "http://www.oecd.org/science/inno/38235147.pdf?5.7"
scheme: FOS
subject: "Social and economic geography"
- id: "http://www.oecd.org/science/inno/38235147.pdf?5.8"
scheme: FOS
subject: "Media and communications"
- id: "http://www.oecd.org/science/inno/38235147.pdf?5.9"
scheme: FOS
subject: "Other social sciences"
- id: "http://www.oecd.org/science/inno/38235147.pdf?6"
scheme: FOS
subject: "Humanities"
- id: "http://www.oecd.org/science/inno/38235147.pdf?6.1"
scheme: FOS
subject: "History and archaeology"
- id: "http://www.oecd.org/science/inno/38235147.pdf?6.2"
scheme: FOS
subject: "Languages and literature"
- id: "http://www.oecd.org/science/inno/38235147.pdf?6.3"
scheme: FOS
subject: "Philosophy, ethics and religion"
- id: "http://www.oecd.org/science/inno/38235147.pdf?6.4"
scheme: FOS
subject: "Arts (arts, history of arts, performing arts, music)"
- id: "http://www.oecd.org/science/inno/38235147.pdf?6.5"
scheme: FOS
subject: "Other humanities"
@@ -0,0 +1,11 @@
// This file is part of InvenioRDM
// Copyright (C) 2023 CERN.
//
// Invenio App RDM is free software; you can redistribute it and/or modify it
// under the terms of the MIT License; see LICENSE file for more details.
/**
* Add here all the overridden components of your app.
*/
export const overriddenComponents = {}
@@ -0,0 +1,96 @@
/*
████████╗██╗ ██╗███████╗███╗ ███╗███████╗███████╗
╚══██╔══╝██║ ██║██╔════╝████╗ ████║██╔════╝██╔════╝
██║ ███████║█████╗ ██╔████╔██║█████╗ ███████╗
██║ ██╔══██║██╔══╝ ██║╚██╔╝██║██╔══╝ ╚════██║
██║ ██║ ██║███████╗██║ ╚═╝ ██║███████╗███████║
╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝╚══════╝
*/
/*******************************
Theme Selection
*******************************/
/* To override a theme for an individual element
specify theme name below
*/
/* Global */
@site : 'rdm';
@reset : 'default';
/* Elements */
@button : 'rdm';
@container : 'rdm';
@divider : 'rdm';
@flag : 'rdm';
@header : 'rdm';
@icon : 'default';
@image : 'rdm';
@input : 'rdm';
@label : 'rdm';
@list : 'rdm';
@loader : 'rdm';
@placeholder : 'rdm';
@rail : 'rdm';
@reveal : 'rdm';
@segment : 'rdm';
@step : 'rdm';
/* Collections */
@breadcrumb : 'rdm';
@form : 'rdm';
@grid : 'rdm';
@menu : 'rdm';
@message : 'rdm';
@table : 'rdm';
/* Modules */
@accordion : 'rdm';
@checkbox : 'rdm';
@dimmer : 'rdm';
@dropdown : 'rdm';
@embed : 'rdm';
@modal : 'rdm';
@nag : 'rdm';
@popup : 'rdm';
@progress : 'rdm';
@rating : 'rdm';
@search : 'rdm';
@shape : 'rdm';
@sidebar : 'rdm';
@sticky : 'rdm';
@tab : 'rdm';
@transition : 'default';
/* Views */
@ad : 'rdm';
@card : 'rdm';
@comment : 'rdm';
@feed : 'rdm';
@item : 'rdm';
@statistic : 'rdm';
/*******************************
Folders
*******************************/
/* Path to theme packages */
@themesFolder : '~semantic-ui-less/themes';
/* Path to site override folder */
@siteFolder : '../../less/site';
@imagesFolder : '../../images';
/*******************************
Import Theme
*******************************/
@import (multiple) "themes/rdm/theme.less";
@fontPath : "../../../themes/@{theme}/assets/fonts";
/* End Config */
@@ -0,0 +1 @@
# This file exists only to add templates/ folder to git repository.
@@ -0,0 +1 @@
# This file exists only to add templates/ folder to git repository.
@@ -0,0 +1,128 @@
# Example of a full infrastructure stack
#
# Note, this file is not suitable for a production deployment. It is only an
# example of all the infrastructure components needed in a real production
# deployment.
#
# Usage::
#
# $ docker compose up -f docker-compose.full.yml -d
#
# Following services are included:
# - Frontend: Nginx (exposed ports: 40 and 443)
# - UI application: UWSGI (not exposed)
# - API application: UWSGI (not exposed)
# - Cache: Redis (exposed port: 6379)
# - DB: (PostgresSQL/MySQL) (exposed port: 5432 or 3306)
# - Message queue: RabbitMQ (exposed ports: 5672, 15672)
# - Search platform: (OpenSearch) (exposed ports: 9200, 9600)
# - OpenSearch Dashboard/Kibana (view OS/ES indexes) (exposed ports: 5601)
#
services:
cache:
extends:
file: docker-services.yml
service: cache
volumes:
- cache_data:/data
db:
extends:
file: docker-services.yml
service: db
volumes:
- data:/var/lib/postgresql/data
mq:
extends:
file: docker-services.yml
service: mq
volumes:
- mq_data:/var/lib/rabbitmq
search:
extends:
file: docker-services.yml
service: search
volumes:
- search_data:/usr/share/opensearch/data
opensearch-dashboards:
extends:
file: docker-services.yml
service: opensearch-dashboards
pgadmin:
extends:
file: docker-services.yml
service: pgadmin
s3:
extends:
file: docker-services.yml
service: s3
# Frontend
frontend:
extends:
file: docker-services.yml
service: frontend
volumes:
- static_data:/opt/invenio/var/instance/static
- ./docker/nginx/conf.d:/etc/nginx/conf.d:Z
depends_on:
- web-ui
- web-api
ports:
- "${DOCKER_SERVICES_IP_BIND:-127.0.0.1}:8080:80"
- "${DOCKER_SERVICES_IP_BIND:-127.0.0.1}:8443:443"
# UI Application
web-ui:
extends:
file: docker-services.yml
service: app
command: uwsgi /opt/invenio/var/instance/uwsgi_ui.ini
image: i-form-data-repository:latest
ports:
- "${DOCKER_SERVICES_IP_BIND:-127.0.0.1}:5000:5000"
volumes:
- static_data:/opt/invenio/var/instance/static
# API Rest Application
web-api:
extends:
file: docker-services.yml
service: app
command: uwsgi /opt/invenio/var/instance/uwsgi_rest.ini
image: i-form-data-repository:latest
ports:
- "${DOCKER_SERVICES_IP_BIND:-127.0.0.1}:5001:5000"
# Worker
worker:
extends:
file: docker-services.yml
service: app
command: celery -A invenio_app.celery worker --beat --loglevel=INFO
image: i-form-data-repository:latest
depends_on:
search:
condition: service_started
cache:
condition: service_started
db:
condition: service_started
mq:
condition: service_started
# Jobs scheduler
scheduler:
extends:
file: docker-services.yml
service: app
command: celery -A invenio_app.celery beat --scheduler invenio_jobs.services.scheduler:RunScheduler --loglevel=INFO
image: i-form-data-repository:latest
depends_on:
mq:
condition: service_started
db:
condition: service_started
volumes:
static_data:
data:
search_data:
mq_data:
cache_data:
+47
View File
@@ -0,0 +1,47 @@
# Backend services needed for development.
#
# This file will start all the backend services needed to run InvenioRDM
# locally in development mode.
#
# Usage::
#
# $ docker compose up -d
#
# Following services are included:
# - Cache: Redis (exposed port: 6379)
# - DB: (PostgresSQL/MySQL) (exposed port: 5432 or 3306)
# - Message queue: RabbitMQ (exposed ports: 5672, 15672)
# - OpenSearch (exposed ports: 9200, 9600)
# - Kibana (view ES indexes) (exposed ports: 5601)
#
services:
cache:
extends:
file: docker-services.yml
service: cache
db:
extends:
file: docker-services.yml
service: db
mq:
extends:
file: docker-services.yml
service: mq
search:
extends:
file: docker-services.yml
service: search
opensearch-dashboards:
extends:
file: docker-services.yml
service: opensearch-dashboards
pgadmin:
extends:
file: docker-services.yml
service: pgadmin
s3:
extends:
file: docker-services.yml
service: s3
volumes:
data:
+111
View File
@@ -0,0 +1,111 @@
services:
app:
build:
context: ./
args:
- ENVIRONMENT=DEV
image: i-form-data-repository
restart: "unless-stopped"
environment:
- "INVENIO_ACCOUNTS_SESSION_REDIS_URL=redis://cache:6379/1"
- "INVENIO_BROKER_URL=amqp://guest:guest@mq:5672/"
- "INVENIO_CACHE_REDIS_URL=redis://cache:6379/0"
- "INVENIO_CACHE_TYPE=redis"
- "INVENIO_CELERY_BROKER_URL=amqp://guest:guest@mq:5672/"
- "INVENIO_CELERY_RESULT_BACKEND=redis://cache:6379/2"
- "INVENIO_COMMUNITIES_IDENTITIES_CACHE_REDIS_URL=redis://cache:6379/4"
- "INVENIO_SEARCH_HOSTS=['search:9200']"
- "INVENIO_SECRET_KEY=CHANGE_ME"
- "INVENIO_SQLALCHEMY_DATABASE_URI=postgresql+psycopg2://i-form-data-repository:i-form-data-repository@db/i-form-data-repository"
- "INVENIO_WSGI_PROXIES=2"
- "INVENIO_RATELIMIT_STORAGE_URL=redis://cache:6379/3"
frontend:
build:
context: ./docker/nginx/
dockerfile: Dockerfile
image: i-form-data-repository-frontend
restart: "unless-stopped"
ports:
- "${DOCKER_SERVICES_IP_BIND:-127.0.0.1}:8080:80"
- "${DOCKER_SERVICES_IP_BIND:-127.0.0.1}:8443:443"
cache:
image: docker.io/library/redis:7
restart: "unless-stopped"
read_only: true
ports:
- "${DOCKER_SERVICES_IP_BIND:-127.0.0.1}:6379:6379"
db:
image: docker.io/library/postgres:14.13
restart: "unless-stopped"
environment:
- "POSTGRES_USER=i-form-data-repository"
- "POSTGRES_PASSWORD=i-form-data-repository"
- "POSTGRES_DB=i-form-data-repository"
ports:
- "${DOCKER_SERVICES_IP_BIND:-127.0.0.1}:5432:5432"
pgadmin:
image: docker.io/dpage/pgadmin4:6
restart: "unless-stopped"
ports:
- "${DOCKER_SERVICES_IP_BIND:-127.0.0.1}:5050:80"
environment:
PGADMIN_DEFAULT_EMAIL: "info@repo.i-form.ie"
PGADMIN_DEFAULT_PASSWORD: "i-form-data-repository"
volumes:
- ./docker/pgadmin/servers.json:/pgadmin4/servers.json
mq:
image: docker.io/library/rabbitmq:3-management
restart: "unless-stopped"
ports:
- "${DOCKER_SERVICES_IP_BIND:-127.0.0.1}:15672:15672"
- "${DOCKER_SERVICES_IP_BIND:-127.0.0.1}:5672:5672"
search:
image: docker.io/opensearchproject/opensearch:2.17.1
restart: "unless-stopped"
environment:
# settings only for development. DO NOT use in production!
- bootstrap.memory_lock=true
- "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m"
- "OPENSEARCH_INITIAL_ADMIN_PASSWORD=guekxe3mvqieke1!%&ieIADE"
- "DISABLE_INSTALL_DEMO_CONFIG=true"
- "DISABLE_SECURITY_PLUGIN=true"
- "discovery.type=single-node"
- "cluster.routing.allocation.disk.threshold_enabled=false"
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
mem_limit: 2g
ports:
- "${DOCKER_SERVICES_IP_BIND:-127.0.0.1}:9200:9200"
- "${DOCKER_SERVICES_IP_BIND:-127.0.0.1}:9600:9600"
opensearch-dashboards:
image: docker.io/opensearchproject/opensearch-dashboards:2.17.1
ports:
- "${DOCKER_SERVICES_IP_BIND:-127.0.0.1}:5601:5601"
expose:
- "5601"
environment:
# settings only for development. DO NOT use in production!
- 'OPENSEARCH_HOSTS=["http://search:9200"]'
- "DISABLE_SECURITY_DASHBOARDS_PLUGIN=true"
s3:
image: docker.io/minio/minio:RELEASE.2022-10-24T18-35-07Z
restart: "unless-stopped"
ports:
- "${DOCKER_SERVICES_IP_BIND:-127.0.0.1}:9000:9000"
- "${DOCKER_SERVICES_IP_BIND:-127.0.0.1}:9001:9001"
environment:
MINIO_ROOT_USER: CHANGE_ME
MINIO_ROOT_PASSWORD: CHANGE_ME
volumes:
- ./data:/data
command: server /data --console-address :9001
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
@@ -0,0 +1,5 @@
FROM docker.io/library/nginx
COPY nginx.conf /etc/nginx/nginx.conf
COPY conf.d/* /etc/nginx/conf.d/
COPY test.key /etc/ssl/private/test.key
COPY test.crt /etc/ssl/certs/test.crt
@@ -0,0 +1,129 @@
# This nginx configuration defines two servers, one on port 80 and one on port
# 443. All traffix on port 80 is redirect to port 443 on SSL.
#
# Nginx proxies all requests on port 443 to upstream the application server
# which is expected to be running on port 5000/5001.
# HTTP server
server {
# Redirects all requests to https. - this is in addition to HAProxy which
# already redirects http to https. This redirect is needed in case you access
# the server directly (e.g. useful for debugging).
listen 80 default_server; # IPv4
listen [::]:80 default_server; # IPv6
server_name _;
return 301 https://$host$request_uri;
}
# Upstream servers
upstream ui_server {
server web-ui:5000;
}
upstream api_server {
server web-api:5000;
}
# HTTPS server
server {
listen 443 default_server ssl http2; # IPv4
listen [::]:443 default_server ssl http2; # IPv6
server_name _;
charset utf-8;
keepalive_timeout 5;
# SSL configuration according to best practices from
# https://mozilla.github.io/server-side-tls/ssl-config-generator/
# The provided certificate (test.crt) and private key (test.key) is only for
# testing and must never be used in production environment.
ssl_certificate /etc/ssl/certs/test.crt;
ssl_certificate_key /etc/ssl/private/test.key;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
# Accepted protocols and ciphers
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_prefer_server_ciphers on;
add_header Strict-Transport-Security "max-age=15768000"; # 6 months
# Request ID tracing (allows end-to-end tracking of requests for better
# troubleshooting)
add_header X-Request-ID $request_id;
# The request body is sent to the proxied server immediately as it is
# received
proxy_request_buffering off;
# Sets the HTTP protocol v1.1 for proxying in order to not use the buffer
# in case of chunked transfer encoding
proxy_http_version 1.1;
# Proxying to the application server
## UI server
location / {
uwsgi_pass ui_server;
include uwsgi_params;
uwsgi_buffering off;
uwsgi_request_buffering off;
chunked_transfer_encoding off;
uwsgi_param HTTP_HOST $host;
uwsgi_param HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for;
uwsgi_param HTTP_X_FORWARDED_PROTO $scheme;
# Pass request id to the ui server
uwsgi_param HTTP_X_REQUEST_ID $request_id;
# X-Session-ID / X-User-ID is read by nginx and included in the logs,
# however we don't want to expose them to clients so we are hiding them.
uwsgi_hide_header X-Session-ID;
uwsgi_hide_header X-User-ID;
# Max upload size (except for files) is set to 100mb as default.
client_max_body_size 100m;
}
## Most API
location /api {
uwsgi_pass api_server;
include uwsgi_params;
uwsgi_buffering off;
uwsgi_request_buffering off;
chunked_transfer_encoding off;
uwsgi_param HTTP_HOST $host;
uwsgi_param HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for;
uwsgi_param HTTP_X_FORWARDED_PROTO $scheme;
# Pass request id to the api server
uwsgi_param HTTP_X_REQUEST_ID $request_id;
# X-Session-ID / X-User-ID is read by nginx and included in the logs,
# however we don't want to expose them to clients so we are hiding them.
uwsgi_hide_header X-Session-ID;
uwsgi_hide_header X-User-ID;
# Max upload size (except for files) is set to 100mb as default.
client_max_body_size 100m;
}
## API files
# Another location is defined in order to allow large file uploads in the files
# API without exposing the other parts of the application to receive huge
# request bodies. This includes part content uploads of multipart file uploads.
location ~ /api/records/.+/draft/files/.+/content(/[0-9]+)?/?$ {
gzip off;
uwsgi_pass api_server;
include uwsgi_params;
uwsgi_buffering off;
uwsgi_request_buffering off;
chunked_transfer_encoding off;
uwsgi_param HTTP_HOST $host;
uwsgi_param HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for;
uwsgi_param HTTP_X_FORWARDED_PROTO $scheme;
# Pass request id to api server
uwsgi_param HTTP_X_REQUEST_ID $request_id;
# X-Session-ID / X-User-ID is read by nginx and included in the logs,
# however we don't want to expose them to clients so we are hiding them.
uwsgi_hide_header X-Session-ID;
uwsgi_hide_header X-User-ID;
# Max upload size for files is set to 50GB (configure as needed).
client_max_body_size 50G;
}
# Static content is served directly by nginx and not the application server.
location /static {
alias /opt/invenio/var/instance/static;
autoindex off;
}
}
@@ -0,0 +1,81 @@
user nginx;
worker_processes 1;
error_log /var/log/nginx/error_real.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
types {
# The default MIME types file doesn't assign "application/javascript"
# to "*.mjs" files (ECMAScript modules)
application/javascript js mjs;
}
# Standard log format
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# Request tracing log format - includes request id, session id, user id,
# and request timing.
log_format trace '$remote_addr - [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" $request_id '
'$msec $request_time '
'$upstream_http_x_session_id $upstream_http_x_user_id';
access_log /var/log/nginx/access.log trace;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
gzip on;
gzip_disable "msie6";
gzip_http_version 1.1;
gzip_comp_level 5; # or anything between 4-6
gzip_min_length 100;
gzip_proxied any;
# We may need more mime-types here (eg. 'application/x-bibtex')
gzip_types
application/atom+xml
application/javascript
application/json
application/ld+json
application/manifest+json
application/octet-stream
application/rss+xml
application/vnd.geo+json
application/vnd.ms-fontobject
application/x-font-ttf
application/x-javascript
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
application/xml+rss
font/opentype
image/bmp
image/svg+xml
image/x-icon
text/cache-manifest
text/css
text/javascript
text/plain
text/vcard
text/vnd.rim.location.xloc
text/vtt
text/x-component
text/x-cross-domain-policy
text/xml;
gzip_vary on;
include /etc/nginx/conf.d/*.conf;
}
@@ -0,0 +1,33 @@
-----BEGIN CERTIFICATE-----
MIIFpzCCA4+gAwIBAgIUSz9J4Gq7+Qn5md8T24tFHEPr3OcwDQYJKoZIhvcNAQEL
BQAwYzELMAkGA1UEBhMCQ0gxCjAIBgNVBAgMAS4xCjAIBgNVBAcMAS4xCjAIBgNV
BAoMAS4xCjAIBgNVBAsMAS4xEjAQBgNVBAMMCWxvY2FsaG9zdDEQMA4GCSqGSIb3
DQEJARYBLjAeFw0yNTExMjcwOTQ1MTVaFw0yNjExMjcwOTQ1MTVaMGMxCzAJBgNV
BAYTAkNIMQowCAYDVQQIDAEuMQowCAYDVQQHDAEuMQowCAYDVQQKDAEuMQowCAYD
VQQLDAEuMRIwEAYDVQQDDAlsb2NhbGhvc3QxEDAOBgkqhkiG9w0BCQEWAS4wggIi
MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC24k/6OfzIdlxXvrlW1xSo7QZp
55sWsct0NK1bPiWElEybZgcVMYg5nK037Nk9xZPh59j/LD7wKvw+S6RVd6k8+UBU
ms4QrZOSG9CyMXlneEc+Pl/4pzM+2R1NMQG0f9tsc3R5Eom+e5sK4XEcVPrrcHs0
QKYZT734lVq1oFKmVHn/2CfECfwv+M3Vh2uY2s1vDWQL2HGCumeyHspbuIxfX+zA
KlR3WlOC82g13eIpJRVQeVznOPm7O1c8qSMEe32YR6JjsYwaEGPX5f7EnOtp0KLu
YusP8mgotU5h32KXmyGGPQa9tjUWvjiEuZMGeRY51ppsdDg4N8HVEkuKXkEU7BxS
19kFQUZUrdH8a9ziO+xGQ63qJ0kZxqn3rHXsuMHpqf/1s9oscj/SIITuXQVGm/I0
tE7cd8d+FxxS3ZAWYtNneq08810Jt3EKHzqnKimdUdK5ewV6suQgm9zAOdesOayQ
JBsrjtJfYptveyQyx5WNi2raKPSzMnsCJ3wQqijR8hmX6uBkjmDod+fcqxp++1d7
b5G6uZqp1BbUBn822Zj3Y3xA7Ytc0Gw1qGWE22LG6//JxZ5BnINWeOvic0i6x7Hw
qeBjJM80wUsTAK8khE+YnBe1xhiexJMXn5MnrIljjv7u79EqSAkx/hBL0co14WI8
5HxbqKTsub4g8EIfuQIDAQABo1MwUTAdBgNVHQ4EFgQUgaT39u46Jud7DJdbgF6I
pEB6XI0wHwYDVR0jBBgwFoAUgaT39u46Jud7DJdbgF6IpEB6XI0wDwYDVR0TAQH/
BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAc8bweJSg/8S82x0cabl4bl+WiqG2
PYSzPgMnMXK0rbx8sss9cUIeKoOEWR0DzLdnTE9xPI4rLaKwK3LRv4JWmx1QjIac
tvrnDdoO6uKubqS4Vf0Q+QSeiVIIvu4qveK8syhJaEZJtQiUaYanxYSkn8skOhoL
ZZv/t8Iu0KDJ1EI5eNMCDTzny8VOYk08Nx97TAGazgCp6fx3xpk7mc3iNQcCrtmC
3emhW0Pgro8tHg9bECtugLk/pyBys0mt65gUMXu572LOUdNoOq1jbsXU2/HpA9G2
/5IntXmP8k6i7w+ZtbN8JpwfUTg25JSGYVEZ0SrtAj6AfLZvG+MdrhWcw7XCbm2a
94h2O1H0rQ2u4EEOqPpAXByVCyfGmQQxzyCinLy42eNPcAiehdSDEgTInIHxmIik
PqCYyWL/s1ltbV+zai1FKK7GU2N911e5kcioGHIpWjo/a+aNsmcw+umpSjyFkQ2x
FtE8i4oePPosSNhDZdpv+0PDygKGU8uMZLO09IOeUIeyZlphCUglBM2dDZY3Rpzg
AQxYMVvP75ceNl4XZ0UFbzM937/a6ElsOSrP1zNHPV8AGWX2VNKWqGMd+qADu8/A
3pcDjJk+YLwT6343+tYc7rRu8skXtMxxRgwvAUdCUaTjNT924PaOf6ImoVhpPgkf
1i0GCvJT5yQK4q4=
-----END CERTIFICATE-----
@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQC24k/6OfzIdlxX
vrlW1xSo7QZp55sWsct0NK1bPiWElEybZgcVMYg5nK037Nk9xZPh59j/LD7wKvw+
S6RVd6k8+UBUms4QrZOSG9CyMXlneEc+Pl/4pzM+2R1NMQG0f9tsc3R5Eom+e5sK
4XEcVPrrcHs0QKYZT734lVq1oFKmVHn/2CfECfwv+M3Vh2uY2s1vDWQL2HGCumey
HspbuIxfX+zAKlR3WlOC82g13eIpJRVQeVznOPm7O1c8qSMEe32YR6JjsYwaEGPX
5f7EnOtp0KLuYusP8mgotU5h32KXmyGGPQa9tjUWvjiEuZMGeRY51ppsdDg4N8HV
EkuKXkEU7BxS19kFQUZUrdH8a9ziO+xGQ63qJ0kZxqn3rHXsuMHpqf/1s9oscj/S
IITuXQVGm/I0tE7cd8d+FxxS3ZAWYtNneq08810Jt3EKHzqnKimdUdK5ewV6suQg
m9zAOdesOayQJBsrjtJfYptveyQyx5WNi2raKPSzMnsCJ3wQqijR8hmX6uBkjmDo
d+fcqxp++1d7b5G6uZqp1BbUBn822Zj3Y3xA7Ytc0Gw1qGWE22LG6//JxZ5BnINW
eOvic0i6x7HwqeBjJM80wUsTAK8khE+YnBe1xhiexJMXn5MnrIljjv7u79EqSAkx
/hBL0co14WI85HxbqKTsub4g8EIfuQIDAQABAoICABfEBBmj1HYmb2yVo9clnxEu
sBEuIEjMNQC2YbrEMjLu5J+jHBOEesvl0Nq+JCLzXHrUWq4aTVl/dIUR5lqW8L60
M0hrT5D6RX2MsMufQ0QPbM6pY2ZYMAAgTb78udh/bv/CZyXeo1jGDklVL5I7dtoG
pXQOXKdYZfr6Sa3llif4PVxidhRzKbsALZtsfC6CbITcbB5f86xF1fjfKHPP4Sn5
uLXmKlDSQ5z2TZoGaf/nykPJaanAjS9oEDeZUSwhchpKYM9swKSYcakaQcfCDpOT
IcExyJMrcJ6tpPByC4lhBvO/VXNszKxWbtjMls8WCC3e9fVXCwE/OaibNobWJcW+
hbZr/rZxPZM948f2l0xRTUB/o8stQ1wY95oIU27C/tnZamDawnwmLVwP7LiSZamI
fUGLPS4UpKAXfVFZzEqV6glkQ1DhwjgfkVBaenTQbWhUn6NddTzcb5v/UZuwC3Ze
M+4M9zc8UAV4IxflLw1Dp2bdi3yU4pwQh5+sFvOaRLC8AQHoZsS3ueviFh5Mfcy4
iIHbEbP2VbhyM6CRbxW3HQBdmCdfNFl7/62rEs+TlwpnL5xGpBFYIkU1wjFn1U+S
VN2EtWMv/+HCjKtdsZ+yE01tfQdu2mAAvRQNMVEWCUhTt9JQQ2tXWo+wndSCFVZV
VcC7saRySZbcDkIjhm8JAoIBAQDaq682Cpg6YiQTTByzlMDAv1d7/j1EPzIkHgqx
sud42Vpu2MKpWq3CZKq5RAjLPQH0djAI9r7sGPQwwZFsFOJ9sAoPz29azVRpI+ay
Re0gs8itqMjjjGGXw6pN4tUbMovwAUpSFNbGj0ux0idmmqdxr1YA3sDsfP4ApY24
E+bq1W1aBkGU4nJwPGxcRIA9L1v4NhpT1L+N/S2TcQuSaFFuWvxFqi86OC3dnqid
e/obG1yR9AwWQQQVoFUvADpJa/7TUGq4ij8bMT6dcrQaQ4RLNbMtHk65x+Qttv//
hwZe+07A/YDBaLWqUBueKw5S9al0lheAR31litxEWRZnVwPVAoIBAQDWGq+x0uvw
TSCc9QHuYXGGq83SwRmnnECw2Uxf+PWTbL/6ryJqAFEVBTb3Kz04BKjOqHW8zUq+
vxBxGI4J1SDr5dbgyGWDbTf+vHr6xDPD/JBM7sS3nk1In1gsHHyG5rP+gwffD/07
1RECsio88EYDOzGqjMGOnSnGhDaoK47I+yOGXQPmqX2X0YC4ycAOv3BvWh6daYkb
9rztbRz2ngnMu6Ehj/hCchQj3q4CliNR7YIfMHl86hVoHhs2ymvg+hrgqfh7QFnV
Atzcuh5aEujACZLtUJOst6+we5u2bjSHwPXy5h7eBcCwH0mmgRBZVgBbyALHnck1
KxLMgMPXhXJVAoIBAQDSDjg6VoUTGHGFJAkyLQPYZDX6wyhBZd+ZuE4Xkz8t5MUt
VAXyv0vJQACMBaHY8hrtpZbRFY4jqHjyWQ+D3rAPgsq3k1FpzXJ3qWgT+n4meu2c
fFW12IVrTydKuEp0XOL2Q5cMMD588OwKvlDhDFErMP4RyelTg2JQZrgzitK45Rqt
bvMSvVCnJjQFkjwKCnNzhS1XODhmgj2EtAQkuRb4Rmit1ySU7aCJkr5wwcZowajz
/5aYzg3JZIJPqw1SuG5KuaY67Xpfebencac2z4LG6KfdAI8pga5ch710zlU9anWl
iB9mK1rPZzKQhtW0tY35k7Cxpnr7zx92fIm77WedAoIBAHxaI5F0n/SB119SLjz1
+6nsPy8ZWH0xE6Gjk+hqALgPgbFn5uUKKg27aaFFS9ktW54r2bY+xhrjffkx+c1c
LDLW22bS/aLH3K3nasYbDrXWCzmjtD2xg9GaOuvj36+6bvBzyi6UatBFgAvAzyd1
pjRaPQ6BkinyvkC+qcAjDFtPAeMYQxvFdVyoIcsx4oquRe9muEFU+n1zYWfE5/2U
7LwsffmwVNDC0U/EFe0Kppj/CYRz8xvKGYTPd57rEp0oplO2ZMuxJHvDnePVdat7
MBPZe6y6EAtQ5InsQRREDd6LBE5/uY3aaX/hrDU44PYCLVMhZ/voeOSYj+KXJygW
KcECggEARPZy6CC8dT1bJOdh2o44qgOmbfZqCThzWeE0N7wsKJvHwAGNgB+qyl7H
cixUUcXfBQmezFN0MhVf7F7ShtuJdaVjfLKTjedPzqxGUBLDozt2rnVvMcOK5LKv
6BzRH8+Z8K97TDfEfCw493+9SVDTz/+jWy2USvBRc8DkNNU5QHqDfasVmEWd9xWc
621jPrF6UG2y75oiKIbgkrsgF9kXYCglzwa0Y1XSz7k6McX6aI6VpcqEKuDvchvD
xGpVvOatiDNsnYInf0yUPxDH0TRjfqiChzfz9qhNoWjFGcQO4Ax5Ba9Giub1cZfB
NkuWkf4v3IVpMofi+eIU909FiFXNeQ==
-----END PRIVATE KEY-----
@@ -0,0 +1,13 @@
{
"Servers": {
"1": {
"Name": "i-form-data-repository-db",
"Group": "Servers",
"Host": "i-form-data-repository-db-1",
"Port": 5432,
"MaintenanceDB": "postgres",
"Username": "i-form-data-repository",
"SSLMode": "prefer"
}
}
}
@@ -0,0 +1,14 @@
[uwsgi]
socket = 0.0.0.0:5000
stats = 0.0.0.0:9001
module = invenio_app.wsgi_rest:application
master = true
die-on-term = true
processes = 2
threads = 2
mount = /api=invenio_app.wsgi_rest:application
manage-script-name = true
wsgi-disable-file-wrapper = true
single-interpreter = true
buffer-size = 8192
reload-on-rss = 666
@@ -0,0 +1,12 @@
[uwsgi]
socket = 0.0.0.0:5000
stats = 0.0.0.0:9000
module = invenio_app.wsgi_ui:application
master = true
die-on-term = true
processes = 2
threads = 2
single-interpreter = true
buffer-size = 8192
wsgi-disable-file-wrapper = true
reload-on-rss = 666
+233
View File
@@ -0,0 +1,233 @@
"""
InvenioRDM settings for I-Form Data Repository project.
This file was automatically generated by 'invenio-cli init'.
For the full list of settings and their values, see
https://inveniordm.docs.cern.ch/operate/customize/configuration/.
"""
from datetime import datetime
from invenio_i18n import lazy_gettext as _
def _(x): # needed to avoid start time failure with lazy strings
return x
# Flask
# =====
# See https://flask.palletsprojects.com/en/1.1.x/config/
# Define the value of the cache control header `max-age` returned by the server when serving
# public files. Files will be cached by the browser for the provided number of seconds.
# See flask documentation for more information:
# https://flask.palletsprojects.com/en/2.1.x/config/#SEND_FILE_MAX_AGE_DEFAULT
SEND_FILE_MAX_AGE_DEFAULT = 300
# Use Rspack instead of Webpack for faster build times
WEBPACKEXT_PROJECT = "invenio_assets.webpack:rspack_project"
# SECURITY WARNING: keep the secret key used in production secret!
# Do not commit it to a source code repository.
# TODO: Set
SECRET_KEY="CHANGE_ME"
# Since HAProxy and Nginx route all requests no matter the host header
# provided, the trusted hosts variable is set to localhost. In production it
# should be set to the correct host and it is strongly recommended to only
# route correct hosts to the application.
TRUSTED_HOSTS = ['0.0.0.0', 'localhost', '127.0.0.1']
# Flask-SQLAlchemy
# ================
# See https://flask-sqlalchemy.palletsprojects.com/en/2.x/config/
# TODO: Set
SQLALCHEMY_DATABASE_URI="postgresql+psycopg2://i-form-data-repository:i-form-data-repository@localhost/i-form-data-repository"
# Invenio-App
# ===========
# See https://invenio-app.readthedocs.io/en/latest/configuration.html
APP_DEFAULT_SECURE_HEADERS = {
'content_security_policy': {
'default-src': [
"'self'",
'data:', # for fonts
"'unsafe-inline'", # for inline scripts and styles
"blob:", # for pdf preview
# Add your own policies here (e.g. analytics)
],
'script-src': [
"'self'", "blob:", "'wasm-unsafe-eval'" # for WASM-based workers
# Multipart file uploads use a Web Worker running `hash-wasm` to compute content checksums
# (e.g., MD5) of uploaded parts. This requires both 'blob:' and 'wasm-unsafe-eval' enabled in `script-src`.
],
},
'content_security_policy_report_only': False,
'content_security_policy_report_uri': None,
'force_file_save': False,
'force_https': True,
'force_https_permanent': False,
'frame_options': 'sameorigin',
'frame_options_allow_from': None,
'session_cookie_http_only': True,
'session_cookie_secure': True,
'strict_transport_security': True,
'strict_transport_security_include_subdomains': True,
'strict_transport_security_max_age': 31556926, # One year in seconds
'strict_transport_security_preload': False,
}
# Flask-Babel
# ===========
# See https://python-babel.github.io/flask-babel/#configuration
# Default locale (language)
BABEL_DEFAULT_LOCALE = 'en'
# Default time zone
BABEL_DEFAULT_TIMEZONE = 'Europe/Zurich'
# Invenio-I18N
# ============
# See https://invenio-i18n.readthedocs.io/en/latest/configuration.html
# Other supported languages (do not include BABEL_DEFAULT_LOCALE in list).
I18N_LANGUAGES = [
('ga', _('Irish')),
]
# Invenio-Theme
# =============
# See https://invenio-theme.readthedocs.io/en/latest/configuration.html
# Name used in header and UI
THEME_SITENAME = "I-Form Data Repository"
# Frontpage title
THEME_FRONTPAGE_TITLE = "I-Form Data Repository"
# Header logo
THEME_LOGO = 'images/invenio-rdm.svg'
# Invenio-App-RDM
# ===============
# See https://github.com/inveniosoftware/invenio-app-rdm/blob/master/invenio_app_rdm/config.py
# Instance's theme entrypoint file. Path relative to the ``assets/`` folder.
INSTANCE_THEME_FILE = './less/theme.less'
# Email address for administrator emails (like file checksum alerts)
APP_RDM_ADMIN_EMAIL_RECIPIENT = "info@repo.i-form.ie"
# Default values for the deposit form
APP_RDM_DEPOSIT_FORM_DEFAULTS = {
"publication_date": lambda: datetime.now().strftime("%Y-%m-%d"),
"rights": [
{
"id": "cc-by-4.0",
"title": "Creative Commons Attribution 4.0 International",
"description": ("The Creative Commons Attribution license allows "
"re-distribution and re-use of a licensed work "
"on the condition that the creator is "
"appropriately credited."),
"link": "https://creativecommons.org/licenses/by/4.0/legalcode",
}
],
"publisher": "I-Form Data Repository",
}
APP_RDM_DEPOSIT_FORM_AUTOCOMPLETE_NAMES = 'search' # "search_only" or "off"
# Enable new Uppy-based UI for depositing large files (Invenio RDM v13+)
APP_RDM_DEPOSIT_NG_FILES_UI_ENABLED = True
# Invenio-Files-Rest
# ==================
FILES_REST_STORAGE_FACTORY='invenio_s3.s3fs_storage_factory'
# Invenio-S3
# ==========
S3_ENDPOINT_URL='http://localhost:9000/'
S3_ACCESS_KEY_ID='CHANGE_ME'
S3_SECRET_ACCESS_KEY='CHANGE_ME'
# Allow S3 endpoint in the CSP rules
APP_DEFAULT_SECURE_HEADERS['content_security_policy']['default-src'].append(
S3_ENDPOINT_URL
)
# Invenio-Records-Resources
# =========================
# See https://github.com/inveniosoftware/invenio-records-resources/blob/master/invenio_records_resources/config.py
# TODO: Set with your own hostname when deploying to production
SITE_UI_URL = "https://127.0.0.1"
SITE_API_URL = "https://127.0.0.1/api"
# Invenio-RDM-Records
# ===================
# See https://inveniordm.docs.cern.ch/operate/customize/dois/
DATACITE_ENABLED = False
DATACITE_USERNAME = ""
DATACITE_PASSWORD = ""
DATACITE_PREFIX = ""
DATACITE_TEST_MODE = True
DATACITE_DATACENTER_SYMBOL = ""
# Authentication - Invenio-Accounts and Invenio-OAuthclient
# =========================================================
# See: https://inveniordm.docs.cern.ch/operate/customize/authentication/
# Invenio-Accounts
# ----------------
# See https://github.com/inveniosoftware/invenio-accounts/blob/master/invenio_accounts/config.py
ACCOUNTS_LOCAL_LOGIN_ENABLED = True # enable local login
SECURITY_REGISTERABLE = True # local login: allow users to register
SECURITY_RECOVERABLE = True # local login: allow users to reset the password
SECURITY_CHANGEABLE = True # local login: allow users to change psw
SECURITY_CONFIRMABLE = True # local login: users can confirm e-mail address
SECURITY_LOGIN_WITHOUT_CONFIRMATION = False # require users to confirm email before being able to login
# Invenio-OAuthclient
# -------------------
# See https://github.com/inveniosoftware/invenio-oauthclient/blob/master/invenio_oauthclient/config.py
OAUTHCLIENT_REMOTE_APPS = {} # configure external login providers
from invenio_oauthclient.views.client import auto_redirect_login
ACCOUNTS_LOGIN_VIEW_FUNCTION = auto_redirect_login # autoredirect to external login if enabled
OAUTHCLIENT_AUTO_REDIRECT_TO_EXTERNAL_LOGIN = False # autoredirect to external login
# Invenio-UserProfiles
# --------------------
USERPROFILES_READ_ONLY = False # allow users to change profile info (name, email, etc...)
# OAI-PMH
# =======
# See https://github.com/inveniosoftware/invenio-oaiserver/blob/master/invenio_oaiserver/config.py
OAISERVER_ID_PREFIX = "repo.i-form.ie"
"""The prefix that will be applied to the generated OAI-PMH ids."""
OAISERVER_ADMIN_EMAILS = [
"info@repo.i-form.ie",
]
# Invenio-Search
# --------------
SEARCH_INDEX_PREFIX = "i-form-data-repository-"
# Invenio-Administration
# ----------------------
from invenio_app_rdm import __version__
ADMINISTRATION_DISPLAY_VERSIONS = [
("invenio-app-rdm", f"v{__version__}"),
("i-form-data-repository", "v1.0.0"),
]
@@ -0,0 +1,104 @@
import glob
import os
import shutil
import json
def main():
# 1. Ensure ga directories exist and have translations.json
packages = [
'invenio_communities',
'invenio_search_ui',
'invenio_app_rdm',
'invenio_requests',
'invenio_jobs',
'invenio_rdm_records',
'invenio_administration'
]
bases = [
'/opt/invenio/src/.venv/lib/python3.12/site-packages',
'/opt/invenio/var/instance/assets/translations'
]
for pkg in packages:
for base in bases:
for root, dirs, files_in_dir in os.walk(base):
if root.endswith('messages') and pkg in root:
ga_dir = os.path.join(root, 'ga')
os.makedirs(ga_dir, exist_ok=True)
json_path = os.path.join(ga_dir, 'translations.json')
if not os.path.exists(json_path) or os.path.getsize(json_path) <= 2:
with open(json_path, 'w') as fp:
fp.write('{}')
print(f"Created empty translations.json: {json_path}")
# 2. Copy the actual compiled translations if they exist
copies = [
(
'/opt/invenio/src/.venv/lib/python3.12/site-packages/invenio_communities/assets/semantic-ui/translations/invenio_communities/messages/ga/translations.json',
'/opt/invenio/var/instance/assets/translations/invenio_communities/messages/ga/translations.json'
),
(
'/opt/invenio/src/.venv/lib/python3.12/site-packages/invenio_search_ui/assets/semantic-ui/translations/invenio_search_ui/messages/ga/translations.json',
'/opt/invenio/var/instance/assets/translations/invenio_search_ui/messages/ga/translations.json'
)
]
for src, dst in copies:
if os.path.exists(src):
os.makedirs(os.path.dirname(dst), exist_ok=True)
shutil.copy2(src, dst)
print(f"Copied compiled translations: {src} -> {dst}")
# 3. Extract app_rdm translations from global ga.json
global_ga = '/opt/invenio/var/instance/translations/ga.json'
app_rdm_dst = '/opt/invenio/var/instance/assets/translations/invenio_app_rdm/messages/ga/translations.json'
if os.path.exists(global_ga):
try:
with open(global_ga, 'r') as fp:
ga_data = json.load(fp)
app_rdm_data = ga_data.get('invenio_app_rdm', {})
os.makedirs(os.path.dirname(app_rdm_dst), exist_ok=True)
with open(app_rdm_dst, 'w') as fp:
json.dump(app_rdm_data, fp, indent=2)
print(f"Extracted invenio_app_rdm translations to {app_rdm_dst}")
# Also extract search_ui and communities if they were not copied
search_ui_dst = '/opt/invenio/var/instance/assets/translations/invenio_search_ui/messages/ga/translations.json'
if 'invenio_search_ui' in ga_data:
os.makedirs(os.path.dirname(search_ui_dst), exist_ok=True)
with open(search_ui_dst, 'w') as fp:
json.dump(ga_data['invenio_search_ui'], fp, indent=2)
print(f"Extracted invenio_search_ui translations to {search_ui_dst}")
communities_dst = '/opt/invenio/var/instance/assets/translations/invenio_communities/messages/ga/translations.json'
if 'invenio_communities' in ga_data:
os.makedirs(os.path.dirname(communities_dst), exist_ok=True)
with open(communities_dst, 'w') as fp:
json.dump(ga_data['invenio_communities'], fp, indent=2)
print(f"Extracted invenio_communities translations to {communities_dst}")
except Exception as e:
print(f"Error extracting translations: {e}")
# 4. Patch all _generatedTranslations.js files
files = glob.glob('/opt/invenio/src/.venv/lib/python3.12/site-packages/**/_generatedTranslations.js', recursive=True) + glob.glob('/opt/invenio/var/instance/assets/**/_generatedTranslations.js', recursive=True)
for f in files:
with open(f, 'r') as fp:
content = fp.read()
if 'TRANSLATE_GA' not in content:
lines = content.split('\n')
last_import = -1
for i, line in enumerate(lines):
if line.startswith('import '):
last_import = i
if last_import != -1:
lines.insert(last_import + 1, 'import TRANSLATE_GA from "./ga/translations.json";')
content = '\n'.join(lines)
if 'export const translations = {' in content:
content = content.replace(
'export const translations = {',
'export const translations = {\n ga: { translation: TRANSLATE_GA },'
)
with open(f, 'w') as fp:
fp.write(content)
print(f"Patched _generatedTranslations.js: {f}")
if __name__ == '__main__':
main()
+1
View File
@@ -0,0 +1 @@
# This file exists only to add i_form_data_repository/ folder to git repository.
@@ -0,0 +1 @@
# This file exists only to add js/ folder to git repository.
@@ -0,0 +1 @@
# This file exists only to add less/ folder to git repository.
@@ -0,0 +1 @@
# This file exists only to add templates/ folder to git repository.
@@ -0,0 +1,17 @@
"""Additional views."""
from flask import Blueprint
#
# Registration
#
def create_blueprint(app):
"""Register blueprint routes on app."""
blueprint = Blueprint(
"i_form_data_repository",
__name__,
template_folder="./templates",
)
# Add URL rules
return blueprint
@@ -0,0 +1,16 @@
"""JS/CSS Webpack bundles for I-Form Data Repository."""
from invenio_assets.webpack import WebpackThemeBundle
theme = WebpackThemeBundle(
__name__,
"assets",
default="semantic-ui",
themes={
"semantic-ui": dict(
entry={
# Add your webpack entrypoints
},
),
},
)
@@ -0,0 +1,3 @@
[build-system]
requires = ["setuptools", "wheel", "babel>2.8"]
build-backend = "setuptools.build_meta"
+16
View File
@@ -0,0 +1,16 @@
[metadata]
name = i-form-data-repository
[options]
packages = i_form_data_repository
[options.extras_require]
tests =
pytest-invenio>=2.1.0,<3.0.0
[options.entry_points]
invenio_base.blueprints =
i_form_data_repository_views = i_form_data_repository.views:create_blueprint
invenio_assets.webpack =
i_form_data_repository_theme = i_form_data_repository.webpack:theme
+3
View File
@@ -0,0 +1,3 @@
from setuptools import setup
setup()
@@ -0,0 +1 @@
# This file exists only to add templates/ folder to git repository.
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="683.385 263.073 71.61 17.206" xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath150">
<rect style="fill:none" id="rect152" width="89.156677" height="26.135302" x="26.392477" y="51.413708"/>
</clipPath>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath146">
<rect style="fill:none;stroke-width:1.91481" id="rect148" width="178.04289" height="47.98505" x="-1109.9677" y="-174.10544"/>
</clipPath>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath142">
<rect style="fill:none" id="rect144" width="92.982246" height="25.060017" x="27.524937" y="49.298393"/>
</clipPath>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath138">
<rect style="fill:none" id="rect140" width="92.982246" height="25.060017" x="27.524937" y="49.298393"/>
</clipPath>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath134">
<rect style="fill:none" id="rect136" width="92.982246" height="25.060017" x="27.524937" y="49.298393"/>
</clipPath>
</defs>
<g transform="matrix(1, 0, 0, 1, 644.704163, 211.397293)" style="display:inline" id="g5138">
<g aria-label="RDM" transform="scale(1.0429084,0.95885698)" id="text5106" clip-path="url(#clipPath150)" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:condensed;font-size:18.1003px;line-height:1.25;font-family:'DIN Condensed';-inkscape-font-specification:'DIN Condensed, Bold Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#fb8273;fill-opacity:1;stroke:none;stroke-width:3.66485;stroke-miterlimit:4;stroke-dasharray:none">
<path d="M 83.86 57.784 L 83.86 61.802 L 84.909 61.802 C 85.235 61.802 85.495 61.76 85.688 61.675 C 85.881 61.579 86.032 61.446 86.14 61.277 C 86.237 61.108 86.303 60.903 86.339 60.662 C 86.375 60.408 86.394 60.119 86.394 59.793 C 86.394 59.467 86.375 59.184 86.339 58.942 C 86.303 58.689 86.231 58.472 86.122 58.291 C 85.893 57.953 85.458 57.784 84.819 57.784 L 83.86 57.784 Z M 82.013 68.934 L 82.013 56.046 L 84.982 56.046 C 87.154 56.046 88.24 57.307 88.24 59.829 C 88.24 60.589 88.119 61.235 87.878 61.766 C 87.649 62.297 87.238 62.725 86.647 63.051 L 88.638 68.934 L 86.683 68.934 L 84.964 63.431 L 83.86 63.431 L 83.86 68.934 L 82.013 68.934 Z" style="stroke-width:3.66485" id="path154"/>
<path d="M 89.72 68.934 L 89.72 56.046 L 92.453 56.046 C 93.515 56.046 94.318 56.336 94.861 56.915 C 95.416 57.494 95.693 58.315 95.693 59.377 L 95.693 65.404 C 95.693 66.611 95.398 67.504 94.806 68.083 C 94.227 68.65 93.388 68.934 92.29 68.934 L 89.72 68.934 Z M 91.566 57.784 L 91.566 67.196 L 92.417 67.196 C 92.936 67.196 93.304 67.069 93.521 66.816 C 93.738 66.55 93.847 66.14 93.847 65.585 L 93.847 59.377 C 93.847 58.87 93.744 58.478 93.539 58.2 C 93.334 57.923 92.96 57.784 92.417 57.784 L 91.566 57.784 Z" style="stroke-width:3.66485" id="path156"/>
<path d="M 97.427 68.934 L 97.427 56.046 L 99.201 56.046 L 101.572 62.87 L 101.608 62.87 L 103.961 56.046 L 105.753 56.046 L 105.753 68.934 L 103.907 68.934 L 103.907 61.096 L 103.871 61.096 L 102.042 66.635 L 101.119 66.635 L 99.309 61.096 L 99.273 61.096 L 99.273 68.934 L 97.427 68.934 Z" style="stroke-width:3.66485" id="path158"/>
</g>
<g style="display:inline" transform="matrix(0.52224634,0,0,0.52224634,607.20148,140.22432)" id="layer1-0" clip-path="url(#clipPath146)">
<g transform="matrix(0.238125,0,0,0.238125,-1173.8821,-166.25235)" style="display:inline" id="g25963-9">
<path id="rect25941-7" style="fill:#ffffff" d="M 358.114 36.556 L 372.162 36.556 L 372.162 100.8 L 358.114 100.8 L 358.114 36.556 Z"/>
<path style="fill:#ffffff" id="path25943-1" d="M 686.276 33.005 C 667.509 33.005 652.244 48.273 652.244 67.039 C 652.244 74.319 654.55 81.067 658.458 86.607 L 628.38 113.039 C 626.499 114.917 628.447 119.906 630.324 121.788 C 632.203 123.664 637.194 125.61 639.072 123.731 L 665.337 93.837 C 671.116 98.362 678.384 101.07 686.276 101.07 C 705.044 101.07 720.31 85.803 720.31 67.038 C 720.31 48.273 705.044 33.005 686.276 33.005 Z M 686.276 89.727 C 673.766 89.727 663.587 79.55 663.587 67.039 C 663.587 54.528 673.767 44.349 686.276 44.349 C 698.789 44.349 708.964 54.529 708.964 67.039 C 708.964 79.549 698.789 89.727 686.276 89.727 Z"/>
<path transform="translate(358.11441,28.33968)" id="polygon25947-7" style="fill:#ffffff" d="M 113.62 36.814 L 125.814 8.325 L 140.814 8.325 L 113.512 72.427 L 86.21 8.433 L 101.318 8.433 L 113.62 36.814 Z"/>
<path transform="translate(358.11441,28.33968)" id="polygon25949-4" style="fill:#ffffff" d="M 218.848 72.318 L 218.848 43.075 L 254.537 74.124 L 254.537 7.961 L 239.34 7.961 L 239.34 36.974 L 203.65 8.076 L 203.65 72.318 L 218.848 72.318 Z"/>
<path transform="translate(358.11441,28.33968)" id="polygon25951-5" style="fill:#ffffff" d="M 78.537 8.127 L 63.34 8.127 L 63.34 37.14 L 27.65 8.242 L 27.65 72.484 L 42.848 72.484 L 42.848 43.241 L 78.537 74.29 L 78.537 8.127 Z"/>
<path id="rect25953-17" style="fill:#ffffff" d="M 626.114 35.39 L 640.163 35.39 L 640.163 99.633 L 626.114 99.633 L 626.114 35.39 Z"/>
<path transform="translate(358.11441,28.33968)" id="polygon25955-8" style="fill:#ffffff" d="M 193.649 72.079 L 193.649 59.346 L 166.976 59.346 L 166.976 45.624 L 191.783 45.624 L 191.783 32.672 L 166.976 32.672 L 166.976 20.927 L 192.991 20.927 L 192.991 7.974 L 149.193 7.974 L 149.193 72.079 L 193.649 72.079 Z"/>
<g id="g25961-2" transform="matrix(0.38742049,0,0,0.38742049,554.83512,53.02433)">
<path d="M 375.104 38.079 C 375.278 56.263 366.981 70.205 363.594 75.599 C 371.777 70.252 383.492 56.239 383.268 37.938 C 383.442 19.755 371.837 5.811 363.637 0.418 C 366.96 5.765 375.328 19.778 375.104 38.079 Z" id="path25957-5" style="fill:#ffffff"/>
<path d="M 375.104 38.079 C 375.278 56.263 366.981 70.205 363.594 75.599 C 371.777 70.252 383.492 56.239 383.268 37.938 C 383.442 19.755 371.837 5.811 363.637 0.418 C 366.96 5.765 375.328 19.778 375.104 38.079 Z" id="path25959-4" style="fill:none;stroke:#ffffff"/>
</g>
</g>
</g>
<path id="rect122" clip-path="url(#clipPath142)" style="fill:none;fill-rule:evenodd" d="M 39.317 56.478 L 106.911 51.676 L 108.712 66.345 L 40.517 64.544 L 39.317 56.478 Z"/>
<path id="rect126" style="fill:none" d="M 49.04 62.641 L 50.24 61.259 L 108.849 63.06 L 107.048 57.839 L 49.04 62.641 Z" clip-path="url(#clipPath138)"/>
<path id="rect130" clip-path="url(#clipPath134)" style="fill:none" d="M 48.903 60.997 L 101.707 56.195 L 103.508 62.511 L 50.103 60.71 L 48.903 60.997 Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.7 KiB

@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="86.247925mm"
height="21.786226mm"
viewBox="0 0 86.247925 21.786226"
version="1.1"
id="svg19281"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
sodipodi:docname="invenio-logo-white-new.svg">
<defs
id="defs19275" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="8.8165889"
inkscape:cx="162.9882"
inkscape:cy="41.170821"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:pagecheckerboard="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="3440"
inkscape:window-height="1395"
inkscape:window-x="0"
inkscape:window-y="1"
inkscape:window-maximized="1" />
<metadata
id="metadata19278">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(1088.6061,158.39311)">
<a
transform="matrix(0.26458333,0,0,0.26458333,-1186.9384,-166.74773)"
style="display:inline"
id="a4998">
<g
transform="matrix(0.9,0,0,0.9,49.346774,1.872297)"
style="display:inline"
id="g25963">
<rect
y="36.555683"
width="14.048"
height="64.244003"
id="rect25941"
x="358.11441"
style="fill:#ffffff" />
<g
transform="translate(358.11441,28.33968)"
id="g25945">
<path
inkscape:connector-curvature="0"
d="m 328.162,4.665 c -18.767,0 -34.032,15.268 -34.032,34.034 0,7.28 2.306,14.028 6.214,19.568 l -30.078,26.432 c -1.881,1.878 0.067,6.867 1.944,8.749 1.879,1.876 6.87,3.822 8.748,1.943 l 26.265,-29.894 c 5.779,4.525 13.047,7.233 20.939,7.233 18.768,0 34.034,-15.267 34.034,-34.032 0,-18.765 -15.266,-34.033 -34.034,-34.033 z m 0,56.722 c -12.51,0 -22.689,-10.177 -22.689,-22.688 0,-12.511 10.18,-22.69 22.689,-22.69 12.513,0 22.688,10.18 22.688,22.69 0,12.51 -10.175,22.688 -22.688,22.688 z"
id="path25943"
style="fill:#ffffff" />
</g>
<polygon
points="125.814,8.325 140.814,8.325 113.512,72.427 86.21,8.433 101.318,8.433 113.62,36.814 "
id="polygon25947"
style="fill:#ffffff"
transform="translate(358.11441,28.33968)" />
<polygon
points="239.34,36.974 203.65,8.076 203.65,72.318 218.848,72.318 218.848,43.075 254.537,74.124 254.537,7.961 239.34,7.961 "
id="polygon25949"
style="fill:#ffffff"
transform="translate(358.11441,28.33968)" />
<polygon
points="42.848,72.484 42.848,43.241 78.537,74.29 78.537,8.127 63.34,8.127 63.34,37.14 27.65,8.242 27.65,72.484 "
id="polygon25951"
style="fill:#ffffff"
transform="translate(358.11441,28.33968)" />
<rect
x="626.11444"
y="35.389698"
width="14.049"
height="64.242996"
id="rect25953"
style="fill:#ffffff" />
<polygon
points="193.649,59.346 166.976,59.346 166.976,45.624 191.783,45.624 191.783,32.672 166.976,32.672 166.976,20.927 192.991,20.927 192.991,7.974 149.193,7.974 149.193,72.079 193.649,72.079 "
id="polygon25955"
style="fill:#ffffff"
transform="translate(358.11441,28.33968)" />
<g
id="g25961"
transform="matrix(0.38742049,0,0,0.38742049,554.83512,53.02433)">
<path
inkscape:connector-curvature="0"
d="m 375.104,38.079 c 0.174,18.184 -8.123,32.126 -11.51,37.52 8.183,-5.347 19.898,-19.36 19.674,-37.661 0.174,-18.183 -11.431,-32.127 -19.631,-37.52 3.323,5.347 11.691,19.36 11.467,37.661 z"
id="path25957"
style="fill:#ffffff" />
<path
inkscape:connector-curvature="0"
d="m 375.104,38.079 c 0.174,18.184 -8.123,32.126 -11.51,37.52 8.183,-5.347 19.898,-19.36 19.674,-37.661 0.174,-18.183 -11.431,-32.127 -19.631,-37.52 3.323,5.347 11.691,19.36 11.467,37.661 z"
id="path25959"
style="fill:none;stroke:#ffffff" />
</g>
</g>
</a>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.0 KiB

@@ -0,0 +1 @@
# This file exists only to add templates/ folder to git repository.
@@ -0,0 +1,12 @@
# This file is required to allow string extraction for translations.
# Extraction from Python source files
[python: **.py]
encoding = utf-8
# Extraction from Python config files
[python: **.cfg]
encoding = utf-8
# Extraction from Jinja2 templates
[jinja2: **/templates/**.html]
encoding = utf-8
@@ -0,0 +1,23 @@
{
"invenio_search_ui": {
"invenio_search_ui:Search records...": "Cuardaigh taifid..."
},
"invenio_communities": {
"invenio_communities:You are not a member of any community.": "Níl tú mar bhall d'aon phobal.",
"invenio_communities:There are no new communities.": "Níl aon phobail nua ann.",
"invenio_communities:My Communities": "Mo Phobail",
"invenio_communities:New Communities": "Pobail Nua",
"invenio_communities:Search communities...": "Cuardaigh pobail...",
"invenio_communities:Organize, curate and share your research. Ideal for research projects, departments or temporary working groups.": "Eagraigh, coimeád agus comhroinn do chuid taighde. Ideal do thionscadail taighde, ranna nó grúpaí oibre sealadacha."
},
"invenio_app_rdm": {
"invenio_app_rdm:Search records...": "Cuardaigh taifid...",
"invenio_app_rdm:Search in my communities": "Cuardaigh i mo phobail",
"invenio_app_rdm:Search in my communities...": "Cuardaigh i mo phobail...",
"invenio_app_rdm:My communities": "Mo phobail",
"invenio_app_rdm:Search in my uploads...": "Cuardaigh i mo chuid uaslódálacha...",
"invenio_app_rdm:My uploads": "Mo chuid uaslódálacha",
"invenio_app_rdm:Overview": "Foramharc",
"invenio_app_rdm:Uploads": "Uaslódálacha"
}
}
+443
View File
File diff suppressed because one or more lines are too long
-832
View File
@@ -1,832 +0,0 @@
"""
InvenioRDM settings for InvenioRDM Starter project, modified
for the I-Form data repository.
This file was automatically generated by 'invenio-cli init'
and manually modified to configure.
For the full list of settings and their values, see
https://inveniordm.docs.cern.ch/reference/configuration/.
"""
from copy import deepcopy
from datetime import datetime
import re
from flask import request, url_for
import idutils
from marshmallow import validate
from invenio_rdm_records.services.pids import providers
from invenio_rdm_records.services import facets
from invenio_rdm_records.contrib.journal import (
JOURNAL_CUSTOM_FIELDS,
JOURNAL_CUSTOM_FIELDS_UI,
JOURNAL_NAMESPACE,
)
from invenio_records_resources.services.custom_fields import TextCF
from invenio_records_resources.services.records.queryparser import (
FieldValueMapper,
QueryParser,
SearchFieldTransformer,
)
# from invenio_records_resources.services.records.facets import TermsFacet
from invenio_communities.communities.records.models import CommunityMetadata
from invenio_db import db
from luqum.tree import Phrase
from invenio_access import action_factory
from invenio_records.dictutils import dict_lookup
from invenio_records_permissions.generators import (
ConditionalGenerator,
Generator,
)
from invenio_administration.generators import Administration
from invenio_communities.permissions import CommunityPermissionPolicy
from invenio_rdm_records.services.generators import (
AccessGrant,
CommunityInclusionReviewers,
IfDeleted,
IfExternalDOIRecord,
IfFileIsLocal,
IfNewRecord,
IfRecordDeleted,
IfRestricted,
RecordCommunitiesAction,
RecordOwners,
ResourceAccessToken,
SecretLinks,
SubmissionReviewer,
)
from invenio_rdm_records.services.permissions import RDMRecordPermissionPolicy
from invenio_records_permissions.generators import (
AuthenticatedUser,
Disable,
IfConfig,
SystemProcess,
)
from invenio_oauthclient.contrib.orcid import ORCIDOAuthSettingsHelper
from invenio_oauthclient.views.client import auto_redirect_login
def _(x): # needed to avoid start time failure with lazy strings
return x
RATELIMIT_ENABLED = True
RATELIMIT_AUTHENTICATED_USER = "50000 per hour;900 per minute"
RATELIMIT_GUEST_USER = "30000 per hour;500 per minute"
# Flask
# =====
# See https://flask.palletsprojects.com/en/1.1.x/config/
# Define the value of the cache control header `max-age` returned by the server when serving
# public files. Files will be cached by the browser for the provided number of seconds.
# See flask documentation for more information:
# https://flask.palletsprojects.com/en/2.1.x/config/#SEND_FILE_MAX_AGE_DEFAULT
SEND_FILE_MAX_AGE_DEFAULT = 300
# Set via env variable
# SECRET_KEY=
# App theming settings
EXTENSIONS = ["invenio_theme_iform"]
APP_THEME = ["invenio-theme-iform", "semantic-ui"]
# Since HAProxy and Nginx route all requests no matter the host header
# provided, the allowed hosts variable is set to localhost. In production it
# should be set to the correct host and it is strongly recommended to only
# route correct hosts to the application.
APP_ALLOWED_HOSTS = ["localhost", "localhost:8443", "localhost:5000" "127.0.0.1"]
# Flask-SQLAlchemy
# ================
# See https://flask-sqlalchemy.palletsprojects.com/en/2.x/config/
# Set via env variable
# SQLALCHEMY_DATABASE_URI=
# Invenio-App
# ===========
# See https://invenio-app.readthedocs.io/en/latest/configuration.html
APP_DEFAULT_SECURE_HEADERS = {
"content_security_policy": {
"default-src": [
"'self'",
"data:", # for fonts
"'unsafe-inline'", # for inline scripts and styles
"blob:", # for pdf preview
"fly.storage.tigris.dev", # for S3 object storage
"s3.us-east-1.amazonaws.com", # for S3 object storage
"s3.eu-central-1.amazonaws.com", # for S3 object storage
"s3.eu-west-1.amazonaws.com", # for S3 object storage
# Add your own policies here (e.g. analytics)
],
"img-src": [
"*",
],
},
"force_https": True,
"force_https_permanent": False,
"force_file_save": False,
"frame_options": "sameorigin",
"frame_options_allow_from": None,
"strict_transport_security": True,
"strict_transport_security_preload": False,
"strict_transport_security_max_age": 31556926, # One year in seconds
"strict_transport_security_include_subdomains": True,
"content_security_policy_report_uri": None,
"content_security_policy_report_only": False,
"session_cookie_secure": True,
"session_cookie_http_only": True,
}
# Flask-Babel
# ===========
# See https://python-babel.github.io/flask-babel/#configuration
# Default locale (language)
BABEL_DEFAULT_LOCALE = "en"
# Default time zone
BABEL_DEFAULT_TIMEZONE = "UTC"
# Invenio-I18N
# ============
# See https://invenio-i18n.readthedocs.io/en/latest/configuration.html
# Other supported languages (do not include BABEL_DEFAULT_LOCALE in list).
I18N_LANGUAGES = [
("de", _("German")),
("es", _("Spanish")),
("fr", _("French")),
("it", _("Italian")),
("pt", _("Portuguese")),
("tr", _("Turkish")),
]
# Invenio-Mail
# ===========
# See https://invenio-mail.readthedocs.io/en/latest/configuration.html
# Set this to False when enable email sending.
MAIL_SUPPRESS_SEND = True
# Invenio-Theme
# =============
# See https://invenio-theme.readthedocs.io/en/latest/configuration.html
# The name of the site to be used on the header and as a title.
THEME_SITENAME = "InvenioRDM Starter"
# Frontpage title
THEME_FRONTPAGE_TITLE = "InvenioRDM Starter"
# Frontpage subtitle
THEME_FRONTPAGE_SUBTITLE = (
"A starter project for the turn-key research data management repository."
)
# Header logo
THEME_LOGO = "images/starter.svg"
# Invenio-App-RDM
# ===============
# See https://invenio-app-rdm.readthedocs.io/en/latest/configuration.html
# Instance's theme entrypoint file. Path relative to the ``assets/`` folder.
INSTANCE_THEME_FILE = "./less/theme.less"
# Invenio-Files-Rest
# ==================
FILES_REST_STORAGE_FACTORY = "invenio_s3.s3fs_storage_factory"
# Invenio-S3
# ==========
S3_ENDPOINT_URL = "http://localhost:9000/"
S3_ACCESS_KEY_ID = "CHANGE_ME"
S3_SECRET_ACCESS_KEY = "CHANGE_ME"
S3_REGION_NAME = "eu-west-1"
# Invenio-Records-Resources
# =========================
# See https://github.com/inveniosoftware/invenio-records-resources/blob/master/invenio_records_resources/config.py
SITE_UI_URL = "https://localhost"
SITE_API_URL = "https://localhost/api"
APP_RDM_DEPOSIT_FORM_DEFAULTS = {
"publication_date": lambda: datetime.now().strftime("%Y-%m-%d"),
"rights": [
{
"id": "cc-by-4.0",
"title": "Creative Commons Attribution 4.0 International",
"description": (
"The Creative Commons Attribution license allows "
"re-distribution and re-use of a licensed work "
"on the condition that the creator is "
"appropriately credited."
),
"link": "https://creativecommons.org/licenses/by/4.0/legalcode",
}
],
"resource_type": {
"id": "publication-preprint",
},
}
# See https://github.com/inveniosoftware/invenio-app-rdm/blob/master/invenio_app_rdm/config.py
APP_RDM_DEPOSIT_FORM_AUTOCOMPLETE_NAMES = "search" # "search_only" or "off"
# Invenio-RDM-Records
# ===================
# See https://inveniordm.docs.cern.ch/customize/dois/
DATACITE_ENABLED = False
DATACITE_PREFIX = "10.1234"
#
# Persistent identifiers configuration
#
RDM_PERSISTENT_IDENTIFIER_PROVIDERS = [
# DOI provider for externally managed DOIs
providers.ExternalPIDProvider(
"external",
"doi",
validators=[providers.BlockedPrefixes(config_names=["DATACITE_PREFIX"])],
label=_("DOI"),
),
# OAI identifier
providers.OAIPIDProvider(
"oai",
label=_("OAI ID"),
),
]
"""A list of configured persistent identifier providers."""
RDM_PERSISTENT_IDENTIFIERS = {
"doi": {
"providers": ["external"],
"required": False,
"label": _("DOI"),
"validator": idutils.is_doi,
"normalizer": idutils.normalize_doi,
"is_enabled": providers.ExternalPIDProvider.is_enabled,
},
"oai": {
"providers": ["oai"],
"required": True,
"label": _("OAI"),
"is_enabled": providers.OAIPIDProvider.is_enabled,
},
}
"""The configured persistent identifiers for records."""
RDM_PARENT_PERSISTENT_IDENTIFIERS = {}
def always_valid(identifier):
"""Gives every identifier as valid."""
return True
RDM_RECORDS_IDENTIFIERS_SCHEMES = {
"ark": {"label": _("ARK"), "validator": idutils.is_ark, "datacite": "ARK"},
"arxiv": {"label": _("arXiv"), "validator": idutils.is_arxiv, "datacite": "arXiv"},
"ads": {
"label": _("Bibcode"),
"validator": idutils.is_ads,
"datacite": "bibcode",
},
"crossreffunderid": {
"label": _("Crossref Funder ID"),
"validator": always_valid,
"datacite": "Crossref Funder ID",
},
"doi": {"label": _("DOI"), "validator": idutils.is_doi, "datacite": "DOI"},
"ean13": {"label": _("EAN13"), "validator": idutils.is_ean13, "datacite": "EAN13"},
"eissn": {"label": _("EISSN"), "validator": idutils.is_issn, "datacite": "EISSN"},
"grid": {"label": _("GRID"), "validator": always_valid, "datacite": "GRID"},
"handle": {
"label": _("Handle"),
"validator": idutils.is_handle,
"datacite": "Handle",
},
"igsn": {"label": _("IGSN"), "validator": always_valid, "datacite": "IGSN"},
"isbn": {"label": _("ISBN"), "validator": idutils.is_isbn, "datacite": "ISBN"},
"isni": {"label": _("ISNI"), "validator": idutils.is_isni, "datacite": "ISNI"},
"issn": {"label": _("ISSN"), "validator": idutils.is_issn, "datacite": "ISSN"},
"istc": {"label": _("ISTC"), "validator": idutils.is_istc, "datacite": "ISTC"},
"lissn": {"label": _("LISSN"), "validator": idutils.is_issn, "datacite": "LISSN"},
"lsid": {"label": _("LSID"), "validator": idutils.is_lsid, "datacite": "LSID"},
"pmid": {"label": _("PMID"), "validator": idutils.is_pmid, "datacite": "PMID"},
"purl": {"label": _("PURL"), "validator": idutils.is_purl, "datacite": "PURL"},
"upc": {"label": _("UPC"), "validator": always_valid, "datacite": "UPC"},
"url": {"label": _("URL"), "validator": idutils.is_url, "datacite": "URL"},
"urn": {"label": _("URN"), "validator": idutils.is_urn, "datacite": "URN"},
"w3id": {"label": _("W3ID"), "validator": always_valid, "datacite": "w3id"},
# Custom identifiers added for InvenioRDM Starter
"uuid": {"label": _("UUID"), "validator": always_valid, "datacite": "UUID"},
"guid": {"label": _("GUID"), "validator": always_valid, "datacite": "GUID"},
"other": {"label": _("Other"), "validator": always_valid, "datacite": "Other"},
}
"""These are used for references, main, alternate and related identifiers."""
# Authentication - Invenio-Accounts and Invenio-OAuthclient
# =========================================================
# See: https://inveniordm.docs.cern.ch/customize/authentication/
# Invenio-Accounts
# ----------------
# See https://github.com/inveniosoftware/invenio-accounts/blob/master/invenio_accounts/config.py
ACCOUNTS_LOCAL_LOGIN_ENABLED = True # enable local login
ACCOUNTS_DEFAULT_USER_VISIBILITY = "public"
SECURITY_REGISTERABLE = True # local login: allow users to register
SECURITY_RECOVERABLE = True # local login: allow users to reset the password
SECURITY_CHANGEABLE = True # local login: allow users to change psw
SECURITY_CONFIRMABLE = True # local login: users can confirm e-mail address
SECURITY_LOGIN_WITHOUT_CONFIRMATION = (
False # require users to confirm email before being able to login
)
# Enable optional custom fields
RDM_NAMESPACES = {
**JOURNAL_NAMESPACE,
"rs": None,
}
RDM_CUSTOM_FIELDS = [
*JOURNAL_CUSTOM_FIELDS,
TextCF( # content in markdown format
name="rs:content_text",
),
TextCF( # feature image url
name="rs:image",
field_args={
"validate": validate.URL(),
},
multiple=False,
),
]
RDM_CUSTOM_FIELDS_UI = [
{
"section": _("Publishing information"),
"hide_from_landing_page": True,
"fields": [
# journal
*JOURNAL_CUSTOM_FIELDS_UI["fields"],
],
},
{
"section": _("Images"),
"hide_from_landing_page": True,
"fields": [
dict(
field="rs:image",
ui_widget="Input",
props=dict(
label="Feature Image URL",
icon="image",
required=False,
),
),
],
},
]
RDM_SORT_OPTIONS = {
"bestmatch": dict(
title=_("Best match"),
fields=["_score"],
),
"newest": dict(
title=_("Newest"),
fields=["-metadata.publication_date", "-metadata.dates.date"],
),
"oldest": dict(
title=_("Oldest"),
fields=["metadata.publication_date", "metadata.dates.date"],
),
"version": dict(
title=_("Version"),
fields=["-versions.index"],
),
"updated-desc": dict(
title=_("Recently updated"),
fields=["-updated"],
),
"updated-asc": dict(
title=_("Least recently updated"),
fields=["updated"],
),
"created-desc": dict(
title=_("Recently added"),
fields=["-created"],
),
"created-asc": dict(
title=_("Least recently added"),
fields=["created"],
),
}
# def orcid = TermsFacet(
# field="is_published",
# label=_("ORCID"),
# value_labels={"true": _("Yes"), "false": _("No")},
# )
RDM_FACETS = {
"access_status": {
"facet": facets.access_status,
"ui": {
"field": "access.status",
},
},
"is_published": {
"facet": facets.is_published,
"ui": {
"field": "is_published",
},
},
"file_type": {
"facet": facets.filetype,
"ui": {
"field": "files.types",
},
},
"language": {
"facet": facets.language,
"ui": {
"field": "languages",
},
},
"resource_type": {
"facet": facets.resource_type,
"ui": {
"field": "resource_type.type",
"childAgg": {
"field": "resource_type.subtype",
},
},
},
"subject": {
"facet": facets.subject,
"ui": {
"field": "subjects.subject",
},
},
}
# from https://github.com/zenodo/zenodo-rdm/blob/master/site/zenodo_rdm/queryparser.py
def word_doi(node):
"""Quote DOIs."""
if not node.value.startswith("10."):
return node
return Phrase(f'"{node.value}"')
def word_communities(node):
"""Resolve community slugs to IDs."""
slug = node.value
uuid = (
db.session.query(CommunityMetadata.id)
.filter(CommunityMetadata.slug == slug)
.scalar()
)
return Phrase(f'"{uuid}"')
RDM_SEARCH = {
# Supported values from RDM_FACETS
"facets": ["language", "subject"],
# Supported values from RDM_SORT_OPTIONS
"sort": [
"bestmatch",
"newest",
"oldest",
"updated-desc",
"updated-asc",
"created-desc",
"created-asc",
],
"query_parser_cls": QueryParser.factory(
mapping={
# shortcuts
"title": "metadata.title",
"subject": "metadata.subjects.subject",
"contributor": "metadata.creators.person_or_org.name",
# taken from Zenodo
"doi": FieldValueMapper("pids.doi.identifier", word=word_doi),
"communities": FieldValueMapper(
"parent.communities.ids", word=word_communities
),
# Persistent identifiers
"orcid": "metadata.creators.person_or_org.identifiers.identifier",
"ror": "metadata.creators.affiliations.id",
"issn": "custom_fields.journal\:journal.issn",
# Specific to InveniRDM Starter
"content": "custom_fields.rs\:content_text",
},
tree_transformer_cls=SearchFieldTransformer,
),
}
COMMUNITIES_RECORDS_SEARCH = deepcopy(RDM_SEARCH)
"""Communities record search config is the same as the main record search."""
RDM_SEARCH_DRAFTS = {
"facets": ["is_published", "language", "subject"],
"sort": [
"bestmatch",
"newest",
"oldest",
"updated-desc",
"updated-asc",
"created-desc",
"created-asc",
],
}
"""User records search configuration (i.e. list of uploads)."""
# Toggle to show or hide the 'Browse' menu entry for communities.
COMMUNITIES_SHOW_BROWSE_MENU_ENTRY = True
# Enable featured communities
COMMUNITIES_ADMINISTRATION_DISABLED = False
# Invenio-OAuthclient
# -------------------
# See https://github.com/inveniosoftware/invenio-oauthclient/blob/master/invenio_oauthclient/config.py
# ORCID OAuth Configuration
_orcid_app = ORCIDOAuthSettingsHelper(
title="ORCID",
description="ORCID - Connecting Research and Researchers.",
base_url="https://pub.orcid.org/",
access_token_url="https://orcid.org/oauth/token",
authorize_url="https://orcid.org/oauth/authorize#show_login",
)
# OAuth Remote Apps Configuration
OAUTHCLIENT_REMOTE_APPS = {
"orcid": _orcid_app.remote_app,
}
# OAuth App Credentials (set via environment variables)
ORCID_APP_CREDENTIALS = {
"consumer_key": "", # Set via INVENIO_ORCID_APP_CREDENTIALS_CONSUMER_KEY
"consumer_secret": "", # Set via INVENIO_ORCID_APP_CREDENTIALS_CONSUMER_SECRET
}
# GITHUB_APP_CREDENTIALS = {
# "consumer_key": "CHANGE ME",
# "consumer_secret": "CHANGE",
# }
ACCOUNTS_LOGIN_VIEW_FUNCTION = (
auto_redirect_login # autoredirect to external login if enabled
)
# autoredirect to external login
OAUTHCLIENT_AUTO_REDIRECT_TO_EXTERNAL_LOGIN = False
# Invenio-UserProfiles
# --------------------
USERPROFILES_READ_ONLY = (
False # allow users to change profile info (name, email, etc...)
)
USERPROFILES_EXTEND_SECURITY_FORMS = True
# OAI-PMH
# =======
# See https://github.com/inveniosoftware/invenio-oaiserver/blob/master/invenio_oaiserver/config.py
OAISERVER_ID_PREFIX = "invenio-rdm"
"""The prefix that will be applied to the generated OAI-PMH ids."""
# Invenio-Search
# --------------
SEARCH_INDEX_PREFIX = "invenio-rdm-"
# See https://inveniordm.docs.cern.ch/reference/configuration/
RDM_CITATION_STYLES = [
("apa", _("APA")),
("harvard-cite-them-right", _("Harvard")),
("ieee", _("IEEE")),
("modern-language-association", _("MLA")),
("vancouver", _("Vancouver")),
("chicago-author-date", _("Chicago")),
("american-chemical-society", _("ACS")),
]
RDM_DEFAULT_CITATION_STYLE = "vancouver"
# Redirection of legacy URLs
# --------------------------
REDIRECTOR_RULES = {
# "redirect_name": {
# "source": "/blogs",
# "target": redirect_function,
# },
}
"""InvenioRDMStarter permissions."""
# these are defined here as there is a circular dependency otherwise with the
# permissions.py file
media_files_management_action = action_factory("manage-media-files")
manage_external_doi_files_action = action_factory("manage-external-doi-files")
class IfFilesRestrictedForCommunity(IfRestricted):
"""Conditional generator for files restriction for community."""
def __init__(self, then_, else_):
"""Constructor."""
super().__init__("files", then_, else_)
def _condition(self, record, **kwargs):
"""Check if community can access restricted files of the migrated record."""
try:
can_community_read_files = dict_lookup(
record.parent, "permission_flags.can_community_read_files"
)
except KeyError:
can_community_read_files = True
is_restricted = super()._condition(record, **kwargs)
if is_restricted:
return not can_community_read_files
else:
return False
class MediaFilesManager(Generator):
"""Allows media files management."""
def __init__(self):
"""Constructor."""
super(MediaFilesManager, self).__init__()
def needs(self, **kwargs):
"""Enabling Needs."""
return [media_files_management_action]
class ExternalDOIFilesManager(Generator):
"""Allows to manage files for exteranl DOI records."""
def __init__(self):
"""Initialize generator."""
super(ExternalDOIFilesManager, self).__init__()
def needs(self, **kwargs):
"""Enable Needs."""
return [manage_external_doi_files_action]
class IfRecordManagementAllowedForCommunity(ConditionalGenerator):
"""Conditional generator for community access to record management."""
def _condition(self, record, **kwargs):
"""Check if community can manage the migrated record."""
if record is None:
return False
try:
can_community_manage_record = dict_lookup(
record.parent, "permission_flags.can_community_manage_record"
)
except KeyError:
can_community_manage_record = True
return can_community_manage_record
def query_filter(self, **kwargs):
"""Filters for current identity as super user."""
then_query = self._make_query(self.then_, **kwargs)
else_query = self._make_query(self.else_, **kwargs)
return then_query if then_query else else_query
class InvenioRDMStarterRecordPermissionPolicy(RDMRecordPermissionPolicy):
"""Access control configuration for records."""
#
# High-level permissions (used by low-level)
#
can_manage = [
IfRecordManagementAllowedForCommunity(
then_=RDMRecordPermissionPolicy.can_manage,
else_=[
RecordOwners(),
AccessGrant("manage"),
SystemProcess(),
],
)
]
can_curate = can_manage + [SystemProcess()]
can_review = can_curate + [SystemProcess()]
can_preview = can_curate + [SystemProcess()]
#
# Records
#
# Used for search filtering of deleted records
# cannot be implemented inside can_read - otherwise permission will
# kick in before tombstone renders
can_create = [AuthenticatedUser(), SystemProcess()]
can_read_deleted = [SystemProcess()]
can_read_deleted_files = can_read_deleted
can_media_read_deleted_files = can_read_deleted_files
#
# Drafts
#
# Allow reading metadata of a draft
can_read_draft = can_preview
# Allow reading files of a draft
can_draft_read_files = can_preview + [SystemProcess()]
# Allow updating metadata of a draft
can_update_draft = can_manage
# Allow uploading, updating and deleting files in drafts
can_draft_create_files = can_manage
can_draft_set_content_files = can_manage + [SystemProcess()]
can_draft_get_content_files = can_manage + [SystemProcess()]
can_draft_commit_files = can_manage + [SystemProcess()]
can_draft_update_files = can_manage
can_draft_delete_files = can_manage
can_manage_record_access = can_manage
#
# PIDs
#
can_pid_create = can_review
can_pid_register = can_review
can_pid_update = can_review
can_pid_discard = can_review
can_pid_delete = can_review
#
# Actions
#
# Allow to put a record in edit mode (create a draft from record)
can_edit = can_manage + [SystemProcess()]
# Allow deleting/discarding a draft and all associated files
can_delete_draft = can_manage + [SystemProcess()]
# Allow creating a new version of an existing published record.
can_new_version = can_manage + [SystemProcess()]
# Allow publishing a new record or changes to an existing record.
can_publish = can_manage + [SystemProcess()]
# Allow lifting a record or draft.
can_lift_embargo = can_manage + [SystemProcess()]
#
# Record communities
#
# Who can add record to a community
can_add_community = can_review
# Media files
can_draft_media_create_files = can_manage + [MediaFilesManager(), SystemProcess()]
can_draft_media_read_files = can_draft_media_create_files
can_draft_media_set_content_files = can_manage + [SystemProcess()]
can_draft_media_commit_files = can_manage + [SystemProcess()]
can_draft_media_update_files = can_draft_media_create_files
can_draft_media_delete_files = can_draft_media_create_files
can_moderate = can_manage + [SystemProcess()]
can_media_create_files = can_manage + [SystemProcess()]
can_media_set_content_files = can_manage + [SystemProcess()]
can_media_commit_files = can_manage + [SystemProcess()]
can_media_update_files = can_manage + [SystemProcess()]
can_media_delete_files = can_manage + [SystemProcess()]
can_modify_locked_files = can_manage + [SystemProcess()]
class InvenioRDMStarterCommunityPermissionPolicy(CommunityPermissionPolicy):
"""Permissions for Community CRUD operations.
We start with limited permissions for community creation and moderation.
"""
can_create = [SystemProcess()]
can_moderate = [SystemProcess()]
can_rename = [SystemProcess()]
can_submit_record = [SystemProcess()]
can_include_directly = [SystemProcess()]
RDM_PERMISSION_POLICY = InvenioRDMStarterRecordPermissionPolicy
"""InvenioRDMStarter record permission policy."""
COMMUNITIES_ALLOW_RESTRICTED = False
"""Don't allow restricted records in communities."""
COMMUNITIES_PERMISSION_POLICY = InvenioRDMStarterCommunityPermissionPolicy
"""InvenioRDMStarter community permission policy."""
+83 -10
View File
@@ -3,11 +3,11 @@ update auto-rollback="false":
if [ ! -f update.lock ]; then
touch update.lock
just tag-version
docker compose down
cd i-form-data-repository && docker compose -f docker-compose.full.yml --env-file ../.env down
git pull
docker compose pull
docker compose build
docker compose up -d --wait
cd i-form-data-repository && docker compose -f docker-compose.full.yml --env-file ../.env pull
cd i-form-data-repository && docker compose -f docker-compose.full.yml --env-file ../.env build
cd i-form-data-repository && docker compose -f docker-compose.full.yml --env-file ../.env up -d --wait
rm update.lock
if [ "{{auto-rollback}}" = "true" ]; then
just healthcheck || just rollback
@@ -29,7 +29,7 @@ tag-version:
#!/usr/bin/env bash
git tag backup-$(date +%Y%m%d-%H%M%S)
mkdir -p versions
docker compose images | grep -v "REPOSITORY" > versions/$(date +%Y%m%d-%H%M%S).txt
cd i-form-data-repository && docker compose -f docker-compose.full.yml --env-file ../.env images | grep -v "REPOSITORY" > ../versions/$(date +%Y%m%d-%H%M%S).txt
healthcheck:
#!/usr/bin/env bash
@@ -66,9 +66,9 @@ rollback version="":
# Then check out the version and update
git checkout $version
docker compose down
docker compose build --no-cache
docker compose up -d
cd i-form-data-repository && docker compose -f docker-compose.full.yml --env-file ../.env down
cd i-form-data-repository && docker compose -f docker-compose.full.yml --env-file ../.env build --no-cache
cd i-form-data-repository && docker compose -f docker-compose.full.yml --env-file ../.env up -d
git switch $current_branch # Return to original branch
cleanup-versions:
@@ -81,8 +81,81 @@ cleanup-versions:
deploy *args:
./env.sh {{args}}
docker compose up -d --wait
docker compose exec -it worker setup.sh
cd i-form-data-repository && docker compose -f docker-compose.full.yml --env-file ../.env up -d --wait
cd i-form-data-repository && docker compose -f docker-compose.full.yml --env-file ../.env exec worker bash -c "invenio db init || true; invenio db create || true; invenio alembic upgrade || true; invenio index init || true"
fmt:
bun run prettier --write "**/*.{js,jsx,ts,tsx,html,css,scss,sass,svelte,yaml,json,markdown}"
[working-directory("../invenio-theme-iform/")]
build-theme-wheel:
rm -rf dist
direnv exec . uv build --package invenio-theme-iform
[working-directory("../invenio-config-iform/")]
build-config-wheel:
rm -rf dist
direnv exec . uv build --package invenio-config-iform
build-wheels: build-theme-wheel build-config-wheel
echo "Building fresh wheels for local packages..."
mkdir -p i-form-data-repository/local_wheels
rm -f i-form-data-repository/local_wheels/*.whl
cp ../invenio-theme-iform/dist/*.whl i-form-data-repository/local_wheels/
cp ../invenio-config-iform/dist/*.whl i-form-data-repository/local_wheels/
test-local: build-wheels
#!/usr/bin/env bash
echo "Rebuilding and restarting local docker stack..."
cd i-form-data-repository
docker compose -f docker-compose.full.yml --env-file ../.env down
docker build -t i-form-data-repository:latest --no-cache --build-arg INSTALL_LOCAL_WHEELS=true .
docker compose -f docker-compose.full.yml --env-file ../.env up -d --wait
docker compose -f docker-compose.full.yml --env-file ../.env exec worker bash -c "invenio db init || true; invenio db create || true; invenio alembic upgrade || true; invenio index init || true"
curl -skI https://127.0.0.1:8443/ || echo "HTTPS verification failed"
# Production deployment commands using Docker/Podman
# Load AWS secrets (adjust path as needed)
load-aws-secrets:
@if [ -f aws_secrets.sh ]; then . ./aws_secrets.sh; else echo "AWS secrets file not found"; exit 1; fi
# First-time deployment to production
prod-deploy: load-aws-secrets build-wheels
#!/usr/bin/env bash
echo "Deploying to production (first-time)..."
git switch prod
git pull origin prod
# Build and start containers
cd i-form-data-repository
docker build -t i-form-data-repository:latest --no-cache --build-arg INSTALL_LOCAL_WHEELS=true .
docker compose -f docker-compose.full.yml --env-file ../.env up -d --wait
# Run initial database setup, migrations, and collect static assets
docker compose -f docker-compose.full.yml --env-file ../.env exec worker bash -c " \
invenio db init && \
invenio db create && \
invenio alembic upgrade head && \
invenio collect -v && \
invenio index init \
"
# Update production without full redeploy (pull + migrations + static)
prod-update: load-aws-secrets build-wheels
#!/usr/bin/env bash
echo "Updating production deployment..."
git switch prod
git pull origin prod
cd i-form-data-repository
docker build -t i-form-data-repository:latest --no-cache --build-arg INSTALL_LOCAL_WHEELS=true .
docker compose -f docker-compose.full.yml --env-file ../.env up -d --wait
docker compose -f docker-compose.full.yml --env-file ../.env exec worker bash -c " \
invenio alembic upgrade head && \
invenio collect -v \
"
# Clean all build artefacts and environment
prod-clean:
@echo "Cleaning production build artefacts..."
rm -rf .venv build dist *.egg-info
find . -type d -name "__pycache__" -exec rm -r {} + || true
rm -rf static node_modules
echo "Clean complete. Recreate environment before next deploy."
+7
View File
@@ -0,0 +1,7 @@
[project]
name = "iform-invenio"
version = "0.1.0"
description = "The source code for the I-Form Data Repository"
readme = "README.md"
requires-python = ">=3.12"
dependencies = ["invenio-cli>=1.9.2"]
-39
View File
@@ -1,39 +0,0 @@
#!/bin/bash
echo "-- Setup InvenioRDM --"
# Creating database...
invenio db init create
# Creating files location...
invenio files location create --default s3-default "s3://${INVENIO_S3_BUCKET_NAME}"
# Creating admin role...
invenio roles create admin
# Assigning superuser access to admin role...
invenio access allow superuser-access role admin
# Dropping and re-creating indices...
invenio index destroy --force --yes-i-know
invenio index init
# Creating custom fields for records...
invenio rdm-records custom-fields init
# Creating custom fields for communities...
invenio communities custom-fields init
# Creating rdm fixtures...
invenio rdm-records fixtures
# Creating demo records...
# invenio rdm-records demo records --user user@demo.org
# Creating demo communities
# invenio rdm-records demo communities --user community@demo.org
# Declaring queues...
invenio queues declare
echo "-- Setup completed --"
Generated
+575
View File
@@ -0,0 +1,575 @@
version = 1
revision = 3
requires-python = ">=3.12"
[[package]]
name = "arrow"
version = "1.4.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "python-dateutil" },
{ name = "tzdata" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931, upload-time = "2025-10-18T17:46:46.761Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797, upload-time = "2025-10-18T17:46:45.663Z" },
]
[[package]]
name = "babel"
version = "2.17.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" },
]
[[package]]
name = "binaryornot"
version = "0.4.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "chardet" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a7/fe/7ebfec74d49f97fc55cd38240c7a7d08134002b1e14be8c3897c0dd5e49b/binaryornot-0.4.4.tar.gz", hash = "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061", size = 371054, upload-time = "2017-08-03T15:55:25.08Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/24/7e/f7b6f453e6481d1e233540262ccbfcf89adcd43606f44a028d7f5fae5eb2/binaryornot-0.4.4-py2.py3-none-any.whl", hash = "sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4", size = 9006, upload-time = "2017-08-03T15:55:31.23Z" },
]
[[package]]
name = "certifi"
version = "2025.11.12"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538, upload-time = "2025-11-12T02:54:51.517Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" },
]
[[package]]
name = "chardet"
version = "5.2.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/f7b6ab21ec75897ed80c17d79b15951a719226b9fababf1e40ea74d69079/chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7", size = 2069618, upload-time = "2023-08-01T19:23:02.662Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/38/6f/f5fbc992a329ee4e0f288c1fe0e2ad9485ed064cac731ed2fe47dcc38cbf/chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970", size = 199385, upload-time = "2023-08-01T19:23:00.661Z" },
]
[[package]]
name = "charset-normalizer"
version = "3.4.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" },
{ url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" },
{ url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" },
{ url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" },
{ url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" },
{ url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" },
{ url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" },
{ url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" },
{ url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" },
{ url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" },
{ url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" },
{ url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" },
{ url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" },
{ url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" },
{ url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" },
{ url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" },
{ url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" },
{ url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" },
{ url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" },
{ url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" },
{ url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" },
{ url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" },
{ url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" },
{ url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" },
{ url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" },
{ url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" },
{ url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" },
{ url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" },
{ url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" },
{ url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" },
{ url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" },
{ url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" },
{ url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" },
{ url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" },
{ url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" },
{ url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" },
{ url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" },
{ url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" },
{ url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" },
{ url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" },
{ url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" },
{ url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" },
{ url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" },
{ url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" },
{ url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" },
{ url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" },
{ url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" },
{ url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" },
{ url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" },
]
[[package]]
name = "click"
version = "8.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" },
]
[[package]]
name = "click-default-group"
version = "1.2.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1d/ce/edb087fb53de63dad3b36408ca30368f438738098e668b78c87f93cd41df/click_default_group-1.2.4.tar.gz", hash = "sha256:eb3f3c99ec0d456ca6cd2a7f08f7d4e91771bef51b01bdd9580cc6450fe1251e", size = 3505, upload-time = "2023-08-04T07:54:58.425Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2c/1a/aff8bb287a4b1400f69e09a53bd65de96aa5cee5691925b38731c67fc695/click_default_group-1.2.4-py2.py3-none-any.whl", hash = "sha256:9b60486923720e7fc61731bdb32b617039aba820e22e1c88766b1125592eaa5f", size = 4123, upload-time = "2023-08-04T07:54:56.875Z" },
]
[[package]]
name = "colorama"
version = "0.4.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
]
[[package]]
name = "cookiecutter"
version = "2.6.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "arrow" },
{ name = "binaryornot" },
{ name = "click" },
{ name = "jinja2" },
{ name = "python-slugify" },
{ name = "pyyaml" },
{ name = "requests" },
{ name = "rich" },
]
sdist = { url = "https://files.pythonhosted.org/packages/52/17/9f2cd228eb949a91915acd38d3eecdc9d8893dde353b603f0db7e9f6be55/cookiecutter-2.6.0.tar.gz", hash = "sha256:db21f8169ea4f4fdc2408d48ca44859349de2647fbe494a9d6c3edfc0542c21c", size = 158767, upload-time = "2024-02-21T18:02:41.949Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b6/d9/0137658a353168ffa9d0fc14b812d3834772040858ddd1cb6eeaf09f7a44/cookiecutter-2.6.0-py3-none-any.whl", hash = "sha256:a54a8e37995e4ed963b3e82831072d1ad4b005af736bb17b99c2cbd9d41b6e2d", size = 39177, upload-time = "2024-02-21T18:02:39.569Z" },
]
[[package]]
name = "distlib"
version = "0.4.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" },
]
[[package]]
name = "docker"
version = "7.1.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pywin32", marker = "sys_platform == 'win32'" },
{ name = "requests" },
{ name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/91/9b/4a2ea29aeba62471211598dac5d96825bb49348fa07e906ea930394a83ce/docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c", size = 117834, upload-time = "2024-05-23T11:13:57.216Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e3/26/57c6fb270950d476074c087527a558ccb6f4436657314bfb6cdf484114c4/docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0", size = 147774, upload-time = "2024-05-23T11:13:55.01Z" },
]
[[package]]
name = "filelock"
version = "3.20.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size = 18922, upload-time = "2025-10-08T18:03:50.056Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054, upload-time = "2025-10-08T18:03:48.35Z" },
]
[[package]]
name = "idna"
version = "3.11"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" },
]
[[package]]
name = "iform-invenio"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "invenio-cli" },
]
[package.metadata]
requires-dist = [{ name = "invenio-cli", specifier = ">=1.9.2" }]
[[package]]
name = "invenio-cli"
version = "1.9.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "babel" },
{ name = "click" },
{ name = "click-default-group" },
{ name = "cookiecutter" },
{ name = "docker" },
{ name = "pipenv" },
{ name = "pipfile" },
{ name = "pynpm" },
{ name = "pyyaml" },
{ name = "virtualenv" },
]
sdist = { url = "https://files.pythonhosted.org/packages/82/df/acafd2eda11d3d3f7f3ca200d8a6d20ac45c9b0986edbbc63b8986d71298/invenio_cli-1.9.2.tar.gz", hash = "sha256:88b6e7277e8a6d78d9b54ed84405674083558887567d2467a4aa9492ec4124b2", size = 38932, upload-time = "2025-08-12T19:55:54.941Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/7b/2a/cf5efabd9c7dc43354e259f9acdffe91d44ad404c1a1346b4b149f601c4a/invenio_cli-1.9.2-py2.py3-none-any.whl", hash = "sha256:343b26dc1a1a29c329210f001b8f70376b2f9bfec0c6aa392bf92c302371a620", size = 51975, upload-time = "2025-08-12T19:55:53.709Z" },
]
[[package]]
name = "jinja2"
version = "3.1.6"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markupsafe" },
]
sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
]
[[package]]
name = "markdown-it-py"
version = "4.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mdurl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" },
]
[[package]]
name = "markupsafe"
version = "3.0.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" },
{ url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" },
{ url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" },
{ url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" },
{ url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" },
{ url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" },
{ url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" },
{ url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" },
{ url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" },
{ url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" },
{ url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" },
{ url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" },
{ url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" },
{ url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" },
{ url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" },
{ url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" },
{ url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" },
{ url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" },
{ url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" },
{ url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" },
{ url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" },
{ url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" },
{ url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" },
{ url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" },
{ url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" },
{ url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" },
{ url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" },
{ url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" },
{ url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" },
{ url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" },
{ url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" },
{ url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" },
{ url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" },
{ url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" },
{ url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" },
{ url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" },
{ url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" },
{ url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" },
{ url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" },
{ url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" },
{ url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" },
{ url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" },
{ url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" },
{ url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" },
{ url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" },
{ url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" },
{ url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" },
{ url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" },
{ url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" },
{ url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" },
{ url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" },
{ url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" },
{ url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" },
{ url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" },
{ url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" },
]
[[package]]
name = "mdurl"
version = "0.1.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
]
[[package]]
name = "packaging"
version = "25.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
]
[[package]]
name = "pipenv"
version = "2025.0.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
{ name = "packaging" },
{ name = "setuptools" },
{ name = "virtualenv" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3b/15/4c869c2ec2819f8e6529cc26a044c9f7c714246c972b9b2cbbafda0847f9/pipenv-2025.0.4.tar.gz", hash = "sha256:36fc2a7841ccdb2f58a9f787b296c2e15dea3b5b79b84d4071812f28b7e8d7a2", size = 4479128, upload-time = "2025-07-07T21:45:46.627Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e6/12/0c9830367898ce889d0b21361c66cc42e61a58c10806e3d94f77059aa278/pipenv-2025.0.4-py3-none-any.whl", hash = "sha256:e1fbe4cfd25ab179f123d1fbb1fa1cdc0b3ffcdb1f21c775dcaa12ccc356f2bb", size = 2884977, upload-time = "2025-07-07T21:45:44.8Z" },
]
[[package]]
name = "pipfile"
version = "0.0.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "toml" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3a/01/4486ea9606ef8467c39b0cf6ea414eb4de5467dcb4a97333cf11a371cfd2/pipfile-0.0.2.tar.gz", hash = "sha256:f7d9f15de8b660986557eb3cc5391aa1a16207ac41bc378d03f414762d36c984", size = 18065, upload-time = "2017-03-11T03:27:44.308Z" }
[[package]]
name = "platformdirs"
version = "4.5.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632, upload-time = "2025-10-08T17:44:48.791Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651, upload-time = "2025-10-08T17:44:47.223Z" },
]
[[package]]
name = "pygments"
version = "2.19.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
]
[[package]]
name = "pynpm"
version = "0.3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ef/f0/9208f411486a55414915ee572ab6a01bd4d568b866e2fbd709e43100a8fe/pynpm-0.3.0.tar.gz", hash = "sha256:a69fcaac33e8521ea779484ca78d60e38046b18a0f329d9cd96848e3e0952d26", size = 18217, upload-time = "2025-02-20T12:46:55.975Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0a/e4/6c83230d1112252ec7dff979e858f6ba3182cb863fbf0d17b3cd97f1ff2b/pynpm-0.3.0-py2.py3-none-any.whl", hash = "sha256:5c0319ffba489ff87badc67ddedf6ee60cc4ade220c36b1b47f4b16a8a3e62a7", size = 6316, upload-time = "2025-02-20T12:46:54.151Z" },
]
[[package]]
name = "python-dateutil"
version = "2.9.0.post0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "six" },
]
sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
]
[[package]]
name = "python-slugify"
version = "8.0.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "text-unidecode" },
]
sdist = { url = "https://files.pythonhosted.org/packages/87/c7/5e1547c44e31da50a460df93af11a535ace568ef89d7a811069ead340c4a/python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856", size = 10921, upload-time = "2024-02-08T18:32:45.488Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a4/62/02da182e544a51a5c3ccf4b03ab79df279f9c60c5e82d5e8bec7ca26ac11/python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8", size = 10051, upload-time = "2024-02-08T18:32:43.911Z" },
]
[[package]]
name = "pywin32"
version = "311"
source = { registry = "https://pypi.org/simple" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31", size = 8706543, upload-time = "2025-07-14T20:13:20.765Z" },
{ url = "https://files.pythonhosted.org/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040, upload-time = "2025-07-14T20:13:22.543Z" },
{ url = "https://files.pythonhosted.org/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" },
{ url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" },
{ url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" },
{ url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" },
{ url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" },
{ url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" },
{ url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" },
]
[[package]]
name = "pyyaml"
version = "6.0.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" },
{ url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" },
{ url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" },
{ url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" },
{ url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" },
{ url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" },
{ url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" },
{ url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" },
{ url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" },
{ url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" },
{ url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" },
{ url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" },
{ url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" },
{ url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" },
{ url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" },
{ url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" },
{ url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" },
{ url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" },
{ url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" },
{ url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" },
{ url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" },
{ url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" },
{ url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" },
{ url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" },
{ url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" },
{ url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" },
{ url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" },
{ url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" },
{ url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" },
{ url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" },
{ url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" },
{ url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" },
{ url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" },
{ url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" },
{ url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" },
{ url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" },
{ url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" },
{ url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" },
]
[[package]]
name = "requests"
version = "2.32.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
{ name = "charset-normalizer" },
{ name = "idna" },
{ name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
]
[[package]]
name = "rich"
version = "14.2.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markdown-it-py" },
{ name = "pygments" },
]
sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990, upload-time = "2025-10-09T14:16:53.064Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" },
]
[[package]]
name = "setuptools"
version = "80.9.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" },
]
[[package]]
name = "six"
version = "1.17.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
]
[[package]]
name = "text-unidecode"
version = "1.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ab/e2/e9a00f0ccb71718418230718b3d900e71a5d16e701a3dae079a21e9cd8f8/text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93", size = 76885, upload-time = "2019-08-30T21:36:45.405Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a6/a5/c0b6468d3824fe3fde30dbb5e1f687b291608f9473681bbf7dabbf5a87d7/text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", size = 78154, upload-time = "2019-08-30T21:37:03.543Z" },
]
[[package]]
name = "toml"
version = "0.10.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253, upload-time = "2020-11-01T01:40:22.204Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" },
]
[[package]]
name = "tzdata"
version = "2025.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" },
]
[[package]]
name = "urllib3"
version = "2.5.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" },
]
[[package]]
name = "virtualenv"
version = "20.35.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "distlib" },
{ name = "filelock" },
{ name = "platformdirs" },
]
sdist = { url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c", size = 6028799, upload-time = "2025-10-29T06:57:40.511Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095, upload-time = "2025-10-29T06:57:37.598Z" },
]