1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/pyinventory_ynh.git synced 2024-09-03 20:16:09 +02:00

Merge pull request #104 from YunoHost-Apps/testing

master <- testing
This commit is contained in:
Jens Diemer 2022-09-18 18:00:15 +02:00 committed by GitHub
commit 7bf009e0df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 1231 additions and 691 deletions

View file

@ -10,7 +10,7 @@ trim_trailing_whitespace = true
insert_final_newline = true insert_final_newline = true
[*.py] [*.py]
line_length = 119 max_line_length = 120
[{Makefile,**.mk}] [{Makefile,**.mk}]
indent_style = tab indent_style = tab
@ -18,4 +18,3 @@ insert_final_newline = false
[*.yml] [*.yml]
indent_style = tab indent_style = tab
indent_size = 4

View file

@ -14,7 +14,7 @@ jobs:
strategy: strategy:
max-parallel: 2 max-parallel: 2
matrix: matrix:
python-version: [3.9, 3.8, 3.7] python-version: ["3.10", "3.9", "3.8", "3.7"]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
@ -23,13 +23,18 @@ jobs:
run: | run: |
git fetch origin master git fetch origin master
- name: 'Set up Python ${{ matrix.python-version }}' - name: 'Set up Python ${{ matrix.python-version }}'
uses: actions/setup-python@v1 uses: actions/setup-python@v2
with: with:
python-version: '${{ matrix.python-version }}' python-version: '${{ matrix.python-version }}'
- uses: actions/cache@v2
with:
path: ~/.cache/
key: dot-cache-files
- name: 'Install package' - name: 'Install package'
run: | run: |
pip3 install poetry make install-poetry
make install make install
- name: 'List installed packages' - name: 'List installed packages'
@ -40,13 +45,12 @@ jobs:
run: | run: |
make pytest make pytest
- name: 'Run Safety check'
run: |
make safety
- name: 'Upload coverage report' - name: 'Upload coverage report'
uses: codecov/codecov-action@v2 uses: codecov/codecov-action@v2
with: with:
fail_ci_if_error: false fail_ci_if_error: false
verbose: true verbose: true
- name: 'Run linters'
if: matrix.python-version == '3.8'
run: |
make lint

View file

@ -18,13 +18,12 @@ check-poetry:
install-poetry: ## install or update poetry install-poetry: ## install or update poetry
pip3 install -U pip pip3 install -U pip
pip3 install -U poetry pip3 install -U "poetry<1.2" # https://forum.yunohost.org/t/invalid-pep-440-version-0-16-0-ynh1/21293
install: check-poetry ## install project via poetry install: check-poetry ## install project via poetry
poetry install poetry install
update: install-poetry ## update the sources and installation and generate "conf/requirements.txt" update: install-poetry ## update the sources and installation and generate "conf/requirements.txt"
poetry run pip install -U pip
poetry update poetry update
poetry export -f requirements.txt --output conf/requirements.txt poetry export -f requirements.txt --output conf/requirements.txt
@ -45,7 +44,7 @@ tox: check-poetry ## Run pytest via tox with all environments
poetry run tox poetry run tox
pytest: install ## Run pytest pytest: install ## Run pytest
poetry run python3 ./run_pytest.py poetry run pytest
local-test: install ## Run local_test.py to run the project locally local-test: install ## Run local_test.py to run the project locally
poetry run python3 ./local_test.py poetry run python3 ./local_test.py
@ -53,6 +52,8 @@ local-test: install ## Run local_test.py to run the project locally
local-diff-settings: ## Run "manage.py diffsettings" with local test local-diff-settings: ## Run "manage.py diffsettings" with local test
poetry run python3 local_test/opt_yunohost/manage.py diffsettings poetry run python3 local_test/opt_yunohost/manage.py diffsettings
safety: ## Run https://github.com/pyupio/safety
poetry run safety check --full-report
############################################################################## ##############################################################################

View file

