diff --git a/Makefile b/Makefile index 7e8b78f..82e6ab4 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ tox: check-poetry ## Run pytest via tox with all environments poetry run tox 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 poetry run python3 ./local_test.py diff --git a/README.md b/README.md index c301584..6474743 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,9 @@ yunohost backup restore 20201223-163434 --apps django_example_ynh Debug the installation, e.g.: ```bash +root@yunohost:~# cat /etc/yunohost/apps/django_example_ynh/settings.yml +... + root@yunohost:~# ls -la /var/www/django_example_ynh/ total 18 drwxr-xr-x 4 root root 4 Dec 8 08:36 . @@ -172,6 +175,7 @@ System check identified no issues (0 silenced). root@yunohost:~# tail -f /var/log/django_example_ynh/django_example_ynh.log root@yunohost:~# cat /etc/systemd/system/systemd.service +... root@yunohost:~# systemctl reload-or-restart django_example_ynh root@yunohost:~# journalctl --unit=django_example_ynh --follow diff --git a/README_fr.md b/README_fr.md index 6d2d5dd..0ab2503 100644 --- a/README_fr.md +++ b/README_fr.md @@ -142,6 +142,9 @@ yunohost backup restore 20201223-163434 --apps django_example_ynh Debug the installation, e.g.: ```bash +root@yunohost:~# cat /etc/yunohost/apps/django_example_ynh/settings.yml +... + root@yunohost:~# ls -la /var/www/django_example_ynh/ total 18 drwxr-xr-x 4 root root 4 Dec 8 08:36 . @@ -172,6 +175,7 @@ System check identified no issues (0 silenced). root@yunohost:~# tail -f /var/log/django_example_ynh/django_example_ynh.log root@yunohost:~# cat /etc/systemd/system/systemd.service +... root@yunohost:~# systemctl reload-or-restart django_example_ynh root@yunohost:~# journalctl --unit=django_example_ynh --follow diff --git a/conf/requirements.txt b/conf/requirements.txt index 8c4aff5..5d5bd0f 100644 --- a/conf/requirements.txt +++ b/conf/requirements.txt @@ -16,9 +16,9 @@ django-ipware==4.0.2; python_version >= "3.7" and python_full_version < "3.0.0" django-redis==5.2.0; python_version >= "3.7" and python_full_version < "4.0.0" \ --hash=sha256:8a99e5582c79f894168f5865c52bd921213253b7fd64d16733ae4591564465de \ --hash=sha256:1d037dc02b11ad7aa11f655d26dac3fb1af32630f61ef4428860a2e29ff92026 -django-yunohost-integration==0.2.5; python_version >= "3.7" and python_full_version < "4.0.0" \ - --hash=sha256:b5f9beea73515ffb8816644cde766cdd0170ce75441ceb9ac11e185f40470186 \ - --hash=sha256:2cade1dc6d77974139624883475dfe360fe04a86335b635f1fac2401acae56d8 +django-yunohost-integration==0.3.0; python_version >= "3.7" and python_full_version < "4.0.0" \ + --hash=sha256:f7f8e9d55c50231bb32d3809b240d6ac718aadac1a1f471284baa1bfa6e98dff \ + --hash=sha256:d0e9cc91d241075613cb54b5da0879ad9b8ad3d22b84130cd7a331025650406e django==3.2.15; python_version >= "3.7" and python_full_version < "4.0.0" \ --hash=sha256:115baf5049d5cf4163e43492cdc7139c306ed6d451e7d3571fe9612903903713 \ --hash=sha256:f71934b1a822f14a86c9ac9634053689279cd04ae69cb6ade4a59471b886582b diff --git a/conf/settings.py b/conf/settings.py index a1daedc..5d77582 100644 --- a/conf/settings.py +++ b/conf/settings.py @@ -15,7 +15,9 @@ from django_yunohost_integration.base_settings import * # noqa from django_yunohost_integration.secret_key import get_or_create_secret as __get_or_create_secret -DEBUG = False # Don't turn DEBUG on in production! +# Set via config_panel.toml +DEBUG_ENABLED = '__DEBUG_ENABLED__' +DEBUG = bool(int(DEBUG_ENABLED)) # ----------------------------------------------------------------------------- diff --git a/conf/urls.py b/conf/urls.py index e76b15e..cfd7ae6 100644 --- a/conf/urls.py +++ b/conf/urls.py @@ -25,12 +25,12 @@ if settings.PATH_URL: # settings.PATH_URL is the $YNH_APP_ARG_PATH # Prefix all urls with "PATH_URL": urlpatterns = [ - path(f'{settings.PATH_URL}/', admin.site.urls), path(f'{settings.PATH_URL}/debug/', request_media_debug_view), + path(f'{settings.PATH_URL}/', admin.site.urls), ] else: # Installed to domain root, without a path prefix urlpatterns = [ - path('/', admin.site.urls), path('/debug/', request_media_debug_view), + path('/', admin.site.urls), ] diff --git a/config_panel.toml b/config_panel.toml new file mode 100644 index 0000000..c7144fc --- /dev/null +++ b/config_panel.toml @@ -0,0 +1,16 @@ +version = "1.0" + +[main] +name = "django_example_ynh configuration" +services = ["__APP__"] + + [main.config] + name = "Configuration Options" + + [main.config.debug_enabled] + ask = "Enable DEBUG mode" + type = "boolean" + yes = "1" + no = "0" + help = "Should be never enabled in production!" + bind = "debug_enabled:__FINALPATH__/settings.py" diff --git a/doc/DISCLAIMER.md b/doc/DISCLAIMER.md index f6b962b..9d298c1 100644 --- a/doc/DISCLAIMER.md +++ b/doc/DISCLAIMER.md @@ -110,6 +110,9 @@ yunohost backup restore 20201223-163434 --apps django_example_ynh Debug the installation, e.g.: ```bash +root@yunohost:~# cat /etc/yunohost/apps/django_example_ynh/settings.yml +... + root@yunohost:~# ls -la /var/www/django_example_ynh/ total 18 drwxr-xr-x 4 root root 4 Dec 8 08:36 . @@ -140,6 +143,7 @@ System check identified no issues (0 silenced). root@yunohost:~# tail -f /var/log/django_example_ynh/django_example_ynh.log root@yunohost:~# cat /etc/systemd/system/systemd.service +... root@yunohost:~# systemctl reload-or-restart django_example_ynh root@yunohost:~# journalctl --unit=django_example_ynh --follow diff --git a/local_test.py b/local_test.py index e2664e5..1f857e9 100644 --- a/local_test.py +++ b/local_test.py @@ -22,6 +22,9 @@ def main(): django_settings_path=BASE_PATH / 'conf' / 'settings.py', destination=BASE_PATH / 'local_test', runserver=True, + extra_replacements={ + '__DEBUG_ENABLED__': '1', + }, ) diff --git a/poetry.lock b/poetry.lock index 9ab0cd4..5813385 100644 --- a/poetry.lock +++ b/poetry.lock @@ -253,7 +253,7 @@ hiredis = ["redis[hiredis] (>=3,!=4.0.0,!=4.0.1)"] [[package]] name = "django-yunohost-integration" -version = "0.2.5" +version = "0.3.0" description = "Glue code to package django projects as yunohost apps." category = "main" optional = false @@ -718,7 +718,7 @@ docs = ["jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "jaraco.packaging (>=9) [metadata] lock-version = "1.1" python-versions = ">=3.7,<4.0.0" # TODO: Update to >=3.8 after YunoHost updates to Bullseye -content-hash = "477d486f59495a9e626d97f184b0c05db2642a62627f98758cdb90221cea1ebf" +content-hash = "e1bf9af0ee47f901c1febf1757dafc4f2c736b9df0d36d33cbd44883ee06c556" [metadata.files] asgiref = [ @@ -861,8 +861,8 @@ django-redis = [ {file = "django_redis-5.2.0-py3-none-any.whl", hash = "sha256:1d037dc02b11ad7aa11f655d26dac3fb1af32630f61ef4428860a2e29ff92026"}, ] django-yunohost-integration = [ - {file = "django_yunohost_integration-0.2.5-py3-none-any.whl", hash = "sha256:b5f9beea73515ffb8816644cde766cdd0170ce75441ceb9ac11e185f40470186"}, - {file = "django_yunohost_integration-0.2.5.tar.gz", hash = "sha256:2cade1dc6d77974139624883475dfe360fe04a86335b635f1fac2401acae56d8"}, + {file = "django_yunohost_integration-0.3.0-py3-none-any.whl", hash = "sha256:f7f8e9d55c50231bb32d3809b240d6ac718aadac1a1f471284baa1bfa6e98dff"}, + {file = "django_yunohost_integration-0.3.0.tar.gz", hash = "sha256:d0e9cc91d241075613cb54b5da0879ad9b8ad3d22b84130cd7a331025650406e"}, ] docopt = [ {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, diff --git a/pyproject.toml b/pyproject.toml index 9ce7b39..73cf763 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ homepage = "https://github.com/YunoHost-Apps/django_example_ynh" [tool.poetry.dependencies] python = ">=3.7,<4.0.0" # TODO: Update to >=3.8 after YunoHost updates to Bullseye -django_yunohost_integration = {version = "*", extras = ["ynh"]} +django_yunohost_integration = {version = ">=0.3.0", extras = ["ynh"]} [tool.poetry.dev-dependencies] bx_py_utils = "*" # https://github.com/boxine/bx_py_utils @@ -63,7 +63,7 @@ lines_after_imports=2 [tool.pytest.ini_options] # https://docs.pytest.org/en/latest/customize.html#pyproject-toml minversion = "6.0" -norecursedirs = ".* .git __pycache__ conf coverage* dist htmlcov" +norecursedirs = ".* .git __pycache__ conf local_test coverage* dist htmlcov" # sometimes helpfull "addopts" arguments: # -vv # --verbose diff --git a/run_pytest.py b/run_pytest.py deleted file mode 100644 index 086b5ef..0000000 --- a/run_pytest.py +++ /dev/null @@ -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() diff --git a/scripts/_common.sh b/scripts/_common.sh index b95ce9c..fee5921 100644 --- a/scripts/_common.sh +++ b/scripts/_common.sh @@ -11,6 +11,13 @@ admin=$YNH_APP_ARG_ADMIN is_public=$YNH_APP_ARG_IS_PUBLIC app=$YNH_APP_INSTANCE_NAME +#================================================= +# ARGUMENTS FROM CONFIG PANEL +#================================================= + +# 'debug_enabled' -> '__DEBUG_ENABLED__' -> settings.DEBUG +debug_enabled="0" + #================================================= # SET CONSTANTS #================================================= @@ -20,11 +27,7 @@ final_path=/opt/yunohost/$app log_path=/var/log/$app log_file="${log_path}/django_example_ynh.log" -# XXX: Is this okay? -adminmail="${admin}@${domain}" - -# Default: settings.DEBUG=False -django_debug="False" +adminmail=$(ynh_user_get_info --username=$admin --key=mail) #================================================= # COMMON VARIABLES diff --git a/scripts/install b/scripts/install index 727dad1..5eab770 100755 --- a/scripts/install +++ b/scripts/install @@ -61,7 +61,7 @@ redis_db=$(ynh_redis_get_free_db) ynh_app_setting_set --app="$app" --key=redis_db --value="$redis_db" # Always deactivate settings.DEBUG: -ynh_app_setting_set --app=$app --key=django_debug --value="False" +ynh_app_setting_set --app="$app" --key=debug_enabled --value="$debug_enabled" #================================================= # STANDARD MODIFICATIONS @@ -105,9 +105,9 @@ ynh_script_progression --message="Configuring system user..." 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 ynh_secure_remove "${final_path}/venv" @@ -118,6 +118,11 @@ python3 -m venv --without-pip "${final_path}/venv" cp ../conf/requirements.txt "$final_path/requirements.txt" chown -R "$app:" "$final_path" +#================================================= +# PIP INSTALLATION +#================================================= +ynh_script_progression --message="Install project via pip..." --weight=45 + #run source in a 'sub shell' ( set +o nounset diff --git a/scripts/restore b/scripts/restore index 34d464f..0401327 100755 --- a/scripts/restore +++ b/scripts/restore @@ -79,10 +79,10 @@ ynh_script_progression --message="Reinstalling dependencies..." --weight=20 ynh_exec_warn_less ynh_install_app_dependencies "$pkg_dependencies" #================================================= -# REINSTALL PYTHON VIRTUALENV +# PYTHON VIRTUALENV # 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 ynh_secure_remove "${final_path}/venv" @@ -91,6 +91,10 @@ ynh_secure_remove "${final_path}/venv" python3 -m venv --without-pip "${final_path}/venv" chown -R "$app:" "$final_path" +#================================================= +# PIP INSTALLATION +#================================================= +ynh_script_progression --message="Install project via pip..." --weight=45 #run source in a 'sub shell' ( set +o nounset diff --git a/scripts/upgrade b/scripts/upgrade index f639cbb..9dfc208 100755 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -29,7 +29,11 @@ db_user=$db_name admin_mail=$(ynh_user_get_info "$admin" mail) redis_db=$(ynh_app_setting_get --app="$app" --key=redis_db) -django_debug=$(ynh_app_setting_get --app="$app" --key=django_debug) +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 #================================================= # BACKUP BEFORE UPGRADE THEN ACTIVE TRAP @@ -59,7 +63,7 @@ ynh_systemd_action --service_name="$app" --action="stop" #================================================= # Always deactivate settings.DEBUG: -ynh_app_setting_set --app=$app --key=django_debug --value="False" +ynh_app_setting_set --app=$app --key=debug_enabled --value="False" #================================================= # NGINX CONFIGURATION @@ -96,9 +100,9 @@ ynh_script_progression --message="Configuring a systemd 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 ynh_secure_remove "${final_path}/venv" @@ -109,6 +113,10 @@ python3 -m venv --without-pip "${final_path}/venv" cp ../conf/requirements.txt "$final_path/requirements.txt" chown -R "$app:" "$final_path" +#================================================= +# PIP INSTALLATION +#================================================= +ynh_script_progression --message="Install project via pip..." --weight=45 #run source in a 'sub shell' ( set +o nounset diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..d1a679f --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,41 @@ +""" + 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', + }, + ) + 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() diff --git a/tests/test_django_project.py b/tests/test_django_project.py index 91ad6ab..cb6460b 100644 --- a/tests/test_django_project.py +++ b/tests/test_django_project.py @@ -30,9 +30,28 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase): def test_urls(self): assert reverse('admin:index') == '/app_path/' - # In example app, the debug view is in urls.py: + def test_request_media_debug_view(self): assert reverse(request_media_debug_view) == '/app_path/debug/' + self.client.cookies['SSOwAuthUser'] = 'test' + kwargs = dict( + path='/app_path/debug/', + HTTP_REMOTE_USER='test', + HTTP_AUTH_USER='test', + HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz', + secure=True, + ) + assert settings.DEBUG is False + with self.assertRaisesMessage(AssertionError, 'Only in DEBUG mode available!'): + self.client.get(**kwargs) + + with override_settings(DEBUG=True): + response = self.client.get(**kwargs) + self.assert_html_parts( + response, + parts=('request.META',), + ) + def test_auth(self): # SecurityMiddleware should redirects all non-HTTPS requests to HTTPS: assert settings.SECURE_SSL_REDIRECT is True