diff --git a/inventory_project/settings/base.py b/inventory_project/settings/base.py index 1cc421d..ae6fc34 100644 --- a/inventory_project/settings/base.py +++ b/inventory_project/settings/base.py @@ -31,6 +31,7 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'django.contrib.sites', 'bx_py_utils', # https://github.com/boxine/bx_py_utils 'import_export', # https://github.com/django-import-export/django-import-export @@ -41,12 +42,14 @@ INSTALLED_APPS = [ 'tagulous', # https://github.com/radiac/django-tagulous 'adminsortable2', # https://github.com/jrief/django-admin-sortable2 'axes', # https://github.com/jazzband/django-axes + 'django_processinfo', # https://github.com/jedie/django-processinfo/ 'inventory.apps.InventoryConfig', ] ROOT_URLCONF = 'inventory_project.urls' WSGI_APPLICATION = 'inventory_project.wsgi.application' +SITE_ID = 1 AUTHENTICATION_BACKENDS = [ 'axes.backends.AxesBackend', @@ -54,6 +57,8 @@ AUTHENTICATION_BACKENDS = [ ] MIDDLEWARE = [ + 'django_processinfo.middlewares.ProcessInfoMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.locale.LocaleMiddleware', 'django.middleware.common.CommonMiddleware', @@ -109,6 +114,14 @@ STATIC_ROOT = str(__Path(BASE_PATH, 'static')) MEDIA_URL = '/media/' MEDIA_ROOT = str(__Path(BASE_PATH, 'media')) +# _____________________________________________________________________________ +# django-processinfo + +from django_processinfo import app_settings as PROCESSINFO # noqa + + +PROCESSINFO.ADD_INFO = False # Don't add info in HTML page + # _____________________________________________________________________________ # Django-dbbackup diff --git a/inventory_project/tests/test_admin.py b/inventory_project/tests/test_admin.py index 48db912..b350dd1 100644 --- a/inventory_project/tests/test_admin.py +++ b/inventory_project/tests/test_admin.py @@ -1,8 +1,11 @@ -import pytest +from django.contrib.auth.models import User from django.test import TestCase +from django_processinfo.models import ProcessInfo, SiteStatistics +from model_bakery import baker + +from inventory.permissions import get_or_create_normal_user_group -@pytest.mark.django_db class AdminAnonymousTests(TestCase): """ Anonymous will be redirected to the login page. @@ -15,3 +18,58 @@ class AdminAnonymousTests(TestCase): def test_login_de(self): response = self.client.get("/admin/", HTTP_ACCEPT_LANGUAGE="de") self.assertRedirects(response, expected_url="/admin/login/?next=/admin/") + + +class ProcessinfoAdminTestCase(TestCase): + @classmethod + def setUpTestData(cls): + cls.superuser = baker.make( + User, is_staff=True, is_active=True, is_superuser=True + ) + cls.normaluser = baker.make( + User, is_staff=True, is_active=True, is_superuser=False + ) + assert cls.normaluser.user_permissions.count() == 0 + group = get_or_create_normal_user_group()[0] + cls.normaluser.groups.set([group]) + + def test_superuser_access(self): + self.client.force_login(self.superuser) + + assert SiteStatistics.objects.count() == 0 + assert ProcessInfo.objects.count() == 0 + + response = self.client.get('/admin/django_processinfo/sitestatistics/') + self.assertTemplateUsed(response, 'admin/django_processinfo/change_list.html') + + response = response.content.decode("utf-8") + self.assertInHTML('

System information

', response) + self.assertInHTML('
Living processes (current/avg/max)
', response) + + assert SiteStatistics.objects.count() == 1 + assert ProcessInfo.objects.count() == 1 + + response = self.client.get('/admin/django_processinfo/processinfo/') + self.assertTemplateUsed(response, 'admin/django_processinfo/change_list.html') + + response = response.content.decode("utf-8") + self.assertInHTML('

System information