@ -1,45 +1,49 @@
<!--
N.B.: This README was automatically generated by https://github.com/YunoHost/apps/tree/master/tools/README-generator
It shall NOT be edited by hand.
-->
# PyInventory for YunoHost # PyInventory for YunoHost
[![Integration level](https://dash.yunohost.org/integration/pyinventory.svg)](https://dash.yunohost.org/appci/app/pyinventory) [![CI Pipeline](https://ci-apps.yunohost.org/ci/badges/pyinventory.status.svg)](https://ci-apps.yunohost.org/ci/apps/pyinventory/) [![Maintain status](https://ci-apps.yunohost.org/ci/badges/pyinventory.maintain.svg)](https://dash.yunohost.org/appci/app/pyinventory) [![Integration level](https://dash.yunohost.org/integration/pyinventory.svg)](https://dash.yunohost.org/appci/app/pyinventory) ![Working status](https://ci-apps.yunohost.org/ci/badges/pyinventory.status.svg) ![Maintenance status](https://ci-apps.yunohost.org/ci/badges/pyinventory.maintain.svg)
[![pytest](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/pytest.yml/badge.svg?branch=master)](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/pytest.yml) [![YunoHost apps package linter](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/package_linter.yml/badge.svg)](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/package_linter.yml) [![Coverage Status on codecov.io](https://codecov.io/gh/YunoHost-Apps/pyinventory_ynh/branch/master/graph/badge.svg)](https://codecov.io/gh/YunoHost-Apps/pyinventory_ynh)
[![Install PyInventory with YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=pyinventory) [![Install PyInventory with YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=pyinventory)
*[Lire ce readme en français.](./README_fr.md)*
> *This package allows you to install PyInventory quickly and simply on a YunoHost server. > *This package allows you to install PyInventory quickly and simply on a YunoHost server.
If you don't have YunoHost, please consult [the guide](https://yunohost.org/#/install) to learn how to install it.* If you don't have YunoHost, please consult [the guide](https://yunohost.org/#/install) to learn how to install it.*
Pull requests welcome ;)
## Overview ## Overview
[PyInventory](https://github.com/jedie/PyInventory) is a libre web-based management to catalog things including state and location etc. using [Python](https://www.python.org/)/[Django](https://www.djangoproject.com/). [PyInventory](https://github.com/jedie/PyInventory) is a libre web-based management to catalog things including state and location etc. using [Python](https://www.python.org/)/[Django](https://www.djangoproject.com/).
[![Integration level](https://dash.yunohost.org/integration/pyinventory.svg)](https://dash.yunohost.org/appci/app/pyinventory) [![CI Pipeline](https://ci-apps.yunohost.org/ci/badges/pyinventory.status.svg)](https://ci-apps.yunohost.org/ci/apps/pyinventory/) [![Maintain status](https://ci-apps.yunohost.org/ci/badges/pyinventory.maintain.svg)](https://dash.yunohost.org/appci/app/pyinventory)
[![pytest](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/pytest.yml/badge.svg?branch=master)](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/pytest.yml) [![YunoHost apps package linter](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/package_linter.yml/badge.svg)](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/package_linter.yml) [![Coverage Status on codecov.io](https://codecov.io/gh/YunoHost-Apps/pyinventory_ynh/branch/master/graph/badge.svg)](https://codecov.io/gh/YunoHost-Apps/pyinventory_ynh)
![pyinventory @ PyPi](https://img.shields.io/pypi/v/pyinventory?label=pyinventory%20%40%20PyPi)
![Python Versions](https://img.shields.io/pypi/pyversions/pyinventory)
![License GPL V3+](https://img.shields.io/pypi/l/pyinventory)
Pull requests welcome ;)
This package for YunoHost used [django-yunohost-integration](https://github.com/YunoHost-Apps/django_yunohost_integration) This package for YunoHost used [django-yunohost-integration](https://github.com/YunoHost-Apps/django_yunohost_integration)
More screenshots are here: jedie.github.io/tree/master/screenshots/PyInventory
**Shipped version:** 0.16.0~ynh1
## Screenshots ## Screenshots
More screenshots are here: [jedie.github.io/tree/master/screenshots/PyInventory](https://github.com/jedie/jedie.github.io/blob/master/screenshots/PyInventory/README.creole) ![Screenshot of PyInventory](./doc/screenshots/pyinventory_v010_screenshot_2.png)
![Screenshot of PyInventory](./doc/screenshots/pyinventory_v010_screenshot_3.png)
![Screenshot of PyInventory](./doc/screenshots/pyinventory_v020_screenshot_1.png)
![Screenshot of PyInventory](./doc/screenshots/pyinventory_v0110_screenshot_memo_1.png)
![Screenshot of PyInventory](./doc/screenshots/gitkeep)
---- ## Disclaimers / important information
![PyInventory v0.2.0](https://raw.githubusercontent.com/jedie/jedie.github.io/master/screenshots/PyInventory/PyInventory%20v0.2.0%20screenshot%201.png)
----
![PyInventory v0.1.0 screenshot 2](https://raw.githubusercontent.com/jedie/jedie.github.io/master/screenshots/PyInventory/PyInventory%20v0.1.0%20screenshot%202.png)
----
![PyInventory v0.11.0 screenshot memo](https://raw.githubusercontent.com/jedie/jedie.github.io/master/screenshots/PyInventory/PyInventory%20v0.11.0%20screenshot%20memo%201.png)
----
![PyInventory v0.1.0 screenshot 3](https://raw.githubusercontent.com/jedie/jedie.github.io/master/screenshots/PyInventory/PyInventory%20v0.1.0%20screenshot%203.png)
----
More screenshots are here: [jedie.github.io/tree/master/screenshots/PyInventory](https://github.com/jedie/jedie.github.io/blob/master/screenshots/PyInventory/README.creole)
## Settings and upgrades ## Settings and upgrades
@ -193,3 +197,24 @@ Notes:
* SQlite database will be used * SQlite database will be used
* A super user with username `test` and password `test` is created * A super user with username `test` and password `test` is created
* The page is available under `http://127.0.0.1:8000/app_path/` * The page is available under `http://127.0.0.1:8000/app_path/`
## Documentation and resources
* Official app website: <https://github.com/jedie/PyInventory>
* Upstream app code repository: <https://github.com/jedie/PyInventory>
* YunoHost documentation for this app: <https://yunohost.org/app_pyinventory>
* Report a bug: <https://github.com/YunoHost-Apps/pyinventory_ynh/issues>
## Developer info
Please send your pull request to the [testing branch](https://github.com/YunoHost-Apps/pyinventory_ynh/tree/testing).
To try the testing branch, please proceed like that.
``` bash
sudo yunohost app install https://github.com/YunoHost-Apps/pyinventory_ynh/tree/testing --debug
or
sudo yunohost app upgrade pyinventory -u https://github.com/YunoHost-Apps/pyinventory_ynh/tree/testing --debug
```
**More info regarding app packaging:** <https://yunohost.org/packaging_apps>

220
README_fr.md Normal file
View file

@ -0,0 +1,220 @@
<!--
N.B.: This README was automatically generated by https://github.com/YunoHost/apps/tree/master/tools/README-generator
It shall NOT be edited by hand.
-->
# PyInventory pour YunoHost
[![Niveau d'intégration](https://dash.yunohost.org/integration/pyinventory.svg)](https://dash.yunohost.org/appci/app/pyinventory) ![Statut du fonctionnement](https://ci-apps.yunohost.org/ci/badges/pyinventory.status.svg) ![Statut de maintenance](https://ci-apps.yunohost.org/ci/badges/pyinventory.maintain.svg)
[![Installer PyInventory avec YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=pyinventory)
*[Read this readme in english.](./README.md)*
> *Ce package vous permet d'installer PyInventory rapidement et simplement sur un serveur YunoHost.
Si vous n'avez pas YunoHost, regardez [ici](https://yunohost.org/#/install) pour savoir comment l'installer et en profiter.*
## Vue d'ensemble
[PyInventory](https://github.com/jedie/PyInventory) is a libre web-based management to catalog things including state and location etc. using [Python](https://www.python.org/)/[Django](https://www.djangoproject.com/).
[![Integration level](https://dash.yunohost.org/integration/pyinventory.svg)](https://dash.yunohost.org/appci/app/pyinventory) [![CI Pipeline](https://ci-apps.yunohost.org/ci/badges/pyinventory.status.svg)](https://ci-apps.yunohost.org/ci/apps/pyinventory/) [![Maintain status](https://ci-apps.yunohost.org/ci/badges/pyinventory.maintain.svg)](https://dash.yunohost.org/appci/app/pyinventory)
[![pytest](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/pytest.yml/badge.svg?branch=master)](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/pytest.yml) [![YunoHost apps package linter](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/package_linter.yml/badge.svg)](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/package_linter.yml) [![Coverage Status on codecov.io](https://codecov.io/gh/YunoHost-Apps/pyinventory_ynh/branch/master/graph/badge.svg)](https://codecov.io/gh/YunoHost-Apps/pyinventory_ynh)
![pyinventory @ PyPi](https://img.shields.io/pypi/v/pyinventory?label=pyinventory%20%40%20PyPi)
![Python Versions](https://img.shields.io/pypi/pyversions/pyinventory)
![License GPL V3+](https://img.shields.io/pypi/l/pyinventory)
Pull requests welcome ;)
This package for YunoHost used [django-yunohost-integration](https://github.com/YunoHost-Apps/django_yunohost_integration)
More screenshots are here: jedie.github.io/tree/master/screenshots/PyInventory
**Version incluse :** 0.16.0~ynh1
## Captures d'écran
![Capture d'écran de PyInventory](./doc/screenshots/pyinventory_v010_screenshot_2.png)
![Capture d'écran de PyInventory](./doc/screenshots/pyinventory_v010_screenshot_3.png)
![Capture d'écran de PyInventory](./doc/screenshots/pyinventory_v020_screenshot_1.png)
![Capture d'écran de PyInventory](./doc/screenshots/pyinventory_v0110_screenshot_memo_1.png)
![Capture d'écran de PyInventory](./doc/screenshots/gitkeep)
## Avertissements / informations importantes
## Settings and upgrades
Almost everything related to PyInventory's configuration is handled in a `"../conf/settings.py"` file.
You can edit the file `/opt/yunohost/pyinventory/local_settings.py` to enable or disable features.
Test sending emails:
```bash
ssh admin@yourdomain.tld
root@yunohost:~# cd /opt/yunohost/pyinventory/
root@yunohost:/opt/yunohost/pyinventory# source venv/bin/activate
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py sendtestemail --admins
```
Background info: Error mails are send to all [settings.ADMINS](https://docs.djangoproject.com/en/2.2/ref/settings/#std:setting-ADMINS). By default the YunoHost admin is inserted here.
To check current ADMINS run:
```bash
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py sendtestemail --admins
```
If you prefere to send error emails to a extrnal email address, just do something like this:
```bash
echo "ADMINS = (('Your Name', 'example@domain.tld'),)" >> /opt/yunohost/pyinventory/local_settings.py
```
To check the effective settings, run this:
```bash
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py diffsettings
```
# Miscellaneous
## SSO authentication
[SSOwat](https://github.com/YunoHost/SSOwat) is fully supported via [django-yunohost-integration](https://github.com/YunoHost-Apps/django_yunohost_integration):
* First user (`$YNH_APP_ARG_ADMIN`) will be created as Django's super user
* All new users will be created as normal users
* Login via SSO is fully supported
* User Email, First / Last name will be updated from SSO data
## Links
* Report a bug about this package: https://github.com/YunoHost-Apps/pyinventory_ynh
* Report a bug about PyInventory itself: https://github.com/jedie/PyInventory
* YunoHost website: https://yunohost.org/
---
# Developer info
## package installation / debugging
Please send your pull request to https://github.com/YunoHost-Apps/pyinventory_ynh
Try 'main' branch, e.g.:
```bash
sudo yunohost app install https://github.com/YunoHost-Apps/pyinventory_ynh/tree/master --debug
or
sudo yunohost app upgrade pyinventory -u https://github.com/YunoHost-Apps/pyinventory_ynh/tree/master --debug
```
Try 'testing' branch, e.g.:
```bash
sudo yunohost app install https://github.com/YunoHost-Apps/pyinventory_ynh/tree/testing --debug
or
sudo yunohost app upgrade pyinventory -u https://github.com/YunoHost-Apps/pyinventory_ynh/tree/testing --debug
```
To remove call e.g.:
```bash
sudo yunohost app remove pyinventory
```
Backup / remove / restore cycle, e.g.:
```bash
yunohost backup create --apps pyinventory
yunohost backup list
archives:
- pyinventory-pre-upgrade1
- 20201223-163434
yunohost app remove pyinventory
yunohost backup restore 20201223-163434 --apps pyinventory
```
Debug installation, e.g.:
```bash
root@yunohost:~# ls -la /var/www/pyinventory/
total 18
drwxr-xr-x 4 root root 4 Dec 8 08:36 .
drwxr-xr-x 6 root root 6 Dec 8 08:36 ..
drwxr-xr-x 2 root root 2 Dec 8 08:36 media
drwxr-xr-x 7 root root 8 Dec 8 08:40 static
root@yunohost:~# ls -la /opt/yunohost/pyinventory/
total 58
drwxr-xr-x 5 pyinventory pyinventory 11 Dec 8 08:39 .
drwxr-xr-x 3 root root 3 Dec 8 08:36 ..
-rw-r--r-- 1 pyinventory pyinventory 460 Dec 8 08:39 gunicorn.conf.py
-rw-r--r-- 1 pyinventory pyinventory 0 Dec 8 08:39 local_settings.py
-rwxr-xr-x 1 pyinventory pyinventory 274 Dec 8 08:39 manage.py
-rw-r--r-- 1 pyinventory pyinventory 171 Dec 8 08:39 secret.txt
drwxr-xr-x 6 pyinventory pyinventory 6 Dec 8 08:37 venv
-rw-r--r-- 1 pyinventory pyinventory 115 Dec 8 08:39 wsgi.py
-rw-r--r-- 1 pyinventory pyinventory 4737 Dec 8 08:39 settings.py
root@yunohost:~# cd /opt/yunohost/pyinventory/
root@yunohost:/opt/yunohost/pyinventory# source venv/bin/activate
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py check
PyInventory v0.8.2 (Django v2.2.17)
DJANGO_SETTINGS_MODULE='settings'
PROJECT_PATH:/opt/yunohost/pyinventory/venv/lib/python3.7/site-packages
BASE_PATH:/opt/yunohost/pyinventory
System check identified no issues (0 silenced).
root@yunohost:~# tail -f /var/log/pyinventory/pyinventory.log
root@yunohost:~# cat /etc/systemd/system/pyinventory.service
root@yunohost:~# systemctl reload-or-restart pyinventory
root@yunohost:~# journalctl --unit=pyinventory --follow
```
## local test
For quicker developing of PyInventory in the context of YunoHost app,
it's possible to run the Django developer server with the settings
and urls made for YunoHost installation.
e.g.:
```bash
~$ git clone https://github.com/YunoHost-Apps/pyinventory_ynh.git
~$ cd pyinventory_ynh/
~/pyinventory_ynh$ make
install-poetry install or update poetry
install install PyInventory via poetry
update update the sources and installation
local-test Run local_test.py to run pyinventory_ynh locally
~/pyinventory_ynh$ make install-poetry
~/pyinventory_ynh$ make install
~/pyinventory_ynh$ make local-test
```
Notes:
* SQlite database will be used
* A super user with username `test` and password `test` is created
* The page is available under `http://127.0.0.1:8000/app_path/`
## Documentations et ressources
* Site officiel de l'app : <https://github.com/jedie/PyInventory>
* Dépôt de code officiel de l'app : <https://github.com/jedie/PyInventory>
* Documentation YunoHost pour cette app : <https://yunohost.org/app_pyinventory>
* Signaler un bug : <https://github.com/YunoHost-Apps/pyinventory_ynh/issues>
## Informations pour les développeurs
Merci de faire vos pull request sur la [branche testing](https://github.com/YunoHost-Apps/pyinventory_ynh/tree/testing).
Pour essayer la branche testing, procédez comme suit.
``` bash
sudo yunohost app install https://github.com/YunoHost-Apps/pyinventory_ynh/tree/testing --debug
ou
sudo yunohost app upgrade pyinventory -u https://github.com/YunoHost-Apps/pyinventory_ynh/tree/testing --debug
```
**Plus d'infos sur le packaging d'applications :** <https://yunohost.org/packaging_apps>

View file

@ -16,7 +16,7 @@
setup_sub_dir=1 setup_sub_dir=1
setup_root=1 setup_root=1
setup_nourl=0 setup_nourl=0
setup_private=1 setup_private=0
setup_public=1 setup_public=1
upgrade=1 upgrade=1
backup_restore=1 backup_restore=1

View file

@ -17,4 +17,4 @@ accesslog = '__LOG_FILE__'
errorlog = '__LOG_FILE__' errorlog = '__LOG_FILE__'
# https://docs.gunicorn.org/en/latest/settings.html#pidfile # https://docs.gunicorn.org/en/latest/settings.html#pidfile
pidfile = '__FINAL_HOME_PATH__/gunicorn.pid' pidfile = '__FINALPATH__/gunicorn.pid'

View file

@ -1,4 +1,4 @@
#!__FINAL_HOME_PATH__/venv/bin/python #!__FINALPATH__/venv/bin/python
import os import os
import sys import sys

View file

@ -1,17 +1,11 @@
location __PATH__/static/ { location __PATH__/static/ {
# Django static files # Service static files by nginx
# e.g.: /var/www/$app/static
alias __PUBLIC_PATH__/static/; alias __PUBLIC_PATH__/static/;
expires 30d; expires 30d;
} }
# TODO: django-sendfile2:
#location __PATH__/media/ {
# # DATA_DIR/media/
# alias __PUBLIC_PATH__/media/;
# expires 30d;
#}
location __PATH__/ { location __PATH__/ {
# https://github.com/benoitc/gunicorn/blob/master/examples/nginx.conf # https://github.com/benoitc/gunicorn/blob/master/examples/nginx.conf

View file

@ -7,24 +7,24 @@ async-timeout==4.0.2; python_version >= "3.7" and python_full_version < "4.0.0"
bleach==5.0.1; python_version >= "3.7" and python_full_version < "4.0.0" \ bleach==5.0.1; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \
--hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c
bx-django-utils==26; python_version >= "3.7" and python_full_version < "4.0.0" \ bx-django-utils==31; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:c04776c4c6b275ddcadae79fd1578e6ae9ba92d8cf752a9ee4f2b70a22f4236e \ --hash=sha256:bc26ad6c78c43bbf78c9b32ea2ced76dace95ca22bd4acee4ef76a6e5253e3e0 \
--hash=sha256:19349d0a8fa165d87b4fd544efb61418f7d6c41cfabaa46d0153bb6d844262a1 --hash=sha256:5779673dbce2dfabbbdadcf443bd67273e792da855082e2ea8b26a4e354689bd
bx-py-utils==67; python_version >= "3.7" and python_full_version < "4.0.0" \ bx-py-utils==68; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:4810dcab69146ffd5c31d45710c47fa9ac63f074b26326bc2f17eb7eb7f5e09e \ --hash=sha256:00c3fbc9b5f48626a0a58141aaa90104349bac9723941c64f528f8742b0961db \
--hash=sha256:981877273d1c480f8d6f1de78b1a034c97b5e420df75e66799b320ff9133a047 --hash=sha256:fe5808c379db7165a51cbf5e4d947ef783d78bdfb5c47665e85e9cfe0b520ff9
certifi==2022.6.15; python_version >= "3.7" and python_version < "4" and python_full_version < "4.0.0" \ certifi==2022.9.14; python_version >= "3.7" and python_version < "4" and python_full_version < "4.0.0" \
--hash=sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412 \ --hash=sha256:e232343de1ab72c2aa521b625c80f699e356830fd0e2c620b465b304b17b0516 \
--hash=sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d --hash=sha256:36973885b9542e6bd01dea287b2b4b3b21236307c56324fcc3f1160f2d655ed5
charset-normalizer==2.1.0; python_version >= "3.7" and python_version < "4" and python_full_version < "4.0.0" and python_full_version >= "3.6.0" \ charset-normalizer==2.1.1; python_version >= "3.7" and python_version < "4" and python_full_version < "4.0.0" and python_full_version >= "3.6.0" \
--hash=sha256:575e708016ff3a5e3681541cb9d79312c416835686d054a23accb873b254f413 \ --hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 \
--hash=sha256:5189b6f22b01957427f35b6a08d9a0bc45b46d3788ef5a92e978433c7a35f8a5 --hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f
colorama==0.4.5; python_version >= "3.7" and python_full_version < "3.0.0" and sys_platform == "win32" or python_version >= "3.7" and python_full_version < "4.0.0" and sys_platform == "win32" and python_full_version >= "3.5.0" \ colorama==0.4.5; python_version >= "3.7" and python_full_version < "3.0.0" and sys_platform == "win32" or python_version >= "3.7" and python_full_version < "4.0.0" and sys_platform == "win32" and python_full_version >= "3.5.0" \
--hash=sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da \ --hash=sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da \
--hash=sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4 --hash=sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4
colorlog==6.6.0; python_version >= "3.7" and python_full_version < "4.0.0" \ colorlog==6.7.0; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:351c51e866c86c3217f08e4b067a7974a678be78f07f85fc2d55b8babde6d94e \ --hash=sha256:0d33ca236784a1ba3ff9c532d4964126d8a2c44f1f0cb1d2b0728196f512f662 \
--hash=sha256:344f73204009e4c83c5b6beb00b3c45dc70fcdae3c80db919e0a4171d006fde8 --hash=sha256:bd94bd21c1e13fac7bd3153f4bc3a7dc0eb0974b8bc2fdf1a989e474f6e582e5
defusedxml==0.7.1; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version < "4.0.0" and python_full_version >= "3.5.0" \ defusedxml==0.7.1; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version < "4.0.0" and python_full_version >= "3.5.0" \
--hash=sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61 \ --hash=sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61 \
--hash=sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69 --hash=sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69
@ -37,51 +37,51 @@ diff-match-patch==20200713; python_version >= "3.7" and python_full_version < "4
django-admin-sortable2==1.0.4; python_version >= "3.7" and python_full_version < "4.0.0" \ django-admin-sortable2==1.0.4; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:f96044003176c6684c5f969792ca833a505d654fa0f7b24232a0a610e4332a53 \ --hash=sha256:f96044003176c6684c5f969792ca833a505d654fa0f7b24232a0a610e4332a53 \
--hash=sha256:e22956889533b48a35a7f02859ae3a939753fa9a7d7d532cefc2835b41bdcebb --hash=sha256:e22956889533b48a35a7f02859ae3a939753fa9a7d7d532cefc2835b41bdcebb
django-axes==5.36.0; python_version >= "3.7" and python_full_version < "4.0.0" \ django-axes==5.39.0; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:bac08a7047fde26ffb54813c971fd40eeadb4ecb8d342a6e47d53de666d1a792 \ --hash=sha256:97702552f7939c81db5bba2ef855ae43f20df92fa261cb79fd4c8633ba3b3955 \
--hash=sha256:466e6ed1affd0866c78f245ee658d2619f74250aca5856852d86e61dba400eda --hash=sha256:8f039f8e98f050f13f654efca599d8a04d0b57d330c590cf89ec2bf731c9a7fb
django-ckeditor==6.3.2; python_version >= "3.7" and python_full_version < "4.0.0" \ django-ckeditor==6.3.0; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:ce0c806e40172dbea35330a207632701a6d418314ae8c8fa140fd277d9322c96 \ --hash=sha256:d04f350f4a200c2a0f96307fc8827bd4e87af5694fb12d53189ba92025b2da37 \
--hash=sha256:e1580105c9ff6fcaca6345acda1dc01416733027c61c6387e02dd5960b8ade3c --hash=sha256:b5c03d77b9fe848bf12520512a82d07533afa8678040731b1d4d86c1dcea8344
django-dbbackup==4.0.1; python_version >= "3.7" and python_full_version < "4.0.0" \ django-dbbackup==4.0.1; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:c2f17877f44ce0d2315e5c3b2ac5f39f1fdf9be49b7fcd0c96e389ddb19ed141 \ --hash=sha256:c2f17877f44ce0d2315e5c3b2ac5f39f1fdf9be49b7fcd0c96e389ddb19ed141 \
--hash=sha256:5762039354f2f9c996c008a9eaf3a8e59aa809a1ea594c07d1de5a5e4cd36fa3 --hash=sha256:5762039354f2f9c996c008a9eaf3a8e59aa809a1ea594c07d1de5a5e4cd36fa3
django-debug-toolbar==3.5.0; python_version >= "3.7" and python_full_version < "4.0.0" \ django-debug-toolbar==3.6.0; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:97965f2630692de316ea0c1ca5bfa81660d7ba13146dbc6be2059cf55b35d0e5 \ --hash=sha256:95fc2fd29c56cc86678aae9f6919ececefe892f2a78c4004b193a223a8380c3d \
--hash=sha256:89a52128309eb4da12738801ff0c202d2ff8730d1c3225fac6acf630c303e661 --hash=sha256:fe7fe3f21865218827e2162ecc06eba386dfe8cffe4f3501c49bb4359e06a0e6
django-import-export==2.8.0; python_version >= "3.7" and python_full_version < "4.0.0" \ django-import-export==2.9.0; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:33c37b2921ef84e2cd9aa0eb76d04a7c2b538c9d04cb1ed97ac32600876cab30 \ --hash=sha256:02ce3a8e191992fa7aa1d660877ac6764fa9e32a5ba6394293f2fc761a5bdd19 \
--hash=sha256:31d7dcfba22251e3ef93accb7da844f58c4d78585db9dd7dae37bb76f939da2c --hash=sha256:126d32a4410c42b6e1bf060355bf45968f6fe427c3b7ed04c96873bd45d7549a
django-ipware==4.0.2; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version < "4.0.0" and python_full_version >= "3.6.0" \ django-ipware==4.0.2; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version < "4.0.0" and python_full_version >= "3.6.0" \
--hash=sha256:602a58325a4808bd19197fef2676a0b2da2df40d0ecf21be414b2ff48c72ad05 \ --hash=sha256:602a58325a4808bd19197fef2676a0b2da2df40d0ecf21be414b2ff48c72ad05 \
--hash=sha256:878dbb06a87e25550798e9ef3204ed70a200dd8b15e47dcef848cf08244f04c9 --hash=sha256:878dbb06a87e25550798e9ef3204ed70a200dd8b15e47dcef848cf08244f04c9
django-js-asset==2.0.0; python_version >= "3.7" and python_full_version < "4.0.0" \ django-js-asset==2.0.0; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:86f9f300d682537ddaf0487dc2ab356581b8f50c069bdba91d334a46e449f923 \ --hash=sha256:86f9f300d682537ddaf0487dc2ab356581b8f50c069bdba91d334a46e449f923 \
--hash=sha256:adc1ee1efa853fad42054b540c02205344bb406c9bddf87c9e5377a41b7db90f --hash=sha256:adc1ee1efa853fad42054b540c02205344bb406c9bddf87c9e5377a41b7db90f
django-processinfo==1.0.2; python_version >= "3.7" and python_full_version < "4.0.0" \ django-processinfo==1.1.0; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:3cacad233a5428a5cc6292eafbfddd97948d8d1e4f47e47175a7fcdfcee90f12 \ --hash=sha256:e5d883c2bd4d3a197357bb381a4c19165b5c9ff9a852f96b0dd1ccfd98e2e4a2 \
--hash=sha256:08aefdf7285d1eaa595e46570bcc12f2dfd9e24594d524246110614819076b6c --hash=sha256:c7d1fe2203655925294c860878509fe2a6eb1a5390a170c848023e4619b903da
django-redis==5.2.0; python_version >= "3.7" and python_full_version < "4.0.0" \ django-redis==5.2.0; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:8a99e5582c79f894168f5865c52bd921213253b7fd64d16733ae4591564465de \ --hash=sha256:8a99e5582c79f894168f5865c52bd921213253b7fd64d16733ae4591564465de \
--hash=sha256:1d037dc02b11ad7aa11f655d26dac3fb1af32630f61ef4428860a2e29ff92026 --hash=sha256:1d037dc02b11ad7aa11f655d26dac3fb1af32630f61ef4428860a2e29ff92026
django-reversion-compare==0.15.0; python_version >= "3.7" and python_full_version < "4.0.0" \ django-reversion-compare==0.15.0; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:ed0264a2852d9d867023f1874948b8234dad9c2d2fa22ea18cfd5f28f304d7a0 \ --hash=sha256:ed0264a2852d9d867023f1874948b8234dad9c2d2fa22ea18cfd5f28f304d7a0 \
--hash=sha256:d6f37b106aec287ae17a076bb7db1184ab02ab1898f0e8693f2779fbdaf71697 --hash=sha256:d6f37b106aec287ae17a076bb7db1184ab02ab1898f0e8693f2779fbdaf71697
django-reversion==5.0.1; python_version >= "3.7" and python_full_version < "4.0.0" \ django-reversion==5.0.2; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:a2b26a4b84b11338136ca9d6457a4af3070992c7a89623b349009a123f28ea1d \ --hash=sha256:243a12ee4e04c1611c0f076fbfc3074f1ad40afc45adc64de5ba2414cc4eaf29 \
--hash=sha256:45206cc0393fa18b7d5c0332b982736a0f6eb6d2b908ad7cc86e370ce7d4a807 --hash=sha256:5ae3f0a529530bc24afd64b084b690c96d615b70a45bad3a68dc12fcf50ed8c9
django-tagulous==1.3.3; python_version >= "3.7" and python_full_version < "4.0.0" \ django-tagulous==1.3.3; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:d445590ae1b5cb9b8c5a425f97bf5f01148a33419c19edeb721ebd9fdd6792fe \ --hash=sha256:d445590ae1b5cb9b8c5a425f97bf5f01148a33419c19edeb721ebd9fdd6792fe \
--hash=sha256:ad3bb85f4cce83a47e4c0257143229cb92a294defa02fe661823b0442b35d478 --hash=sha256:ad3bb85f4cce83a47e4c0257143229cb92a294defa02fe661823b0442b35d478
django-tools==0.50.0; python_version >= "3.7" and python_full_version < "4.0.0" \ django-tools==0.54.0; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:c53805b60f6745d9d3a729d2b0add72eb27284362e0aef73d72b1a69704e4357 \ --hash=sha256:5040a91282be9d1c9d379b0c65da50bcb3691bff03cee54fd4123ace238c3a43 \
--hash=sha256:4ce9f524ba08d2071a762dc66e7f85ac1664b41cc8fa0ce686a651c1610b3d67 --hash=sha256:a7b7bfa5b9c5a81966454d17dffb2403cee25a806c858ee0486a08798227598f
django-yunohost-integration==0.2.4; python_version >= "3.7" and python_full_version < "4.0.0" \ django-yunohost-integration==0.4.0; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:f5cdb5480025e90de0221d2b1c6282f517fd0c903702563cccb771cb3e1d9417 \ --hash=sha256:560a280d509f8e28ea4b932d6682c91fab5d50f62b907981b9e0376556c8df7b \
--hash=sha256:a4b3617a3b39225d6162fa88827e9fe8b65388e26a0bbc23ea665c62aa8cb044 --hash=sha256:11a4add7cac2331e06348ef0c3eae597fe01f37867cde1f315ca707625527cdb
django==3.2.14; python_version >= "3.7" and python_full_version < "4.0.0" \ django==3.2.15; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:a8681e098fa60f7c33a4b628d6fcd3fe983a0939ff1301ecacac21d0b38bad56 \ --hash=sha256:115baf5049d5cf4163e43492cdc7139c306ed6d451e7d3571fe9612903903713 \
--hash=sha256:677182ba8b5b285a4e072f3ac17ceee6aff1b5ce77fd173cc5b6a2d3dc022fcf --hash=sha256:f71934b1a822f14a86c9ac9634053689279cd04ae69cb6ade4a59471b886582b
et-xmlfile==1.1.0; python_version >= "3.7" and python_full_version < "4.0.0" \ et-xmlfile==1.1.0; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada \ --hash=sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada \
--hash=sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c --hash=sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c
@ -90,9 +90,9 @@ gunicorn==20.1.0; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8 --hash=sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8
icdiff==2.0.5; python_version >= "3.7" and python_full_version < "4.0.0" \ icdiff==2.0.5; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:35d24b728e48b7e0a12bdb69386d3bfc7eef4fe922d0ac1cd70d6e5c11630bae --hash=sha256:35d24b728e48b7e0a12bdb69386d3bfc7eef4fe922d0ac1cd70d6e5c11630bae
idna==3.3; python_version >= "3.7" and python_version < "4" and python_full_version < "4.0.0" \ idna==3.4; python_version >= "3.7" and python_version < "4" and python_full_version < "4.0.0" \
--hash=sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff \ --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 \
--hash=sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4
importlib-metadata==4.2.0; python_version >= "3.7" and python_full_version < "4.0.0" and python_version < "3.8" \ importlib-metadata==4.2.0; python_version >= "3.7" and python_full_version < "4.0.0" and python_version < "3.8" \
--hash=sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b \ --hash=sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b \
--hash=sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31 --hash=sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31
@ -118,8 +118,8 @@ pillow==9.2.0; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:37ff6b522a26d0538b753f0b4e8e164fdada12db6c6f00f62145d732d8a3152e \ --hash=sha256:37ff6b522a26d0538b753f0b4e8e164fdada12db6c6f00f62145d732d8a3152e \
--hash=sha256:c79698d4cd9318d9481d89a77e2d3fcaeff5486be641e60a4b49f3d2ecca4e28 \ --hash=sha256:c79698d4cd9318d9481d89a77e2d3fcaeff5486be641e60a4b49f3d2ecca4e28 \
--hash=sha256:254164c57bab4b459f14c64e93df11eff5ded575192c294a0c49270f22c5d93d \ --hash=sha256:254164c57bab4b459f14c64e93df11eff5ded575192c294a0c49270f22c5d93d \
--hash=sha256:408673ed75594933714482501fe97e055a42996087eeca7e5d06e33218d05aa8 \ --hash=sha256:adabc0bce035467fb537ef3e5e74f2847c8af217ee0be0455d4fec8adc0462fc \
--hash=sha256:727dd1389bc5cb9827cbd1f9d40d2c2a1a0c9b32dd2261db522d22a604a6eec9 \ --hash=sha256:336b9036127eab855beec9662ac3ea13a4544a523ae273cbf108b228ecac8437 \
--hash=sha256:50dff9cc21826d2977ef2d2a205504034e3a4563ca6f5db739b0d1026658e004 \ --hash=sha256:50dff9cc21826d2977ef2d2a205504034e3a4563ca6f5db739b0d1026658e004 \
--hash=sha256:cb6259196a589123d755380b65127ddc60f4c64b21fc3bb46ce3a6ea663659b0 \ --hash=sha256:cb6259196a589123d755380b65127ddc60f4c64b21fc3bb46ce3a6ea663659b0 \
--hash=sha256:7b0554af24df2bf96618dac71ddada02420f946be943b181108cac55a7a2dcd4 \ --hash=sha256:7b0554af24df2bf96618dac71ddada02420f946be943b181108cac55a7a2dcd4 \
@ -169,34 +169,30 @@ pillow==9.2.0; python_version >= "3.7" and python_full_version < "4.0.0" \
pprintpp==0.4.0; python_version >= "3.7" and python_full_version < "4.0.0" \ pprintpp==0.4.0; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d \ --hash=sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d \
--hash=sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403 --hash=sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403
psycopg2==2.8.6; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.4.0") \ psycopg2==2.9.3; python_version >= "3.6" \
--hash=sha256:068115e13c70dc5982dfc00c5d70437fe37c014c808acce119b5448361c03725 \ --hash=sha256:083707a696e5e1c330af2508d8fab36f9700b26621ccbcb538abe22e15485362 \
--hash=sha256:d160744652e81c80627a909a0e808f3c6653a40af435744de037e3172cf277f5 \ --hash=sha256:d3ca6421b942f60c008f81a3541e8faf6865a28d5a9b48544b0ee4f40cac7fca \
--hash=sha256:b8cae8b2f022efa1f011cc753adb9cbadfa5a184431d09b273fb49b4167561ad \ --hash=sha256:9572e08b50aed176ef6d66f15a21d823bb6f6d23152d35e8451d7d2d18fdac56 \
--hash=sha256:f22ea9b67aea4f4a1718300908a2fb62b3e4276cf00bd829a97ab5894af42ea3 \ --hash=sha256:a81e3866f99382dfe8c15a151f1ca5fde5815fde879348fe5a9884a7c092a305 \
--hash=sha256:26e7fd115a6db75267b325de0fba089b911a4a12ebd3d0b5e7acb7028bc46821 \ --hash=sha256:cb10d44e6694d763fa1078a26f7f6137d69f555a78ec85dc2ef716c37447e4b2 \
--hash=sha256:00195b5f6832dbf2876b8bf77f12bdce648224c89c880719c745b90515233301 \ --hash=sha256:4295093a6ae3434d33ec6baab4ca5512a5082cc43c0505293087b8a46d108461 \
--hash=sha256:a49833abfdede8985ba3f3ec641f771cca215479f41523e99dace96d5b8cce2a \ --hash=sha256:34b33e0162cfcaad151f249c2649fd1030010c16f4bbc40a604c1cb77173dcf7 \
--hash=sha256:f974c96fca34ae9e4f49839ba6b78addf0346777b46c4da27a7bf54f48d3057d \ --hash=sha256:0762c27d018edbcb2d34d51596e4346c983bd27c330218c56c4dc25ef7e819bf \
--hash=sha256:6a3d9efb6f36f1fe6aa8dbb5af55e067db802502c55a9defa47c5a1dad41df84 \ --hash=sha256:8cf3878353cc04b053822896bc4922b194792df9df2f1ad8da01fb3043602126 \
--hash=sha256:56fee7f818d032f802b8eed81ef0c1232b8b42390df189cab9cfa87573fe52c5 \ --hash=sha256:06f32425949bd5fe8f625c49f17ebb9784e1e4fe928b7cce72edc36fb68e4c0c \
--hash=sha256:ad2fe8a37be669082e61fb001c185ffb58867fdbb3e7a6b0b0d2ffe232353a3e \ --hash=sha256:8e841d1bf3434da985cc5ef13e6f75c8981ced601fd70cc6bf33351b91562981
--hash=sha256:56007a226b8e95aa980ada7abdea6b40b75ce62a433bd27cec7a8178d57f4051 \ pyinventory==0.16.0; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:2c93d4d16933fea5bbacbe1aaf8fa8c1348740b2e50b3735d1b0bf8154cbf0f3 \ --hash=sha256:ff7d36eb42775f05d2ab12b22f361d1ac7cbf324c25505cb6ec5745371701eb1 \
--hash=sha256:d5062ae50b222da28253059880a871dc87e099c25cb68acf613d9d227413d6f7 \ --hash=sha256:130f9f5474928cf1989fb578e453fec75cedabf2ce1425db5bb38f462896a3d8
--hash=sha256:fb23f6c71107c37fd667cb4ea363ddeb936b348bbd6449278eb92c189699f543
pyinventory==0.14.0; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:115673c5d6463ed79544c8faa8ffe8358bc6222f169f7e27ec7ffbbad9951fe3 \
--hash=sha256:3e1e1ac4cfdb5f2caca452e4e17d7526901da6eba662c83521895782e3b94321
pyparsing==3.0.9; python_version >= "3.7" and python_full_version < "4.0.0" and python_full_version >= "3.6.8" \ pyparsing==3.0.9; python_version >= "3.7" and python_full_version < "4.0.0" and python_full_version >= "3.6.8" \
--hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc \ --hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc \
--hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb --hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb
python-stdnum==1.17; python_version >= "3.7" and python_full_version < "4.0.0" \ python-stdnum==1.17; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:374e2b5e13912ccdbf50b0b23fca2c3e0531174805c32d74e145f37756328340 \ --hash=sha256:374e2b5e13912ccdbf50b0b23fca2c3e0531174805c32d74e145f37756328340 \
--hash=sha256:a46e6cf9652807314d369b654b255c86a59f93d18be2834f3d567ed1a346c547 --hash=sha256:a46e6cf9652807314d369b654b255c86a59f93d18be2834f3d567ed1a346c547
pytz==2022.1; python_version >= "3.7" and python_full_version < "4.0.0" \ pytz==2022.2.1; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c \ --hash=sha256:220f481bdafa09c3955dfbdddb7b57780e9a94f5127e35456a48589b9e0c0197 \
--hash=sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7 --hash=sha256:cea221417204f2d1a2aa03ddae3e867921971d0d76f14d87abb4414415bbdcf5
pyyaml==6.0; python_version >= "3.7" and python_full_version < "4.0.0" \ pyyaml==6.0; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53 \ --hash=sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53 \
--hash=sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c \ --hash=sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c \
@ -205,6 +201,13 @@ pyyaml==6.0; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5 \ --hash=sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5 \
--hash=sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513 \ --hash=sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513 \
--hash=sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a \ --hash=sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a \
--hash=sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358 \
--hash=sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1 \
--hash=sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d \
--hash=sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f \
--hash=sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782 \
--hash=sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7 \
--hash=sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf \
--hash=sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86 \ --hash=sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86 \
--hash=sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f \ --hash=sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f \
--hash=sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92 \ --hash=sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92 \
@ -249,9 +252,9 @@ tablib==3.2.1; python_version >= "3.7" and python_full_version < "4.0.0" \
typing-extensions==4.3.0; python_version >= "3.7" and python_full_version < "4.0.0" and python_version < "3.8" \ typing-extensions==4.3.0; python_version >= "3.7" and python_full_version < "4.0.0" and python_version < "3.8" \
--hash=sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02 \ --hash=sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02 \
--hash=sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6 --hash=sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6
urllib3==1.26.11; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4" or python_full_version >= "3.6.0" and python_version < "4" and python_version >= "3.7" and python_full_version < "4.0.0" \ urllib3==1.26.12; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4" or python_full_version >= "3.6.0" and python_version < "4" and python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:c33ccba33c819596124764c23a97d25f32b28433ba0dedeb77d873a38722c9bc \ --hash=sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997 \
--hash=sha256:ea6e8fb210b19d950fab93b60c9009226c63a28808bc8386e05301e25883ac0a --hash=sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e
webencodings==0.5.1; python_version >= "3.7" and python_full_version < "4.0.0" \ webencodings==0.5.1; python_version >= "3.7" and python_full_version < "4.0.0" \
--hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \
--hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# Please do not modify this file, it will be reset at the next update. # Please do not modify this file, it will be reset at the next update.
# You can edit the file __FINAL_HOME_PATH__/local_settings.py and add/modify the settings you need. # You can edit the file __FINALPATH__/local_settings.py and add/modify the settings you need.
# The parameters you add in local_settings.py will overwrite these, # 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. # but you can use the options and documentation in this file to find out what can be done.
@ -11,20 +11,19 @@
from pathlib import Path as __Path from pathlib import Path as __Path
from django_yunohost_integration.base_settings import * # noqa 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 django_yunohost_integration.secret_key import get_or_create_secret as __get_or_create_secret
from inventory_project.settings.base import * # noqa from inventory_project.settings.base import * # noqa:F401,F403
DEBUG = False # Don't turn DEBUG on in production! from django_yunohost_integration.base_settings import LOGGING # noqa:F401 isort:skip
# -----------------------------------------------------------------------------
FINAL_HOME_PATH = __Path('__FINAL_HOME_PATH__') # /opt/yunohost/$app FINALPATH = __Path('__FINALPATH__') # /opt/yunohost/$app
assert FINAL_HOME_PATH.is_dir(), f'Directory not exists: {FINAL_HOME_PATH}' assert FINALPATH.is_dir(), f'Directory not exists: {FINALPATH}'
FINAL_WWW_PATH = __Path('__FINAL_WWW_PATH__') # /var/www/$app PUBLIC_PATH = __Path('__PUBLIC_PATH__') # /var/www/$app
assert FINAL_WWW_PATH.is_dir(), f'Directory not exists: {FINAL_WWW_PATH}' assert PUBLIC_PATH.is_dir(), f'Directory not exists: {PUBLIC_PATH}'
LOG_FILE = __Path('__LOG_FILE__') # /var/log/$app/pyinventory.log LOG_FILE = __Path('__LOG_FILE__') # /var/log/$app/pyinventory.log
assert LOG_FILE.is_file(), f'File not exists: {LOG_FILE}' assert LOG_FILE.is_file(), f'File not exists: {LOG_FILE}'
@ -33,13 +32,22 @@ PATH_URL = '__PATH_URL__' # $YNH_APP_ARG_PATH
PATH_URL = PATH_URL.strip('/') PATH_URL = PATH_URL.strip('/')
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# config_panel.toml settings:
ROOT_URLCONF = 'urls' # /opt/yunohost/pyinventory/ynh_urls.py DEBUG_ENABLED = '__DEBUG_ENABLED__'
DEBUG = bool(int(DEBUG_ENABLED))
LOG_LEVEL = '__LOG_LEVEL__'
ADMIN_EMAIL = '__ADMIN_EMAIL__'
DEFAULT_FROM_EMAIL = '__DEFAULT_FROM_EMAIL__'
# -----------------------------------------------------------------------------
# Function that will be called to finalize a user profile: # Function that will be called to finalize a user profile:
YNH_SETUP_USER = 'setup_user.setup_project_user' YNH_SETUP_USER = 'setup_user.setup_project_user'
SECRET_KEY = __get_or_create_secret(FINAL_HOME_PATH / 'secret.txt') # /opt/yunohost/$app/secret.txt SECRET_KEY = __get_or_create_secret(FINALPATH / 'secret.txt') # /opt/yunohost/$app/secret.txt
INSTALLED_APPS.append('django_yunohost_integration') INSTALLED_APPS.append('django_yunohost_integration')
@ -65,18 +73,20 @@ LOGIN_URL = '/yunohost/sso/'
LOGOUT_REDIRECT_URL = '/yunohost/sso/' LOGOUT_REDIRECT_URL = '/yunohost/sso/'
# /yunohost/sso/?action=logout # /yunohost/sso/?action=logout
ROOT_URLCONF = 'urls' # .../conf/urls.py
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
ADMINS = (('__ADMIN__', '__ADMINMAIL__'),) ADMINS = (('__ADMIN__', ADMIN_EMAIL),)
MANAGERS = ADMINS MANAGERS = ADMINS
DATABASES = { DATABASES = {
'default': { 'default': {
'ENGINE': 'django.db.backends.postgresql', 'ENGINE': 'django.db.backends.postgresql',
'NAME': '__APP__', 'NAME': '__DB_NAME__',
'USER': '__APP__', 'USER': '__DB_USER__',
'PASSWORD': '__DB_PWD__', 'PASSWORD': '__DB_PWD__',
'HOST': '127.0.0.1', 'HOST': '127.0.0.1',
'PORT': '5432', # Default Postgres Port 'PORT': '5432', # Default Postgres Port
@ -95,11 +105,10 @@ EMAIL_SUBJECT_PREFIX = f'[{SITE_TITLE}] '
# E-mail address that error messages come from. # E-mail address that error messages come from.
SERVER_EMAIL = 'noreply@__DOMAIN__' SERVER_EMAIL = ADMIN_EMAIL
# Default email address to use for various automated correspondence from # Default email address to use for various automated correspondence from
# the site managers. Used for registration emails. # the site managers. Used for registration emails.
DEFAULT_FROM_EMAIL = '__ADMINMAIL__'
# List of URLs your site is supposed to serve # List of URLs your site is supposed to serve
ALLOWED_HOSTS = ['__DOMAIN__'] ALLOWED_HOSTS = ['__DOMAIN__']
@ -131,8 +140,8 @@ else:
STATIC_URL = '/static/' STATIC_URL = '/static/'
MEDIA_URL = '/media/' MEDIA_URL = '/media/'
STATIC_ROOT = str(FINAL_WWW_PATH / 'static') STATIC_ROOT = str(PUBLIC_PATH / 'static')
MEDIA_ROOT = str(FINAL_WWW_PATH / 'media') MEDIA_ROOT = str(PUBLIC_PATH / 'media')
# _____________________________________________________________________________ # _____________________________________________________________________________
# django-ckeditor # django-ckeditor
@ -142,46 +151,22 @@ CKEDITOR_BASEPATH = STATIC_URL + 'ckeditor/ckeditor/'
# _____________________________________________________________________________ # _____________________________________________________________________________
# Django-dbbackup # Django-dbbackup
DBBACKUP_STORAGE_OPTIONS['location'] = str(FINAL_HOME_PATH / 'backups') DBBACKUP_STORAGE_OPTIONS['location'] = str(FINALPATH / 'backups')
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
LOGGING = { # Set log file to e.g.: /var/log/$app/$app.log
'version': 1, LOGGING['handlers']['log_file']['filename'] = str(LOG_FILE)
'disable_existing_loggers': True,
'formatters': { LOGGING['loggers']['inventory'] = {
'verbose': { 'handlers': ['syslog', 'log_file', 'mail_admins'],
'format': '{asctime} {levelname} {name} {module}.{funcName} {message}', 'level': 'INFO',
'style': '{', 'propagate': False,
},
},
'handlers': {
'mail_admins': {
'level': 'ERROR',
'formatter': 'verbose',
'class': 'django.utils.log.AdminEmailHandler',
'include_html': True,
},
'log_file': {
'level': 'DEBUG',
'class': 'logging.handlers.WatchedFileHandler',
'formatter': 'verbose',
'filename': str(LOG_FILE),
},
},
'loggers': {
'': {'handlers': ['log_file', 'mail_admins'], 'level': 'INFO', 'propagate': False},
'django': {'handlers': ['log_file', 'mail_admins'], 'level': 'INFO', 'propagate': False},
'axes': {'handlers': ['log_file', 'mail_admins'], 'level': 'WARNING', 'propagate': False},
'django_tools': {'handlers': ['log_file', 'mail_admins'], 'level': 'INFO', 'propagate': False},
'django_yunohost_integration': {'handlers': ['log_file', 'mail_admins'], 'level': 'INFO', 'propagate': False},
'inventory': {'handlers': ['log_file', 'mail_admins'], 'level': 'INFO', 'propagate': False},
},
} }
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
try: try:
from local_settings import * # noqa from local_settings import * # noqa:F401,F403
except ImportError: except ImportError:
pass pass

View file

@ -1,5 +1,5 @@
[Unit] [Unit]
Description=PyInventory application server Description=__APP__ server
After=redis.service postgresql.service After=redis.service postgresql.service
[Service] [Service]

View file

@ -1,36 +1,18 @@
from django.conf import settings from django.conf import settings
from django.conf.urls import include, static from django.conf.urls import include
from django.contrib import admin from django.contrib import admin
from django.urls import path from django.urls import path
# def debug_view(request):
# """ debug request.META """
# if not request.user.is_authenticated:
# from django.shortcuts import redirect
# return redirect('admin:index')
#
# import pprint
# meta = pprint.pformat(request.META)
# html = f'<html><body>request.META: <pre>{meta}</pre></body></html>'
# from django.http import HttpResponse
# return HttpResponse(html)
if settings.PATH_URL: if settings.PATH_URL:
# settings.PATH_URL is the $YNH_APP_ARG_PATH # settings.PATH_URL is the $YNH_APP_ARG_PATH
# Prefix all urls with "PATH_URL": # Prefix all urls with "PATH_URL":
urlpatterns = [ urlpatterns = [
# path(f'{settings.PATH_URL}/debug/', debug_view),
# MEDIA_URL contains the "PATH_URL" already: # MEDIA_URL contains the "PATH_URL" already:
path(settings.MEDIA_URL.lstrip('/'), include('django_tools.serve_media_app.urls')), path(settings.MEDIA_URL.lstrip('/'), include('django_tools.serve_media_app.urls')),
path(f'{settings.PATH_URL}/', admin.site.urls), path(f'{settings.PATH_URL}/', admin.site.urls),
path(f'{settings.PATH_URL}/ckeditor/', include('ckeditor_uploader.urls')), path(f'{settings.PATH_URL}/ckeditor/', include('ckeditor_uploader.urls')),
] ]
if settings.SERVE_FILES:
urlpatterns += static.static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
else: else:
# Installed to domain root, without a path prefix # Installed to domain root, without a path prefix
# Just use the default project urls.py # Just use the default project urls.py

35
config_panel.toml Normal file
View file

@ -0,0 +1,35 @@
version = "1.0"
[main]
name = "django_example_ynh configuration"
services = ["__APP__"]
[main.config]
name = "Configuration Options"
[main.config.default_from_email]
ask = "from email"
type = "email"
help = "Default email address to use for various automated emails."
bind = "default_from_email:__FINALPATH__/settings.py"
[main.config.admin_email]
ask = "ADMIN email"
type = "email"
help = "EMail address for error emails."
bind = "admin_email:__FINALPATH__/settings.py"
[main.config.debug_enabled]
ask = "DEBUG mode"
type = "boolean"
yes = "1"
no = "0"
help = "Should be never enabled in production!"
bind = "debug_enabled:__FINALPATH__/settings.py"
[main.config.log_level]
type = "string"
ask = "Log Level"
choices = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
default = "WARNING"
bind = "log_level:__FINALPATH__/settings.py"

15
doc/DESCRIPTION.md Normal file
View file

@ -0,0 +1,15 @@
[PyInventory](https://github.com/jedie/PyInventory) is a libre web-based management to catalog things including state and location etc. using [Python](https://www.python.org/)/[Django](https://www.djangoproject.com/).
[![Integration level](https://dash.yunohost.org/integration/pyinventory.svg)](https://dash.yunohost.org/appci/app/pyinventory) [![CI Pipeline](https://ci-apps.yunohost.org/ci/badges/pyinventory.status.svg)](https://ci-apps.yunohost.org/ci/apps/pyinventory/) [![Maintain status](https://ci-apps.yunohost.org/ci/badges/pyinventory.maintain.svg)](https://dash.yunohost.org/appci/app/pyinventory)
[![pytest](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/pytest.yml/badge.svg?branch=master)](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/pytest.yml) [![YunoHost apps package linter](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/package_linter.yml/badge.svg)](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/package_linter.yml) [![Coverage Status on codecov.io](https://codecov.io/gh/YunoHost-Apps/pyinventory_ynh/branch/master/graph/badge.svg)](https://codecov.io/gh/YunoHost-Apps/pyinventory_ynh)
![pyinventory @ PyPi](https://img.shields.io/pypi/v/pyinventory?label=pyinventory%20%40%20PyPi)
![Python Versions](https://img.shields.io/pypi/pyversions/pyinventory)
![License GPL V3+](https://img.shields.io/pypi/l/pyinventory)
Pull requests welcome ;)
This package for YunoHost used [django-yunohost-integration](https://github.com/YunoHost-Apps/django_yunohost_integration)
More screenshots are here: jedie.github.io/tree/master/screenshots/PyInventory

152
doc/DISCLAIMER.md Normal file
View file

@ -0,0 +1,152 @@
## Settings and upgrades
Almost everything related to PyInventory's configuration is handled in a `"../conf/settings.py"` file.
You can edit the file `/opt/yunohost/pyinventory/local_settings.py` to enable or disable features.
Test sending emails:
```bash
ssh admin@yourdomain.tld
root@yunohost:~# cd /opt/yunohost/pyinventory/
root@yunohost:/opt/yunohost/pyinventory# source venv/bin/activate
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py sendtestemail --admins
```
Background info: Error mails are send to all [settings.ADMINS](https://docs.djangoproject.com/en/2.2/ref/settings/#std:setting-ADMINS). By default the YunoHost admin is inserted here.
To check current ADMINS run:
```bash
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py sendtestemail --admins
```
If you prefere to send error emails to a extrnal email address, just do something like this:
```bash
echo "ADMINS = (('Your Name', 'example@domain.tld'),)" >> /opt/yunohost/pyinventory/local_settings.py
```
To check the effective settings, run this:
```bash
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py diffsettings
```
# Miscellaneous
## SSO authentication
[SSOwat](https://github.com/YunoHost/SSOwat) is fully supported via [django-yunohost-integration](https://github.com/YunoHost-Apps/django_yunohost_integration):
* First user (`$YNH_APP_ARG_ADMIN`) will be created as Django's super user
* All new users will be created as normal users
* Login via SSO is fully supported
* User Email, First / Last name will be updated from SSO data
## Links
* Report a bug about this package: https://github.com/YunoHost-Apps/pyinventory_ynh
* Report a bug about PyInventory itself: https://github.com/jedie/PyInventory
* YunoHost website: https://yunohost.org/
---
# Developer info
## package installation / debugging
Please send your pull request to https://github.com/YunoHost-Apps/pyinventory_ynh
Try 'main' branch, e.g.:
```bash
sudo yunohost app install https://github.com/YunoHost-Apps/pyinventory_ynh/tree/master --debug
or
sudo yunohost app upgrade pyinventory -u https://github.com/YunoHost-Apps/pyinventory_ynh/tree/master --debug
```
Try 'testing' branch, e.g.:
```bash
sudo yunohost app install https://github.com/YunoHost-Apps/pyinventory_ynh/tree/testing --debug
or
sudo yunohost app upgrade pyinventory -u https://github.com/YunoHost-Apps/pyinventory_ynh/tree/testing --debug
```
To remove call e.g.:
```bash
sudo yunohost app remove pyinventory
```
Backup / remove / restore cycle, e.g.:
```bash
yunohost backup create --apps pyinventory
yunohost backup list
archives:
- pyinventory-pre-upgrade1
- 20201223-163434
yunohost app remove pyinventory
yunohost backup restore 20201223-163434 --apps pyinventory
```
Debug installation, e.g.:
```bash
root@yunohost:~# ls -la /var/www/pyinventory/
total 18
drwxr-xr-x 4 root root 4 Dec 8 08:36 .
drwxr-xr-x 6 root root 6 Dec 8 08:36 ..
drwxr-xr-x 2 root root 2 Dec 8 08:36 media
drwxr-xr-x 7 root root 8 Dec 8 08:40 static
root@yunohost:~# ls -la /opt/yunohost/pyinventory/
total 58
drwxr-xr-x 5 pyinventory pyinventory 11 Dec 8 08:39 .
drwxr-xr-x 3 root root 3 Dec 8 08:36 ..
-rw-r--r-- 1 pyinventory pyinventory 460 Dec 8 08:39 gunicorn.conf.py
-rw-r--r-- 1 pyinventory pyinventory 0 Dec 8 08:39 local_settings.py
-rwxr-xr-x 1 pyinventory pyinventory 274 Dec 8 08:39 manage.py
-rw-r--r-- 1 pyinventory pyinventory 171 Dec 8 08:39 secret.txt
drwxr-xr-x 6 pyinventory pyinventory 6 Dec 8 08:37 venv
-rw-r--r-- 1 pyinventory pyinventory 115 Dec 8 08:39 wsgi.py
-rw-r--r-- 1 pyinventory pyinventory 4737 Dec 8 08:39 settings.py
root@yunohost:~# cd /opt/yunohost/pyinventory/
root@yunohost:/opt/yunohost/pyinventory# source venv/bin/activate
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py check
PyInventory v0.8.2 (Django v2.2.17)
DJANGO_SETTINGS_MODULE='settings'
PROJECT_PATH:/opt/yunohost/pyinventory/venv/lib/python3.7/site-packages
BASE_PATH:/opt/yunohost/pyinventory
System check identified no issues (0 silenced).
root@yunohost:~# tail -f /var/log/pyinventory/pyinventory.log
root@yunohost:~# cat /etc/systemd/system/pyinventory.service
root@yunohost:~# systemctl reload-or-restart pyinventory
root@yunohost:~# journalctl --unit=pyinventory --follow
```
## local test
For quicker developing of PyInventory in the context of YunoHost app,
it's possible to run the Django developer server with the settings
and urls made for YunoHost installation.
e.g.:
```bash
~$ git clone https://github.com/YunoHost-Apps/pyinventory_ynh.git
~$ cd pyinventory_ynh/
~/pyinventory_ynh$ make
install-poetry install or update poetry
install install PyInventory via poetry
update update the sources and installation
local-test Run local_test.py to run pyinventory_ynh locally
~/pyinventory_ynh$ make install-poetry
~/pyinventory_ynh$ make install
~/pyinventory_ynh$ make local-test
```
Notes:
* SQlite database will be used
* A super user with username `test` and password `test` is created
* The page is available under `http://127.0.0.1:8000/app_path/`

0
doc/screenshots/gitkeep Normal file
View file

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

View file

@ -22,6 +22,9 @@ def main():
django_settings_path=BASE_PATH / 'conf' / 'settings.py', django_settings_path=BASE_PATH / 'conf' / 'settings.py',
destination=BASE_PATH / 'local_test', destination=BASE_PATH / 'local_test',
runserver=True, runserver=True,
extra_replacements={
'__DEBUG_ENABLED__': '1',
},
) )

View file

@ -5,8 +5,13 @@
"description": { "description": {
"en": "Web based management to catalog things including state and location etc." "en": "Web based management to catalog things including state and location etc."
}, },
"version": "0.14.0~ynh1", "version": "0.16.0~ynh1",
"url": "https://github.com/jedie/PyInventory", "url": "https://github.com/jedie/PyInventory",
"upstream": {
"license": "GPL-3.0",
"website": "https://github.com/jedie/PyInventory",
"code": "https://github.com/jedie/PyInventory"
},
"license": "GPL-3.0", "license": "GPL-3.0",
"maintainer": { "maintainer": {
"name": "Jens Diemer", "name": "Jens Diemer",
@ -14,18 +19,17 @@
}, },
"previous_maintainers": [], "previous_maintainers": [],
"requirements": { "requirements": {
"yunohost": ">= 4.0" "yunohost": ">= 4.4"
}, },
"multi_instance": true, "multi_instance": true,
"services": [ "services": [
"nginx" "nginx", "postgresql", "redis"
], ],
"arguments": { "arguments": {
"install" : [ "install" : [
{ {
"name": "domain", "name": "domain",
"type": "domain", "type": "domain"
"example": "domain.org"
}, },
{ {
"name": "path", "name": "path",
@ -35,9 +39,8 @@
}, },
{ {
"name": "admin", "name": "admin",
"type": "user", "type": "user"
"example": "johndoe" }
} ]
]
} }
} }

614
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,20 +1,19 @@
[tool.poetry] [tool.poetry]
name = "pyinventory_ynh" name = "pyinventory_ynh"
version = "0.14.0~ynh1" version = "0.16.0~ynh1"
description = "Test pyinventory_ynh via local_test.py" description = "Test pyinventory_ynh via local_test.py"
authors = ["JensDiemer <git@jensdiemer.de>"] authors = ["JensDiemer <git@jensdiemer.de>"]
license = "GPL" license = "GPL"
[tool.poetry.dependencies] [tool.poetry.dependencies]
# Keep Python 3.7 until Yunohost contains a newer Python Version ;)
python = ">=3.7,<4.0.0" python = ">=3.7,<4.0.0"
pyinventory = {version = ">=0.14.0", extras = ["psycopg2-source"]} pyinventory = {version = ">=0.16.0", extras = ["psycopg2-source"]}
# Note: "ynh" extras will install gunicorn, psycopg2, django-redis and django-axes # Note: "ynh" extras will install gunicorn, psycopg2, django-redis and django-axes
django_yunohost_integration = {version = ">=v0.2.0", extras = ["ynh"]} django_yunohost_integration = {version = "*", extras = ["ynh"]}
# TODO: Update psycopg2 after PyInventory updates Django >2.2 update psycopg2 = "*" # https://github.com/psycopg/psycopg2/
# See: https://github.com/psycopg/psycopg2/issues/1293
psycopg2 = "<2.9" # https://www.psycopg.org/docs/install.html#build-prerequisites
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
bx_py_utils = "*" bx_py_utils = "*"
@ -23,14 +22,16 @@ pytest = "*"
pytest-cov = "*" pytest-cov = "*"
pytest-django = "*" pytest-django = "*"
pytest-darker = "*" # https://github.com/akaihola/pytest-darker pytest-darker = "*" # https://github.com/akaihola/pytest-darker
pytest-flake8 = "*" flake8 = "*"
pytest-isort = "*" isort = "*"
coveralls = "*" coveralls = "*"
flynt = "*" flynt = "*"
pyupgrade = "*" pyupgrade = "*"
EditorConfig = "*" # https://github.com/editorconfig/editorconfig-core-py
safety = "*" # https://github.com/pyupio/safety
[build-system] [build-system]
requires = ["poetry-core>=1.0.0"] requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"
@ -59,15 +60,15 @@ line_length = 120
atomic=true atomic=true
profile='black' profile='black'
line_length=120 line_length=120
skip_glob=["*/htmlcov/*","*/migrations/*"]
known_first_party=["inventory"] known_first_party=["inventory"]
skip_glob=["*/htmlcov/*","*/migrations/*","*/local_test/*"]
lines_after_imports=2 lines_after_imports=2
[tool.pytest.ini_options] [tool.pytest.ini_options]
# https://docs.pytest.org/en/latest/customize.html#pyproject-toml # https://docs.pytest.org/en/latest/customize.html#pyproject-toml
minversion = "6.0" minversion = "6.0"
norecursedirs = ".* .git __pycache__ conf coverage* dist htmlcov" norecursedirs = ".* .git __pycache__ conf local_test coverage* dist htmlcov"
# sometimes helpfull "addopts" arguments: # sometimes helpfull "addopts" arguments:
# -vv # -vv
# --verbose # --verbose
@ -76,7 +77,6 @@ norecursedirs = ".* .git __pycache__ conf coverage* dist htmlcov"
# --full-trace # --full-trace
# -p no:warnings # -p no:warnings
addopts = """ addopts = """
--import-mode=importlib
--reuse-db --reuse-db
--nomigrations --nomigrations
--cov=. --cov=.
@ -86,21 +86,22 @@ addopts = """
--no-cov-on-fail --no-cov-on-fail
--showlocals --showlocals
--darker --darker
--flake8
--isort
--doctest-modules --doctest-modules
--failed-first --failed-first
--last-failed-no-failures all
--new-first --new-first
""" """
[tool.coverage.run]
omit = [".*"]
[tool.tox] [tool.tox]
# https://tox.readthedocs.io/en/latest/example/basic.html#pyproject-toml-tox-legacy-ini # https://tox.readthedocs.io/en/latest/example/basic.html#pyproject-toml-tox-legacy-ini
legacy_tox_ini = """ legacy_tox_ini = """
[tox] [tox]
isolated_build = True isolated_build = True
envlist = py39,py38,py37 envlist = py{37,38,39,310}
skip_missing_interpreters = True skip_missing_interpreters = True
[testenv] [testenv]

View file

@ -1,25 +0,0 @@
"""
Run pytest against local test creation
"""
from pathlib import Path
try:
from django_yunohost_integration.pytest_helper import run_pytest
except ImportError as err:
raise ImportError('Did you forget to activate a virtual environment?') from err
BASE_PATH = Path(__file__).parent
def main():
run_pytest(
django_settings_path=BASE_PATH / 'conf' / 'settings.py',
destination=BASE_PATH / 'local_test',
)
if __name__ == '__main__':
main()

View file

@ -13,6 +13,22 @@ app=$YNH_APP_INSTANCE_NAME
# Currently not used: PyInventory has no public pages, yet! # Currently not used: PyInventory has no public pages, yet!
is_public=$YNH_APP_ARG_IS_PUBLIC is_public=$YNH_APP_ARG_IS_PUBLIC
#=================================================
# ARGUMENTS FROM CONFIG PANEL
#=================================================
# '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}"
#================================================= #=================================================
# SET CONSTANTS # SET CONSTANTS
#================================================= #=================================================
@ -20,7 +36,7 @@ is_public=$YNH_APP_ARG_IS_PUBLIC
public_path=/var/www/$app public_path=/var/www/$app
final_path=/opt/yunohost/$app final_path=/opt/yunohost/$app
log_path=/var/log/$app log_path=/var/log/$app
log_file="${log_path}/pyinventory.log" log_file="${log_path}/${app}.log"
#================================================= #=================================================
# COMMON VARIABLES # COMMON VARIABLES
@ -71,17 +87,3 @@ ynh_redis_remove_db() {
redis-cli -n "$db" flushall redis-cli -n "$db" flushall
} }
#=================================================
# Execute a command as another user
# usage: ynh_exec_as USER COMMAND [ARG ...]
ynh_exec_as() {
local USER=$1
shift 1
if [[ $USER = $(whoami) ]]; then
eval "$@"
else
sudo -u "$USER" "$@"
fi
}

View file

@ -6,6 +6,9 @@
# IMPORT GENERIC HELPERS # IMPORT GENERIC HELPERS
#================================================= #=================================================
YNH_APP_ARG_DOMAIN=$YNH_APP_NEW_DOMAIN
YNH_APP_ARG_PATH=$YNH_APP_NEW_PATH
source _common.sh source _common.sh
source /usr/share/yunohost/helpers source /usr/share/yunohost/helpers
@ -30,10 +33,21 @@ final_path=$(ynh_app_setting_get --app="$app" --key=final_path)
log_path=$(ynh_app_setting_get --app="$app" --key=log_path) log_path=$(ynh_app_setting_get --app="$app" --key=log_path)
port=$(ynh_app_setting_get --app="$app" --key=port) port=$(ynh_app_setting_get --app="$app" --key=port)
db_pwd=$(ynh_app_setting_get --app="$app" --key=psqlpwd) db_pwd=$(ynh_app_setting_get --app="$app" --key=psqlpwd)
admin_mail=$(ynh_user_get_info "$admin" mail) db_name=$(ynh_sanitize_dbid --db_name="$app")
db_user=$db_name
redis_db=$(ynh_app_setting_get --app="$app" --key=redis_db) redis_db=$(ynh_app_setting_get --app="$app" --key=redis_db)
#-------------------------------------------------
# config_panel.toml settings:
debug_enabled=$(ynh_app_setting_get --app="$app" --key=debug_enabled)
log_level=$(ynh_app_setting_get --app="$app" --key=log_level)
admin_email=$(ynh_app_setting_get --app="$app" --key=admin_email)
default_from_email=$(ynh_app_setting_get --app="$app" --key=default_from_email)
#================================================= #=================================================
# BACKUP BEFORE UPGRADE THEN ACTIVE TRAP # BACKUP BEFORE UPGRADE THEN ACTIVE TRAP
#================================================= #=================================================
@ -72,7 +86,7 @@ fi
#================================================= #=================================================
# STOP SYSTEMD SERVICE # STOP SYSTEMD SERVICE
#================================================= #=================================================
ynh_script_progression --message="Stopping systemd services..." ynh_script_progression --message="Stopping systemd service '$app'..."
ynh_systemd_action --service_name="$app" --action="stop" ynh_systemd_action --service_name="$app" --action="stop"
@ -112,36 +126,19 @@ fi
#================================================= #=================================================
# MODIFY SETTINGS # MODIFY SETTINGS
#================================================= #=================================================
ynh_script_progression --message="Modify PyInventory's config file..." ynh_script_progression --message="Modify $app config file..."
# save old settings file domain=$YNH_APP_NEW_DOMAIN
settings="$final_path/settings.py" path_url=$YNH_APP_NEW_PATH
ynh_backup_if_checksum_is_different --file="$settings"
cp "../conf/settings.py" "$settings" ynh_add_config --template="settings.py" --destination="$final_path/settings.py"
ynh_replace_string --match_string="__APP__" --replace_string="$app" --target_file="$settings"
ynh_replace_string --match_string="__DB_PWD__" --replace_string="$db_pwd" --target_file="$settings"
ynh_replace_string --match_string="__ADMIN__" --replace_string="$admin" --target_file="$settings"
ynh_replace_string --match_string="__ADMINMAIL__" --replace_string="$admin_mail" --target_file="$settings"
ynh_replace_string --match_string="__FINAL_HOME_PATH__" --replace_string="$final_path" --target_file="$settings"
ynh_replace_string --match_string="__FINAL_WWW_PATH__" --replace_string="$public_path" --target_file="$settings"
ynh_replace_string --match_string="__LOG_FILE__" --replace_string="$log_file" --target_file="$settings"
ynh_replace_string --match_string="__REDIS_DB__" --replace_string="$redis_db" --target_file="$settings"
# Difference to install/upgrade scripts: Use $new_domain and $new_path here:
ynh_replace_string --match_string="__DOMAIN__" --replace_string="$new_domain" --target_file="$settings"
ynh_replace_string --match_string="__PATH_URL__" --replace_string="$new_path" --target_file="$settings"
# Recalculate and store the config file checksum into the app settings
ynh_store_file_checksum --file="$settings"
#================================================= #=================================================
# GENERIC FINALISATION # GENERIC FINALISATION
#================================================= #=================================================
# START SYSTEMD SERVICE # START SYSTEMD SERVICE
#================================================= #=================================================
ynh_script_progression --message="Starting systemd services..." --weight=5 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"

View file

@ -50,19 +50,29 @@ ynh_app_setting_set --app="$app" --key=path --value="$path_url"
# Find a free port # Find a free port
port=$(ynh_find_port --port=8000) port=$(ynh_find_port --port=8000)
# Set port as application setting # Set port as application setting
# https://github.com/YunoHost/yunohost/blob/dev/data/helpers.d/setting # https://yunohost.org/en/contribute/packaging_apps/helpers
# https://github.com/YunoHost/yunohost/blob/dev/helpers/setting
ynh_app_setting_set --app="$app" --key=port --value="$port" ynh_app_setting_set --app="$app" --key=port --value="$port"
db_pwd=$(ynh_app_setting_get --app="$app" --key=psqlpwd) db_pwd=$(ynh_app_setting_get --app="$app" --key=psqlpwd)
admin_mail=$(ynh_user_get_info --username="$admin" --key=mail)
redis_db=$(ynh_redis_get_free_db) redis_db=$(ynh_redis_get_free_db)
ynh_app_setting_set --app="$app" --key=redis_db --value="$redis_db"
#-------------------------------------------------
# config_panel.toml settings:
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"
#================================================= #=================================================
# STANDARD MODIFICATIONS # STANDARD MODIFICATIONS
#================================================= #=================================================
# INSTALL DEPENDENCIES # INSTALL DEPENDENCIES
#================================================= #=================================================
ynh_script_progression --message="Installing dependencies..." --weight=20 ynh_script_progression --message="Installing $app dependencies..." --weight=20
ynh_exec_warn_less ynh_install_app_dependencies "$pkg_dependencies" ynh_exec_warn_less ynh_install_app_dependencies "$pkg_dependencies"
@ -86,21 +96,22 @@ ynh_psql_setup_db --db_user="$db_user" --db_name="$db_name"
ynh_script_progression --message="Configuring nginx web server..." ynh_script_progression --message="Configuring nginx web server..."
# Create a dedicated nginx config # Create a dedicated nginx config
# https://github.com/YunoHost/yunohost/blob/dev/data/helpers.d/nginx # https://yunohost.org/en/contribute/packaging_apps/helpers
# https://github.com/YunoHost/yunohost/blob/dev/helpers/nginx
ynh_add_nginx_config "public_path" "port" ynh_add_nginx_config "public_path" "port"
#================================================= #=================================================
# CREATE DEDICATED USER # CREATE DEDICATED USER
#================================================= #=================================================
ynh_script_progression --message="Configuring system user..." ynh_script_progression --message="Configuring system user '$app'..."
# A home directory for venv and settings etc. # A home directory for venv and settings etc.
ynh_system_user_create --username="$app" --home_dir="$final_path" --use_shell ynh_system_user_create --username="$app" --home_dir="$final_path" --use_shell
#================================================= #=================================================
# PIP INSTALLATION # PYTHON VIRTUALENV
#================================================= #=================================================
ynh_script_progression --message="Install project via pip..." --weight=50 ynh_script_progression --message="Create Python virtualenv..." --weight=5
# Always recreate everything fresh with current python version # Always recreate everything fresh with current python version
ynh_secure_remove "${final_path}/venv" ynh_secure_remove "${final_path}/venv"
@ -111,6 +122,11 @@ python3 -m venv --without-pip "${final_path}/venv"
cp ../conf/requirements.txt "$final_path/requirements.txt" cp ../conf/requirements.txt "$final_path/requirements.txt"
chown -R "$app:" "$final_path" chown -R "$app:" "$final_path"
#=================================================
# PIP INSTALLATION
#=================================================
ynh_script_progression --message="Install project via pip..." --weight=45
#run source in a 'sub shell' #run source in a 'sub shell'
( (
set +o nounset set +o nounset
@ -124,43 +140,17 @@ chown -R "$app:" "$final_path"
#================================================= #=================================================
# copy config files # copy config files
# ================================================ # ================================================
ynh_script_progression --message="Create project configuration files..." ynh_script_progression --message="Create $app configuration files..."
gunicorn_conf="$final_path/gunicorn.conf.py" ynh_add_config --template="gunicorn.conf.py" --destination="$final_path/gunicorn.conf.py"
cp "../conf/gunicorn.conf.py" "$gunicorn_conf"
ynh_replace_string --match_string="__FINAL_HOME_PATH__" --replace_string="$final_path" --target_file="$gunicorn_conf"
ynh_replace_string --match_string="__LOG_FILE__" --replace_string="$log_file" --target_file="$gunicorn_conf"
ynh_replace_string --match_string="__PORT__" --replace_string="$port" --target_file="$gunicorn_conf"
ynh_store_file_checksum --file="$gunicorn_conf"
cp ../conf/manage.py "$final_path/manage.py" ynh_add_config --template="manage.py" --destination="$final_path/manage.py"
ynh_replace_string --match_string="__FINAL_HOME_PATH__" --replace_string="$final_path" --target_file="$final_path/manage.py"
ynh_store_file_checksum --file="$final_path/manage.py"
chmod +x "$final_path/manage.py" chmod +x "$final_path/manage.py"
settings="$final_path/settings.py" ynh_add_config --template="settings.py" --destination="$final_path/settings.py"
cp "../conf/settings.py" "$settings" ynh_add_config --template="setup_user.py" --destination="$final_path/setup_user.py"
ynh_add_config --template="urls.py" --destination="$final_path/urls.py"
ynh_replace_string --match_string="__APP__" --replace_string="$app" --target_file="$settings" ynh_add_config --template="wsgi.py" --destination="$final_path/wsgi.py"
ynh_replace_string --match_string="__DB_PWD__" --replace_string="$db_pwd" --target_file="$settings"
ynh_replace_string --match_string="__ADMIN__" --replace_string="$admin" --target_file="$settings"
ynh_replace_string --match_string="__ADMINMAIL__" --replace_string="$admin_mail" --target_file="$settings"
ynh_replace_string --match_string="__FINAL_HOME_PATH__" --replace_string="$final_path" --target_file="$settings"
ynh_replace_string --match_string="__FINAL_WWW_PATH__" --replace_string="$public_path" --target_file="$settings"
ynh_replace_string --match_string="__LOG_FILE__" --replace_string="$log_file" --target_file="$settings"
ynh_replace_string --match_string="__REDIS_DB__" --replace_string="$redis_db" --target_file="$settings"
ynh_replace_string --match_string="__DOMAIN__" --replace_string="$domain" --target_file="$settings"
ynh_replace_string --match_string="__PATH_URL__" --replace_string="$path_url" --target_file="$settings"
# Calculate and store the config file checksum into the app settings
ynh_store_file_checksum --file="$settings"
ynh_app_setting_set --app="$app" --key=redis_db --value="$redis_db"
cp ../conf/setup_user.py "$final_path/setup_user.py"
cp ../conf/urls.py "$final_path/urls.py"
cp ../conf/wsgi.py "$final_path/wsgi.py"
touch "$final_path/local_settings.py" touch "$final_path/local_settings.py"
@ -178,7 +168,7 @@ cd "$final_path" || exit
./manage.py collectstatic --no-input ./manage.py collectstatic --no-input
# Create/update Django superuser (set unusable password, because auth done via SSOwat): # Create/update Django superuser (set unusable password, because auth done via SSOwat):
./manage.py create_superuser --username="$admin" --email="$admin_mail" ./manage.py create_superuser --username="$admin" --email="$(ynh_user_get_info "$admin" mail)"
# Check the configuration # Check the configuration
# This may fail in some cases with errors, etc., but the app works and the user can fix issues later. # This may fail in some cases with errors, etc., but the app works and the user can fix issues later.
@ -198,7 +188,7 @@ ynh_use_logrotate "$log_file"
#================================================= #=================================================
ynh_script_progression --message="Integrating service in YunoHost..." ynh_script_progression --message="Integrating service in YunoHost..."
yunohost service add $app --description="Web based management to catalog things" --log="${log_file}" yunohost service add $app --log="${log_file}"
#================================================= #=================================================
# GENERIC FINALIZATION # GENERIC FINALIZATION
@ -218,15 +208,29 @@ chmod o-rwx "$final_path"
#================================================= #=================================================
# SETUP SYSTEMD # SETUP SYSTEMD
#================================================= #=================================================
ynh_script_progression --message="Configuring a systemd service..." ynh_script_progression --message="Configuring systemd service '$app'..." --weight=5
# https://github.com/YunoHost/yunohost/blob/dev/data/helpers.d/systemd # https://yunohost.org/en/contribute/packaging_apps/helpers
ynh_add_systemd_config --service="$app" --template="pyinventory.service" # https://github.com/YunoHost/yunohost/blob/dev/helpers/systemd
ynh_add_systemd_config --service="$app" --template="systemd.service"
#================================================= #=================================================
# Start pyinventory via systemd # SETUP SSOWAT
#================================================= #=================================================
ynh_script_progression --message="Starting PyInventory's services..." --weight=5 ynh_script_progression --message="Configuring SSOwat..."
# Make app public if necessary or protect it
if [ $is_public -eq 1 ]
then
# Everyone can access the app.
# The "main" permission is automatically created before the install script.
ynh_permission_update --permission "main" --add "visitors"
fi
#=================================================
# 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"

View file

@ -36,7 +36,7 @@ fi
#================================================= #=================================================
# STOP PYINVENTORY'S SERVICES # STOP PYINVENTORY'S SERVICES
#================================================= #=================================================
ynh_script_progression --message="Stopping and removing systemd services..." --weight=5 ynh_script_progression --message="Stopping and removing systemd service '$app'..." --weight=5
ynh_remove_systemd_config --service="$app" ynh_remove_systemd_config --service="$app"

View file

@ -20,8 +20,8 @@ ynh_abort_if_errors
#================================================= #=================================================
ynh_script_progression --message="Loading settings..." ynh_script_progression --message="Loading settings..."
public_path=$(ynh_app_setting_get --app="$app" --key=public_path)
final_path=$(ynh_app_setting_get --app="$app" --key=final_path) final_path=$(ynh_app_setting_get --app="$app" --key=final_path)
public_path=$(ynh_app_setting_get --app="$app" --key=public_path)
db_name=$(ynh_app_setting_get --app="$app" --key=db_name) db_name=$(ynh_app_setting_get --app="$app" --key=db_name)
db_user=$db_name db_user=$db_name
db_pwd=$(ynh_app_setting_get --app="$app" --key=psqlpwd) db_pwd=$(ynh_app_setting_get --app="$app" --key=psqlpwd)
@ -34,8 +34,6 @@ path_url=$(ynh_app_setting_get --app="$app" --key=path)
#================================================= #=================================================
ynh_script_progression --message="Validating restoration parameters..." ynh_script_progression --message="Validating restoration parameters..."
ynh_webpath_available --domain=$domain --path_url=$path_url \
|| ynh_die --message="Path not available: ${domain}${path_url}"
test ! -d $final_path \ test ! -d $final_path \
|| ynh_die --message="There is already a directory: $final_path " || ynh_die --message="There is already a directory: $final_path "
@ -50,12 +48,10 @@ ynh_restore_file --origin_path="/etc/nginx/conf.d/$domain.d/$app.conf"
#================================================= #=================================================
# RESTORE THE APP MAIN DIR # RESTORE THE APP MAIN DIR
#================================================= #=================================================
ynh_script_progression --message="Restoring the app main directory..." ynh_script_progression --message="Restoring $app main directory..."
ynh_restore_file --origin_path="$public_path"
ynh_restore_file --origin_path="$final_path" ynh_restore_file --origin_path="$final_path"
ynh_restore_file --origin_path="$public_path"
touch "$final_path/local_settings.py"
#================================================= #=================================================
# RECREATE THE DEDICATED USER # RECREATE THE DEDICATED USER
@ -83,10 +79,10 @@ ynh_script_progression --message="Reinstalling dependencies..." --weight=20
ynh_exec_warn_less ynh_install_app_dependencies "$pkg_dependencies" ynh_exec_warn_less ynh_install_app_dependencies "$pkg_dependencies"
#================================================= #=================================================
# REINSTALL PYTHON VIRTUALENV # PYTHON VIRTUALENV
# Maybe the backup contains a other Python version # Maybe the backup contains a other Python version
#================================================= #=================================================
ynh_script_progression --message="Upgrade Python virtualenv..." --weight=50 ynh_script_progression --message="Recreate Python virtualenv..." --weight=5
# Always recreate everything fresh with current python version # Always recreate everything fresh with current python version
ynh_secure_remove "${final_path}/venv" ynh_secure_remove "${final_path}/venv"
@ -95,6 +91,10 @@ ynh_secure_remove "${final_path}/venv"
python3 -m venv --without-pip "${final_path}/venv" python3 -m venv --without-pip "${final_path}/venv"
chown -R "$app:" "$final_path" chown -R "$app:" "$final_path"
#=================================================
# PIP INSTALLATION
#=================================================
ynh_script_progression --message="Install project via pip..." --weight=45
#run source in a 'sub shell' #run source in a 'sub shell'
( (
set +o nounset set +o nounset
@ -127,7 +127,7 @@ systemctl enable $app.service --quiet
#================================================= #=================================================
ynh_script_progression --message="Integrating service in YunoHost..." ynh_script_progression --message="Integrating service in YunoHost..."
yunohost service add $app --description="Web based management to catalog things" --log="${log_file}" yunohost service add $app --log="${log_file}"
#================================================= #=================================================
# RESTORE THE LOGROTATE CONFIGURATION # RESTORE THE LOGROTATE CONFIGURATION
@ -158,7 +158,7 @@ chmod o-rwx "$final_path"
#================================================= #=================================================
# START PYINVENTORY # START PYINVENTORY
#================================================= #=================================================
ynh_script_progression --message="Starting a systemd service..." --weight=5 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"

View file

@ -21,14 +21,44 @@ domain=$(ynh_app_setting_get --app="$app" --key=domain)
path_url=$(ynh_app_setting_get --app="$app" --key=path) path_url=$(ynh_app_setting_get --app="$app" --key=path)
port=$(ynh_app_setting_get --app="$app" --key=port) port=$(ynh_app_setting_get --app="$app" --key=port)
db_pwd=$(ynh_app_setting_get --app="$app" --key=psqlpwd) db_pwd=$(ynh_app_setting_get --app="$app" --key=psqlpwd)
admin_mail=$(ynh_user_get_info "$admin" mail) db_name=$(ynh_sanitize_dbid --db_name="$app")
db_user=$db_name
redis_db=$(ynh_app_setting_get --app="$app" --key=redis_db) redis_db=$(ynh_app_setting_get --app="$app" --key=redis_db)
#-------------------------------------------------
# config_panel.toml settings:
debug_enabled=$(ynh_app_setting_get --app="$app" --key=debug_enabled)
if [ -z "$debug_enabled" ]; then
debug_enabled="0"
ynh_app_setting_set --app="$app" --key=debug_enabled --value="$debug_enabled"
fi
log_level=$(ynh_app_setting_get --app="$app" --key=log_level)
if [ -z "$log_level" ]; then
log_level="WARNING"
ynh_app_setting_set --app="$app" --key=log_level --value="$log_level"
fi
admin_email=$(ynh_app_setting_get --app="$app" --key=admin_email)
if [ -z "$admin_email" ]; then
admin_email="${admin}@${domain}"
ynh_app_setting_set --app="$app" --key=admin_email --value="$admin_email"
fi
default_from_email=$(ynh_app_setting_get --app="$app" --key=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
#================================================= #=================================================
# BACKUP BEFORE UPGRADE THEN ACTIVE TRAP # BACKUP BEFORE UPGRADE THEN ACTIVE TRAP
#================================================= #=================================================
ynh_script_progression --message="Backing up the app before upgrading (may take a while)..." --weight=40 ynh_script_progression --message="Backing up $app before upgrading (may take a while)..." --weight=40
# Backup the current version of the app # Backup the current version of the app
ynh_backup_before_upgrade ynh_backup_before_upgrade
@ -44,7 +74,7 @@ ynh_abort_if_errors
#================================================= #=================================================
# STOP SYSTEMD SERVICE # STOP SYSTEMD SERVICE
#================================================= #=================================================
ynh_script_progression --message="Stopping systemd services..." --weight=5 ynh_script_progression --message="Stopping systemd service '$app'..." --weight=5
ynh_systemd_action --service_name="$app" --action="stop" ynh_systemd_action --service_name="$app" --action="stop"
@ -54,7 +84,8 @@ ynh_systemd_action --service_name="$app" --action="stop"
ynh_script_progression --message="Upgrading nginx web server configuration..." ynh_script_progression --message="Upgrading nginx web server configuration..."
# Create a dedicated nginx config # Create a dedicated nginx config
# https://github.com/YunoHost/yunohost/blob/dev/data/helpers.d/nginx # https://yunohost.org/en/contribute/packaging_apps/helpers
# https://github.com/YunoHost/yunohost/blob/dev/helpers/nginx
ynh_add_nginx_config "public_path" "port" ynh_add_nginx_config "public_path" "port"
#================================================= #=================================================
@ -77,14 +108,14 @@ ynh_system_user_create --username="$app" --home_dir="$final_path" --use_shell
#================================================= #=================================================
# SETUP SYSTEMD # SETUP SYSTEMD
#================================================= #=================================================
ynh_script_progression --message="Configuring a systemd service..." ynh_script_progression --message="Configuring systemd service '$app'..." --weight=5
ynh_add_systemd_config --service="$app" --template="pyinventory.service" ynh_add_systemd_config --service="$app" --template="systemd.service"
#================================================= #=================================================
# UPGRADE VENV # PYTHON VIRTUALENV
#================================================= #=================================================
ynh_script_progression --message="Upgrade project via pip..." --weight=50 ynh_script_progression --message="Recreate Python virtualenv..." --weight=5
# Always recreate everything fresh with current python version # Always recreate everything fresh with current python version
ynh_secure_remove "${final_path}/venv" ynh_secure_remove "${final_path}/venv"
@ -95,6 +126,10 @@ python3 -m venv --without-pip "${final_path}/venv"
cp ../conf/requirements.txt "$final_path/requirements.txt" cp ../conf/requirements.txt "$final_path/requirements.txt"
chown -R "$app:" "$final_path" chown -R "$app:" "$final_path"
#=================================================
# PIP INSTALLATION
#=================================================
ynh_script_progression --message="Install project via pip..." --weight=45
#run source in a 'sub shell' #run source in a 'sub shell'
( (
set +o nounset set +o nounset
@ -110,50 +145,15 @@ chown -R "$app:" "$final_path"
# ================================================ # ================================================
ynh_script_progression --message="Create project configuration files..." ynh_script_progression --message="Create project configuration files..."
gunicorn_conf="$final_path/gunicorn.conf.py" ynh_add_config --template="gunicorn.conf.py" --destination="$final_path/gunicorn.conf.py"
ynh_backup_if_checksum_is_different --file="$gunicorn_conf"
cp "../conf/gunicorn.conf.py" "$gunicorn_conf"
ynh_replace_string --match_string="__FINAL_HOME_PATH__" --replace_string="$final_path" --target_file="$gunicorn_conf"
ynh_replace_string --match_string="__LOG_FILE__" --replace_string="$log_file" --target_file="$gunicorn_conf"
ynh_replace_string --match_string="__PORT__" --replace_string="$port" --target_file="$gunicorn_conf"
ynh_store_file_checksum --file="$gunicorn_conf"
cp ../conf/manage.py "$final_path/manage.py" ynh_add_config --template="manage.py" --destination="$final_path/manage.py"
ynh_replace_string --match_string="__FINAL_HOME_PATH__" --replace_string="$final_path" --target_file="$final_path/manage.py"
ynh_store_file_checksum --file="$final_path/manage.py"
chmod +x "$final_path/manage.py" chmod +x "$final_path/manage.py"
# save old settings file ynh_add_config --template="settings.py" --destination="$final_path/settings.py"
settings="$final_path/settings.py" ynh_add_config --template="setup_user.py" --destination="$final_path/setup_user.py"
ynh_backup_if_checksum_is_different --file="$settings" ynh_add_config --template="urls.py" --destination="$final_path/urls.py"
ynh_add_config --template="wsgi.py" --destination="$final_path/wsgi.py"
cp "../conf/settings.py" "$settings"
ynh_replace_string --match_string="__APP__" --replace_string="$app" --target_file="$settings"
ynh_replace_string --match_string="__DB_PWD__" --replace_string="$db_pwd" --target_file="$settings"
ynh_replace_string --match_string="__ADMIN__" --replace_string="$admin" --target_file="$settings"
ynh_replace_string --match_string="__ADMINMAIL__" --replace_string="$admin_mail" --target_file="$settings"
ynh_replace_string --match_string="__FINAL_HOME_PATH__" --replace_string="$final_path" --target_file="$settings"
ynh_replace_string --match_string="__FINAL_WWW_PATH__" --replace_string="$public_path" --target_file="$settings"
ynh_replace_string --match_string="__LOG_FILE__" --replace_string="$log_file" --target_file="$settings"
ynh_replace_string --match_string="__REDIS_DB__" --replace_string="$redis_db" --target_file="$settings"
ynh_replace_string --match_string="__DOMAIN__" --replace_string="$domain" --target_file="$settings"
ynh_replace_string --match_string="__PATH_URL__" --replace_string="$path_url" --target_file="$settings"
# Recalculate and store the config file checksum into the app settings
ynh_store_file_checksum --file="$settings"
ynh_backup_if_checksum_is_different --file="$final_path/setup_user.py"
cp ../conf/setup_user.py "$final_path/setup_user.py"
ynh_backup_if_checksum_is_different --file="$final_path/urls.py"
cp ../conf/urls.py "$final_path/urls.py"
ynh_backup_if_checksum_is_different --file="$final_path/wsgi.py"
cp ../conf/wsgi.py "$final_path/wsgi.py"
touch "$final_path/local_settings.py"
#================================================= #=================================================
# MIGRATE PYINVENTORY # MIGRATE PYINVENTORY
@ -169,7 +169,7 @@ cd "$final_path" || exit
./manage.py collectstatic --no-input ./manage.py collectstatic --no-input
# Create/update Django superuser (set unusable password, because auth done via SSOwat): # Create/update Django superuser (set unusable password, because auth done via SSOwat):
./manage.py create_superuser --username="$admin" --email="$admin_mail" ./manage.py create_superuser --username="$admin" --email="$(ynh_user_get_info "$admin" mail)"
# Check the configuration # Check the configuration
# This may fail in some cases with errors, etc., but the app works and the user can fix issues later. # This may fail in some cases with errors, etc., but the app works and the user can fix issues later.
@ -189,7 +189,7 @@ ynh_use_logrotate --non-append
#================================================= #=================================================
ynh_script_progression --message="Integrating service in YunoHost..." ynh_script_progression --message="Integrating service in YunoHost..."
yunohost service add $app --description="Web based management to catalog things" --log="${log_file}" yunohost service add $app --log="${log_file}"
#================================================= #=================================================
# GENERIC FINALIZATION # GENERIC FINALIZATION
@ -207,9 +207,9 @@ chmod o-rwx "$public_path"
chmod o-rwx "$final_path" chmod o-rwx "$final_path"
#================================================= #=================================================
# Start pyinventory via systemd # Start the app server via systemd
#================================================= #=================================================
ynh_script_progression --message="Starting PyInventory's services..." --weight=5 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"

View file

@ -1,17 +0,0 @@
#!/bin/bash
# Test to create the python virtual env and install all requirements.
# Note: Maybe you didn't have all OS packages installed ;)
set -e
final_path="./local_test"
set -x
mkdir -p "${final_path}/"
python3 -m venv "${final_path}/venv"
source "${final_path}/venv/bin/activate"
$final_path/venv/bin/pip install --upgrade wheel pip
$final_path/venv/bin/pip install --no-deps -r "./conf/requirements.txt"

43
tests/conftest.py Normal file
View file

@ -0,0 +1,43 @@
"""
Special pytest init:
- Build a "local_test" YunoHost installation
- init Django with this local test installation
So the pytests will run against this local test installation
"""
import os
import sys
from pathlib import Path
import django
from django_yunohost_integration.local_test import create_local_test
BASE_PATH = Path(__file__).parent.parent
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
def pytest_configure():
print('Compile YunoHost files...')
final_path = create_local_test(
django_settings_path=BASE_PATH / 'conf' / 'settings.py',
destination=BASE_PATH / 'local_test',
runserver=False,
extra_replacements={
'__DEBUG_ENABLED__': '0',
'__LOG_LEVEL__': 'INFO',
'__ADMIN_EMAIL__': 'foo-bar@test.tld',
'__DEFAULT_FROM_EMAIL__': 'django_app@test.tld',
},
)
print('Local test files created here:')
print(f'"{final_path}"')
os.chdir(final_path)
final_home_str = str(final_path)
if final_home_str not in sys.path:
sys.path.insert(0, final_home_str)
django.setup()

View file

@ -27,17 +27,24 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
assert settings.configured is True assert settings.configured is True
assert settings.PATH_URL == 'app_path' assert settings.PATH_URL == 'app_path'
assert settings.ROOT_URLCONF == 'urls'
assert reverse('admin:index') == '/app_path/'
def assert_path(path, end_text): def assert_path(path, end_text):
assert isinstance(path, Path) assert isinstance(path, Path)
path = str(path) path = str(path)
assert path.endswith(end_text) assert path.endswith(end_text)
assert_path(settings.FINAL_HOME_PATH, '/local_test/opt_yunohost') assert_path(settings.FINALPATH, '/local_test/opt_yunohost')
assert_path(settings.FINAL_WWW_PATH, '/local_test/var_www') assert_path(settings.PUBLIC_PATH, '/local_test/var_www')
assert_path(settings.LOG_FILE, '/local_test/var_log_pyinventory.log') assert_path(settings.LOG_FILE, '/local_test/var_log_pyinventory.log')
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_urls(self): def test_urls(self):
assert reverse('admin:index') == '/app_path/' assert reverse('admin:index') == '/app_path/'
@ -66,7 +73,6 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
response = self.client.get('/app_path/', secure=True) response = self.client.get('/app_path/', secure=True)
self.assertRedirects(response, expected_url='/app_path/login/?next=/app_path/', fetch_redirect_response=False) self.assertRedirects(response, expected_url='/app_path/login/?next=/app_path/', fetch_redirect_response=False)
@override_settings(SECURE_SSL_REDIRECT=False)
def test_create_unknown_user(self): def test_create_unknown_user(self):
assert User.objects.count() == 0 assert User.objects.count() == 0
@ -77,6 +83,7 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
HTTP_REMOTE_USER='test', HTTP_REMOTE_USER='test',
HTTP_AUTH_USER='test', HTTP_AUTH_USER='test',
HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz', HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz',
secure=True,
) )
assert User.objects.count() == 1 assert User.objects.count() == 1
@ -95,7 +102,6 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
), ),
) )
@override_settings(SECURE_SSL_REDIRECT=False)
def test_wrong_auth_user(self): def test_wrong_auth_user(self):
assert User.objects.count() == 0 assert User.objects.count() == 0
assert AccessLog.objects.count() == 0 assert AccessLog.objects.count() == 0
@ -107,6 +113,7 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
HTTP_REMOTE_USER='test', HTTP_REMOTE_USER='test',
HTTP_AUTH_USER='foobar', # <<< wrong user name HTTP_AUTH_USER='foobar', # <<< wrong user name
HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz', HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz',
secure=True,
) )
assert User.objects.count() == 1 assert User.objects.count() == 1
@ -120,7 +127,6 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
assert response.status_code == 403 # Forbidden assert response.status_code == 403 # Forbidden
@override_settings(SECURE_SSL_REDIRECT=False)
def test_wrong_cookie(self): def test_wrong_cookie(self):
assert User.objects.count() == 0 assert User.objects.count() == 0
assert AccessLog.objects.count() == 0 assert AccessLog.objects.count() == 0
@ -132,6 +138,7 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
HTTP_REMOTE_USER='test', HTTP_REMOTE_USER='test',
HTTP_AUTH_USER='test', HTTP_AUTH_USER='test',
HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz', HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz',
secure=True,
) )
assert User.objects.count() == 1 assert User.objects.count() == 1
@ -145,7 +152,6 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
assert response.status_code == 403 # Forbidden assert response.status_code == 403 # Forbidden
@override_settings(SECURE_SSL_REDIRECT=False)
def test_wrong_authorization_user(self): def test_wrong_authorization_user(self):
assert User.objects.count() == 0 assert User.objects.count() == 0
@ -155,7 +161,11 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
path='/app_path/', path='/app_path/',
HTTP_REMOTE_USER='test', HTTP_REMOTE_USER='test',
HTTP_AUTH_USER='test', HTTP_AUTH_USER='test',
HTTP_AUTHORIZATION=generate_basic_auth(username='foobar', password='test123'), # <<< wrong user name HTTP_AUTHORIZATION=generate_basic_auth(
username='foobar', # <<< wrong user name
password='test123',
),
secure=True,
) )
assert User.objects.count() == 1 assert User.objects.count() == 1

View file

@ -4,7 +4,9 @@ import shutil
import subprocess import subprocess
from pathlib import Path from pathlib import Path
from bx_py_utils.path import assert_is_file from django_tools.serve_media_app.utils import clean_filename
from django_tools.unittest_utils.assertments import assert_is_dir, assert_is_file
from django_tools.unittest_utils.project_setup import check_editor_config
import inventory import inventory
@ -32,7 +34,7 @@ def poetry_check_output(*args):
output = subprocess.check_output( output = subprocess.check_output(
(poerty_bin,) + args, (poerty_bin,) + args,
universal_newlines=True, text=True,
env=os.environ, env=os.environ,
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
cwd=str(PACKAGE_ROOT), cwd=str(PACKAGE_ROOT),
@ -47,7 +49,7 @@ def test_poetry_check():
def test_requirements_txt(): def test_requirements_txt():
requirements_txt = Path('conf', 'requirements.txt') requirements_txt = PACKAGE_ROOT / 'conf' / 'requirements.txt'
assert_is_file(requirements_txt) assert_is_file(requirements_txt)
output = poetry_check_output('export', '-f', 'requirements.txt') output = poetry_check_output('export', '-f', 'requirements.txt')
@ -57,8 +59,32 @@ def test_requirements_txt():
diff = '\n'.join( diff = '\n'.join(
difflib.unified_diff( difflib.unified_diff(
current_content.splitlines(), output.splitlines(), fromfile=str(requirements_txt), tofile='FRESH EXPORT' current_content.splitlines(),
output.splitlines(),
fromfile=str(requirements_txt),
tofile='FRESH EXPORT',
) )
) )
print(diff) print(diff)
assert diff == '', f'{requirements_txt} is not up-to-date! (Hint: call: "make update")' assert diff == '', f'{requirements_txt} is not up-to-date! (Hint: call: "make update")'
def test_screenshot_filenames():
"""
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
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():
check_editor_config(package_root=PACKAGE_ROOT)