mirror of
https://github.com/YunoHost-Apps/django-fmd_ynh.git
synced 2024-09-03 18:26:27 +02:00
Merge pull request #27 from YunoHost-Apps/cookiecutter-template
Cookiecutter template
This commit is contained in:
commit
73d32b5a04
49 changed files with 3481 additions and 2187 deletions
|
@ -1,4 +1,4 @@
|
|||
# see http://editorconfig.org
|
||||
# see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
|
@ -10,11 +10,11 @@ trim_trailing_whitespace = true
|
|||
insert_final_newline = true
|
||||
|
||||
[*.py]
|
||||
max_line_length = 100
|
||||
max_line_length = 119
|
||||
|
||||
[{Makefile,**.mk}]
|
||||
indent_style = tab
|
||||
insert_final_newline = false
|
||||
|
||||
[*.yml]
|
||||
indent_style = tab
|
||||
[{*.yaml,*.yml}]
|
||||
indent_size = 2
|
||||
|
|
4
.flake8
4
.flake8
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
# Move to pyproject.toml after: https://gitlab.com/pycqa/flake8/-/issues/428
|
||||
# Move to pyproject.toml after: https://github.com/PyCQA/flake8/issues/234
|
||||
#
|
||||
[flake8]
|
||||
exclude = .pytest_cache, .tox, dist, htmlcov, local_test
|
||||
exclude = .*, dist, htmlcov, local_test
|
||||
ignore = F405
|
||||
max-line-length = 119
|
||||
|
|
17
.github/workflows/package_linter.yml
vendored
17
.github/workflows/package_linter.yml
vendored
|
@ -1,6 +1,8 @@
|
|||
name: YunoHost apps package linter
|
||||
|
||||
on:
|
||||
# Allow to manually trigger the workflow
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
@ -12,12 +14,25 @@ jobs:
|
|||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.9'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install toml
|
||||
|
||||
- name: 'Clone YunoHost apps package linter'
|
||||
run: |
|
||||
git clone --depth=1 https://github.com/YunoHost/package_linter ~/package_linter
|
||||
|
||||
- name: 'Install requirements'
|
||||
run: pip3 install toml
|
||||
|
||||
- name: 'Run linter'
|
||||
run: |
|
||||
~/package_linter/package_linter.py .
|
||||
|
|
56
.github/workflows/pytest.yml
vendored
56
.github/workflows/pytest.yml
vendored
|
@ -1,56 +0,0 @@
|
|||
name: pytest
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 8 * * *'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
max-parallel: 2
|
||||
matrix:
|
||||
python-version: ["3.10", "3.9", "3.8", "3.7"]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: 'fetch master'
|
||||
run: |
|
||||
git fetch origin master
|
||||
- name: 'Set up Python ${{ matrix.python-version }}'
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '${{ matrix.python-version }}'
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/
|
||||
key: dot-cache-files
|
||||
|
||||
- name: 'Install package'
|
||||
run: |
|
||||
pip3 install poetry
|
||||
make install
|
||||
|
||||
- name: 'List installed packages'
|
||||
run: |
|
||||
poetry run pip freeze
|
||||
|
||||
- name: 'Run tests with Python v${{ matrix.python-version }}'
|
||||
run: |
|
||||
make pytest
|
||||
|
||||
- name: 'Run Safety check'
|
||||
run: |
|
||||
make safety
|
||||
|
||||
- name: 'Upload coverage report'
|
||||
uses: codecov/codecov-action@v2
|
||||
with:
|
||||
fail_ci_if_error: false
|
||||
verbose: true
|
60
.github/workflows/tests.yml
vendored
Normal file
60
.github/workflows/tests.yml
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
name: tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 8 * * *'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["3.12", "3.11", "3.10"]
|
||||
steps:
|
||||
- name: Checkout
|
||||
run: |
|
||||
echo $GITHUB_REF $GITHUB_SHA
|
||||
git clone https://github.com/$GITHUB_REPOSITORY.git .
|
||||
git fetch origin $GITHUB_SHA:temporary-ci-branch
|
||||
git checkout $GITHUB_SHA || (git fetch && git checkout $GITHUB_SHA)
|
||||
|
||||
- name: 'Set up Python ${{ matrix.python-version }}'
|
||||
uses: actions/setup-python@v4
|
||||
# https://github.com/marketplace/actions/setup-python
|
||||
with:
|
||||
python-version: '${{ matrix.python-version }}'
|
||||
cache: 'pip' # caching pip dependencies
|
||||
cache-dependency-path: '**/requirements.*.txt'
|
||||
|
||||
- name: 'Bootstrap dev venv'
|
||||
# The first CLI call will create the .venv
|
||||
run: |
|
||||
./dev-cli.py version
|
||||
|
||||
- name: 'dev CLI help'
|
||||
run: |
|
||||
./dev-cli.py --help
|
||||
|
||||
- name: 'Safety'
|
||||
run: |
|
||||
./dev-cli.py safety
|
||||
|
||||
- name: 'Run tests with Python v${{ matrix.python-version }}'
|
||||
env:
|
||||
PYTHONUNBUFFERED: 1
|
||||
PYTHONWARNINGS: always
|
||||
run: |
|
||||
./dev-cli.py tox
|
||||
|
||||
- name: 'Upload coverage report'
|
||||
uses: codecov/codecov-action@v3
|
||||
# https://github.com/marketplace/actions/codecov
|
||||
with:
|
||||
fail_ci_if_error: false
|
||||
verbose: true
|
||||
|
13
.gitignore
vendored
13
.gitignore
vendored
|
@ -1,11 +1,18 @@
|
|||
.*
|
||||
*.egg-info
|
||||
__pycache__
|
||||
/dist/
|
||||
/build/
|
||||
/coverage.*
|
||||
/htmlcov/
|
||||
*.orig
|
||||
|
||||
!.github
|
||||
!.editorconfig
|
||||
!.flake8
|
||||
!.gitignore
|
||||
!.gitkeep
|
||||
!/doc/screenshots/.gitkeep
|
||||
__pycache__
|
||||
|
||||
secret.txt
|
||||
/local_test/
|
||||
/coverage.xml
|
||||
/htmlcov/
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# All available README files by language
|
||||
|
||||
- [Read the README in English](README.md)
|
||||
- [Lea el README en español](README_es.md)
|
||||
- [Irakurri README euskaraz](README_eu.md)
|
||||
- [Lire le README en français](README_fr.md)
|
||||
- [Le o README en galego](README_gl.md)
|
||||
|
|
8
LICENSE
8
LICENSE
|
@ -1,7 +1,7 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
@ -645,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found.
|
|||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
|
@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box".
|
|||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
<https://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
|
|
58
Makefile
58
Makefile
|
@ -1,58 +0,0 @@
|
|||
SHELL := /bin/bash
|
||||
MAX_LINE_LENGTH := 100
|
||||
|
||||
all: help
|
||||
|
||||
help:
|
||||
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z0-9 -]+:.*?## / {printf "\033[36m%-22s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||||
|
||||
check-poetry:
|
||||
@if [[ "$(shell poetry --version 2>/dev/null)" == *"Poetry"* ]] ; \
|
||||
then \
|
||||
echo "Poetry found, ok." ; \
|
||||
else \
|
||||
echo 'Please install poetry first, with e.g.:' ; \
|
||||
echo 'make install-poetry' ; \
|
||||
exit 1 ; \
|
||||
fi
|
||||
|
||||
install-poetry: ## install or update poetry
|
||||
curl -sSL https://install.python-poetry.org | python3 -
|
||||
|
||||
install: check-poetry ## install project via poetry
|
||||
poetry install
|
||||
|
||||
update: check-poetry ## update the sources and installation and generate "conf/requirements.txt"
|
||||
poetry self update
|
||||
poetry update -v
|
||||
poetry export -f requirements.txt --output conf/requirements.txt
|
||||
|
||||
lint: ## Run code formatters and linter
|
||||
poetry run isort --check-only .
|
||||
poetry run flake8 .
|
||||
|
||||
fix-code-style: ## Fix code formatting
|
||||
poetry run black --verbose --safe --line-length=${MAX_LINE_LENGTH} --skip-string-normalization .
|
||||
poetry run isort .
|
||||
|
||||
tox-listenvs: check-poetry ## List all tox test environments
|
||||
poetry run tox --listenvs
|
||||
|
||||
tox: check-poetry ## Run pytest via tox with all environments
|
||||
poetry run tox
|
||||
|
||||
pytest: install ## Run pytest
|
||||
poetry run pytest
|
||||
|
||||
local-test: install ## Run local_test.py to run the project locally
|
||||
poetry run python3 ./local_test.py
|
||||
|
||||
local-diff-settings: ## Run "manage.py diffsettings" with local test
|
||||
poetry run python3 local_test/opt_yunohost/manage.py diffsettings
|
||||
|
||||
safety: ## Run https://github.com/pyupio/safety
|
||||
poetry run safety check --full-report
|
||||
|
||||
##############################################################################
|
||||
|
||||
.PHONY: help check-poetry install-poetry install update local-test
|
|
@ -32,11 +32,12 @@ Pull requests welcome ;)
|
|||
This package for YunoHost used [django-yunohost-integration](https://github.com/YunoHost-Apps/django_yunohost_integration)
|
||||
|
||||
|
||||
**Shipped version:** 0.3.2~ynh2
|
||||
**Shipped version:** 0.4.1~ynh1
|
||||
## Documentation and resources
|
||||
|
||||
- Official app website: <https://gitlab.com/jedie/django-find-my-device>
|
||||
- Upstream app code repository: <https://gitlab.com/jedie/django-find-my-device>
|
||||
- Official user documentation: <https://gitlab.com/jedie/django-find-my-device>
|
||||
- Official admin documentation: <https://github.com/YunoHost-Apps/django-fmd_ynh>
|
||||
- Upstream app code repository: <https://github.com/YunoHost-Apps/django-fmd_ynh>
|
||||
- YunoHost Store: <https://apps.yunohost.org/app/django-fmd>
|
||||
- Report a bug: <https://github.com/YunoHost-Apps/django-fmd_ynh/issues>
|
||||
|
||||
|
|
56
README_es.md
Normal file
56
README_es.md
Normal file
|
@ -0,0 +1,56 @@
|
|||
<!--
|
||||
Este archivo README esta generado automaticamente<https://github.com/YunoHost/apps/tree/master/tools/readme_generator>
|
||||
No se debe editar a mano.
|
||||
-->
|
||||
|
||||
# django-fmd para Yunohost
|
||||
|
||||
[![Nivel de integración](https://dash.yunohost.org/integration/django-fmd.svg)](https://dash.yunohost.org/appci/app/django-fmd) ![Estado funcional](https://ci-apps.yunohost.org/ci/badges/django-fmd.status.svg) ![Estado En Mantención](https://ci-apps.yunohost.org/ci/badges/django-fmd.maintain.svg)
|
||||
|
||||
[![Instalar django-fmd con Yunhost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=django-fmd)
|
||||
|
||||
*[Leer este README en otros idiomas.](./ALL_README.md)*
|
||||
|
||||
> *Este paquete le permite instalardjango-fmd rapidamente y simplement en un servidor YunoHost.*
|
||||
> *Si no tiene YunoHost, visita [the guide](https://yunohost.org/install) para aprender como instalarla.*
|
||||
|
||||
## Descripción general
|
||||
|
||||
Find My Device Server implemented in Python using Django.
|
||||
Usable for the Andorid App [**FindMyDevice**](https://gitlab.com/Nulide/findmydevice/) by [Nnulide](https://nulide.de/):
|
||||
|
||||
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" alt="Get FindMyDevice on F-Droid" height="80">](https://f-droid.org/packages/de.nulide.findmydevice/)
|
||||
|
||||
[![pytest](https://github.com/YunoHost-Apps/django-fmd_ynh/actions/workflows/pytest.yml/badge.svg?branch=master)](https://github.com/YunoHost-Apps/django-fmd_ynh/actions/workflows/pytest.yml) [![YunoHost apps package linter](https://github.com/YunoHost-Apps/django-fmd_ynh/actions/workflows/package_linter.yml/badge.svg)](https://github.com/YunoHost-Apps/django-fmd_ynh/actions/workflows/package_linter.yml) [![Coverage Status on codecov.io](https://codecov.io/gh/YunoHost-Apps/django-fmd_ynh/branch/master/graph/badge.svg)](https://codecov.io/gh/YunoHost-Apps/django-fmd_ynh)
|
||||
|
||||
[![django-fmd @ PyPi](https://img.shields.io/pypi/v/django-fmd?label=django-fmd%20%40%20PyPi)](https://pypi.org/project/django-fmd/)
|
||||
[![Python Versions](https://img.shields.io/pypi/pyversions/django-fmd)](https://gitlab.com/jedie/django-find-my-device/-/blob/main/pyproject.toml)
|
||||
[![License GPL V3+](https://img.shields.io/pypi/l/django-fmd)](https://gitlab.com/jedie/django-find-my-device/-/blob/main/LICENSE)
|
||||
|
||||
Pull requests welcome ;)
|
||||
|
||||
This package for YunoHost used [django-yunohost-integration](https://github.com/YunoHost-Apps/django_yunohost_integration)
|
||||
|
||||
|
||||
**Versión actual:** 0.4.1~ynh1
|
||||
## Documentaciones y recursos
|
||||
|
||||
- Documentación usuario oficial: <https://gitlab.com/jedie/django-find-my-device>
|
||||
- Documentación administrador oficial: <https://github.com/YunoHost-Apps/django-fmd_ynh>
|
||||
- Repositorio del código fuente oficial de la aplicación : <https://github.com/YunoHost-Apps/django-fmd_ynh>
|
||||
- Catálogo YunoHost: <https://apps.yunohost.org/app/django-fmd>
|
||||
- Reportar un error: <https://github.com/YunoHost-Apps/django-fmd_ynh/issues>
|
||||
|
||||
## Información para desarrolladores
|
||||
|
||||
Por favor enviar sus correcciones a la [`branch testing`](https://github.com/YunoHost-Apps/django-fmd_ynh/tree/testing
|
||||
|
||||
Para probar la rama `testing`, sigue asÍ:
|
||||
|
||||
```bash
|
||||
sudo yunohost app install https://github.com/YunoHost-Apps/django-fmd_ynh/tree/testing --debug
|
||||
o
|
||||
sudo yunohost app upgrade django-fmd -u https://github.com/YunoHost-Apps/django-fmd_ynh/tree/testing --debug
|
||||
```
|
||||
|
||||
**Mas informaciones sobre el empaquetado de aplicaciones:** <https://yunohost.org/packaging_apps>
|
|
@ -32,11 +32,12 @@ Pull requests welcome ;)
|
|||
This package for YunoHost used [django-yunohost-integration](https://github.com/YunoHost-Apps/django_yunohost_integration)
|
||||
|
||||
|
||||
**Paketatutako bertsioa:** 0.3.2~ynh2
|
||||
**Paketatutako bertsioa:** 0.4.1~ynh1
|
||||
## Dokumentazioa eta baliabideak
|
||||
|
||||
- Aplikazioaren webgune ofiziala: <https://gitlab.com/jedie/django-find-my-device>
|
||||
- Jatorrizko aplikazioaren kode-gordailua: <https://gitlab.com/jedie/django-find-my-device>
|
||||
- Erabiltzaileen dokumentazio ofiziala: <https://gitlab.com/jedie/django-find-my-device>
|
||||
- Administratzaileen dokumentazio ofiziala: <https://github.com/YunoHost-Apps/django-fmd_ynh>
|
||||
- Jatorrizko aplikazioaren kode-gordailua: <https://github.com/YunoHost-Apps/django-fmd_ynh>
|
||||
- YunoHost Denda: <https://apps.yunohost.org/app/django-fmd>
|
||||
- Eman errore baten berri: <https://github.com/YunoHost-Apps/django-fmd_ynh/issues>
|
||||
|
||||
|
|
|
@ -32,11 +32,12 @@ Pull requests welcome ;)
|
|||
This package for YunoHost used [django-yunohost-integration](https://github.com/YunoHost-Apps/django_yunohost_integration)
|
||||
|
||||
|
||||
**Version incluse :** 0.3.2~ynh2
|
||||
**Version incluse :** 0.4.1~ynh1
|
||||
## Documentations et ressources
|
||||
|
||||
- Site officiel de l’app : <https://gitlab.com/jedie/django-find-my-device>
|
||||
- Dépôt de code officiel de l’app : <https://gitlab.com/jedie/django-find-my-device>
|
||||
- Documentation officielle utilisateur : <https://gitlab.com/jedie/django-find-my-device>
|
||||
- Documentation officielle de l’admin : <https://github.com/YunoHost-Apps/django-fmd_ynh>
|
||||
- Dépôt de code officiel de l’app : <https://github.com/YunoHost-Apps/django-fmd_ynh>
|
||||
- YunoHost Store : <https://apps.yunohost.org/app/django-fmd>
|
||||
- Signaler un bug : <https://github.com/YunoHost-Apps/django-fmd_ynh/issues>
|
||||
|
||||
|
|
|
@ -32,11 +32,12 @@ Pull requests welcome ;)
|
|||
This package for YunoHost used [django-yunohost-integration](https://github.com/YunoHost-Apps/django_yunohost_integration)
|
||||
|
||||
|
||||
**Versión proporcionada:** 0.3.2~ynh2
|
||||
**Versión proporcionada:** 0.4.1~ynh1
|
||||
## Documentación e recursos
|
||||
|
||||
- Web oficial da app: <https://gitlab.com/jedie/django-find-my-device>
|
||||
- Repositorio de orixe do código: <https://gitlab.com/jedie/django-find-my-device>
|
||||
- Documentación oficial para usuarias: <https://gitlab.com/jedie/django-find-my-device>
|
||||
- Documentación oficial para admin: <https://github.com/YunoHost-Apps/django-fmd_ynh>
|
||||
- Repositorio de orixe do código: <https://github.com/YunoHost-Apps/django-fmd_ynh>
|
||||
- Tenda YunoHost: <https://apps.yunohost.org/app/django-fmd>
|
||||
- Informar dun problema: <https://github.com/YunoHost-Apps/django-fmd_ynh/issues>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
请勿手动编辑。
|
||||
-->
|
||||
|
||||
# YunoHost 的 django-fmd
|
||||
# YunoHost 上的 django-fmd
|
||||
|
||||
[![集成程度](https://dash.yunohost.org/integration/django-fmd.svg)](https://dash.yunohost.org/appci/app/django-fmd) ![工作状态](https://ci-apps.yunohost.org/ci/badges/django-fmd.status.svg) ![维护状态](https://ci-apps.yunohost.org/ci/badges/django-fmd.maintain.svg)
|
||||
|
||||
|
@ -32,11 +32,12 @@ Pull requests welcome ;)
|
|||
This package for YunoHost used [django-yunohost-integration](https://github.com/YunoHost-Apps/django_yunohost_integration)
|
||||
|
||||
|
||||
**分发版本:** 0.3.2~ynh2
|
||||
**分发版本:** 0.4.1~ynh1
|
||||
## 文档与资源
|
||||
|
||||
- 官方应用网站: <https://gitlab.com/jedie/django-find-my-device>
|
||||
- 上游应用代码库: <https://gitlab.com/jedie/django-find-my-device>
|
||||
- 官方用户文档: <https://gitlab.com/jedie/django-find-my-device>
|
||||
- 官方管理文档: <https://github.com/YunoHost-Apps/django-fmd_ynh>
|
||||
- 上游应用代码库: <https://github.com/YunoHost-Apps/django-fmd_ynh>
|
||||
- YunoHost 商店: <https://apps.yunohost.org/app/django-fmd>
|
||||
- 报告 bug: <https://github.com/YunoHost-Apps/django-fmd_ynh/issues>
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Configuration for Gunicorn
|
||||
"""
|
||||
|
@ -14,8 +13,8 @@ workers = multiprocessing.cpu_count() * 2 + 1
|
|||
loglevel = 'info'
|
||||
|
||||
# https://docs.gunicorn.org/en/latest/settings.html#logging
|
||||
accesslog = '/var/log/__APP__/__APP__.log'
|
||||
errorlog = '/var/log/__APP__/__APP__.log'
|
||||
accesslog = '__LOG_FILE__'
|
||||
errorlog = '__LOG_FILE__'
|
||||
|
||||
# https://docs.gunicorn.org/en/latest/settings.html#pidfile
|
||||
pidfile = '__INSTALL_DIR__/gunicorn.pid'
|
||||
pidfile = '__DATA_DIR__/gunicorn.pid' # /home/yunohost.app/$app/gunicorn.pid
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!__INSTALL_DIR__/venv/bin/python3
|
||||
#!__DATA_DIR__/venv/bin/python
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
|
||||
location __PATH__/static/ {
|
||||
# Service static files by nginx
|
||||
# e.g.: /var/www/$app/static
|
||||
alias __INSTALL_DIR__/public/static/;
|
||||
# e.g.: /var/www/$app/static/
|
||||
alias __INSTALL_DIR__/static/;
|
||||
expires 30d;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,215 +1,455 @@
|
|||
asgiref==3.5.2 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4 \
|
||||
--hash=sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424
|
||||
async-timeout==4.0.2 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15 \
|
||||
--hash=sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c
|
||||
bleach==5.0.1 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \
|
||||
--hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c
|
||||
bx-django-utils==35 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:341b27ad0b72a903acf2f28def0fe371def811c1b2305da9806124869a698fc8 \
|
||||
--hash=sha256:5151806d349a9dafc8dba9636239422022bab211b5b02afa52fce1f58ec2e6ab
|
||||
bx-py-utils==69 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:728fd575c4d5048e114b502a97d19679f9abcda90889a6896534c48348320460 \
|
||||
--hash=sha256:b25419e020c9c5ea16938a45cf5120086a5ac29648be78a8eb98ae202515fee1
|
||||
certifi==2022.9.24 ; python_version >= "3.7" and python_version < "4" \
|
||||
--hash=sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14 \
|
||||
--hash=sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382
|
||||
charset-normalizer==2.1.1 ; python_version >= "3.7" and python_version < "4" \
|
||||
--hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 \
|
||||
--hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f
|
||||
colorama==0.4.5 ; python_version >= "3.7" and python_full_version < "4.0.0" and sys_platform == "win32" \
|
||||
--hash=sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da \
|
||||
--hash=sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4
|
||||
colorlog==6.7.0 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:0d33ca236784a1ba3ff9c532d4964126d8a2c44f1f0cb1d2b0728196f512f662 \
|
||||
--hash=sha256:bd94bd21c1e13fac7bd3153f4bc3a7dc0eb0974b8bc2fdf1a989e474f6e582e5
|
||||
deprecated==1.2.13 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d \
|
||||
--hash=sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d
|
||||
django-axes==5.39.0 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:8f039f8e98f050f13f654efca599d8a04d0b57d330c590cf89ec2bf731c9a7fb \
|
||||
--hash=sha256:97702552f7939c81db5bba2ef855ae43f20df92fa261cb79fd4c8633ba3b3955
|
||||
django-debug-toolbar==3.7.0 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:1e3acad24e3d351ba45c6fa2072e4164820307332a776b16c9f06d1f89503465 \
|
||||
--hash=sha256:80de23066b624d3970fd296cf02d61988e5d56c31aa0dc4a428970b46e2883a8
|
||||
django-fmd==0.3.2 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:52bc6ff3af170b4ea0860f42863f24abccf904c75b6179197caef55cec793295 \
|
||||
--hash=sha256:eb02e13d68591c657e3c1e9fb8e536140f4736921c94b7aa17dc98480c1eec31
|
||||
django-ipware==4.0.2 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:602a58325a4808bd19197fef2676a0b2da2df40d0ecf21be414b2ff48c72ad05 \
|
||||
--hash=sha256:878dbb06a87e25550798e9ef3204ed70a200dd8b15e47dcef848cf08244f04c9
|
||||
django-redis==5.2.0 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:1d037dc02b11ad7aa11f655d26dac3fb1af32630f61ef4428860a2e29ff92026 \
|
||||
--hash=sha256:8a99e5582c79f894168f5865c52bd921213253b7fd64d16733ae4591564465de
|
||||
django-tools==0.54.0 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
#
|
||||
# This file is autogenerated by pip-compile with Python 3.11
|
||||
# by the following command:
|
||||
#
|
||||
# ./dev-cli.py update
|
||||
#
|
||||
argon2-cffi==23.1.0 \
|
||||
--hash=sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08 \
|
||||
--hash=sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea
|
||||
# via django-fmd
|
||||
argon2-cffi-bindings==21.2.0 \
|
||||
--hash=sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670 \
|
||||
--hash=sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f \
|
||||
--hash=sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583 \
|
||||
--hash=sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194 \
|
||||
--hash=sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c \
|
||||
--hash=sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a \
|
||||
--hash=sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082 \
|
||||
--hash=sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5 \
|
||||
--hash=sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f \
|
||||
--hash=sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7 \
|
||||
--hash=sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d \
|
||||
--hash=sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f \
|
||||
--hash=sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae \
|
||||
--hash=sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3 \
|
||||
--hash=sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86 \
|
||||
--hash=sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367 \
|
||||
--hash=sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d \
|
||||
--hash=sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93 \
|
||||
--hash=sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb \
|
||||
--hash=sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e \
|
||||
--hash=sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351
|
||||
# via argon2-cffi
|
||||
asgiref==3.8.1 \
|
||||
--hash=sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47 \
|
||||
--hash=sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590
|
||||
# via
|
||||
# django
|
||||
# django-axes
|
||||
async-timeout==4.0.3 \
|
||||
--hash=sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f \
|
||||
--hash=sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028
|
||||
# via cli-base-utilities
|
||||
bleach==6.1.0 \
|
||||
--hash=sha256:0a31f1837963c41d46bbf1331b8778e1308ea0791db03cc4e7357b97cf42a8fe \
|
||||
--hash=sha256:3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6
|
||||
# via django-tools
|
||||
bx-django-utils==77 \
|
||||
--hash=sha256:1dcfb05c3c8aba6a41aa70a95e3367c833b5842d1359f693876443c8f21039c5 \
|
||||
--hash=sha256:c731a45f0ffdc3d0996c600a9270f95393c951f2024d7fa7da70d7b0f6448818
|
||||
# via django-fmd
|
||||
bx-py-utils==92 \
|
||||
--hash=sha256:38641b2e1a09ed0c64cd6ba0e03c97fea347302439db0234a0492c365ae32719 \
|
||||
--hash=sha256:849c59429af6ca0bf35265569884193c60be578285a66b533146e5782a10637b
|
||||
# via
|
||||
# bx-django-utils
|
||||
# cli-base-utilities
|
||||
# django-fmd
|
||||
# django-tools
|
||||
certifi==2024.6.2 \
|
||||
--hash=sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516 \
|
||||
--hash=sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56
|
||||
# via requests
|
||||
cffi==1.16.0 \
|
||||
--hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \
|
||||
--hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \
|
||||
--hash=sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417 \
|
||||
--hash=sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab \
|
||||
--hash=sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520 \
|
||||
--hash=sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36 \
|
||||
--hash=sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743 \
|
||||
--hash=sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8 \
|
||||
--hash=sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed \
|
||||
--hash=sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684 \
|
||||
--hash=sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56 \
|
||||
--hash=sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324 \
|
||||
--hash=sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d \
|
||||
--hash=sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235 \
|
||||
--hash=sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e \
|
||||
--hash=sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088 \
|
||||
--hash=sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000 \
|
||||
--hash=sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7 \
|
||||
--hash=sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e \
|
||||
--hash=sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673 \
|
||||
--hash=sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c \
|
||||
--hash=sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe \
|
||||
--hash=sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2 \
|
||||
--hash=sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098 \
|
||||
--hash=sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8 \
|
||||
--hash=sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a \
|
||||
--hash=sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0 \
|
||||
--hash=sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b \
|
||||
--hash=sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896 \
|
||||
--hash=sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e \
|
||||
--hash=sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9 \
|
||||
--hash=sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2 \
|
||||
--hash=sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b \
|
||||
--hash=sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6 \
|
||||
--hash=sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404 \
|
||||
--hash=sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f \
|
||||
--hash=sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0 \
|
||||
--hash=sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4 \
|
||||
--hash=sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc \
|
||||
--hash=sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936 \
|
||||
--hash=sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba \
|
||||
--hash=sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872 \
|
||||
--hash=sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb \
|
||||
--hash=sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614 \
|
||||
--hash=sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1 \
|
||||
--hash=sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d \
|
||||
--hash=sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969 \
|
||||
--hash=sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b \
|
||||
--hash=sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4 \
|
||||
--hash=sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627 \
|
||||
--hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \
|
||||
--hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357
|
||||
# via argon2-cffi-bindings
|
||||
charset-normalizer==3.3.2 \
|
||||
--hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
|
||||
--hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \
|
||||
--hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \
|
||||
--hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \
|
||||
--hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \
|
||||
--hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \
|
||||
--hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \
|
||||
--hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \
|
||||
--hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \
|
||||
--hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \
|
||||
--hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \
|
||||
--hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \
|
||||
--hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \
|
||||
--hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \
|
||||
--hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \
|
||||
--hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \
|
||||
--hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \
|
||||
--hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \
|
||||
--hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \
|
||||
--hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \
|
||||
--hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \
|
||||
--hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \
|
||||
--hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \
|
||||
--hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \
|
||||
--hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \
|
||||
--hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \
|
||||
--hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \
|
||||
--hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \
|
||||
--hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \
|
||||
--hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \
|
||||
--hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \
|
||||
--hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \
|
||||
--hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \
|
||||
--hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \
|
||||
--hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \
|
||||
--hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \
|
||||
--hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \
|
||||
--hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \
|
||||
--hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \
|
||||
--hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \
|
||||
--hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \
|
||||
--hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \
|
||||
--hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \
|
||||
--hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \
|
||||
--hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \
|
||||
--hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \
|
||||
--hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \
|
||||
--hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \
|
||||
--hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \
|
||||
--hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \
|
||||
--hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \
|
||||
--hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \
|
||||
--hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \
|
||||
--hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \
|
||||
--hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \
|
||||
--hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \
|
||||
--hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \
|
||||
--hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \
|
||||
--hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \
|
||||
--hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \
|
||||
--hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \
|
||||
--hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \
|
||||
--hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \
|
||||
--hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \
|
||||
--hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \
|
||||
--hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \
|
||||
--hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \
|
||||
--hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \
|
||||
--hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \
|
||||
--hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \
|
||||
--hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \
|
||||
--hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \
|
||||
--hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \
|
||||
--hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \
|
||||
--hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \
|
||||
--hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \
|
||||
--hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \
|
||||
--hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \
|
||||
--hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \
|
||||
--hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \
|
||||
--hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \
|
||||
--hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \
|
||||
--hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \
|
||||
--hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \
|
||||
--hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \
|
||||
--hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \
|
||||
--hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \
|
||||
--hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \
|
||||
--hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \
|
||||
--hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561
|
||||
# via requests
|
||||
cli-base-utilities==0.8.0 \
|
||||
--hash=sha256:1009551eba81b33a0315c4fcfe3b6ef1633a99e303c9562dff39b824bff83ff0 \
|
||||
--hash=sha256:79628db9fc7ca01b5ab18c97c8fa5f3d8b96af9975c608f7fee9a44256edb2ab
|
||||
# via django-fmd_ynh (pyproject.toml)
|
||||
click==8.1.7 \
|
||||
--hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \
|
||||
--hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de
|
||||
# via
|
||||
# cli-base-utilities
|
||||
# rich-click
|
||||
colorlog==6.8.2 \
|
||||
--hash=sha256:3e3e079a41feb5a1b64f978b5ea4f46040a94f11f0e8bbb8261e3dbbeca64d44 \
|
||||
--hash=sha256:4dcbb62368e2800cb3c5abd348da7e53f6c362dda502ec27c560b2e58a66bd33
|
||||
# via
|
||||
# django-fmd
|
||||
# django-yunohost-integration
|
||||
django==5.0.6 \
|
||||
--hash=sha256:8363ac062bb4ef7c3f12d078f6fa5d154031d129a15170a1066412af49d30905 \
|
||||
--hash=sha256:ff1b61005004e476e0aeea47c7f79b85864c70124030e95146315396f1e7951f
|
||||
# via
|
||||
# bx-django-utils
|
||||
# django-axes
|
||||
# django-debug-toolbar
|
||||
# django-fmd
|
||||
# django-redis
|
||||
# django-tools
|
||||
# django-yunohost-integration
|
||||
django-axes==6.5.0 \
|
||||
--hash=sha256:bb4d602ef6ab823eb9c41f0957196986ee851756fa38566616f8512cba329661 \
|
||||
--hash=sha256:ee6b11b1331bb69a8fb90da9ecfac790ac95f5277ee04f16f55b4a5eb1593691
|
||||
# via django-yunohost-integration
|
||||
django-debug-toolbar==4.4.2 \
|
||||
--hash=sha256:5d7afb2ea5f8730241e5b0735396e16cd1fd8c6b53a2f3e1e30bbab9abb23728 \
|
||||
--hash=sha256:9204050fcb1e4f74216c5b024bc76081451926a6303993d6c513f5e142675927
|
||||
# via django-fmd
|
||||
django-fmd==0.4.1 \
|
||||
--hash=sha256:6d73bad1b812d292d0c22a447e987c9addcd94be51f1bdaa84dd9505b1f0f5a8 \
|
||||
--hash=sha256:fdcd41dc8a2132ef7078fd1b6ec0e5e31ad6b7aa303a4dfce7694a33bbd64b28
|
||||
# via django-fmd_ynh (pyproject.toml)
|
||||
django-redis==5.4.0 \
|
||||
--hash=sha256:6a02abaa34b0fea8bf9b707d2c363ab6adc7409950b2db93602e6cb292818c42 \
|
||||
--hash=sha256:ebc88df7da810732e2af9987f7f426c96204bf89319df4c6da6ca9a2942edd5b
|
||||
# via django-yunohost-integration
|
||||
django-tools==0.54.0 \
|
||||
--hash=sha256:5040a91282be9d1c9d379b0c65da50bcb3691bff03cee54fd4123ace238c3a43 \
|
||||
--hash=sha256:a7b7bfa5b9c5a81966454d17dffb2403cee25a806c858ee0486a08798227598f
|
||||
django-yunohost-integration[ynh]==0.4.1 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:3769859db283a6b4d17468aeb1decab2f79d4b3e128b341342948e7bb3121e8a \
|
||||
--hash=sha256:e097cd209f3e09cbe325eadea36e3eb64c051690297c38dd89a1cd64bc35d92e
|
||||
django==3.2.15 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:115baf5049d5cf4163e43492cdc7139c306ed6d451e7d3571fe9612903903713 \
|
||||
--hash=sha256:f71934b1a822f14a86c9ac9634053689279cd04ae69cb6ade4a59471b886582b
|
||||
gunicorn==20.1.0 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e \
|
||||
--hash=sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8
|
||||
icdiff==2.0.5 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:35d24b728e48b7e0a12bdb69386d3bfc7eef4fe922d0ac1cd70d6e5c11630bae
|
||||
idna==3.4 ; python_version >= "3.7" and python_version < "4" \
|
||||
--hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \
|
||||
--hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2
|
||||
importlib-metadata==4.2.0 ; python_version >= "3.7" and python_version < "3.8" \
|
||||
--hash=sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b \
|
||||
--hash=sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31
|
||||
packaging==21.3 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \
|
||||
--hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522
|
||||
pprintpp==0.4.0 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
# via django-yunohost-integration
|
||||
django-yunohost-integration[ynh]==0.7.1 \
|
||||
--hash=sha256:7dde5ce8cb5ff92a6f6bf7366882652b796d0ce62b8839eda5f800a87b104523 \
|
||||
--hash=sha256:d6dbddd9fae54e3ce4b0fbc6e8a3c0f19ed145c358b8bb8677baddd30ae6a028
|
||||
# via django-fmd_ynh (pyproject.toml)
|
||||
gunicorn==22.0.0 \
|
||||
--hash=sha256:350679f91b24062c86e386e198a15438d53a7a8207235a78ba1b53df4c4378d9 \
|
||||
--hash=sha256:4a0b436239ff76fb33f11c07a16482c521a7e09c1ce3cc293c2330afe01bec63
|
||||
# via
|
||||
# django-fmd
|
||||
# django-yunohost-integration
|
||||
icdiff==2.0.7 \
|
||||
--hash=sha256:f05d1b3623223dd1c70f7848da7d699de3d9a2550b902a8234d9026292fb5762 \
|
||||
--hash=sha256:f79a318891adbf59a45e3a7694f5e1f18c5407065264637072ac8363b759866f
|
||||
# via django-tools
|
||||
idna==3.7 \
|
||||
--hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \
|
||||
--hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0
|
||||
# via requests
|
||||
markdown-it-py==3.0.0 \
|
||||
--hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \
|
||||
--hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb
|
||||
# via rich
|
||||
mdurl==0.1.2 \
|
||||
--hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \
|
||||
--hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba
|
||||
# via markdown-it-py
|
||||
packaging==24.1 \
|
||||
--hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \
|
||||
--hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124
|
||||
# via
|
||||
# cli-base-utilities
|
||||
# django-yunohost-integration
|
||||
# gunicorn
|
||||
pprintpp==0.4.0 \
|
||||
--hash=sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d \
|
||||
--hash=sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403
|
||||
psycopg2==2.9.3 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:06f32425949bd5fe8f625c49f17ebb9784e1e4fe928b7cce72edc36fb68e4c0c \
|
||||
--hash=sha256:0762c27d018edbcb2d34d51596e4346c983bd27c330218c56c4dc25ef7e819bf \
|
||||
--hash=sha256:083707a696e5e1c330af2508d8fab36f9700b26621ccbcb538abe22e15485362 \
|
||||
--hash=sha256:34b33e0162cfcaad151f249c2649fd1030010c16f4bbc40a604c1cb77173dcf7 \
|
||||
--hash=sha256:4295093a6ae3434d33ec6baab4ca5512a5082cc43c0505293087b8a46d108461 \
|
||||
--hash=sha256:8cf3878353cc04b053822896bc4922b194792df9df2f1ad8da01fb3043602126 \
|
||||
--hash=sha256:8e841d1bf3434da985cc5ef13e6f75c8981ced601fd70cc6bf33351b91562981 \
|
||||
--hash=sha256:9572e08b50aed176ef6d66f15a21d823bb6f6d23152d35e8451d7d2d18fdac56 \
|
||||
--hash=sha256:a81e3866f99382dfe8c15a151f1ca5fde5815fde879348fe5a9884a7c092a305 \
|
||||
--hash=sha256:cb10d44e6694d763fa1078a26f7f6137d69f555a78ec85dc2ef716c37447e4b2 \
|
||||
--hash=sha256:d3ca6421b942f60c008f81a3541e8faf6865a28d5a9b48544b0ee4f40cac7fca
|
||||
pycryptodomex==3.15.0 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:04cc393045a8f19dd110c975e30f38ed7ab3faf21ede415ea67afebd95a22380 \
|
||||
--hash=sha256:0776bfaf2c48154ab54ea45392847c1283d2fcf64e232e85565f858baedfc1fa \
|
||||
--hash=sha256:0fadb9f7fa3150577800eef35f62a8a24b9ddf1563ff060d9bd3af22d3952c8c \
|
||||
--hash=sha256:18e2ab4813883ae63396c0ffe50b13554b32bb69ec56f0afaf052e7a7ae0d55b \
|
||||
--hash=sha256:191e73bc84a8064ad1874dba0ebadedd7cce4dedee998549518f2c74a003b2e1 \
|
||||
--hash=sha256:35a8f7afe1867118330e2e0e0bf759c409e28557fb1fc2fbb1c6c937297dbe9a \
|
||||
--hash=sha256:3709f13ca3852b0b07fc04a2c03b379189232b24007c466be0f605dd4723e9d4 \
|
||||
--hash=sha256:4540904c09704b6f831059c0dfb38584acb82cb97b0125cd52688c1f1e3fffa6 \
|
||||
--hash=sha256:463119d7d22d0fc04a0f9122e9d3e6121c6648bcb12a052b51bd1eed1b996aa2 \
|
||||
--hash=sha256:46b3f05f2f7ac7841053da4e0f69616929ca3c42f238c405f6c3df7759ad2780 \
|
||||
--hash=sha256:48697790203909fab02a33226fda546604f4e2653f9d47bc5d3eb40879fa7c64 \
|
||||
--hash=sha256:5676a132169a1c1a3712edf25250722ebc8c9102aa9abd814df063ca8362454f \
|
||||
--hash=sha256:65204412d0c6a8e3c41e21e93a5e6054a74fea501afa03046a388cf042e3377a \
|
||||
--hash=sha256:67e1e6a92151023ccdfcfbc0afb3314ad30080793b4c27956ea06ab1fb9bcd8a \
|
||||
--hash=sha256:6f5b6ba8aefd624834bc177a2ac292734996bb030f9d1b388e7504103b6fcddf \
|
||||
--hash=sha256:7341f1bb2dadb0d1a0047f34c3a58208a92423cdbd3244d998e4b28df5eac0ed \
|
||||
--hash=sha256:78d9621cf0ea35abf2d38fa2ca6d0634eab6c991a78373498ab149953787e5e5 \
|
||||
--hash=sha256:8eecdf9cdc7343001d047f951b9cc805cd68cb6cd77b20ea46af5bffc5bd3dfb \
|
||||
--hash=sha256:94c7b60e1f52e1a87715571327baea0733708ab4723346598beca4a3b6879794 \
|
||||
--hash=sha256:996e1ba717077ce1e6d4849af7a1426f38b07b3d173b879e27d5e26d2e958beb \
|
||||
--hash=sha256:a07a64709e366c2041cd5cfbca592b43998bf4df88f7b0ca73dca37071ccf1bd \
|
||||
--hash=sha256:b6306403228edde6e289f626a3908a2f7f67c344e712cf7c0a508bab3ad9e381 \
|
||||
--hash=sha256:b9279adc16e4b0f590ceff581f53a80179b02cba9056010d733eb4196134a870 \
|
||||
--hash=sha256:c4cb9cb492ea7dcdf222a8d19a1d09002798ea516aeae8877245206d27326d86 \
|
||||
--hash=sha256:dd452a5af7014e866206d41751886c9b4bf379a339fdf2dbfc7dd16c0fb4f8e0 \
|
||||
--hash=sha256:e2b12968522a0358b8917fc7b28865acac002f02f4c4c6020fcb264d76bfd06d \
|
||||
--hash=sha256:e3164a18348bd53c69b4435ebfb4ac8a4076291ffa2a70b54f0c4b80c7834b1d \
|
||||
--hash=sha256:e47bf8776a7e15576887f04314f5228c6527b99946e6638cf2f16da56d260cab \
|
||||
--hash=sha256:f8be976cec59b11f011f790b88aca67b4ea2bd286578d0bd3e31bcd19afcd3e4 \
|
||||
--hash=sha256:fc9bc7a9b79fe5c750fc81a307052f8daabb709bdaabb0fb18fb136b66b653b5
|
||||
pyparsing==3.0.9 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \
|
||||
--hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc
|
||||
python-stdnum==1.17 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:374e2b5e13912ccdbf50b0b23fca2c3e0531174805c32d74e145f37756328340 \
|
||||
--hash=sha256:a46e6cf9652807314d369b654b255c86a59f93d18be2834f3d567ed1a346c547
|
||||
pytz==2022.4 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:2c0784747071402c6e99f0bafdb7da0fa22645f06554c7ae06bf6358897e9c91 \
|
||||
--hash=sha256:48ce799d83b6f8aab2020e369b627446696619e79645419610b9facd909b3174
|
||||
redis==4.3.4 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:a52d5694c9eb4292770084fa8c863f79367ca19884b329ab574d5cb2036b3e54 \
|
||||
--hash=sha256:ddf27071df4adf3821c4f2ca59d67525c3a82e5f268bed97b813cb4fabf87880
|
||||
requests==2.28.1 ; python_version >= "3.7" and python_version < "4" \
|
||||
--hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 \
|
||||
--hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349
|
||||
setuptools==65.4.1 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:1b6bdc6161661409c5f21508763dc63ab20a9ac2f8ba20029aaaa7fdb9118012 \
|
||||
--hash=sha256:3050e338e5871e70c72983072fe34f6032ae1cdeeeb67338199c2f74e083a80e
|
||||
six==1.16.0 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
# via django-tools
|
||||
psycopg2==2.9.9 \
|
||||
--hash=sha256:121081ea2e76729acfb0673ff33755e8703d45e926e416cb59bae3a86c6a4981 \
|
||||
--hash=sha256:38a8dcc6856f569068b47de286b472b7c473ac7977243593a288ebce0dc89516 \
|
||||
--hash=sha256:426f9f29bde126913a20a96ff8ce7d73fd8a216cfb323b1f04da402d452853c3 \
|
||||
--hash=sha256:5e0d98cade4f0e0304d7d6f25bbfbc5bd186e07b38eac65379309c4ca3193efa \
|
||||
--hash=sha256:7e2dacf8b009a1c1e843b5213a87f7c544b2b042476ed7755be813eaf4e8347a \
|
||||
--hash=sha256:a7653d00b732afb6fc597e29c50ad28087dcb4fbfb28e86092277a559ae4e693 \
|
||||
--hash=sha256:ade01303ccf7ae12c356a5e10911c9e1c51136003a9a1d92f7aa9d010fb98372 \
|
||||
--hash=sha256:bac58c024c9922c23550af2a581998624d6e02350f4ae9c5f0bc642c633a2d5e \
|
||||
--hash=sha256:c92811b2d4c9b6ea0285942b2e7cac98a59e166d59c588fe5cfe1eda58e72d59 \
|
||||
--hash=sha256:d1454bde93fb1e224166811694d600e746430c006fbb031ea06ecc2ea41bf156 \
|
||||
--hash=sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024 \
|
||||
--hash=sha256:de80739447af31525feddeb8effd640782cf5998e1a4e9192ebdf829717e3913 \
|
||||
--hash=sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c
|
||||
# via django-yunohost-integration
|
||||
pycparser==2.22 \
|
||||
--hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \
|
||||
--hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc
|
||||
# via cffi
|
||||
pycryptodomex==3.20.0 \
|
||||
--hash=sha256:0daad007b685db36d977f9de73f61f8da2a7104e20aca3effd30752fd56f73e1 \
|
||||
--hash=sha256:108e5f1c1cd70ffce0b68739c75734437c919d2eaec8e85bffc2c8b4d2794305 \
|
||||
--hash=sha256:19764605feea0df966445d46533729b645033f134baeb3ea26ad518c9fdf212c \
|
||||
--hash=sha256:1be97461c439a6af4fe1cf8bf6ca5936d3db252737d2f379cc6b2e394e12a458 \
|
||||
--hash=sha256:25cd61e846aaab76d5791d006497134602a9e451e954833018161befc3b5b9ed \
|
||||
--hash=sha256:2a47bcc478741b71273b917232f521fd5704ab4b25d301669879e7273d3586cc \
|
||||
--hash=sha256:59af01efb011b0e8b686ba7758d59cf4a8263f9ad35911bfe3f416cee4f5c08c \
|
||||
--hash=sha256:5dcac11031a71348faaed1f403a0debd56bf5404232284cf8c761ff918886ebc \
|
||||
--hash=sha256:62a5ec91388984909bb5398ea49ee61b68ecb579123694bffa172c3b0a107079 \
|
||||
--hash=sha256:645bd4ca6f543685d643dadf6a856cc382b654cc923460e3a10a49c1b3832aeb \
|
||||
--hash=sha256:653b29b0819605fe0898829c8ad6400a6ccde096146730c2da54eede9b7b8baa \
|
||||
--hash=sha256:69138068268127cd605e03438312d8f271135a33140e2742b417d027a0539427 \
|
||||
--hash=sha256:6e186342cfcc3aafaad565cbd496060e5a614b441cacc3995ef0091115c1f6c5 \
|
||||
--hash=sha256:76bd15bb65c14900d98835fcd10f59e5e0435077431d3a394b60b15864fddd64 \
|
||||
--hash=sha256:7805830e0c56d88f4d491fa5ac640dfc894c5ec570d1ece6ed1546e9df2e98d6 \
|
||||
--hash=sha256:7a710b79baddd65b806402e14766c721aee8fb83381769c27920f26476276c1e \
|
||||
--hash=sha256:7a7a8f33a1f1fb762ede6cc9cbab8f2a9ba13b196bfaf7bc6f0b39d2ba315a43 \
|
||||
--hash=sha256:82ee7696ed8eb9a82c7037f32ba9b7c59e51dda6f105b39f043b6ef293989cb3 \
|
||||
--hash=sha256:88afd7a3af7ddddd42c2deda43d53d3dfc016c11327d0915f90ca34ebda91499 \
|
||||
--hash=sha256:8af1a451ff9e123d0d8bd5d5e60f8e3315c3a64f3cdd6bc853e26090e195cdc8 \
|
||||
--hash=sha256:8ee606964553c1a0bc74057dd8782a37d1c2bc0f01b83193b6f8bb14523b877b \
|
||||
--hash=sha256:91852d4480a4537d169c29a9d104dda44094c78f1f5b67bca76c29a91042b623 \
|
||||
--hash=sha256:9c682436c359b5ada67e882fec34689726a09c461efd75b6ea77b2403d5665b7 \
|
||||
--hash=sha256:bc3ee1b4d97081260d92ae813a83de4d2653206967c4a0a017580f8b9548ddbc \
|
||||
--hash=sha256:bca649483d5ed251d06daf25957f802e44e6bb6df2e8f218ae71968ff8f8edc4 \
|
||||
--hash=sha256:c39778fd0548d78917b61f03c1fa8bfda6cfcf98c767decf360945fe6f97461e \
|
||||
--hash=sha256:cbe71b6712429650e3883dc81286edb94c328ffcd24849accac0a4dbcc76958a \
|
||||
--hash=sha256:d00fe8596e1cc46b44bf3907354e9377aa030ec4cd04afbbf6e899fc1e2a7781 \
|
||||
--hash=sha256:d3584623e68a5064a04748fb6d76117a21a7cb5eaba20608a41c7d0c61721794 \
|
||||
--hash=sha256:e48217c7901edd95f9f097feaa0388da215ed14ce2ece803d3f300b4e694abea \
|
||||
--hash=sha256:f2e497413560e03421484189a6b65e33fe800d3bd75590e6d78d4dfdb7accf3b \
|
||||
--hash=sha256:ff5c9a67f8a4fba4aed887216e32cbc48f2a6fb2673bb10a99e43be463e15913
|
||||
# via django-fmd
|
||||
pygments==2.18.0 \
|
||||
--hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \
|
||||
--hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a
|
||||
# via rich
|
||||
python-stdnum==1.20 \
|
||||
--hash=sha256:111008e10391d54fb2afad2a10df70d5cb0c6c0a7ec82fec6f022cb8712961d3 \
|
||||
--hash=sha256:ad2a2cf2eb025de408210235f36b4ae31252de3186240ccaa8126e117cb82690
|
||||
# via bx-django-utils
|
||||
pyyaml==6.0.1 \
|
||||
--hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \
|
||||
--hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \
|
||||
--hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \
|
||||
--hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \
|
||||
--hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \
|
||||
--hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \
|
||||
--hash=sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595 \
|
||||
--hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \
|
||||
--hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \
|
||||
--hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \
|
||||
--hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \
|
||||
--hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \
|
||||
--hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \
|
||||
--hash=sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6 \
|
||||
--hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \
|
||||
--hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \
|
||||
--hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \
|
||||
--hash=sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6 \
|
||||
--hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \
|
||||
--hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \
|
||||
--hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \
|
||||
--hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \
|
||||
--hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \
|
||||
--hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \
|
||||
--hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \
|
||||
--hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \
|
||||
--hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \
|
||||
--hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \
|
||||
--hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \
|
||||
--hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \
|
||||
--hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \
|
||||
--hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \
|
||||
--hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \
|
||||
--hash=sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0 \
|
||||
--hash=sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515 \
|
||||
--hash=sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c \
|
||||
--hash=sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c \
|
||||
--hash=sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924 \
|
||||
--hash=sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34 \
|
||||
--hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \
|
||||
--hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \
|
||||
--hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \
|
||||
--hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \
|
||||
--hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \
|
||||
--hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \
|
||||
--hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \
|
||||
--hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \
|
||||
--hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \
|
||||
--hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \
|
||||
--hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \
|
||||
--hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f
|
||||
# via django-yunohost-integration
|
||||
redis==5.0.6 \
|
||||
--hash=sha256:38473cd7c6389ad3e44a91f4c3eaf6bcb8a9f746007f29bf4fb20824ff0b2197 \
|
||||
--hash=sha256:c0d6d990850c627bbf7be01c5c4cbaadf67b48593e913bb71c9819c30df37eee
|
||||
# via django-redis
|
||||
requests==2.32.3 \
|
||||
--hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
|
||||
--hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
|
||||
# via django-fmd
|
||||
rich==13.7.1 \
|
||||
--hash=sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222 \
|
||||
--hash=sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432
|
||||
# via
|
||||
# cli-base-utilities
|
||||
# rich-click
|
||||
rich-click==1.8.3 \
|
||||
--hash=sha256:636d9c040d31c5eee242201b5bf4f2d358bfae4db14bb22ec1cafa717cfd02cd \
|
||||
--hash=sha256:6d75bdfa7aa9ed2c467789a0688bc6da23fbe3a143e19aa6ad3f8bac113d2ab3
|
||||
# via cli-base-utilities
|
||||
six==1.16.0 \
|
||||
--hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
|
||||
--hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
|
||||
sqlparse==0.4.3 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:0323c0ec29cd52bceabc1b4d9d579e311f3e4961b98d174201d5622a23b85e34 \
|
||||
--hash=sha256:69ca804846bb114d2ec380e4360a8a340db83f0ccf3afceeb1404df028f57268
|
||||
typing-extensions==4.3.0 ; python_version >= "3.7" and python_version < "3.8" \
|
||||
--hash=sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02 \
|
||||
--hash=sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6
|
||||
urllib3==1.26.12 ; python_version >= "3.7" and python_version < "4" \
|
||||
--hash=sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e \
|
||||
--hash=sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997
|
||||
webencodings==0.5.1 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
# via bleach
|
||||
sqlparse==0.5.0 \
|
||||
--hash=sha256:714d0a4932c059d16189f58ef5411ec2287a4360f17cdd0edd2d09d4c5087c93 \
|
||||
--hash=sha256:c204494cd97479d0e39f28c93d46c0b2d5959c7b9ab904762ea6c7af211c8663
|
||||
# via
|
||||
# django
|
||||
# django-debug-toolbar
|
||||
tomli==2.0.1 \
|
||||
--hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
|
||||
--hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
|
||||
# via cli-base-utilities
|
||||
tomlkit==0.12.5 \
|
||||
--hash=sha256:af914f5a9c59ed9d0762c7b64d3b5d5df007448eb9cd2edc8a46b1eafead172f \
|
||||
--hash=sha256:eef34fba39834d4d6b73c9ba7f3e4d1c417a4e56f89a7e96e090dd0d24b8fb3c
|
||||
# via cli-base-utilities
|
||||
typing-extensions==4.12.2 \
|
||||
--hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \
|
||||
--hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8
|
||||
# via rich-click
|
||||
urllib3==2.2.2 \
|
||||
--hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \
|
||||
--hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168
|
||||
# via requests
|
||||
webencodings==0.5.1 \
|
||||
--hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \
|
||||
--hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923
|
||||
wrapt==1.14.1 ; python_version >= "3.7" and python_full_version < "4.0.0" \
|
||||
--hash=sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3 \
|
||||
--hash=sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b \
|
||||
--hash=sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4 \
|
||||
--hash=sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2 \
|
||||
--hash=sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656 \
|
||||
--hash=sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3 \
|
||||
--hash=sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff \
|
||||
--hash=sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310 \
|
||||
--hash=sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a \
|
||||
--hash=sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57 \
|
||||
--hash=sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069 \
|
||||
--hash=sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383 \
|
||||
--hash=sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe \
|
||||
--hash=sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87 \
|
||||
--hash=sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d \
|
||||
--hash=sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b \
|
||||
--hash=sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907 \
|
||||
--hash=sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f \
|
||||
--hash=sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0 \
|
||||
--hash=sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28 \
|
||||
--hash=sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1 \
|
||||
--hash=sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853 \
|
||||
--hash=sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc \
|
||||
--hash=sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3 \
|
||||
--hash=sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3 \
|
||||
--hash=sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164 \
|
||||
--hash=sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1 \
|
||||
--hash=sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c \
|
||||
--hash=sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1 \
|
||||
--hash=sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7 \
|
||||
--hash=sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1 \
|
||||
--hash=sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320 \
|
||||
--hash=sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed \
|
||||
--hash=sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1 \
|
||||
--hash=sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248 \
|
||||
--hash=sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c \
|
||||
--hash=sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456 \
|
||||
--hash=sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77 \
|
||||
--hash=sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef \
|
||||
--hash=sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1 \
|
||||
--hash=sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7 \
|
||||
--hash=sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86 \
|
||||
--hash=sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4 \
|
||||
--hash=sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d \
|
||||
--hash=sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d \
|
||||
--hash=sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8 \
|
||||
--hash=sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5 \
|
||||
--hash=sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471 \
|
||||
--hash=sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00 \
|
||||
--hash=sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68 \
|
||||
--hash=sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3 \
|
||||
--hash=sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d \
|
||||
--hash=sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735 \
|
||||
--hash=sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d \
|
||||
--hash=sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569 \
|
||||
--hash=sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7 \
|
||||
--hash=sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59 \
|
||||
--hash=sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5 \
|
||||
--hash=sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb \
|
||||
--hash=sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b \
|
||||
--hash=sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f \
|
||||
--hash=sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462 \
|
||||
--hash=sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015 \
|
||||
--hash=sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af
|
||||
zipp==3.8.1 ; python_version >= "3.7" and python_version < "3.8" \
|
||||
--hash=sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2 \
|
||||
--hash=sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009
|
||||
# via bleach
|
||||
|
|
|
@ -1,43 +1,46 @@
|
|||
#!/usr/bin/env python3
|
||||
################################################################################
|
||||
################################################################################
|
||||
|
||||
# Please do not modify this file, it will be reset at the next update.
|
||||
# You can edit the file __INSTALL_DIR__/local_settings.py and add/modify the settings you need.
|
||||
# You can edit the file __DATA_DIR__/local_settings.py and add/modify the settings you need.
|
||||
# The parameters you add in local_settings.py will overwrite these,
|
||||
# but you can use the options and documentation in this file to find out what can be done.
|
||||
|
||||
################################################################################
|
||||
################################################################################
|
||||
|
||||
from pathlib import Path
|
||||
from pathlib import Path as __Path
|
||||
|
||||
from django_yunohost_integration.base_settings import * # noqa:F401,F403
|
||||
from django_yunohost_integration.secret_key import get_or_create_secret as __get_or_create_secret
|
||||
|
||||
from findmydevice_project.settings.base import * # noqa:F401,F403
|
||||
|
||||
# https://gitlab.com/jedie/django-find-my-device
|
||||
from findmydevice_project.settings.prod import * # noqa:F401,F403 isort:skip
|
||||
|
||||
|
||||
from django_yunohost_integration.base_settings import LOGGING # noqa:F401 isort:skip
|
||||
|
||||
|
||||
INSTALL_DIR = Path('__INSTALL_DIR__')
|
||||
assert INSTALL_DIR.is_dir(), f'Directory not exists: {INSTALL_DIR}'
|
||||
DATA_DIR_PATH = __Path('__DATA_DIR__') # /home/yunohost.app/$app/
|
||||
assert DATA_DIR_PATH.is_dir(), f'Directory not exists: {DATA_DIR_PATH}'
|
||||
|
||||
PUBLIC_PATH = Path('__INSTALL_DIR__/public')
|
||||
assert PUBLIC_PATH.is_dir(), f'Directory not exists: {PUBLIC_PATH}'
|
||||
INSTALL_DIR_PATH = __Path('__INSTALL_DIR__') # /var/www/$app/
|
||||
assert INSTALL_DIR_PATH.is_dir(), f'Directory not exists: {INSTALL_DIR_PATH}'
|
||||
|
||||
LOG_FILE = Path('/var/log/__APP__/__APP__.log')
|
||||
assert LOG_FILE.is_file(), f'File not exists: {LOG_FILE}'
|
||||
LOG_FILE_PATH = __Path('__LOG_FILE__') # /var/log/$app/django_fmd_ynh.log
|
||||
assert LOG_FILE_PATH.is_file(), f'File not exists: {LOG_FILE_PATH}'
|
||||
|
||||
PATH = '__PATH__' # $YNH_APP_ARG_PATH
|
||||
PATH = PATH.strip('/')
|
||||
PATH_URL = '__PATH__'
|
||||
PATH_URL = PATH_URL.strip('/')
|
||||
|
||||
YNH_CURRENT_HOST = '__YNH_CURRENT_HOST__' # YunoHost main domain from: /etc/yunohost/current_host
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# config_panel.toml settings:
|
||||
|
||||
DEBUG_ENABLED = '__DEBUG_ENABLED__'
|
||||
DEBUG = bool(int(DEBUG_ENABLED))
|
||||
DEBUG = DEBUG_ENABLED == '1'
|
||||
|
||||
LOG_LEVEL = '__LOG_LEVEL__'
|
||||
ADMIN_EMAIL = '__ADMIN_EMAIL__'
|
||||
|
@ -49,20 +52,26 @@ DEFAULT_FROM_EMAIL = '__DEFAULT_FROM_EMAIL__'
|
|||
# Function that will be called to finalize a user profile:
|
||||
YNH_SETUP_USER = 'setup_user.setup_project_user'
|
||||
|
||||
SECRET_KEY = __get_or_create_secret(INSTALL_DIR / 'secret.txt')
|
||||
|
||||
INSTALLED_APPS += [
|
||||
'axes', # https://github.com/jazzband/django-axes
|
||||
'django_yunohost_integration',
|
||||
]
|
||||
if 'axes' not in INSTALLED_APPS:
|
||||
INSTALLED_APPS.append('axes') # https://github.com/jazzband/django-axes
|
||||
|
||||
INSTALLED_APPS.append('django_yunohost_integration.apps.YunohostIntegrationConfig')
|
||||
|
||||
|
||||
SECRET_KEY = __get_or_create_secret(
|
||||
DATA_DIR_PATH / 'secret.txt'
|
||||
) # /home/yunohost.app/$app/secret.txt
|
||||
|
||||
|
||||
MIDDLEWARE.insert(
|
||||
MIDDLEWARE.index('django.contrib.auth.middleware.AuthenticationMiddleware') + 1,
|
||||
# login a user via HTTP_REMOTE_USER header from SSOwat:
|
||||
'django_yunohost_integration.sso_auth.auth_middleware.SSOwatRemoteUserMiddleware',
|
||||
)
|
||||
# AxesMiddleware should be the last middleware:
|
||||
MIDDLEWARE.append('axes.middleware.AxesMiddleware')
|
||||
if 'axes.middleware.AxesMiddleware' not in MIDDLEWARE:
|
||||
# AxesMiddleware should be the last middleware:
|
||||
MIDDLEWARE.append('axes.middleware.AxesMiddleware')
|
||||
|
||||
|
||||
# Keep ModelBackend around for per-user permissions and superuser
|
||||
|
@ -140,28 +149,30 @@ CACHES = {
|
|||
# _____________________________________________________________________________
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
|
||||
if PATH:
|
||||
STATIC_URL = f'/{PATH}/static/'
|
||||
MEDIA_URL = f'/{PATH}/media/'
|
||||
if PATH_URL:
|
||||
STATIC_URL = f'/{PATH_URL}/static/'
|
||||
MEDIA_URL = f'/{PATH_URL}/media/'
|
||||
else:
|
||||
# Installed to domain root, without a path prefix?
|
||||
STATIC_URL = '/static/'
|
||||
MEDIA_URL = '/media/'
|
||||
|
||||
STATIC_ROOT = str(PUBLIC_PATH / 'static')
|
||||
MEDIA_ROOT = str(PUBLIC_PATH / 'media')
|
||||
STATIC_ROOT = str(INSTALL_DIR_PATH / 'static')
|
||||
MEDIA_ROOT = str(INSTALL_DIR_PATH / 'media')
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Set log file to e.g.: /var/log/$app/$app.log
|
||||
LOGGING['handlers']['log_file']['filename'] = str(LOG_FILE)
|
||||
LOGGING['handlers']['log_file']['filename'] = str(LOG_FILE_PATH)
|
||||
|
||||
# Example how to add logging to own app:
|
||||
LOGGING['loggers']['findmydevice'] = {
|
||||
'handlers': ['syslog', 'log_file', 'mail_admins'],
|
||||
'level': 'INFO',
|
||||
'propagate': False,
|
||||
}
|
||||
for __logger_name in LOGGING['loggers'].keys():
|
||||
LOGGING['loggers'][__logger_name]['level'] = 'DEBUG' if DEBUG else LOG_LEVEL
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
def setup_project_user(user):
|
||||
"""
|
||||
All users used the Django admin, so we need to set the "staff" user flag.
|
||||
Called from django_yunohost_integration.sso_auth
|
||||
"""
|
||||
user.is_staff = True
|
||||
user.is_superuser = True
|
||||
user.save()
|
||||
return user
|
||||
|
|
|
@ -5,9 +5,9 @@ After=redis.service postgresql.service
|
|||
[Service]
|
||||
User=__APP__
|
||||
Group=__APP__
|
||||
WorkingDirectory=__INSTALL_DIR__/
|
||||
WorkingDirectory=__DATA_DIR__/
|
||||
|
||||
ExecStart=__INSTALL_DIR__/venv/bin/gunicorn --config __INSTALL_DIR__/gunicorn.conf.py wsgi
|
||||
ExecStart=__DATA_DIR__/venv/bin/gunicorn --config __DATA_DIR__/gunicorn.conf.py wsgi
|
||||
|
||||
StandardOutput=syslog
|
||||
StandardError=syslog
|
||||
|
|
20
conf/urls.py
20
conf/urls.py
|
@ -1,23 +1,19 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
urls.py
|
||||
~~~~~~~
|
||||
"""
|
||||
import findmydevice
|
||||
from django.conf import settings
|
||||
from django.urls import include, path
|
||||
from django.views.generic import RedirectView
|
||||
from django.views.static import serve
|
||||
|
||||
import findmydevice
|
||||
|
||||
|
||||
if settings.PATH:
|
||||
# settings.PATH is the $YNH_APP_ARG_PATH
|
||||
# Prefix all urls with "PATH":
|
||||
if settings.PATH_URL:
|
||||
# settings.PATH_URL is app_path
|
||||
# Prefix all urls with "PATH_URL":
|
||||
urlpatterns = [
|
||||
path(f'{settings.PATH}/', include('findmydevice_project.urls')),
|
||||
path('', RedirectView.as_view(url=f'{settings.PATH_URL}/')),
|
||||
path(f'{settings.PATH_URL}/', include('findmydevice_project.urls')),
|
||||
#
|
||||
# TODO: Serve from nginx server ;)
|
||||
path(f'{settings.PATH}/<path:path>', serve, {'document_root': findmydevice.WEB_PATH})
|
||||
path(f'{settings.PATH_URL}/<path:path>', serve, {'document_root': findmydevice.WEB_PATH}),
|
||||
]
|
||||
else:
|
||||
# Installed to domain root, without a path prefix
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# https://yunohost.org/en/packaging_config_panels
|
||||
# https://github.com/YunoHost/example_ynh/blob/master/config_panel.toml.example
|
||||
|
||||
version = "1.0"
|
||||
|
@ -14,13 +15,16 @@ services = ["__APP__"]
|
|||
ask = "from email"
|
||||
type = "email"
|
||||
help = "Default email address to use for various automated emails."
|
||||
bind = "default_from_email:__INSTALL_DIR__/settings.py"
|
||||
#
|
||||
# We can't use "__DATA_DIR__" in bind value, because of this bug:
|
||||
# https://github.com/YunoHost/issues/issues/2283
|
||||
bind = "default_from_email:/home/yunohost.app/__APP__/settings.py"
|
||||
|
||||
[main.config.admin_email]
|
||||
ask = "ADMIN email"
|
||||
type = "email"
|
||||
help = "EMail address for error emails."
|
||||
bind = "admin_email:__INSTALL_DIR__/settings.py"
|
||||
bind = "admin_email:/home/yunohost.app/__APP__/settings.py"
|
||||
|
||||
[main.config.debug_enabled]
|
||||
ask = "DEBUG mode"
|
||||
|
@ -28,11 +32,11 @@ services = ["__APP__"]
|
|||
yes = "1"
|
||||
no = "0"
|
||||
help = "Should be never enabled in production!"
|
||||
bind = "debug_enabled:__INSTALL_DIR__/settings.py"
|
||||
bind = "debug_enabled:/home/yunohost.app/__APP__/settings.py"
|
||||
|
||||
[main.config.log_level]
|
||||
type = "string"
|
||||
ask = "Log Level"
|
||||
choices = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
||||
default = "WARNING"
|
||||
bind = "log_level:__INSTALL_DIR__/settings.py"
|
||||
bind = "log_level:/home/yunohost.app/__APP__/settings.py"
|
||||
|
|
116
dev-cli.py
Executable file
116
dev-cli.py
Executable file
|
@ -0,0 +1,116 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
bootstrap CLI
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Just call this file, and the magic happens ;)
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
import venv
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def print_no_pip_error():
|
||||
print('Error: Pip not available!')
|
||||
print('Hint: "apt-get install python3-venv"\n')
|
||||
|
||||
|
||||
try:
|
||||
from ensurepip import version
|
||||
except ModuleNotFoundError as err:
|
||||
print(err)
|
||||
print('-' * 100)
|
||||
print_no_pip_error()
|
||||
raise
|
||||
else:
|
||||
if not version():
|
||||
print_no_pip_error()
|
||||
sys.exit(-1)
|
||||
|
||||
|
||||
assert sys.version_info >= (3, 10), f'Python version {sys.version_info} is too old!'
|
||||
|
||||
|
||||
if sys.platform == 'win32': # wtf
|
||||
# Files under Windows, e.g.: .../.venv/Scripts/python.exe
|
||||
BIN_NAME = 'Scripts'
|
||||
FILE_EXT = '.exe'
|
||||
else:
|
||||
# Files under Linux/Mac and all other than Windows, e.g.: .../.venv/bin/python
|
||||
BIN_NAME = 'bin'
|
||||
FILE_EXT = ''
|
||||
|
||||
BASE_PATH = Path(__file__).parent
|
||||
VENV_PATH = BASE_PATH / '.venv'
|
||||
BIN_PATH = VENV_PATH / BIN_NAME
|
||||
PYTHON_PATH = BIN_PATH / f'python{FILE_EXT}'
|
||||
PIP_PATH = BIN_PATH / f'pip{FILE_EXT}'
|
||||
PIP_SYNC_PATH = BIN_PATH / f'pip-sync{FILE_EXT}'
|
||||
|
||||
DEP_LOCK_PATH = BASE_PATH / 'requirements.dev.txt'
|
||||
DEP_HASH_PATH = VENV_PATH / '.dep_hash'
|
||||
|
||||
# script file defined in pyproject.toml as [console_scripts]
|
||||
# (Under Windows: ".exe" not added!)
|
||||
PROJECT_SHELL_SCRIPT = BIN_PATH / 'django_fmd_ynh_dev'
|
||||
|
||||
|
||||
def get_dep_hash():
|
||||
"""Get SHA512 hash from lock file content."""
|
||||
return hashlib.sha512(DEP_LOCK_PATH.read_bytes()).hexdigest()
|
||||
|
||||
|
||||
def store_dep_hash():
|
||||
"""Generate .venv/.dep_hash"""
|
||||
DEP_HASH_PATH.write_text(get_dep_hash())
|
||||
|
||||
|
||||
def venv_up2date():
|
||||
"""Is existing .venv is up-to-date?"""
|
||||
if DEP_HASH_PATH.is_file():
|
||||
return DEP_HASH_PATH.read_text() == get_dep_hash()
|
||||
return False
|
||||
|
||||
|
||||
def verbose_check_call(*popen_args):
|
||||
print(f'\n+ {shlex.join(str(arg) for arg in popen_args)}\n')
|
||||
return subprocess.check_call(popen_args)
|
||||
|
||||
|
||||
def main(argv):
|
||||
assert DEP_LOCK_PATH.is_file(), f'File not found: "{DEP_LOCK_PATH}" !'
|
||||
|
||||
# Create virtual env in ".venv/":
|
||||
if not PYTHON_PATH.is_file():
|
||||
print('Create virtual env here:', VENV_PATH.absolute())
|
||||
builder = venv.EnvBuilder(symlinks=True, upgrade=True, with_pip=True)
|
||||
builder.create(env_dir=VENV_PATH)
|
||||
# Update pip
|
||||
verbose_check_call(PYTHON_PATH, '-m', 'pip', 'install', '-U', 'pip')
|
||||
|
||||
if not PIP_SYNC_PATH.is_file():
|
||||
# Install pip-tools
|
||||
verbose_check_call(PYTHON_PATH, '-m', 'pip', 'install', '-U', 'pip-tools')
|
||||
|
||||
if not PROJECT_SHELL_SCRIPT.is_file() or not venv_up2date():
|
||||
# install requirements via "pip-sync"
|
||||
verbose_check_call(PIP_SYNC_PATH, str(DEP_LOCK_PATH))
|
||||
|
||||
# install project
|
||||
verbose_check_call(PIP_PATH, 'install', '--no-deps', '-e', '.')
|
||||
store_dep_hash()
|
||||
|
||||
# Call our entry point CLI:
|
||||
try:
|
||||
verbose_check_call(PROJECT_SHELL_SCRIPT, *argv[1:])
|
||||
except subprocess.CalledProcessError as err:
|
||||
sys.exit(err.returncode)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv)
|
7
django_fmd_ynh/__init__.py
Normal file
7
django_fmd_ynh/__init__.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
"""
|
||||
django_fmd_ynh
|
||||
YunoHost app package for https://gitlab.com/jedie/django-find-my-device
|
||||
"""
|
||||
|
||||
__version__ = '0.4.1+ynh1'
|
||||
__author__ = 'Jens Diemer <git@jensdiemer.de>'
|
0
django_fmd_ynh/cli/__init__.py
Normal file
0
django_fmd_ynh/cli/__init__.py
Normal file
302
django_fmd_ynh/cli/dev.py
Normal file
302
django_fmd_ynh/cli/dev.py
Normal file
|
@ -0,0 +1,302 @@
|
|||
"""
|
||||
CLI for development
|
||||
"""
|
||||
|
||||
import logging
|
||||
import shlex
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import rich_click as click
|
||||
from cli_base.cli_tools import code_style
|
||||
from cli_base.cli_tools.dev_tools import run_tox
|
||||
from cli_base.cli_tools.subprocess_utils import verbose_check_call
|
||||
from cli_base.cli_tools.test_utils.snapshot import UpdateTestSnapshotFiles
|
||||
from cli_base.cli_tools.verbosity import OPTION_KWARGS_VERBOSE
|
||||
from cli_base.cli_tools.version_info import print_version
|
||||
from django.core.management.commands.test import Command as DjangoTestCommand
|
||||
from django_yunohost_integration.local_test import create_local_test
|
||||
from manageprojects.utilities.publish import publish_package
|
||||
from rich import print
|
||||
from rich.console import Console
|
||||
from rich.traceback import install as rich_traceback_install
|
||||
from rich_click import RichGroup
|
||||
|
||||
import django_fmd_ynh
|
||||
from django_fmd_ynh import constants
|
||||
from django_fmd_ynh.constants import PACKAGE_ROOT
|
||||
from django_fmd_ynh.tests import setup_ynh_tests
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
OPTION_ARGS_DEFAULT_TRUE = dict(is_flag=True, show_default=True, default=True)
|
||||
OPTION_ARGS_DEFAULT_FALSE = dict(is_flag=True, show_default=True, default=False)
|
||||
ARGUMENT_EXISTING_DIR = dict(
|
||||
type=click.Path(exists=True, file_okay=False, dir_okay=True, readable=True, path_type=Path)
|
||||
)
|
||||
ARGUMENT_NOT_EXISTING_DIR = dict(
|
||||
type=click.Path(
|
||||
exists=False,
|
||||
file_okay=False,
|
||||
dir_okay=True,
|
||||
readable=False,
|
||||
writable=True,
|
||||
path_type=Path,
|
||||
)
|
||||
)
|
||||
ARGUMENT_EXISTING_FILE = dict(
|
||||
type=click.Path(exists=True, file_okay=True, dir_okay=False, readable=True, path_type=Path)
|
||||
)
|
||||
|
||||
|
||||
class ClickGroup(RichGroup): # FIXME: How to set the "info_name" easier?
|
||||
def make_context(self, info_name, *args, **kwargs):
|
||||
info_name = './dev-cli.py'
|
||||
return super().make_context(info_name, *args, **kwargs)
|
||||
|
||||
|
||||
@click.group(
|
||||
cls=ClickGroup,
|
||||
epilog=constants.CLI_EPILOG,
|
||||
)
|
||||
def cli():
|
||||
pass
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.option('-v', '--verbosity', **OPTION_KWARGS_VERBOSE)
|
||||
def mypy(verbosity: int):
|
||||
"""Run Mypy (configured in pyproject.toml)"""
|
||||
verbose_check_call('mypy', '.', cwd=PACKAGE_ROOT, verbose=verbosity > 0, exit_on_error=True)
|
||||
|
||||
|
||||
@cli.command()
|
||||
def install():
|
||||
"""
|
||||
Run pip-sync and install 'django_fmd_ynh' via pip as editable.
|
||||
"""
|
||||
verbose_check_call('pip-sync', PACKAGE_ROOT / 'requirements.dev.txt')
|
||||
verbose_check_call('pip', 'install', '--no-deps', '-e', '.')
|
||||
|
||||
|
||||
def _run_safety():
|
||||
verbose_check_call(
|
||||
'safety',
|
||||
'check',
|
||||
'-r',
|
||||
'requirements.dev.txt',
|
||||
'--ignore',
|
||||
'67599', # Ignore CVE-2018-20225: We do not use the `--extra-index-url` option
|
||||
'--ignore',
|
||||
'70612', # Ignore CVE-2019-8341: We don't use Jinja2 directly
|
||||
)
|
||||
|
||||
|
||||
@cli.command()
|
||||
def safety():
|
||||
"""
|
||||
Run safety check against current requirements files
|
||||
"""
|
||||
_run_safety()
|
||||
|
||||
|
||||
@cli.command()
|
||||
def update():
|
||||
"""
|
||||
Update "requirements*.txt" dependencies files
|
||||
"""
|
||||
bin_path = Path(sys.executable).parent
|
||||
|
||||
verbose_check_call(bin_path / 'pip', 'install', '-U', 'pip')
|
||||
verbose_check_call(bin_path / 'pip', 'install', '-U', 'pip-tools')
|
||||
|
||||
extra_env = dict(
|
||||
CUSTOM_COMPILE_COMMAND='./dev-cli.py update',
|
||||
)
|
||||
|
||||
pip_compile_base = [
|
||||
bin_path / 'pip-compile',
|
||||
'--verbose',
|
||||
'--allow-unsafe', # https://pip-tools.readthedocs.io/en/latest/#deprecations
|
||||
'--resolver=backtracking', # https://pip-tools.readthedocs.io/en/latest/#deprecations
|
||||
'--upgrade',
|
||||
'--generate-hashes',
|
||||
]
|
||||
|
||||
# Only "prod" dependencies:
|
||||
verbose_check_call(
|
||||
*pip_compile_base,
|
||||
'pyproject.toml',
|
||||
'--output-file',
|
||||
'conf/requirements.txt',
|
||||
extra_env=extra_env,
|
||||
)
|
||||
|
||||
# dependencies + "dev"-optional-dependencies:
|
||||
verbose_check_call(
|
||||
*pip_compile_base,
|
||||
'pyproject.toml',
|
||||
'--extra=dev',
|
||||
'--output-file',
|
||||
'requirements.dev.txt',
|
||||
extra_env=extra_env,
|
||||
)
|
||||
|
||||
_run_safety()
|
||||
|
||||
# Install new dependencies in current .venv:
|
||||
verbose_check_call(bin_path / 'pip-sync', 'requirements.dev.txt')
|
||||
|
||||
|
||||
@cli.command()
|
||||
def publish():
|
||||
"""
|
||||
Build and upload this project to PyPi
|
||||
"""
|
||||
try:
|
||||
_run_django_test_cli(argv=sys.argv, exit_after_run=True) # Don't publish a broken state
|
||||
except SystemExit as err:
|
||||
assert err.code == 0, f'Exit code is not 0: {err.code}'
|
||||
|
||||
publish_package(
|
||||
module=django_fmd_ynh,
|
||||
package_path=PACKAGE_ROOT,
|
||||
distribution_name='django_fmd_ynh',
|
||||
)
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.option('--color/--no-color', **OPTION_ARGS_DEFAULT_TRUE)
|
||||
@click.option('-v', '--verbosity', **OPTION_KWARGS_VERBOSE)
|
||||
def fix_code_style(color: bool, verbosity: int):
|
||||
"""
|
||||
Fix code style of all your_cool_package source code files via darker
|
||||
"""
|
||||
code_style.fix(package_root=PACKAGE_ROOT, darker_color=color, darker_verbose=verbosity > 0)
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.option('--color/--no-color', **OPTION_ARGS_DEFAULT_TRUE)
|
||||
@click.option('-v', '--verbosity', **OPTION_KWARGS_VERBOSE)
|
||||
def check_code_style(color: bool, verbosity: int):
|
||||
"""
|
||||
Check code style by calling darker + flake8
|
||||
"""
|
||||
code_style.check(package_root=PACKAGE_ROOT, darker_color=color, darker_verbose=verbosity > 0)
|
||||
|
||||
|
||||
@cli.command()
|
||||
def update_test_snapshot_files():
|
||||
"""
|
||||
Update all test snapshot files (by remove and recreate all snapshot files)
|
||||
"""
|
||||
with UpdateTestSnapshotFiles(root_path=PACKAGE_ROOT, verbose=True):
|
||||
# Just recreate them by running tests:
|
||||
_run_django_test_cli(argv=sys.argv, exit_after_run=False)
|
||||
|
||||
|
||||
def _run_django_test_cli(argv, exit_after_run=True):
|
||||
"""
|
||||
Call the origin Django test manage command CLI and pass all args to it.
|
||||
"""
|
||||
setup_ynh_tests()
|
||||
|
||||
print('\nStart Django unittests with:')
|
||||
for default_arg in ('shuffle', 'buffer'):
|
||||
if default_arg not in argv and f'--no-{default_arg}' not in argv:
|
||||
argv.append(f'--{default_arg}')
|
||||
print(shlex.join(argv))
|
||||
print()
|
||||
|
||||
test_command = DjangoTestCommand()
|
||||
test_command.run_from_argv(argv)
|
||||
if exit_after_run:
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
@cli.command() # Dummy command
|
||||
def test():
|
||||
"""
|
||||
Compile YunoHost files and run Django unittests
|
||||
"""
|
||||
_run_django_test_cli(argv=sys.argv, exit_after_run=True)
|
||||
|
||||
|
||||
@cli.command() # Dummy "tox" command
|
||||
def tox():
|
||||
"""
|
||||
Run tox
|
||||
"""
|
||||
run_tox()
|
||||
|
||||
|
||||
@cli.command()
|
||||
def version():
|
||||
"""Print version and exit"""
|
||||
# Pseudo command, because the version always printed on every CLI call ;)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
@cli.command()
|
||||
def local_test():
|
||||
"""
|
||||
Build a "local_test" YunoHost installation and start the Django dev. server against it.
|
||||
"""
|
||||
create_local_test(
|
||||
django_settings_path=PACKAGE_ROOT / 'conf' / 'settings.py',
|
||||
destination=PACKAGE_ROOT / 'local_test',
|
||||
runserver=True,
|
||||
extra_replacements={
|
||||
'__DEBUG_ENABLED__': '1',
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@cli.command()
|
||||
def diffsettings():
|
||||
"""
|
||||
Run "diffsettings" manage command against a "local_test" YunoHost installation.
|
||||
"""
|
||||
destination = PACKAGE_ROOT / 'local_test'
|
||||
create_local_test(
|
||||
django_settings_path=PACKAGE_ROOT / 'conf' / 'settings.py',
|
||||
destination=destination,
|
||||
runserver=False,
|
||||
extra_replacements={
|
||||
'__DEBUG_ENABLED__': '1',
|
||||
},
|
||||
)
|
||||
app_path = destination / 'opt_yunohost'
|
||||
verbose_check_call(
|
||||
sys.executable,
|
||||
app_path / 'manage.py',
|
||||
'diffsettings',
|
||||
cwd=app_path,
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
print_version(django_fmd_ynh)
|
||||
|
||||
if len(sys.argv) >= 2:
|
||||
# Check if we can just pass a command call to origin CLI:
|
||||
command = sys.argv[1]
|
||||
command_map = {
|
||||
'test': _run_django_test_cli,
|
||||
'tox': run_tox,
|
||||
}
|
||||
if real_func := command_map.get(command):
|
||||
real_func(argv=sys.argv, exit_after_run=True)
|
||||
|
||||
console = Console()
|
||||
rich_traceback_install(
|
||||
width=console.size.width, # full terminal width
|
||||
show_locals=True,
|
||||
suppress=[click],
|
||||
max_frames=2,
|
||||
)
|
||||
|
||||
print('Execute Click CLI')
|
||||
cli()
|
11
django_fmd_ynh/constants.py
Normal file
11
django_fmd_ynh/constants.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
from pathlib import Path
|
||||
|
||||
import django_fmd_ynh
|
||||
from bx_py_utils.path import assert_is_file
|
||||
|
||||
|
||||
PACKAGE_ROOT = Path(django_fmd_ynh.__file__).parent.parent
|
||||
assert_is_file(PACKAGE_ROOT / 'pyproject.toml')
|
||||
|
||||
|
||||
CLI_EPILOG = 'Project Homepage: https://github.com/YunoHost-Apps/django-fmd_ynh'
|
63
django_fmd_ynh/tests/__init__.py
Normal file
63
django_fmd_ynh/tests/__init__.py
Normal file
|
@ -0,0 +1,63 @@
|
|||
import os
|
||||
import sys
|
||||
import unittest.util
|
||||
from pathlib import Path
|
||||
|
||||
import django
|
||||
import django_fmd_ynh
|
||||
from bx_py_utils.test_utils.deny_requests import deny_any_real_request
|
||||
from cli_base.cli_tools.verbosity import MAX_LOG_LEVEL, setup_logging
|
||||
from django_fmd_ynh.constants import PACKAGE_ROOT
|
||||
from django_yunohost_integration.local_test import CreateResults, create_local_test
|
||||
from rich import print # noqa
|
||||
|
||||
|
||||
def pre_configure_tests() -> None:
|
||||
print(f'Configure unittests via "load_tests Protocol" from {Path(__file__).relative_to(Path.cwd())}')
|
||||
|
||||
# Hacky way to display more "assert"-Context in failing tests:
|
||||
_MIN_MAX_DIFF = unittest.util._MAX_LENGTH - unittest.util._MIN_DIFF_LEN
|
||||
unittest.util._MAX_LENGTH = int(os.environ.get('UNITTEST_MAX_LENGTH', 300))
|
||||
unittest.util._MIN_DIFF_LEN = unittest.util._MAX_LENGTH - _MIN_MAX_DIFF
|
||||
|
||||
# Deny any request via docket/urllib3 because tests they should mock all requests:
|
||||
deny_any_real_request()
|
||||
|
||||
# Display DEBUG logs in tests:
|
||||
setup_logging(verbosity=MAX_LOG_LEVEL)
|
||||
|
||||
|
||||
def setup_ynh_tests() -> None:
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
|
||||
|
||||
print('Compile YunoHost files...')
|
||||
result: CreateResults = create_local_test(
|
||||
django_settings_path=PACKAGE_ROOT / 'conf' / 'settings.py',
|
||||
destination=PACKAGE_ROOT / 'local_test',
|
||||
runserver=False,
|
||||
extra_replacements={
|
||||
'__DEBUG_ENABLED__': '0', # "1" or "0" string
|
||||
'__LOG_LEVEL__': 'INFO',
|
||||
'__ADMIN_EMAIL__': 'foo-bar@test.tld',
|
||||
'__DEFAULT_FROM_EMAIL__': 'django_app@test.tld',
|
||||
},
|
||||
)
|
||||
print('Local test files created:')
|
||||
print(result)
|
||||
|
||||
data_dir = str(result.data_dir_path)
|
||||
if data_dir not in sys.path:
|
||||
sys.path.insert(0, data_dir)
|
||||
|
||||
django.setup()
|
||||
|
||||
os.chdir(Path(django_fmd_ynh.__file__).parent)
|
||||
|
||||
|
||||
def load_tests(loader, tests, pattern):
|
||||
"""
|
||||
Use unittest "load_tests Protocol" as a hook to setup test environment before running tests.
|
||||
https://docs.python.org/3/library/unittest.html#load-tests-protocol
|
||||
"""
|
||||
pre_configure_tests()
|
||||
return loader.discover(start_dir=Path(__file__).parent, pattern=pattern)
|
168
django_fmd_ynh/tests/test_django_project.py
Normal file
168
django_fmd_ynh/tests/test_django_project.py
Normal file
|
@ -0,0 +1,168 @@
|
|||
from unittest.mock import patch
|
||||
|
||||
import findmydevice
|
||||
from axes.models import AccessLog
|
||||
from bx_django_utils.test_utils.html_assertion import HtmlAssertionMixin, assert_html_response_snapshot
|
||||
from django.conf import LazySettings, settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.template.defaulttags import CsrfTokenNode
|
||||
from django.test import override_settings
|
||||
from django.test.testcases import TestCase
|
||||
from django.urls.base import reverse
|
||||
from django_yunohost_integration.test_utils import generate_basic_auth
|
||||
|
||||
|
||||
@override_settings(DEBUG=False)
|
||||
class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
# Always start a fresh session:
|
||||
self.client = self.client_class()
|
||||
|
||||
def test_settings(self):
|
||||
assert isinstance(settings, LazySettings)
|
||||
assert settings.configured is True
|
||||
|
||||
assert settings.PATH_URL == 'app_path'
|
||||
|
||||
assert str(settings.DATA_DIR_PATH).endswith('/local_test/opt_yunohost'), f'{settings.DATA_DIR_PATH=}'
|
||||
assert str(settings.INSTALL_DIR_PATH).endswith('/local_test/var_www'), f'{settings.INSTALL_DIR_PATH=}'
|
||||
assert str(settings.LOG_FILE_PATH).endswith('/local_test/var_log_django-fmd.log'), f'{settings.LOG_FILE_PATH=}'
|
||||
|
||||
assert settings.ROOT_URLCONF == 'urls'
|
||||
|
||||
def test_config_panel_settings(self):
|
||||
# config_panel.toml settings, set via tests.conftest.pytest_configure():
|
||||
assert settings.DEBUG_ENABLED == '0' and settings.DEBUG is False
|
||||
assert settings.LOG_LEVEL == 'INFO'
|
||||
assert settings.ADMIN_EMAIL == 'foo-bar@test.tld'
|
||||
assert settings.DEFAULT_FROM_EMAIL == 'django_app@test.tld'
|
||||
|
||||
def test_auth(self):
|
||||
assert settings.PATH_URL == 'app_path'
|
||||
self.assertEqual(reverse('admin:index'), '/app_path/admin/')
|
||||
|
||||
# SecurityMiddleware should redirects all non-HTTPS requests to HTTPS:
|
||||
assert settings.SECURE_SSL_REDIRECT is True
|
||||
response = self.client.get('/app_path/admin/', secure=False)
|
||||
self.assertRedirects(
|
||||
response,
|
||||
status_code=301, # permanent redirect
|
||||
expected_url='https://testserver/app_path/admin/',
|
||||
fetch_redirect_response=False,
|
||||
)
|
||||
|
||||
response = self.client.get('/app_path/admin/', secure=True)
|
||||
self.assertRedirects(
|
||||
response,
|
||||
expected_url='/app_path/admin/login/?next=%2Fapp_path%2Fadmin%2F',
|
||||
fetch_redirect_response=False,
|
||||
)
|
||||
|
||||
def test_create_unknown_user(self):
|
||||
assert User.objects.count() == 0
|
||||
|
||||
self.client.cookies['SSOwAuthUser'] = 'test'
|
||||
|
||||
with patch.object(CsrfTokenNode, 'render', return_value='MockedCsrfTokenNode'):
|
||||
response = self.client.get(
|
||||
path='/app_path/admin/',
|
||||
HTTP_REMOTE_USER='test',
|
||||
HTTP_AUTH_USER='test',
|
||||
HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz',
|
||||
secure=True,
|
||||
)
|
||||
|
||||
assert User.objects.count() == 1
|
||||
user = User.objects.first()
|
||||
assert user.username == 'test'
|
||||
assert user.is_active is True
|
||||
assert user.is_staff is True # Set by: conf.setup_user.setup_project_user
|
||||
assert user.is_superuser is True
|
||||
|
||||
self.assert_html_parts(
|
||||
response,
|
||||
parts=(
|
||||
f'<a href="/app_path/admin/">Django Find My Device v{findmydevice.__version__}</a>',
|
||||
'<strong>test</strong>',
|
||||
),
|
||||
)
|
||||
# TODO: assert_html_response_snapshot(response, query_selector='#container', validate=False)
|
||||
|
||||
def test_wrong_auth_user(self):
|
||||
assert User.objects.count() == 0
|
||||
assert AccessLog.objects.count() == 0
|
||||
|
||||
self.client.cookies['SSOwAuthUser'] = 'test'
|
||||
|
||||
response = self.client.get(
|
||||
path='/app_path/admin/',
|
||||
HTTP_REMOTE_USER='test',
|
||||
HTTP_AUTH_USER='foobar', # <<< wrong user name
|
||||
HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz',
|
||||
secure=True,
|
||||
)
|
||||
|
||||
assert User.objects.count() == 1
|
||||
user = User.objects.first()
|
||||
assert user.username == 'test'
|
||||
assert user.is_active is True
|
||||
assert user.is_staff is True # Set by: conf.setup_user.setup_project_user
|
||||
assert user.is_superuser is True
|
||||
|
||||
assert AccessLog.objects.count() == 1
|
||||
|
||||
assert response.status_code == 403 # Forbidden
|
||||
|
||||
def test_wrong_cookie(self):
|
||||
assert User.objects.count() == 0
|
||||
assert AccessLog.objects.count() == 0
|
||||
|
||||
self.client.cookies['SSOwAuthUser'] = 'foobar' # <<< wrong user name
|
||||
|
||||
response = self.client.get(
|
||||
path='/app_path/',
|
||||
HTTP_REMOTE_USER='test',
|
||||
HTTP_AUTH_USER='test',
|
||||
HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz',
|
||||
secure=True,
|
||||
)
|
||||
|
||||
assert User.objects.count() == 1
|
||||
user = User.objects.first()
|
||||
assert user.username == 'test'
|
||||
assert user.is_active is True
|
||||
assert user.is_staff is True # Set by: conf.setup_user.setup_project_user
|
||||
assert user.is_superuser is True
|
||||
|
||||
assert AccessLog.objects.count() == 1
|
||||
|
||||
assert response.status_code == 403 # Forbidden
|
||||
|
||||
def test_wrong_authorization_user(self):
|
||||
assert User.objects.count() == 0
|
||||
|
||||
self.client.cookies['SSOwAuthUser'] = 'test'
|
||||
|
||||
response = self.client.get(
|
||||
path='/app_path/',
|
||||
HTTP_REMOTE_USER='test',
|
||||
HTTP_AUTH_USER='test',
|
||||
HTTP_AUTHORIZATION=generate_basic_auth(
|
||||
username='foobar', # <<< wrong user name
|
||||
password='test123',
|
||||
),
|
||||
secure=True,
|
||||
)
|
||||
|
||||
assert User.objects.count() == 1
|
||||
user = User.objects.first()
|
||||
assert user.username == 'test'
|
||||
assert user.is_active is True
|
||||
assert user.is_staff is True # Set by: conf.setup_user.setup_project_user
|
||||
assert user.is_superuser is True
|
||||
|
||||
assert AccessLog.objects.count() == 1
|
||||
|
||||
assert response.status_code == 403 # Forbidden
|
10
django_fmd_ynh/tests/test_doctests.py
Normal file
10
django_fmd_ynh/tests/test_doctests.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
from bx_py_utils.test_utils.unittest_utils import BaseDocTests
|
||||
|
||||
import django_fmd_ynh
|
||||
|
||||
|
||||
class DocTests(BaseDocTests):
|
||||
def test_doctests(self):
|
||||
self.run_doctests(
|
||||
modules=(django_fmd_ynh,),
|
||||
)
|
95
django_fmd_ynh/tests/test_project_setup.py
Normal file
95
django_fmd_ynh/tests/test_project_setup.py
Normal file
|
@ -0,0 +1,95 @@
|
|||
|
||||
from django_fmd_ynh.cli.dev import PACKAGE_ROOT
|
||||
|
||||
|
||||
try:
|
||||
import tomllib # New in Python 3.11
|
||||
except ImportError:
|
||||
import tomli as tomllib
|
||||
|
||||
from bx_django_utils.filename import clean_filename
|
||||
from bx_py_utils.path import assert_is_dir, assert_is_file
|
||||
from django.test.testcases import TestCase
|
||||
from django_tools.unittest_utils.project_setup import check_editor_config
|
||||
|
||||
from findmydevice import __version__ as upstream_version
|
||||
from django_fmd_ynh import __version__ as ynh_pkg_version
|
||||
|
||||
|
||||
def assert_file_contains_string(file_path, string):
|
||||
with file_path.open('r') as f:
|
||||
for line in f:
|
||||
if string in line:
|
||||
return
|
||||
raise AssertionError(f'File {file_path} does not contain {string!r} !')
|
||||
|
||||
|
||||
class ProjectSetupTestCase(TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
manifest_path = PACKAGE_ROOT / 'manifest.toml'
|
||||
assert_is_file(manifest_path)
|
||||
|
||||
cls.manifest_cfg = tomllib.loads(manifest_path.read_text(encoding='UTF-8'))
|
||||
|
||||
def test_version(self):
|
||||
assert ynh_pkg_version.startswith(
|
||||
upstream_version
|
||||
), f'{ynh_pkg_version=} does not start with {upstream_version=}'
|
||||
self.assertIn('+ynh', ynh_pkg_version)
|
||||
|
||||
# pyproject.toml needs a PEP 440 conform version and used "+ynh"
|
||||
# the YunoHost syntax is: "~ynh", just "convert this:
|
||||
manifest_version = ynh_pkg_version.replace('+', '~')
|
||||
self.assertEqual(self.manifest_cfg['version'], manifest_version)
|
||||
|
||||
def test_screenshot_filenames(self):
|
||||
"""
|
||||
https://forum.yunohost.org/t/yunohost-bot-cant-handle-spaces-in-screenshots/19483
|
||||
"""
|
||||
screenshot_path = PACKAGE_ROOT / 'doc' / 'screenshots'
|
||||
assert_is_dir(screenshot_path)
|
||||
renamed = []
|
||||
for file_path in screenshot_path.iterdir():
|
||||
file_name = file_path.name
|
||||
if file_name.startswith('.'):
|
||||
continue
|
||||
cleaned_name = clean_filename(file_name)
|
||||
if cleaned_name != file_name:
|
||||
new_path = file_path.with_name(cleaned_name)
|
||||
file_path.rename(new_path)
|
||||
renamed.append(f'{file_name!r} renamed to {cleaned_name!r}')
|
||||
assert not renamed, f'Bad screenshots file names found: {", ".join(renamed)}'
|
||||
|
||||
def test_check_editor_config(self):
|
||||
check_editor_config(package_root=PACKAGE_ROOT)
|
||||
|
||||
def test_manifest_toml(self):
|
||||
self.assertEqual(self.manifest_cfg['packaging_format'], 2)
|
||||
self.assertEqual(
|
||||
set(self.manifest_cfg['install'].keys()),
|
||||
{
|
||||
'admin',
|
||||
'admin_email',
|
||||
'debug_enabled',
|
||||
'default_from_email',
|
||||
'domain',
|
||||
'init_main_permission',
|
||||
'log_level',
|
||||
'path',
|
||||
},
|
||||
)
|
||||
self.assertEqual(
|
||||
set(self.manifest_cfg['resources'].keys()),
|
||||
{
|
||||
'apt',
|
||||
'data_dir',
|
||||
'database',
|
||||
'install_dir',
|
||||
'permissions',
|
||||
'ports',
|
||||
'system_user',
|
||||
},
|
||||
)
|
36
django_fmd_ynh/tests/test_readme.py
Normal file
36
django_fmd_ynh/tests/test_readme.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
from pathlib import Path
|
||||
|
||||
from bx_py_utils.auto_doc import assert_readme_block
|
||||
from django_fmd_ynh.cli.dev import PACKAGE_ROOT, cli
|
||||
from django_fmd_ynh.constants import CLI_EPILOG
|
||||
from manageprojects.test_utils.click_cli_utils import invoke_click
|
||||
from manageprojects.tests.base import BaseTestCase
|
||||
|
||||
|
||||
def assert_cli_help_in_readme(text_block: str, marker: str, readme_path: Path):
|
||||
text_block = text_block.replace(CLI_EPILOG, '')
|
||||
text_block = f'```\n{text_block.strip()}\n```'
|
||||
assert_readme_block(
|
||||
readme_path=readme_path,
|
||||
text_block=text_block,
|
||||
start_marker_line=f'[comment]: <> (✂✂✂ auto generated {marker} start ✂✂✂)',
|
||||
end_marker_line=f'[comment]: <> (✂✂✂ auto generated {marker} end ✂✂✂)',
|
||||
)
|
||||
|
||||
|
||||
class ReadmeTestCase(BaseTestCase):
|
||||
def test_main_help(self):
|
||||
stdout = invoke_click(cli, '--help')
|
||||
self.assert_in_content(
|
||||
got=stdout,
|
||||
parts=(
|
||||
'Usage: ./dev-cli.py [OPTIONS] COMMAND [ARGS]...',
|
||||
' local-test ',
|
||||
CLI_EPILOG,
|
||||
),
|
||||
)
|
||||
assert_cli_help_in_readme(
|
||||
text_block=stdout,
|
||||
marker='help',
|
||||
readme_path=PACKAGE_ROOT / 'doc' / 'ADMIN.md',
|
||||
)
|
33
doc/ADMIN.md
33
doc/ADMIN.md
|
@ -30,3 +30,36 @@ To check the effective settings, run this:
|
|||
```bash
|
||||
(venv) root@yunohost:/opt/yunohost/django-fmd# ./manage.py diffsettings
|
||||
```
|
||||
|
||||
|
||||
## Development CLI
|
||||
|
||||
e.g.:
|
||||
|
||||
[comment]: <> (✂✂✂ auto generated help start ✂✂✂)
|
||||
```
|
||||
Usage: ./dev-cli.py [OPTIONS] COMMAND [ARGS]...
|
||||
|
||||
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ --help Show this message and exit. │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
╭─ Commands ───────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ check-code-style Check code style by calling darker + flake8 │
|
||||
│ diffsettings Run "diffsettings" manage command against a "local_test" YunoHost │
|
||||
│ installation. │
|
||||
│ fix-code-style Fix code style of all your_cool_package source code files via darker │
|
||||
│ install Run pip-sync and install 'django_fmd_ynh' via pip as editable. │
|
||||
│ local-test Build a "local_test" YunoHost installation and start the Django dev. │
|
||||
│ server against it. │
|
||||
│ mypy Run Mypy (configured in pyproject.toml) │
|
||||
│ publish Build and upload this project to PyPi │
|
||||
│ safety Run safety check against current requirements files │
|
||||
│ test Compile YunoHost files and run Django unittests │
|
||||
│ tox Run tox │
|
||||
│ update Update "requirements*.txt" dependencies files │
|
||||
│ update-test-snapshot-files Update all test snapshot files (by remove and recreate all snapshot │
|
||||
│ files) │
|
||||
│ version Print version and exit │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
```
|
||||
[comment]: <> (✂✂✂ auto generated help end ✂✂✂)
|
||||
|
|
25
local_settings_source.py
Normal file
25
local_settings_source.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
# This file will be copied to the "local test" files, to overwrite Django settings
|
||||
|
||||
import os
|
||||
|
||||
|
||||
print('Load local settings file:', __file__)
|
||||
|
||||
ENV_TYPE = os.environ.get('ENV_TYPE', None)
|
||||
print(f'ENV_TYPE: {ENV_TYPE!r}')
|
||||
|
||||
if ENV_TYPE == 'local':
|
||||
print(f'Activate settings overwrite by {__file__}')
|
||||
SECURE_SSL_REDIRECT = False # Don't redirect http to https
|
||||
SERVE_FILES = True # May used in urls.py
|
||||
AUTH_PASSWORD_VALIDATORS = [] # accept all passwords
|
||||
ALLOWED_HOSTS = ['127.0.0.1', 'localhost'] # For local dev. server
|
||||
CACHES = { # Setup a working cache, without Redis ;)
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
||||
'LOCATION': 'unique-snowflake',
|
||||
},
|
||||
}
|
||||
elif ENV_TYPE == 'test':
|
||||
SILENCED_SYSTEM_CHECKS = ['security.W018'] # tests runs with DEBUG=True
|
||||
ALLOWED_HOSTS = [] # For unittests (Django's setup_test_environment() will add 'testserver')
|
|
@ -1,32 +0,0 @@
|
|||
"""
|
||||
Build a "local_test" YunoHost installation and start the Django dev. server against it.
|
||||
|
||||
Run via:
|
||||
make local-test
|
||||
|
||||
see README for details ;)
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
try:
|
||||
from django_yunohost_integration.local_test import create_local_test
|
||||
except ImportError as err:
|
||||
raise ImportError('Did you forget to activate a virtual environment?') from err
|
||||
|
||||
BASE_PATH = Path(__file__).parent
|
||||
|
||||
|
||||
def main():
|
||||
create_local_test(
|
||||
django_settings_path=BASE_PATH / 'conf' / 'settings.py',
|
||||
destination=BASE_PATH / 'local_test',
|
||||
runserver=True,
|
||||
extra_replacements={
|
||||
'__DEBUG_ENABLED__': '1',
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -1,67 +1,112 @@
|
|||
#:schema https://raw.githubusercontent.com/YunoHost/apps/master/schemas/manifest.v2.schema.json
|
||||
|
||||
# https://yunohost.org/en/packaging_manifest
|
||||
packaging_format = 2
|
||||
|
||||
id = "django-fmd"
|
||||
name = "django-fmd"
|
||||
description.en = "Web based FritzBox management using Python/Django."
|
||||
description.en = "YunoHost app package for https://gitlab.com/jedie/django-find-my-device"
|
||||
|
||||
version = "0.3.2~ynh2"
|
||||
version = "0.4.1~ynh1"
|
||||
|
||||
maintainers = ["Jens Diemer"]
|
||||
|
||||
|
||||
[upstream]
|
||||
license = "GPL-3.0"
|
||||
website = "https://gitlab.com/jedie/django-find-my-device"
|
||||
code = "https://gitlab.com/jedie/django-find-my-device"
|
||||
# https://yunohost.org/en/packaging_manifest#upstream-section
|
||||
license = "GPL-3.0-or-later"
|
||||
# website = "https://github.com/YunoHost-Apps/django-fmd_ynh" # If the app has no proper website, just remove the 'website' key entirely
|
||||
admindoc = "https://github.com/YunoHost-Apps/django-fmd_ynh"
|
||||
userdoc = "https://gitlab.com/jedie/django-find-my-device"
|
||||
code = "https://github.com/YunoHost-Apps/django-fmd_ynh"
|
||||
|
||||
|
||||
|
||||
[integration]
|
||||
yunohost = ">= 11.2"
|
||||
# https://yunohost.org/en/packaging_manifest#integration-section
|
||||
yunohost = ">= 11.2.12"
|
||||
architectures = "all"
|
||||
multi_instance = false
|
||||
ldap = true
|
||||
sso = true
|
||||
disk = "50M"
|
||||
ram.build = "50M"
|
||||
ram.runtime = "50M"
|
||||
disk = "50M" # **estimate** minimum disk requirement. e.g. 20M, 400M, 1G, ...
|
||||
ram.build = "50M" # **estimate** minimum ram requirement. e.g. 50M, 400M, 1G, ...
|
||||
ram.runtime = "50M" # **estimate** minimum ram requirement. e.g. 50M, 400M, 1G, ...
|
||||
|
||||
|
||||
|
||||
[install]
|
||||
# https://yunohost.org/en/packaging_manifest#install-questions
|
||||
|
||||
[install.domain]
|
||||
# this is a generic question - ask strings are automatically handled by Yunohost's core
|
||||
type = "domain"
|
||||
|
||||
[install.path]
|
||||
# this is a generic question - ask strings are automatically handled by Yunohost's core
|
||||
# setting $path and template variable __PATH__
|
||||
type = "path"
|
||||
default = "/fmd"
|
||||
|
||||
[install.admin]
|
||||
# this is a generic question - ask strings are automatically handled by Yunohost's core
|
||||
type = "user"
|
||||
default = "admin"
|
||||
|
||||
[install.init_main_permission]
|
||||
type = "group"
|
||||
default = "visitors"
|
||||
default = "admins"
|
||||
|
||||
[install.default_from_email] # __DEFAULT_FROM_EMAIL__
|
||||
ask.en = "Default email address to use for various automated emails."
|
||||
type = "email"
|
||||
example = "admin@example.com"
|
||||
|
||||
[install.admin_email] # __ADMIN_EMAIL__
|
||||
ask.en = "EMail address for error emails."
|
||||
type = "email"
|
||||
example = "admin@example.com"
|
||||
|
||||
[install.debug_enabled] # __DEBUG_ENABLED__ will be set to "0" or "1" string
|
||||
ask.en = "Should be never enabled in production!"
|
||||
type = "boolean"
|
||||
|
||||
[install.log_level] # __LOG_LEVEL__
|
||||
ask.en = "Logging level"
|
||||
type = "select"
|
||||
choices = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
||||
default = "WARNING"
|
||||
|
||||
[install.admin]
|
||||
type = "user"
|
||||
|
||||
[resources]
|
||||
[resources.system_user]
|
||||
# This will provision/deprovision a unix system user
|
||||
|
||||
[resources.install_dir]
|
||||
# https://yunohost.org/en/packaging_apps_resources#install-dir
|
||||
# This will create/remove the install dir as /var/www/$app/
|
||||
# and store the corresponding setting $install_dir and template variable __INSTALL_DIR__
|
||||
|
||||
[resources.data_dir]
|
||||
# https://yunohost.org/en/packaging_apps_resources#data-dir
|
||||
# This will create/remove the data dir as /home/yunohost.app/$app/
|
||||
# and store the corresponding setting $data_dir and template variable __DATA_DIR__
|
||||
|
||||
[resources.permissions]
|
||||
# https://yunohost.org/en/packaging_apps_resources#permissions
|
||||
# This will configure SSOwat permission for $domain/$path/
|
||||
# The initial allowed group of user is configured via the init_main_permission question (public=visitors, private=all_users)
|
||||
main.url = "/"
|
||||
|
||||
[resources.ports]
|
||||
main.default = 8000
|
||||
# https://yunohost.org/en/packaging_apps_resources#ports
|
||||
# This will pick a random port for reverse-proxying and store it as the $port setting
|
||||
|
||||
[resources.apt]
|
||||
packages = [
|
||||
"build-essential",
|
||||
"python3-dev",
|
||||
"python3-pip",
|
||||
"python3-venv",
|
||||
"git",
|
||||
"libpq-dev",
|
||||
"postgresql",
|
||||
"postgresql-contrib"
|
||||
]
|
||||
# https://yunohost.org/en/packaging_apps_resources#apt
|
||||
# This will automatically install/uninstall the following apt packages
|
||||
packages = "build-essential, libssl-dev, libnss3-dev, libffi-dev, git, libpq-dev, postgresql, postgresql-contrib"
|
||||
|
||||
[resources.database]
|
||||
# https://yunohost.org/en/packaging_apps_resources#database
|
||||
# This will automatically provision/deprovison a Postgres DB
|
||||
# and store the corresponding credentials in settings $db_user, $db_name, $db_pwd
|
||||
type = "postgresql"
|
||||
|
|
1441
poetry.lock
generated
1441
poetry.lock
generated
File diff suppressed because it is too large
Load diff
203
pyproject.toml
203
pyproject.toml
|
@ -1,51 +1,85 @@
|
|||
[tool.poetry]
|
||||
[project]
|
||||
name = "django-fmd_ynh"
|
||||
version = "0.3.2+ynh1"
|
||||
description = "Test django-fmd_ynh via local_test.py"
|
||||
authors = ["JensDiemer <git@jensdiemer.de>"]
|
||||
license = "GPL"
|
||||
homepage = "https://github.com/YunoHost-Apps/django-fmd_ynh"
|
||||
dynamic = ["version"]
|
||||
description = "YunoHost app package for https://gitlab.com/jedie/django-find-my-device"
|
||||
license = {text = "GPL-3.0-or-later"}
|
||||
readme = "README.md"
|
||||
authors = [
|
||||
{name = 'Jens Diemer', email = 'git@jensdiemer.de'}
|
||||
]
|
||||
requires-python = ">=3.9" # Stay with 3.9 until YunoHost used >=Debian 11 (Bullseye)
|
||||
dependencies = [
|
||||
"django-fmd>=0.4.1", # https://gitlab.com/jedie/django-find-my-device
|
||||
#
|
||||
# extras "ynh" will install: gunicorn, psycopg2, django-redis and django-axes
|
||||
# see: https://github.com/YunoHost-Apps/django_yunohost_integration/blob/main/pyproject.toml
|
||||
"django_yunohost_integration[ynh]>=0.6.0", # https://github.com/YunoHost-Apps/django_yunohost_integration
|
||||
#
|
||||
"cli-base-utilities>=0.4.4", # https://github.com/jedie/cli-base-utilities
|
||||
]
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"bx_django_utils", # https://github.com/boxine/bx_django_utils
|
||||
"beautifulsoup4", # https://pypi.org/project/beautifulsoup4/
|
||||
"manageprojects>=0.15.0", # https://github.com/jedie/manageprojects
|
||||
"pip-tools", # https://github.com/jazzband/pip-tools/
|
||||
"tblib", # https://github.com/ionelmc/python-tblib
|
||||
"tox", # https://github.com/tox-dev/tox
|
||||
"coverage", # https://github.com/nedbat/coveragepy
|
||||
"autopep8", # https://github.com/hhatto/autopep8
|
||||
"pyupgrade", # https://github.com/asottile/pyupgrade
|
||||
"flake8", # https://github.com/pycqa/flake8
|
||||
"flake8-bugbear", # https://github.com/PyCQA/flake8-bugbear
|
||||
"pyflakes", # https://github.com/PyCQA/pyflakes
|
||||
"codespell", # https://github.com/codespell-project/codespell
|
||||
"EditorConfig", # https://github.com/editorconfig/editorconfig-core-py
|
||||
"safety", # https://github.com/pyupio/safety
|
||||
"mypy", # https://github.com/python/mypy
|
||||
"twine", # https://github.com/pypa/twine
|
||||
|
||||
[tool.poetry.urls]
|
||||
"Bug Tracker" = "https://github.com/YunoHost-Apps/django_example_ynh/issues"
|
||||
# https://github.com/akaihola/darker
|
||||
# https://github.com/ikamensh/flynt
|
||||
# https://github.com/pycqa/isort
|
||||
# https://github.com/pygments/pygments
|
||||
"darker[flynt, isort, color]",
|
||||
|
||||
# indirect depencies added because of bug:
|
||||
# https://github.com/pypa/pip/issues/9644 / https://github.com/jazzband/pip-tools/issues/1866
|
||||
# to avoid errors like:
|
||||
# In --require-hashes mode, all requirements must have their versions pinned with ==. These do not: ...
|
||||
"tomli", # Only needed for Python <3.11
|
||||
]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.7,<4.0.0" # TODO: Update to >=3.8 after YunoHost updates to Bullseye
|
||||
django-fmd = ">=0.3.2" # https://gitlab.com/jedie/django-find-my-device
|
||||
[project.urls]
|
||||
Documentation = "https://github.com/YunoHost-Apps/django-fmd_ynh"
|
||||
Source = "https://github.com/YunoHost-Apps/django-fmd_ynh"
|
||||
|
||||
# extras "ynh" will install: gunicorn, psycopg2, django-redis and django-axes
|
||||
# see: https://github.com/YunoHost-Apps/django_yunohost_integration/blob/main/pyproject.toml
|
||||
django_yunohost_integration = {version = ">=0.4.1", extras = ["ynh"]} # https://github.com/YunoHost-Apps/django_yunohost_integration
|
||||
[project.scripts]
|
||||
django_fmd_ynh_app = "django_fmd_ynh.__main__:main"
|
||||
django_fmd_ynh_dev = "django_fmd_ynh.cli.dev:main"
|
||||
|
||||
[ynh-integration]
|
||||
local_settings_source= "local_settings_source.py"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
bx_py_utils = "*" # https://github.com/boxine/bx_py_utils
|
||||
bx_django_utils = "*" # https://github.com/boxine/bx_django_utils
|
||||
tox = "*"
|
||||
pytest = "*"
|
||||
pytest-cov = "*"
|
||||
pytest-django = "*"
|
||||
pytest-darker = "*" # https://github.com/akaihola/pytest-darker
|
||||
coveralls = "*"
|
||||
isort = "*"
|
||||
flake8 = "*"
|
||||
EditorConfig = "*" # https://github.com/editorconfig/editorconfig-core-py
|
||||
safety = "*" # https://github.com/pyupio/safety
|
||||
requests = "*" # https://github.com/psf/requests
|
||||
packaging = "*" # https://github.com/pypa/packagi
|
||||
beautifulsoup4 = "*" # https://pypi.org/project/beautifulsoup4/
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
requires = ["setuptools>=61.0", "setuptools_scm>=7.1"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["."]
|
||||
include = ["django_fmd_ynh*"]
|
||||
|
||||
[tool.setuptools.dynamic]
|
||||
version = {attr = "django_fmd_ynh.__version__"}
|
||||
|
||||
|
||||
[tool.darker]
|
||||
src = ['.']
|
||||
# YunoHost apps still use "master" istead of "main", isn't it?
|
||||
revision = "origin/master..."
|
||||
line_length = 100
|
||||
verbose = true
|
||||
line_length = 119
|
||||
color = true
|
||||
skip_string_normalization = true
|
||||
diff = false
|
||||
check = false
|
||||
|
@ -61,54 +95,83 @@ log_level = "INFO"
|
|||
# https://pycqa.github.io/isort/docs/configuration/config_files/#pyprojecttoml-preferred-format
|
||||
atomic=true
|
||||
profile='black'
|
||||
line_length=100
|
||||
skip_glob=["*/htmlcov/*","*/migrations/*","*/local_test/*"]
|
||||
known_first_party=["findmydevice","findmydevice_project","findmydevice_tests"]
|
||||
skip_glob=[".*", "*/htmlcov/*","*/migrations/*","*/local_test/*"]
|
||||
known_first_party=['django-fmd', 'django_fmd_ynh']
|
||||
line_length=119
|
||||
lines_after_imports=2
|
||||
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
# https://docs.pytest.org/en/latest/customize.html#pyproject-toml
|
||||
minversion = "6.0"
|
||||
norecursedirs = ".* .git __pycache__ conf local_test coverage* dist htmlcov"
|
||||
# sometimes helpfull "addopts" arguments:
|
||||
# -vv
|
||||
# --verbose
|
||||
# --capture=no
|
||||
# --trace-config
|
||||
# --full-trace
|
||||
# -p no:warnings
|
||||
addopts = """
|
||||
--reuse-db
|
||||
--nomigrations
|
||||
--cov=.
|
||||
--cov-report term-missing
|
||||
--cov-report html
|
||||
--cov-report xml
|
||||
--no-cov-on-fail
|
||||
--showlocals
|
||||
--darker
|
||||
--doctest-modules
|
||||
--failed-first
|
||||
--new-first
|
||||
"""
|
||||
|
||||
|
||||
[tool.coverage.run]
|
||||
omit = [".*"]
|
||||
branch = true
|
||||
parallel = true
|
||||
concurrency = ["multiprocessing"]
|
||||
source = ['.']
|
||||
command_line = './dev-cli.py test'
|
||||
disable_warnings = ["couldnt-parse"]
|
||||
|
||||
[tool.coverage.report]
|
||||
omit = ['.*', '*/tests/*']
|
||||
skip_empty = true
|
||||
fail_under = 10
|
||||
show_missing = true
|
||||
exclude_lines = [
|
||||
'if self.debug:',
|
||||
'pragma: no cover',
|
||||
'raise NotImplementedError',
|
||||
'if __name__ == .__main__.:',
|
||||
]
|
||||
|
||||
|
||||
[tool.tox]
|
||||
# https://tox.readthedocs.io/en/latest/example/basic.html#pyproject-toml-tox-legacy-ini
|
||||
[tool.tox] # https://tox.wiki/en/latest/config.html#pyproject-toml
|
||||
legacy_tox_ini = """
|
||||
[tox]
|
||||
isolated_build = True
|
||||
envlist = py{37,38,39,310}
|
||||
envlist = py{312,311,310}
|
||||
skip_missing_interpreters = True
|
||||
|
||||
[testenv]
|
||||
passenv = *
|
||||
whitelist_externals = make
|
||||
skip_install = true
|
||||
commands_pre =
|
||||
pip install -U pip-tools
|
||||
pip-sync requirements.dev.txt
|
||||
commands =
|
||||
make pytest
|
||||
{envpython} -m coverage run --context='{envname}'
|
||||
{envpython} -m coverage combine --append
|
||||
{envpython} -m coverage xml
|
||||
{envpython} -m coverage report
|
||||
"""
|
||||
|
||||
|
||||
[tool.mypy]
|
||||
warn_unused_configs = true
|
||||
ignore_missing_imports = true
|
||||
allow_redefinition = true # https://github.com/python/mypy/issues/7165
|
||||
show_error_codes = true
|
||||
plugins = []
|
||||
exclude = ['.venv', 'tests']
|
||||
|
||||
|
||||
[manageprojects] # https://github.com/jedie/manageprojects
|
||||
initial_revision = "1f3a70e"
|
||||
initial_date = 2024-05-21T21:22:39+02:00
|
||||
cookiecutter_template = "https://github.com/jedie/cookiecutter_templates/"
|
||||
cookiecutter_directory = "yunohost_django_package"
|
||||
|
||||
[manageprojects.cookiecutter_context.cookiecutter]
|
||||
project_name = "django-fmd"
|
||||
full_name = "Jens Diemer"
|
||||
github_username = "jedie"
|
||||
author_email = "git@jensdiemer.de"
|
||||
upstream_pkg_name = "django-fmd"
|
||||
upstream_url = "https://gitlab.com/jedie/django-find-my-device"
|
||||
upstream_pkg_app_name = "findmydevice"
|
||||
upstream_pkg_project_name = "findmydevice_project"
|
||||
ynh_app_pkg_name = "django_fmd_ynh"
|
||||
ynh_app_url = "https://github.com/YunoHost-Apps/django-fmd_ynh"
|
||||
bug_tracker_url = "https://gitlab.com/jedie/django-find-my-device/-/issues"
|
||||
upstream_version = "0.4.0"
|
||||
ynh_version = "+ynh1"
|
||||
package_description = "YunoHost app package for https://gitlab.com/jedie/django-find-my-device"
|
||||
license = "GPL-3.0-or-later"
|
||||
_template = "https://github.com/jedie/cookiecutter_templates/"
|
||||
|
|
1219
requirements.dev.txt
Normal file
1219
requirements.dev.txt
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,33 +1,187 @@
|
|||
#!/bin/bash
|
||||
|
||||
#=================================================
|
||||
# COMMON VARIABLES
|
||||
# RETRIEVE ARGUMENTS FROM THE MANIFEST
|
||||
#=================================================
|
||||
|
||||
# Transfer the main SSO domain to the App:
|
||||
ynh_current_host=$(cat /etc/yunohost/current_host)
|
||||
__YNH_CURRENT_HOST__=${ynh_current_host}
|
||||
|
||||
#=================================================
|
||||
# ARGUMENTS FROM CONFIG PANEL
|
||||
#=================================================
|
||||
|
||||
# 'debug_enabled' -> '__DEBUG_ENABLED__' -> settings.DEBUG
|
||||
debug_enabled="0" # "1" or "0" string
|
||||
|
||||
# 'log_level' -> '__LOG_LEVEL__' -> settings.LOG_LEVEL
|
||||
log_level="WARNING"
|
||||
|
||||
# 'admin_email' -> '__ADMIN_EMAIL__' add in settings.ADMINS
|
||||
admin_email="${admin}@${domain}"
|
||||
|
||||
# 'default_from_email' -> '__DEFAULT_FROM_EMAIL__' -> settings.DEFAULT_FROM_EMAIL
|
||||
default_from_email="${app}@${domain}"
|
||||
|
||||
#=================================================
|
||||
# SET CONSTANTS
|
||||
#=================================================
|
||||
|
||||
# e.g.: point pip cache to: /home/yunohost.app/$app/.cache/
|
||||
XDG_CACHE_HOME="$data_dir/.cache/"
|
||||
|
||||
log_path=/var/log/$app
|
||||
log_file="${log_path}/${app}.log"
|
||||
|
||||
#=================================================
|
||||
# HELPERS
|
||||
#=================================================
|
||||
|
||||
|
||||
#==================================================================================
|
||||
# myynh_install_python() Borrowed from:
|
||||
# https://github.com/YunoHost-Apps/homeassistant_ynh/blob/master/scripts/_common.sh
|
||||
# Until we get a newer Python in YunoHost, see:
|
||||
# https://forum.yunohost.org/t/use-newer-python-than-3-9/22568
|
||||
#==================================================================================
|
||||
py_required_major=3.11
|
||||
py_required_version=$(curl -Ls https://www.python.org/ftp/python/ \
|
||||
| grep '>'$py_required_major | cut -d '/' -f 2 \
|
||||
| cut -d '>' -f 2 | sort -rV | head -n 1) #3.11.8
|
||||
|
||||
#=================================================
|
||||
# PERSONAL HELPERS
|
||||
#=================================================
|
||||
myynh_install_python() {
|
||||
# Declare an array to define the options of this helper.
|
||||
local legacy_args=u
|
||||
local -A args_array=( [p]=python= )
|
||||
local python
|
||||
# Manage arguments with getopts
|
||||
ynh_handle_getopts_args "$@"
|
||||
|
||||
_install_fmd_venv() {
|
||||
ynh_exec_as "$app" python3 -m venv --upgrade "$install_dir/venv"
|
||||
# Check python version from APT
|
||||
local py_apt_version=$(python3 --version | cut -d ' ' -f 2)
|
||||
|
||||
venvpython="$install_dir/venv/bin/python3"
|
||||
# Usefull variables
|
||||
local python_major=${python%.*}
|
||||
|
||||
ynh_add_config --template="requirements.txt" --destination="$install_dir/requirements.txt"
|
||||
# Check existing built version of python in /usr/local/bin
|
||||
if [ -e "/usr/local/bin/python$python_major" ]
|
||||
then
|
||||
local py_built_version=$(/usr/local/bin/python$python_major --version \
|
||||
| cut -d ' ' -f 2)
|
||||
else
|
||||
local py_built_version=0
|
||||
fi
|
||||
|
||||
ynh_exec_as "$app" "$venvpython" -m ensurepip
|
||||
ynh_exec_as "$app" "$venvpython" -m pip install --upgrade wheel pip setuptools
|
||||
ynh_exec_as "$app" "$venvpython" -m pip install --no-deps -r "$install_dir/requirements.txt"
|
||||
# Compare version
|
||||
if $(dpkg --compare-versions $py_apt_version ge $python)
|
||||
then
|
||||
# APT >= Required
|
||||
ynh_print_info --message="Using provided python3..."
|
||||
|
||||
py_app_version="python3"
|
||||
|
||||
else
|
||||
# Either python already built or to build
|
||||
if $(dpkg --compare-versions $py_built_version ge $python)
|
||||
then
|
||||
# Built >= Required
|
||||
ynh_print_info --message="Using already used python3 built version..."
|
||||
|
||||
py_app_version="/usr/local/bin/python${py_built_version%.*}"
|
||||
|
||||
else
|
||||
# APT < Minimal & Actual < Minimal => Build & install Python into /usr/local/bin
|
||||
ynh_print_info --message="Building python (may take a while)..."
|
||||
|
||||
# Store current direcotry
|
||||
local MY_DIR=$(pwd)
|
||||
|
||||
# Create a temp direcotry
|
||||
tmpdir="$(mktemp --directory)"
|
||||
cd "$tmpdir"
|
||||
|
||||
# Download
|
||||
wget --output-document="Python-$python.tar.xz" \
|
||||
"https://www.python.org/ftp/python/$python/Python-$python.tar.xz" 2>&1
|
||||
|
||||
# Extract
|
||||
tar xf "Python-$python.tar.xz"
|
||||
|
||||
# Install
|
||||
cd "Python-$python"
|
||||
./configure --enable-optimizations
|
||||
ynh_exec_warn_less make -j4
|
||||
ynh_exec_warn_less make altinstall
|
||||
|
||||
# Go back to working directory
|
||||
cd "$MY_DIR"
|
||||
|
||||
# Clean
|
||||
ynh_secure_remove "$tmpdir"
|
||||
|
||||
# Set version
|
||||
py_app_version="/usr/local/bin/python$python_major"
|
||||
fi
|
||||
fi
|
||||
# Save python version in settings
|
||||
ynh_app_setting_set --app=$app --key=python --value="$python"
|
||||
}
|
||||
#==================================================================================
|
||||
#==================================================================================
|
||||
|
||||
myynh_setup_python_venv() {
|
||||
# Always recreate everything fresh with current python version
|
||||
ynh_secure_remove "$data_dir/venv"
|
||||
|
||||
myynh_install_python --python="$py_required_version"
|
||||
|
||||
# Create a virtualenv with python installed by myynh_install_python():
|
||||
# Skip pip because of: https://github.com/YunoHost/issues/issues/1960
|
||||
$py_app_version -m venv --without-pip "$data_dir/venv"
|
||||
|
||||
chown -c -R "$app:" "$data_dir"
|
||||
|
||||
# run source in a 'sub shell'
|
||||
(
|
||||
set +o nounset
|
||||
source "$data_dir/venv/bin/activate"
|
||||
set -o nounset
|
||||
set -x
|
||||
ynh_exec_as $app $data_dir/venv/bin/python3 -m ensurepip
|
||||
ynh_exec_as $app $data_dir/venv/bin/pip3 install --upgrade wheel pip setuptools
|
||||
ynh_exec_as $app $data_dir/venv/bin/pip3 install --no-deps -r "$data_dir/requirements.txt"
|
||||
)
|
||||
}
|
||||
|
||||
myynh_setup_log_file() {
|
||||
(
|
||||
set -x
|
||||
|
||||
mkdir -p "$(dirname "$log_file")"
|
||||
touch "$log_file"
|
||||
|
||||
chown -c -R $app:$app "$log_path"
|
||||
chmod -c o-rwx "$log_path"
|
||||
)
|
||||
}
|
||||
|
||||
myynh_fix_file_permissions() {
|
||||
(
|
||||
set -x
|
||||
|
||||
# /var/www/$app/
|
||||
chown -c -R "$app:www-data" "$install_dir"
|
||||
chmod -c o-rwx "$install_dir"
|
||||
|
||||
# /home/yunohost.app/$app/
|
||||
chown -c -R "$app:" "$data_dir"
|
||||
chmod -c o-rwx "$data_dir"
|
||||
)
|
||||
}
|
||||
|
||||
#=================================================
|
||||
# EXPERIMENTAL HELPERS
|
||||
#=================================================
|
||||
|
||||
#=================================================
|
||||
# FUTURE OFFICIAL HELPERS
|
||||
# Redis HELPERS
|
||||
#=================================================
|
||||
|
||||
# get the first available redis database
|
||||
|
@ -35,27 +189,27 @@ _install_fmd_venv() {
|
|||
# usage: ynh_redis_get_free_db
|
||||
# | returns: the database number to use
|
||||
ynh_redis_get_free_db() {
|
||||
local result max db
|
||||
result=$(redis-cli INFO keyspace)
|
||||
local result max db
|
||||
result=$(redis-cli INFO keyspace)
|
||||
|
||||
# get the num
|
||||
max=$(cat /etc/redis/redis.conf | grep ^databases | grep -Eow "[0-9]+")
|
||||
# get the num
|
||||
max=$(cat /etc/redis/redis.conf | grep ^databases | grep -Eow "[0-9]+")
|
||||
|
||||
db=0
|
||||
# default Debian setting is 15 databases
|
||||
for i in $(seq 0 "$max")
|
||||
do
|
||||
if ! echo "$result" | grep -q "db$i"
|
||||
then
|
||||
db=$i
|
||||
break 1
|
||||
fi
|
||||
db=-1
|
||||
done
|
||||
db=0
|
||||
# default Debian setting is 15 databases
|
||||
for i in $(seq 0 "$max")
|
||||
do
|
||||
if ! echo "$result" | grep -q "db$i"
|
||||
then
|
||||
db=$i
|
||||
break 1
|
||||
fi
|
||||
db=-1
|
||||
done
|
||||
|
||||
test "$db" -eq -1 && ynh_die "No available Redis databases..."
|
||||
test "$db" -eq -1 && ynh_die "No available Redis databases..."
|
||||
|
||||
echo "$db"
|
||||
echo "$db"
|
||||
}
|
||||
|
||||
# Create a master password and set up global settings
|
||||
|
@ -64,6 +218,7 @@ ynh_redis_get_free_db() {
|
|||
# usage: ynh_redis_remove_db database
|
||||
# | arg: database - the database to erase
|
||||
ynh_redis_remove_db() {
|
||||
local db=$1
|
||||
redis-cli -n "$db" flushall
|
||||
local db=$1
|
||||
redis-cli -n "$db" flushall
|
||||
}
|
||||
|
||||
|
|
|
@ -18,27 +18,38 @@ ynh_print_info --message="Declaring files to be backed up..."
|
|||
# BACKUP THE APP MAIN DIR
|
||||
#=================================================
|
||||
|
||||
# /var/www/$app/
|
||||
ynh_backup --src_path="$install_dir"
|
||||
|
||||
# /home/yunohost.app/$app/
|
||||
ynh_backup --src_path="$data_dir"
|
||||
|
||||
#=================================================
|
||||
# SYSTEM CONFIGURATION
|
||||
# BACKUP THE NGINX CONFIGURATION
|
||||
#=================================================
|
||||
|
||||
ynh_backup --src_path="/etc/nginx/conf.d/$domain.d/$app.conf"
|
||||
|
||||
ynh_backup --src_path="/etc/systemd/system/$app.service"
|
||||
|
||||
ynh_backup --src_path="/etc/logrotate.d/$app"
|
||||
|
||||
ynh_backup --src_path="/var/log/$app/"
|
||||
|
||||
#=================================================
|
||||
# BACKUP THE PostgreSQL DATABASE
|
||||
#=================================================
|
||||
ynh_print_info --message="Backing up the PostgreSQL database..."
|
||||
|
||||
ynh_psql_dump_db --database="$db_name" > db.sql
|
||||
|
||||
#=================================================
|
||||
# SPECIFIC BACKUP
|
||||
#=================================================
|
||||
# BACKUP LOGROTATE
|
||||
#=================================================
|
||||
|
||||
ynh_backup --src_path="/etc/logrotate.d/$app"
|
||||
|
||||
#=================================================
|
||||
# BACKUP SYSTEMD
|
||||
#=================================================
|
||||
|
||||
ynh_backup --src_path="/etc/systemd/system/$app.service"
|
||||
|
||||
#=================================================
|
||||
# END OF SCRIPT
|
||||
#=================================================
|
||||
|
|
|
@ -16,34 +16,31 @@ source /usr/share/yunohost/helpers
|
|||
#=================================================
|
||||
ynh_script_progression --message="Stopping systemd service '$app'..."
|
||||
|
||||
ynh_systemd_action --service_name="$app" --action="stop"
|
||||
ynh_systemd_action --service_name=$app --action="stop" --log_path="$log_file"
|
||||
|
||||
#=================================================
|
||||
# STANDARD MODIFICATIONS
|
||||
#=================================================
|
||||
# MODIFY URL IN NGINX CONF
|
||||
#=================================================
|
||||
ynh_script_progression --message="Updating NGINX web server configuration..."
|
||||
ynh_script_progression --message="Updating nginx web server configuration..."
|
||||
|
||||
ynh_change_url_nginx_config
|
||||
|
||||
#=================================================
|
||||
# SPECIFIC MODIFICATIONS
|
||||
# UPDATE DJANGO SETTINGS
|
||||
#=================================================
|
||||
# MODIFY SETTINGS
|
||||
#=================================================
|
||||
ynh_script_progression --message="Modify $app config file..."
|
||||
ynh_script_progression --message="Update $app settings file..." --weight=1
|
||||
|
||||
ynh_add_config --template="settings.py" --destination="$install_dir/settings.py"
|
||||
path=$new_path
|
||||
domain=$new_domain
|
||||
|
||||
ynh_add_config --template="settings.py" --destination="$data_dir/settings.py"
|
||||
|
||||
#=================================================
|
||||
# GENERIC FINALISATION
|
||||
#=================================================
|
||||
# START SYSTEMD SERVICE
|
||||
#=================================================
|
||||
ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
|
||||
|
||||
ynh_systemd_action --service_name="$app" --action="start"
|
||||
ynh_systemd_action --service_name=$app --action="start" --log_path="$log_file"
|
||||
|
||||
#=================================================
|
||||
# END OF SCRIPT
|
||||
|
|
159
scripts/install
159
scripts/install
|
@ -7,110 +7,147 @@
|
|||
source _common.sh
|
||||
source /usr/share/yunohost/helpers
|
||||
|
||||
# Install parameters are automatically saved as settings
|
||||
#
|
||||
# Settings are automatically loaded as bash variables
|
||||
# in every app script context, therefore typically these will exist:
|
||||
# - $domain
|
||||
# - $path
|
||||
# - $language
|
||||
# ... etc
|
||||
#
|
||||
# Resources defined in the manifest are provisioned prior to this script
|
||||
# and corresponding settings are also available, such as:
|
||||
# - $install_dir
|
||||
# - $port
|
||||
# - $db_name
|
||||
# ...
|
||||
|
||||
mkdir -p "$install_dir/public/media" "$install_dir/public/static"
|
||||
mkdir -p "$install_dir"
|
||||
#
|
||||
# $app is the app id (i.e. 'example' for first install,
|
||||
# or 'example__2', '__3', ... for multi-instance installs)
|
||||
#
|
||||
|
||||
mkdir -p "/var/log/$app"
|
||||
touch "/var/log/$app/$app.log"
|
||||
#=================================================
|
||||
# SETTINGS
|
||||
#=================================================
|
||||
ynh_script_progression --message="Storing installation settings..."
|
||||
|
||||
# Logging:
|
||||
log_file="/var/log/$app/$app.log"
|
||||
ynh_app_setting_set --app=$app --key=log_file --value="$log_file"
|
||||
|
||||
# Redis:
|
||||
redis_db=$(ynh_redis_get_free_db)
|
||||
ynh_app_setting_set --app="$app" --key=redis_db --value="$redis_db"
|
||||
ynh_app_setting_set --app=$app --key=redis_db --value="$redis_db"
|
||||
|
||||
# 'debug_enabled' -> '__DEBUG_ENABLED__' -> settings.DEBUG
|
||||
debug_enabled="0"
|
||||
|
||||
# 'log_level' -> '__LOG_LEVEL__' -> settings.LOG_LEVEL
|
||||
log_level="WARNING"
|
||||
|
||||
# 'admin_email' -> '__ADMIN_EMAIL__' add in settings.ADMINS
|
||||
admin_email="${admin}@${domain}"
|
||||
|
||||
# 'default_from_email' -> '__DEFAULT_FROM_EMAIL__' -> settings.DEFAULT_FROM_EMAIL
|
||||
default_from_email="${app}@${domain}"
|
||||
|
||||
|
||||
ynh_app_setting_set --app="$app" --key=debug_enabled --value="$debug_enabled"
|
||||
ynh_app_setting_set --app="$app" --key=log_level --value="$log_level"
|
||||
ynh_app_setting_set --app="$app" --key=admin_email --value="$admin_email"
|
||||
ynh_app_setting_set --app="$app" --key=default_from_email --value="$default_from_email"
|
||||
# App settings:
|
||||
ynh_app_setting_set --app=$app --key=default_from_email --value="$default_from_email"
|
||||
ynh_app_setting_set --app=$app --key=admin_email --value="$admin_email"
|
||||
ynh_app_setting_set --app=$app --key=debug_enabled --value="$debug_enabled"
|
||||
ynh_app_setting_set --app=$app --key=log_level --value="$log_level"
|
||||
|
||||
#=================================================
|
||||
# INSTALLATION
|
||||
# CHECK IF THE APP CAN BE INSTALLED WITH THESE ARGS
|
||||
#=================================================
|
||||
ynh_script_progression --message="Installing project via pip..." --weight=45
|
||||
ynh_script_progression --message="Validating installation parameters..."
|
||||
|
||||
_install_fmd_venv
|
||||
mkdir -p "$install_dir/media" "$install_dir/static"
|
||||
|
||||
mkdir -p "$install_dir/public/media" "$install_dir/public/static"
|
||||
#=================================================
|
||||
# SETUP LOG FILE
|
||||
#=================================================
|
||||
ynh_script_progression --message="Setup logging..."
|
||||
|
||||
chmod o-rwx "$install_dir"
|
||||
chown -R "$app:www-data" "$install_dir"
|
||||
myynh_setup_log_file
|
||||
|
||||
mkdir -p "/var/log/$app"
|
||||
touch "/var/log/$app/$app.log"
|
||||
# Use logrotate to manage application logfile(s)
|
||||
ynh_use_logrotate --logfile="$log_file" --specific_user=$app
|
||||
|
||||
chmod o-rwx "/var/log/$app"
|
||||
chown -R "$app:$app" "/var/log/$app"
|
||||
#=================================================
|
||||
# PYTHON VIRTUALENV
|
||||
#=================================================
|
||||
ynh_script_progression --message="Create and setup Python virtualenv..." --weight=45
|
||||
cp ../conf/requirements.txt "$data_dir/requirements.txt"
|
||||
myynh_setup_python_venv
|
||||
|
||||
#=================================================
|
||||
# copy config files
|
||||
# ================================================
|
||||
ynh_script_progression --message="Create $app configuration files..."
|
||||
|
||||
ynh_add_config --template="gunicorn.conf.py" --destination="$install_dir/gunicorn.conf.py"
|
||||
ynh_add_config --template="gunicorn.conf.py" --destination="$data_dir/gunicorn.conf.py"
|
||||
|
||||
ynh_add_config --template="manage.py" --destination="$install_dir/manage.py"
|
||||
chmod +x "$install_dir/manage.py"
|
||||
ynh_add_config --template="manage.py" --destination="$data_dir/manage.py"
|
||||
chmod -c +x "$data_dir/manage.py"
|
||||
|
||||
ynh_add_config --template="settings.py" --destination="$install_dir/settings.py"
|
||||
ynh_add_config --template="setup_user.py" --destination="$install_dir/setup_user.py"
|
||||
ynh_add_config --template="urls.py" --destination="$install_dir/urls.py"
|
||||
ynh_add_config --template="wsgi.py" --destination="$install_dir/wsgi.py"
|
||||
ynh_add_config --template="settings.py" --destination="$data_dir/settings.py"
|
||||
ynh_add_config --template="setup_user.py" --destination="$data_dir/setup_user.py"
|
||||
ynh_add_config --template="urls.py" --destination="$data_dir/urls.py"
|
||||
ynh_add_config --template="wsgi.py" --destination="$data_dir/wsgi.py"
|
||||
|
||||
touch "$install_dir/local_settings.py"
|
||||
touch "$data_dir/local_settings.py"
|
||||
|
||||
#=================================================
|
||||
# MIGRATE / COLLECTSTATIC / CREATEADMIN
|
||||
#=================================================
|
||||
ynh_script_progression --message="migrate/collectstatic/createadmin..." --weight=10
|
||||
|
||||
pushd "$install_dir"
|
||||
# Just for debugging:
|
||||
ynh_exec_as "$app" "$venvpython" ./manage.py diffsettings
|
||||
cd "$data_dir" || exit
|
||||
|
||||
ynh_exec_as "$app" "$venvpython" ./manage.py migrate --no-input
|
||||
ynh_exec_as "$app" "$venvpython" ./manage.py collectstatic --no-input
|
||||
# Just for debugging:
|
||||
./manage.py diffsettings
|
||||
|
||||
# Create/update Django superuser (set unusable password, because auth done via SSOwat):
|
||||
ynh_exec_as "$app" "$venvpython" ./manage.py create_superuser --username="$admin" --email="$(ynh_user_get_info "$admin" mail)"
|
||||
./manage.py migrate --no-input
|
||||
./manage.py collectstatic --no-input
|
||||
|
||||
# Check the configuration
|
||||
# This may fail in some cases with errors, etc., but the app works and the user can fix issues later.
|
||||
ynh_exec_as "$app" "$venvpython" ./manage.py check --deploy || true
|
||||
popd
|
||||
# Create/update Django superuser (set unusable password, because auth done via SSOwat):
|
||||
./manage.py create_superuser --username="$admin" --email="$(ynh_user_get_info "$admin" mail)"
|
||||
|
||||
# Check the configuration
|
||||
# This may fail in some cases with errors, etc., but the app works and the user can fix issues later.
|
||||
./manage.py check --deploy || true
|
||||
|
||||
#=================================================
|
||||
# SYSTEM CONFIGURATION
|
||||
# INTEGRATE SERVICE IN YUNOHOST
|
||||
#=================================================
|
||||
ynh_script_progression --message="Adding system configurations related to $app..." --weight=1
|
||||
ynh_script_progression --message="Integrating service in YunoHost..."
|
||||
|
||||
# Create a dedicated nginx config
|
||||
ynh_add_nginx_config
|
||||
yunohost service add $app
|
||||
|
||||
# Create a dedicated systemd config
|
||||
ynh_add_systemd_config --service="$app" --template="systemd.service"
|
||||
yunohost service add "$app" --description="$app service" --log="/var/log/$app/$app.log"
|
||||
#=================================================
|
||||
# GENERIC FINALIZATION
|
||||
#=================================================
|
||||
# SECURE FILES AND DIRECTORIES
|
||||
#=================================================
|
||||
ynh_script_progression --message="Set file permissions..."
|
||||
myynh_fix_file_permissions
|
||||
|
||||
# Use logrotate to manage app-specific logfile(s)
|
||||
ynh_use_logrotate
|
||||
#=================================================
|
||||
# SETUP SYSTEMD
|
||||
#=================================================
|
||||
ynh_script_progression --message="Configuring systemd service '$app'..." --weight=5
|
||||
|
||||
# https://yunohost.org/en/packaging_apps_helpers#ynh-add-systemd-config
|
||||
# https://github.com/YunoHost/yunohost/blob/dev/helpers/systemd
|
||||
ynh_add_systemd_config --service=$app --template="systemd.service"
|
||||
|
||||
#=================================================
|
||||
# Start the app server via systemd
|
||||
#=================================================
|
||||
ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
|
||||
|
||||
ynh_systemd_action --service_name="$app" --action="start"
|
||||
ynh_systemd_action --service_name=$app --action="start" --log_path="$log_file"
|
||||
|
||||
#=================================================
|
||||
# NGINX CONFIGURATION
|
||||
#=================================================
|
||||
ynh_script_progression --message="Configuring nginx web server..."
|
||||
|
||||
# Create a dedicated nginx config
|
||||
# https://yunohost.org/en/contribute/packaging_apps/helpers
|
||||
# https://github.com/YunoHost/yunohost/blob/dev/helpers/nginx
|
||||
ynh_add_nginx_config "public_path" "port"
|
||||
|
||||
#=================================================
|
||||
# END OF SCRIPT
|
||||
|
|
|
@ -10,22 +10,57 @@ source _common.sh
|
|||
source /usr/share/yunohost/helpers
|
||||
|
||||
#=================================================
|
||||
# REMOVE SYSTEM CONFIGURATIONS
|
||||
# STANDARD REMOVE
|
||||
#=================================================
|
||||
# REMOVE SERVICE FROM ADMIN PANEL
|
||||
#=================================================
|
||||
ynh_script_progression --message="Removing system configurations related to $app..." --weight=1
|
||||
|
||||
# Remove a service from the admin panel, added by `yunohost service add`
|
||||
if yunohost service status "$app" >/dev/null 2>&1; then
|
||||
yunohost service remove "$app"
|
||||
if yunohost service status $app >/dev/null 2>&1
|
||||
then
|
||||
ynh_script_progression --message="Removing $app service integration..."
|
||||
yunohost service remove $app
|
||||
fi
|
||||
|
||||
ynh_remove_logrotate
|
||||
#=================================================
|
||||
# STOP PYINVENTORY'S SERVICES
|
||||
#=================================================
|
||||
ynh_script_progression --message="Stopping and removing systemd service '$app'..." --weight=5
|
||||
|
||||
ynh_remove_systemd_config --service="$app"
|
||||
ynh_remove_systemd_config --service=$app
|
||||
|
||||
##=================================================
|
||||
## REMOVE REDIS DB
|
||||
##=================================================
|
||||
|
||||
ynh_redis_remove_db
|
||||
|
||||
#=================================================
|
||||
# REMOVE APP MAIN DIR
|
||||
#=================================================
|
||||
ynh_script_progression --message="Removing app main directory..."
|
||||
|
||||
# /var/www/$app/
|
||||
ynh_secure_remove --file="$install_dir"
|
||||
|
||||
# /home/yunohost.app/$app/
|
||||
ynh_secure_remove --file="$data_dir"
|
||||
|
||||
#=================================================
|
||||
# REMOVE NGINX CONFIGURATION
|
||||
#=================================================
|
||||
ynh_script_progression --message="Removing nginx web server configuration..."
|
||||
|
||||
# Remove the dedicated nginx config
|
||||
ynh_remove_nginx_config
|
||||
|
||||
ynh_redis_remove_db "$redis_db"
|
||||
#=================================================
|
||||
# REMOVE LOGROTATE CONFIGURATION
|
||||
#=================================================
|
||||
ynh_script_progression --message="Removing logrotate configuration..."
|
||||
|
||||
# Remove the app-specific logrotate config
|
||||
ynh_remove_logrotate
|
||||
|
||||
#=================================================
|
||||
# END OF SCRIPT
|
||||
|
|
104
scripts/restore
104
scripts/restore
|
@ -10,56 +10,90 @@ source ../settings/scripts/_common.sh
|
|||
source /usr/share/yunohost/helpers
|
||||
|
||||
#=================================================
|
||||
# RESTORE THE APP MAIN DIR
|
||||
# STANDARD RESTORATION STEPS
|
||||
#=================================================
|
||||
ynh_script_progression --message="Restoring the app main directory..." --weight=1
|
||||
|
||||
ynh_restore_file --origin_path="$install_dir"
|
||||
|
||||
chmod o-rwx "$install_dir"
|
||||
chown -R "$app:www-data" "$install_dir"
|
||||
|
||||
# RESTORE THE NGINX CONFIGURATION
|
||||
#=================================================
|
||||
# RESTORE THE POSTGRES DATABASE
|
||||
#=================================================
|
||||
ynh_script_progression --message="Restoring the Postgresql database..." --weight=1
|
||||
|
||||
ynh_psql_connect_as --user="$db_user" --password="$db_pwd" --database="$db_name" < ./db.sql
|
||||
|
||||
#=================================================
|
||||
# PYTHON VIRTUALENV
|
||||
#=================================================
|
||||
ynh_script_progression --message="Update Python virtualenv..." --weight=5
|
||||
|
||||
python3 -m venv --upgrade --without-pip "$install_dir/venv"
|
||||
|
||||
#=================================================
|
||||
# RESTORE SYSTEM CONFIGURATIONS
|
||||
#=================================================
|
||||
ynh_script_progression --message="Restoring system configurations related to $app..." --weight=1
|
||||
ynh_script_progression --message="Restoring the NGINX web server configuration..." --weight=1
|
||||
|
||||
ynh_restore_file --origin_path="/etc/nginx/conf.d/$domain.d/$app.conf"
|
||||
|
||||
#=================================================
|
||||
# RESTORE THE APP MAIN DIR
|
||||
#=================================================
|
||||
ynh_script_progression --message="Restoring $app main directory..."
|
||||
|
||||
ynh_restore_file --origin_path="$install_dir"
|
||||
ynh_restore_file --origin_path="$data_dir"
|
||||
|
||||
#=================================================
|
||||
# PYTHON VIRTUALENV
|
||||
# Maybe the backup contains a other Python version
|
||||
#=================================================
|
||||
ynh_script_progression --message="Create and setup Python virtualenv..." --weight=45
|
||||
|
||||
myynh_setup_python_venv
|
||||
|
||||
#=================================================
|
||||
# Fix file permissions
|
||||
#=================================================
|
||||
ynh_script_progression --message="Set file permissions..."
|
||||
|
||||
myynh_fix_file_permissions
|
||||
|
||||
#=================================================
|
||||
# RESTORE THE PostgreSQL DATABASE
|
||||
#=================================================
|
||||
ynh_script_progression --message="Restoring the PostgreSQL database..." --weight=5
|
||||
|
||||
ynh_psql_connect_as --user=$db_user --password=$db_pwd --database=$db_name < ./db.sql
|
||||
|
||||
#=================================================
|
||||
# RESTORE SYSTEMD
|
||||
#=================================================
|
||||
ynh_script_progression --message="Restoring the systemd $app configuration..."
|
||||
|
||||
ynh_restore_file --origin_path="/etc/systemd/system/$app.service"
|
||||
systemctl enable "$app.service" --quiet
|
||||
yunohost service add "$app" --description="$app service" --log="/var/log/$app/$app.log"
|
||||
systemctl enable $app.service --quiet
|
||||
|
||||
#=================================================
|
||||
# INTEGRATE SERVICE IN YUNOHOST
|
||||
#=================================================
|
||||
ynh_script_progression --message="Integrating service in YunoHost..."
|
||||
|
||||
yunohost service add $app
|
||||
|
||||
#=================================================
|
||||
# RESTORE THE LOGROTATE CONFIGURATION
|
||||
#=================================================
|
||||
ynh_script_progression --message="Setup logging..."
|
||||
|
||||
myynh_setup_log_file
|
||||
ynh_restore_file --origin_path="/etc/logrotate.d/$app"
|
||||
|
||||
ynh_restore_file --origin_path="/var/log/$app/"
|
||||
chmod o-rwx "/var/log/$app"
|
||||
chown -R "$app:" "/var/log/$app"
|
||||
|
||||
#=================================================
|
||||
# GENERIC FINALIZATION
|
||||
#=================================================
|
||||
# RELOAD NGINX AND PHP-FPM OR THE APP SERVICE
|
||||
# SECURE FILES AND DIRECTORIES
|
||||
#=================================================
|
||||
ynh_script_progression --message="Reloading NGINX web server and $app's service..." --weight=1
|
||||
ynh_script_progression --message="Set file permissions..."
|
||||
myynh_fix_file_permissions
|
||||
|
||||
ynh_systemd_action --service_name="$app" --action="start" --log_path="/var/log/$app/$app.log"
|
||||
#=================================================
|
||||
# GENERIC FINALIZATION
|
||||
#=================================================
|
||||
# START PYINVENTORY
|
||||
#=================================================
|
||||
ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
|
||||
|
||||
ynh_systemd_action --service_name=nginx --action=reload
|
||||
ynh_systemd_action --service_name=$app --action="start" --log_path="$log_file"
|
||||
|
||||
#=================================================
|
||||
# RELOAD NGINX
|
||||
#=================================================
|
||||
ynh_script_progression --message="Reloading nginx web server..."
|
||||
|
||||
ynh_systemd_action --service_name="nginx" --action="reload"
|
||||
|
||||
#=================================================
|
||||
# END OF SCRIPT
|
||||
|
|
114
scripts/upgrade
114
scripts/upgrade
|
@ -7,31 +7,27 @@
|
|||
source _common.sh
|
||||
source /usr/share/yunohost/helpers
|
||||
|
||||
#=================================================
|
||||
# STANDARD UPGRADE STEPS
|
||||
#=================================================
|
||||
# ENSURE DOWNWARD COMPATIBILITY
|
||||
#=================================================
|
||||
ynh_script_progression --message="Ensuring downward compatibility..." --weight=1
|
||||
#-------------------------------------------------
|
||||
# config_panel.toml settings:
|
||||
|
||||
if [ -z "${debug_enabled:-}" ]; then
|
||||
debug_enabled="0"
|
||||
ynh_app_setting_set --app="$app" --key=debug_enabled --value="$debug_enabled"
|
||||
if [ -z "$debug_enabled" ]; then
|
||||
debug_enabled="0"
|
||||
ynh_app_setting_set --app=$app --key=debug_enabled --value="$debug_enabled"
|
||||
fi
|
||||
|
||||
if [ -z "${log_level:-}" ]; then
|
||||
log_level="WARNING"
|
||||
ynh_app_setting_set --app="$app" --key=log_level --value="$log_level"
|
||||
if [ -z "$log_level" ]; then
|
||||
log_level="WARNING"
|
||||
ynh_app_setting_set --app=$app --key=log_level --value="$log_level"
|
||||
fi
|
||||
|
||||
if [ -z "${admin_email:-}" ]; then
|
||||
admin_email="${admin}@${domain}"
|
||||
ynh_app_setting_set --app="$app" --key=admin_email --value="$admin_email"
|
||||
if [ -z "$admin_email" ]; then
|
||||
admin_email="${admin}@${domain}"
|
||||
ynh_app_setting_set --app=$app --key=admin_email --value="$admin_email"
|
||||
fi
|
||||
|
||||
if [ -z "${default_from_email:-}" ]; then
|
||||
default_from_email="${app}@${domain}"
|
||||
ynh_app_setting_set --app="$app" --key=default_from_email --value="$default_from_email"
|
||||
if [ -z "$default_from_email" ]; then
|
||||
default_from_email="${app}@${domain}"
|
||||
ynh_app_setting_set --app=$app --key=default_from_email --value="$default_from_email"
|
||||
fi
|
||||
|
||||
#=================================================
|
||||
|
@ -41,76 +37,82 @@ fi
|
|||
#=================================================
|
||||
ynh_script_progression --message="Stopping systemd service '$app'..." --weight=5
|
||||
|
||||
ynh_systemd_action --service_name="$app" --action="stop" --log_path="/var/log/$app/$app.log"
|
||||
ynh_systemd_action --service_name=$app --action="stop" --log_path="$log_file"
|
||||
|
||||
|
||||
#=================================================
|
||||
# PIP INSTALLATION
|
||||
# SETUP SYSTEMD
|
||||
#=================================================
|
||||
ynh_script_progression --message="Installing project via pip..." --weight=45
|
||||
ynh_script_progression --message="Configuring systemd service '$app'..." --weight=5
|
||||
|
||||
# Always recreate everything fresh with current python version
|
||||
ynh_secure_remove "$install_dir/venv"
|
||||
ynh_add_systemd_config --service=$app --template="systemd.service"
|
||||
|
||||
_install_fmd_venv
|
||||
|
||||
chmod o-rwx "$install_dir"
|
||||
chown -R "$app:www-data" "$install_dir"
|
||||
#=================================================
|
||||
# PYTHON VIRTUALENV
|
||||
#=================================================
|
||||
ynh_script_progression --message="Create and setup Python virtualenv..." --weight=45
|
||||
cp ../conf/requirements.txt "$data_dir/requirements.txt"
|
||||
myynh_setup_python_venv
|
||||
|
||||
#=================================================
|
||||
# copy config files
|
||||
# ================================================
|
||||
ynh_script_progression --message="Create $app configuration files..."
|
||||
ynh_script_progression --message="Create project configuration files..."
|
||||
|
||||
ynh_add_config --template="gunicorn.conf.py" --destination="$install_dir/gunicorn.conf.py"
|
||||
ynh_add_config --template="gunicorn.conf.py" --destination="$data_dir/gunicorn.conf.py"
|
||||
|
||||
ynh_add_config --template="manage.py" --destination="$install_dir/manage.py"
|
||||
chmod +x "$install_dir/manage.py"
|
||||
ynh_add_config --template="manage.py" --destination="$data_dir/manage.py"
|
||||
chmod -c +x "$data_dir/manage.py"
|
||||
|
||||
ynh_add_config --template="settings.py" --destination="$install_dir/settings.py"
|
||||
ynh_add_config --template="setup_user.py" --destination="$install_dir/setup_user.py"
|
||||
ynh_add_config --template="urls.py" --destination="$install_dir/urls.py"
|
||||
ynh_add_config --template="wsgi.py" --destination="$install_dir/wsgi.py"
|
||||
ynh_add_config --template="settings.py" --destination="$data_dir/settings.py"
|
||||
ynh_add_config --template="setup_user.py" --destination="$data_dir/setup_user.py"
|
||||
ynh_add_config --template="urls.py" --destination="$data_dir/urls.py"
|
||||
ynh_add_config --template="wsgi.py" --destination="$data_dir/wsgi.py"
|
||||
|
||||
#=================================================
|
||||
# MIGRATE PYINVENTORY
|
||||
#=================================================
|
||||
ynh_script_progression --message="migrate/collectstatic/createadmin..." --weight=10
|
||||
|
||||
pushd "$install_dir"
|
||||
# Just for debugging:
|
||||
ynh_exec_as "$app" "$venvpython" ./manage.py diffsettings
|
||||
cd "$data_dir" || exit
|
||||
|
||||
ynh_exec_as "$app" "$venvpython" ./manage.py migrate --no-input
|
||||
ynh_exec_as "$app" "$venvpython" ./manage.py collectstatic --no-input
|
||||
# Just for debugging:
|
||||
./manage.py diffsettings
|
||||
|
||||
# Create/update Django superuser (set unusable password, because auth done via SSOwat):
|
||||
ynh_exec_as "$app" "$venvpython" ./manage.py create_superuser --username="$admin" --email="$(ynh_user_get_info "$admin" mail)"
|
||||
./manage.py migrate --no-input
|
||||
./manage.py collectstatic --no-input
|
||||
|
||||
# Create/update Django superuser (set unusable password, because auth done via SSOwat):
|
||||
./manage.py create_superuser --username="$admin" --email="$(ynh_user_get_info "$admin" mail)"
|
||||
|
||||
# Check the configuration
|
||||
# This may fail in some cases with errors, etc., but the app works and the user can fix issues later.
|
||||
./manage.py check --deploy || true
|
||||
|
||||
# Check the configuration
|
||||
# This may fail in some cases with errors, etc., but the app works and the user can fix issues later.
|
||||
ynh_exec_as "$app" "$venvpython" ./manage.py check --deploy || true
|
||||
popd
|
||||
|
||||
#=================================================
|
||||
# REAPPLY SYSTEM CONFIGURATIONS
|
||||
# SETUP LOGROTATE
|
||||
#=================================================
|
||||
ynh_script_progression --message="Upgrading system configurations related to $app..." --weight=1
|
||||
ynh_script_progression --message="Upgrading logrotate configuration..."
|
||||
|
||||
ynh_add_nginx_config
|
||||
# Use logrotate to manage app-specific logfile(s)
|
||||
ynh_use_logrotate --logfile="$log_file" --specific_user=$app --non-append
|
||||
|
||||
ynh_add_systemd_config --service="$app" --template="systemd.service"
|
||||
yunohost service add "$app" --description="$app service" --log="/var/log/$app/$app.log"
|
||||
|
||||
ynh_use_logrotate --non-append
|
||||
chmod o-rwx "/var/log/$app"
|
||||
chown -R "$app:" "/var/log/$app"
|
||||
#=================================================
|
||||
# GENERIC FINALIZATION
|
||||
#=================================================
|
||||
# SECURE FILES AND DIRECTORIES
|
||||
#=================================================
|
||||
ynh_script_progression --message="Set file permissions..."
|
||||
myynh_fix_file_permissions
|
||||
|
||||
#=================================================
|
||||
# Start the app server via systemd
|
||||
#=================================================
|
||||
ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
|
||||
|
||||
ynh_systemd_action --service_name="$app" --action="start"
|
||||
yunohost service add $app
|
||||
ynh_systemd_action --service_name=$app --action="start" --log_path="$log_file"
|
||||
|
||||
#=================================================
|
||||
# END OF SCRIPT
|
||||
|
|
24
tests.toml
24
tests.toml
|
@ -7,3 +7,27 @@ test_format = 1.0
|
|||
# ------------
|
||||
# Tests to run
|
||||
# ------------
|
||||
|
||||
# NB: the tests to run are automatically deduced by the CI script according to the
|
||||
# content of the app's manifest. The declarations below allow to customize which
|
||||
# tests are ran, possibly add special test suite to test special args, or
|
||||
# declare which commits to test upgrade from.
|
||||
#
|
||||
# You can also decide (though this is discouraged!) to ban/ignore some tests,
|
||||
|
||||
# The test IDs to be used in only/exclude statements are:
|
||||
# install.root, install.subdir, install.nourl, install.multi, backup_restore, upgrade, upgrade.someCommitId change_url
|
||||
#exclude = ["install.private", "install.multi"]
|
||||
|
||||
# -------------------------------
|
||||
# Default args to use for install
|
||||
# -------------------------------
|
||||
|
||||
# By default, the CI will automagically fill the 'standard' args
|
||||
# such as domain, path, admin, is_public and password with relevant values
|
||||
# and also install args with a "default" provided in the manifest..
|
||||
# It should only make sense to declare custom args here for args with no default values
|
||||
|
||||
args.default_from_email = "default_from_email@example.tld"
|
||||
args.admin_email = "admin_email@example.tld"
|
||||
|
||||
|
|
Loading…
Reference in a new issue