', response) + self.assertInHTML('
Living processes (current/avg/max)
', response) + + assert SiteStatistics.objects.count() == 1 + assert ProcessInfo.objects.count() == 1 + + def test_normal_user_access(self): + self.client.force_login(self.normaluser) + + assert SiteStatistics.objects.count() == 0 + assert ProcessInfo.objects.count() == 0 + + response = self.client.get('/admin/django_processinfo/sitestatistics/') + assert response.status_code == 403 + + response = self.client.get('/admin/django_processinfo/processinfo/') + assert response.status_code == 403 + + assert SiteStatistics.objects.count() == 1 + assert ProcessInfo.objects.count() == 1 diff --git a/poetry.lock b/poetry.lock index 18aac3d..30a4522 100644 --- a/poetry.lock +++ b/poetry.lock @@ -324,6 +324,17 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "django-processinfo" +version = "1.0.0" +description = "Django application to collect information about the running server processes." +category = "main" +optional = false +python-versions = ">=3.7,<4.0.0" + +[package.dependencies] +Django = "*" + [[package]] name = "django-reversion" version = "3.0.8" @@ -614,6 +625,17 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "model-bakery" +version = "1.2.0" +description = "Smart object creation facility for Django." +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +django = ">=1.11.0" + [[package]] name = "odfpy" version = "1.4.1" @@ -1205,7 +1227,7 @@ postgres = ["psycopg2-binary"] [metadata] lock-version = "1.1" python-versions = ">=3.7,<4.0.0" -content-hash = "c9de646c31e5e1f0b0ff9b003d6290da61eca039c78aef8e6786894584fa37cf" +content-hash = "745c33aa94cad303222f51896f0a9a11abdb4896cb00f87f522fe7eaa8c2325a" [metadata.files] appdirs = [ @@ -1414,6 +1436,10 @@ django-js-asset = [ {file = "django-js-asset-1.2.2.tar.gz", hash = "sha256:c163ae80d2e0b22d8fb598047cd0dcef31f81830e127cfecae278ad574167260"}, {file = "django_js_asset-1.2.2-py2.py3-none-any.whl", hash = "sha256:8ec12017f26eec524cab436c64ae73033368a372970af4cf42d9354fcb166bdd"}, ] +django-processinfo = [ + {file = "django-processinfo-1.0.0.tar.gz", hash = "sha256:0df4b3a011a7adb1f6b722964aca4693e79fa003b7f780025cc0d04073f00c49"}, + {file = "django_processinfo-1.0.0-py3-none-any.whl", hash = "sha256:829e2937a9fae54ef8c0a3cb5e99a09490cf66252cee498de833377839d7e497"}, +] django-reversion = [ {file = "django-reversion-3.0.8.tar.gz", hash = "sha256:49e9930f90322dc6a2754dd26144285cfcc1c5bd0c1c39ca95d5602c5054ae32"}, {file = "django_reversion-3.0.8-py3-none-any.whl", hash = "sha256:9cfadeec2df37cb53d795ab79f6792f9eed8e70363dcf3a275dc19a58b971a8f"}, @@ -1503,6 +1529,10 @@ mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] +model-bakery = [ + {file = "model_bakery-1.2.0-py2.py3-none-any.whl", hash = "sha256:b25f400b392067f02d841a0ef33e861543c04b1702dc004020bdd50e1dbce05f"}, + {file = "model_bakery-1.2.0.tar.gz", hash = "sha256:088698cdf62e5ccedeb97e55ceb966c974cc79e2514928aec9beab27a8c1faf4"}, +] odfpy = [ {file = "odfpy-1.4.1-py2.7.egg", hash = "sha256:fc3b8d1bc098eba4a0fda865a76d9d1e577c4ceec771426bcb169a82c5e9dfe0"}, {file = "odfpy-1.4.1.tar.gz", hash = "sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec"}, diff --git a/pyproject.toml b/pyproject.toml index 074acc5..5d2809e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,6 +40,7 @@ uWSGI = "*" # https://www.djangoproject.com/download/#supported-versions # v2.2 LTS - extended support until April 2022 django = "2.2.*" +django-processinfo = "*" # https://github.com/jedie/django-processinfo/ django-debug-toolbar = "*" # http://django-debug-toolbar.readthedocs.io/en/stable/changes.html django-import-export = "*" # https://github.com/django-import-export/django-import-export django-dbbackup = "*" # https://github.com/django-dbbackup/django-dbbackup @@ -72,6 +73,7 @@ flake8 = "*" flynt = "*" autopep8 = "*" pyupgrade = "*" +model_bakery = "*" # https://github.com/model-bakers/model_bakery [tool.poetry.scripts] manage = "inventory_project.manage:main"