commit
b05c6c81d6
8
.flake8
8
.flake8
|
@ -1,8 +0,0 @@
|
|||
[flake8]
|
||||
exclude =
|
||||
*migrations*,
|
||||
__init__.py,
|
||||
*cache*,
|
||||
venv/,
|
||||
src/manage.py,
|
||||
src/network_inventory/settings/*
|
|
@ -51,7 +51,7 @@
|
|||
pkgs.python310Packages.pip
|
||||
(pkgs.writeScriptBin "dev" "${builtins.readFile ./dev.sh}")
|
||||
];
|
||||
PYTHON_KEYRING_BACKEND="keyring.backends.fail.Keyring";
|
||||
PYTHON_KEYRING_BACKEND = "keyring.backends.fail.Keyring";
|
||||
shellHook = ''
|
||||
export DJANGO_SETTINGS_MODULE=network_inventory.settings.local
|
||||
'';
|
||||
|
@ -68,8 +68,10 @@
|
|||
checkInputs = [ pkgs.inventoryDevEnv ];
|
||||
checkPhase = ''
|
||||
mkdir -p $out
|
||||
flake8 . --count --show-source --statistics
|
||||
pylint --rc-file pyproject.toml -j 0 -E src/
|
||||
cd src/ && mypy --config-file=../pyproject.toml .
|
||||
'';
|
||||
DJANGO_SETTINGS_MODULE = "network_inventory.settings.ram_test";
|
||||
};
|
||||
tests = pkgs.stdenv.mkDerivation {
|
||||
dontPatch = true;
|
||||
|
|
|
@ -20,14 +20,14 @@ tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"]
|
|||
|
||||
[[package]]
|
||||
name = "astroid"
|
||||
version = "2.15.5"
|
||||
version = "2.15.6"
|
||||
description = "An abstract syntax tree for Python with inference support."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7.2"
|
||||
files = [
|
||||
{file = "astroid-2.15.5-py3-none-any.whl", hash = "sha256:078e5212f9885fa85fbb0cf0101978a336190aadea6e13305409d099f71b2324"},
|
||||
{file = "astroid-2.15.5.tar.gz", hash = "sha256:1039262575027b441137ab4a62a793a9b43defb42c32d5670f38686207cd780f"},
|
||||
{file = "astroid-2.15.6-py3-none-any.whl", hash = "sha256:389656ca57b6108f939cf5d2f9a2a825a3be50ba9d589670f393236e0a03b91c"},
|
||||
{file = "astroid-2.15.6.tar.gz", hash = "sha256:903f024859b7c7687d7a7f3a3f73b17301f8e42dfd9cc9df9d4418172d3e2dbd"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -38,22 +38,6 @@ wrapt = [
|
|||
{version = ">=1.14,<2", markers = "python_version >= \"3.11\""},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autopep8"
|
||||
version = "2.0.2"
|
||||
description = "A tool that automatically formats Python code to conform to the PEP 8 style guide"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "autopep8-2.0.2-py2.py3-none-any.whl", hash = "sha256:86e9303b5e5c8160872b2f5ef611161b2893e9bfe8ccc7e2f76385947d57a2f1"},
|
||||
{file = "autopep8-2.0.2.tar.gz", hash = "sha256:f9849cdd62108cb739dbcdbfb7fdcc9a30d1b63c4cc3e1c1f893b5360941b61c"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pycodestyle = ">=2.10.0"
|
||||
tomli = {version = "*", markers = "python_version < \"3.11\""}
|
||||
|
||||
[[package]]
|
||||
name = "black"
|
||||
version = "22.12.0"
|
||||
|
@ -92,14 +76,14 @@ uvloop = ["uvloop (>=0.15.2)"]
|
|||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.1.3"
|
||||
version = "8.1.4"
|
||||
description = "Composable command line interface toolkit"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
|
||||
{file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
|
||||
{file = "click-8.1.4-py3-none-any.whl", hash = "sha256:2739815aaa5d2c986a88f1e9230c55e17f0caad3d958a5e13ad0797c166db9e3"},
|
||||
{file = "click-8.1.4.tar.gz", hash = "sha256:b97d0c74955da062a7d4ef92fadb583806a585b2ea81958a81bd72726cbb8e37"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -200,14 +184,14 @@ graph = ["objgraph (>=1.7.2)"]
|
|||
|
||||
[[package]]
|
||||
name = "django"
|
||||
version = "4.2.2"
|
||||
version = "4.2.3"
|
||||
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "Django-4.2.2-py3-none-any.whl", hash = "sha256:672b3fa81e1f853bb58be1b51754108ab4ffa12a77c06db86aa8df9ed0c46fe5"},
|
||||
{file = "Django-4.2.2.tar.gz", hash = "sha256:2a6b6fbff5b59dd07bef10bcb019bee2ea97a30b2a656d51346596724324badf"},
|
||||
{file = "Django-4.2.3-py3-none-any.whl", hash = "sha256:f7c7852a5ac5a3da5a8d5b35cc6168f31b605971441798dac845f17ca8028039"},
|
||||
{file = "Django-4.2.3.tar.gz", hash = "sha256:45a747e1c5b3d6df1b141b1481e193b033fd1fdbda3ff52677dc81afdaacbaed"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -275,14 +259,14 @@ Django = ">=2.2"
|
|||
|
||||
[[package]]
|
||||
name = "django-htmx"
|
||||
version = "1.15.0"
|
||||
version = "1.16.0"
|
||||
description = "Extensions for using Django with htmx."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "django_htmx-1.15.0-py3-none-any.whl", hash = "sha256:b76068485905ad9f911419746f07f877633bb036c0870a0f9fc13dec42c6e425"},
|
||||
{file = "django_htmx-1.15.0.tar.gz", hash = "sha256:bac7ff59bf507db6d40424f635f83889ce028a54f47663f227083413de22cabf"},
|
||||
{file = "django_htmx-1.16.0-py3-none-any.whl", hash = "sha256:360d11266666e5d92bda57069f671f2c04642eb1fc071e4c4160cf9f504cbfa6"},
|
||||
{file = "django_htmx-1.16.0.tar.gz", hash = "sha256:56a65045e079503877ba1354acb481030cf54da1e1f731d33c280e0a14b214cf"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -322,16 +306,56 @@ python-monkey-business = ">=1.0.0"
|
|||
dev = ["Pillow", "black", "dj-database-url", "django-selenosis", "flake8", "pytest", "pytest-cov", "pytest-django", "pytest-xdist", "selenium"]
|
||||
test = ["Pillow", "dj-database-url", "django-selenosis", "pytest", "pytest-cov", "pytest-django", "pytest-xdist", "selenium"]
|
||||
|
||||
[[package]]
|
||||
name = "django-stubs"
|
||||
version = "4.2.3"
|
||||
description = "Mypy stubs for Django"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "django-stubs-4.2.3.tar.gz", hash = "sha256:dadab39b46d9ae8f37a8e879c590f39a9e042b565c03fa0c5a8f754b441b1f23"},
|
||||
{file = "django_stubs-4.2.3-py3-none-any.whl", hash = "sha256:e30e2e4927ba14bec587ed2c686404b6b8e473cabe9baca445e7d2e1e0d7b14f"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
django = "*"
|
||||
django-stubs-ext = ">=4.2.2"
|
||||
mypy = ">=1.0.0"
|
||||
tomli = {version = "*", markers = "python_version < \"3.11\""}
|
||||
types-pytz = "*"
|
||||
types-PyYAML = "*"
|
||||
typing-extensions = "*"
|
||||
|
||||
[package.extras]
|
||||
compatible-mypy = ["mypy (>=1.4.0,<1.5.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "django-stubs-ext"
|
||||
version = "4.2.2"
|
||||
description = "Monkey-patching and extensions for django-stubs"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "django-stubs-ext-4.2.2.tar.gz", hash = "sha256:c69d1cc46f1c4c3b7894b685a5022c29b2a36c7cfb52e23762eaf357ebfc2c98"},
|
||||
{file = "django_stubs_ext-4.2.2-py3-none-any.whl", hash = "sha256:fdacc65a14d2d4b97334b58ff178a5853ec8c8c76cec406e417916ad67536ce4"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
django = "*"
|
||||
typing-extensions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "django-tables2"
|
||||
version = "2.5.3"
|
||||
version = "2.6.0"
|
||||
description = "Table/data-grid framework for Django"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "django-tables2-2.5.3.tar.gz", hash = "sha256:f6c1623aac188d29aae9cf6b4de3211c96c525e49890654bec3359c181600eb9"},
|
||||
{file = "django_tables2-2.5.3-py2.py3-none-any.whl", hash = "sha256:e336fdf8899a8fab110550a40cad956064bd4054818e0b972c1893b3e2542168"},
|
||||
{file = "django-tables2-2.6.0.tar.gz", hash = "sha256:479eed04007cc04bcf764a6fb7a5e3955d94b878ba7f3a4bd4edbd2f7769e08d"},
|
||||
{file = "django_tables2-2.6.0-py2.py3-none-any.whl", hash = "sha256:04f23c1181d93716c67085a3c324b449180fd0c5162ef4619acb0b2d9a166133"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -354,14 +378,14 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
description = "Backport of PEP 654 (exception groups)"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"},
|
||||
{file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"},
|
||||
{file = "exceptiongroup-1.1.2-py3-none-any.whl", hash = "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f"},
|
||||
{file = "exceptiongroup-1.1.2.tar.gz", hash = "sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
|
@ -397,23 +421,6 @@ files = [
|
|||
[package.dependencies]
|
||||
python-dateutil = ">=2.4"
|
||||
|
||||
[[package]]
|
||||
name = "flake8"
|
||||
version = "6.0.0"
|
||||
description = "the modular source code checker: pep8 pyflakes and co"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.8.1"
|
||||
files = [
|
||||
{file = "flake8-6.0.0-py2.py3-none-any.whl", hash = "sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7"},
|
||||
{file = "flake8-6.0.0.tar.gz", hash = "sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
mccabe = ">=0.7.0,<0.8.0"
|
||||
pycodestyle = ">=2.10.0,<2.11.0"
|
||||
pyflakes = ">=3.0.0,<3.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "gunicorn"
|
||||
version = "20.1.0"
|
||||
|
@ -561,6 +568,53 @@ Faker = ">=5.4.0,<12.1"
|
|||
[package.extras]
|
||||
tests = ["Django (>=3.0)", "Flask (>=1.0)", "Marshmallow (>=3.9)", "SQLAlchemy (>=1.1.4)", "flask-sqlalchemy (>=2.1)", "mongoengine (>=0.10.1)", "peewee (>=3.7.0)", "pony (>=0.7)", "psycopg2-binary (>=2.8.4)", "pytest"]
|
||||
|
||||
[[package]]
|
||||
name = "mypy"
|
||||
version = "1.4.1"
|
||||
description = "Optional static typing for Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "mypy-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:566e72b0cd6598503e48ea610e0052d1b8168e60a46e0bfd34b3acf2d57f96a8"},
|
||||
{file = "mypy-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ca637024ca67ab24a7fd6f65d280572c3794665eaf5edcc7e90a866544076878"},
|
||||
{file = "mypy-1.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dde1d180cd84f0624c5dcaaa89c89775550a675aff96b5848de78fb11adabcd"},
|
||||
{file = "mypy-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8c4d8e89aa7de683e2056a581ce63c46a0c41e31bd2b6d34144e2c80f5ea53dc"},
|
||||
{file = "mypy-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:bfdca17c36ae01a21274a3c387a63aa1aafe72bff976522886869ef131b937f1"},
|
||||
{file = "mypy-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7549fbf655e5825d787bbc9ecf6028731973f78088fbca3a1f4145c39ef09462"},
|
||||
{file = "mypy-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:98324ec3ecf12296e6422939e54763faedbfcc502ea4a4c38502082711867258"},
|
||||
{file = "mypy-1.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:141dedfdbfe8a04142881ff30ce6e6653c9685b354876b12e4fe6c78598b45e2"},
|
||||
{file = "mypy-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8207b7105829eca6f3d774f64a904190bb2231de91b8b186d21ffd98005f14a7"},
|
||||
{file = "mypy-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:16f0db5b641ba159eff72cff08edc3875f2b62b2fa2bc24f68c1e7a4e8232d01"},
|
||||
{file = "mypy-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:470c969bb3f9a9efcedbadcd19a74ffb34a25f8e6b0e02dae7c0e71f8372f97b"},
|
||||
{file = "mypy-1.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5952d2d18b79f7dc25e62e014fe5a23eb1a3d2bc66318df8988a01b1a037c5b"},
|
||||
{file = "mypy-1.4.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:190b6bab0302cec4e9e6767d3eb66085aef2a1cc98fe04936d8a42ed2ba77bb7"},
|
||||
{file = "mypy-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9d40652cc4fe33871ad3338581dca3297ff5f2213d0df345bcfbde5162abf0c9"},
|
||||
{file = "mypy-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:01fd2e9f85622d981fd9063bfaef1aed6e336eaacca00892cd2d82801ab7c042"},
|
||||
{file = "mypy-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2460a58faeea905aeb1b9b36f5065f2dc9a9c6e4c992a6499a2360c6c74ceca3"},
|
||||
{file = "mypy-1.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2746d69a8196698146a3dbe29104f9eb6a2a4d8a27878d92169a6c0b74435b6"},
|
||||
{file = "mypy-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ae704dcfaa180ff7c4cfbad23e74321a2b774f92ca77fd94ce1049175a21c97f"},
|
||||
{file = "mypy-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:43d24f6437925ce50139a310a64b2ab048cb2d3694c84c71c3f2a1626d8101dc"},
|
||||
{file = "mypy-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c482e1246726616088532b5e964e39765b6d1520791348e6c9dc3af25b233828"},
|
||||
{file = "mypy-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43b592511672017f5b1a483527fd2684347fdffc041c9ef53428c8dc530f79a3"},
|
||||
{file = "mypy-1.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34a9239d5b3502c17f07fd7c0b2ae6b7dd7d7f6af35fbb5072c6208e76295816"},
|
||||
{file = "mypy-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5703097c4936bbb9e9bce41478c8d08edd2865e177dc4c52be759f81ee4dd26c"},
|
||||
{file = "mypy-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e02d700ec8d9b1859790c0475df4e4092c7bf3272a4fd2c9f33d87fac4427b8f"},
|
||||
{file = "mypy-1.4.1-py3-none-any.whl", hash = "sha256:45d32cec14e7b97af848bddd97d85ea4f0db4d5a149ed9676caa4eb2f7402bb4"},
|
||||
{file = "mypy-1.4.1.tar.gz", hash = "sha256:9bbcd9ab8ea1f2e1c8031c21445b511442cc45c89951e49bbf852cbb70755b1b"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
mypy-extensions = ">=1.0.0"
|
||||
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
||||
typing-extensions = ">=4.1.0"
|
||||
|
||||
[package.extras]
|
||||
dmypy = ["psutil (>=4.0)"]
|
||||
install-types = ["pip"]
|
||||
python2 = ["typed-ast (>=1.4.0,<2)"]
|
||||
reports = ["lxml"]
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "1.0.0"
|
||||
|
@ -613,28 +667,16 @@ files = [
|
|||
{file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pep8"
|
||||
version = "1.7.1"
|
||||
description = "Python style guide checker"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "pep8-1.7.1-py2.py3-none-any.whl", hash = "sha256:b22cfae5db09833bb9bd7c8463b53e1a9c9b39f12e304a8d0bba729c501827ee"},
|
||||
{file = "pep8-1.7.1.tar.gz", hash = "sha256:fe249b52e20498e59e0b5c5256aa52ee99fc295b26ec9eaa85776ffdb9fe6374"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "3.8.0"
|
||||
version = "3.8.1"
|
||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "platformdirs-3.8.0-py3-none-any.whl", hash = "sha256:ca9ed98ce73076ba72e092b23d3c93ea6c4e186b3f1c3dad6edd98ff6ffcca2e"},
|
||||
{file = "platformdirs-3.8.0.tar.gz", hash = "sha256:b0cabcb11063d21a0b261d557acb0a9d2126350e63b70cdf7db6347baea456dc"},
|
||||
{file = "platformdirs-3.8.1-py3-none-any.whl", hash = "sha256:cec7b889196b9144d088e4c57d9ceef7374f6c39694ad1577a0aab50d27ea28c"},
|
||||
{file = "platformdirs-3.8.1.tar.gz", hash = "sha256:f87ca4fcff7d2b0f81c6a748a77973d7af0f4d526f98f308477c3c436c74d528"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
|
@ -729,30 +771,6 @@ files = [
|
|||
{file = "psycopg2_binary-2.9.6-cp39-cp39-win_amd64.whl", hash = "sha256:f6a88f384335bb27812293fdb11ac6aee2ca3f51d3c7820fe03de0a304ab6249"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pycodestyle"
|
||||
version = "2.10.0"
|
||||
description = "Python style guide checker"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "pycodestyle-2.10.0-py2.py3-none-any.whl", hash = "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"},
|
||||
{file = "pycodestyle-2.10.0.tar.gz", hash = "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyflakes"
|
||||
version = "3.0.1"
|
||||
description = "passive checker of Python programs"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "pyflakes-3.0.1-py2.py3-none-any.whl", hash = "sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf"},
|
||||
{file = "pyflakes-3.0.1.tar.gz", hash = "sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pylint"
|
||||
version = "2.17.4"
|
||||
|
@ -783,6 +801,41 @@ typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""
|
|||
spelling = ["pyenchant (>=3.2,<4.0)"]
|
||||
testutils = ["gitpython (>3)"]
|
||||
|
||||
[[package]]
|
||||
name = "pylint-django"
|
||||
version = "2.5.3"
|
||||
description = "A Pylint plugin to help Pylint understand the Django web framework"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "pylint-django-2.5.3.tar.gz", hash = "sha256:0ac090d106c62fe33782a1d01bda1610b761bb1c9bf5035ced9d5f23a13d8591"},
|
||||
{file = "pylint_django-2.5.3-py3-none-any.whl", hash = "sha256:56b12b6adf56d548412445bd35483034394a1a94901c3f8571980a13882299d5"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pylint = ">=2.0,<3"
|
||||
pylint-plugin-utils = ">=0.7"
|
||||
|
||||
[package.extras]
|
||||
for-tests = ["coverage", "django-tables2", "django-tastypie", "factory-boy", "pylint (>=2.13)", "pytest", "wheel"]
|
||||
with-django = ["Django"]
|
||||
|
||||
[[package]]
|
||||
name = "pylint-plugin-utils"
|
||||
version = "0.8.2"
|
||||
description = "Utilities and helpers for writing Pylint plugins"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7,<4.0"
|
||||
files = [
|
||||
{file = "pylint_plugin_utils-0.8.2-py3-none-any.whl", hash = "sha256:ae11664737aa2effbf26f973a9e0b6779ab7106ec0adc5fe104b0907ca04e507"},
|
||||
{file = "pylint_plugin_utils-0.8.2.tar.gz", hash = "sha256:d3cebf68a38ba3fba23a873809155562571386d4c1b03e5b4c4cc26c3eee93e4"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pylint = ">=1.7"
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "7.4.0"
|
||||
|
@ -900,14 +953,14 @@ test = ["coverage", "pycodestyle", "pyflakes", "pylint", "pytest", "pytest-cov"]
|
|||
|
||||
[[package]]
|
||||
name = "python-lsp-server"
|
||||
version = "1.7.3"
|
||||
version = "1.7.4"
|
||||
description = "Python Language Server for the Language Server Protocol"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "python-lsp-server-1.7.3.tar.gz", hash = "sha256:a31b0525be6ec831c7d2b476b744e5aa5074633e1d1b77ee97f332cde15983ea"},
|
||||
{file = "python_lsp_server-1.7.3-py3-none-any.whl", hash = "sha256:f4ae64834da1d4312067a8ee05a76c7652167c3c90d1cef44022366d695c4c0e"},
|
||||
{file = "python-lsp-server-1.7.4.tar.gz", hash = "sha256:c84254485a4d9431b24ecefd59741d21c00165611bcf6037bd7d54d0ed06a197"},
|
||||
{file = "python_lsp_server-1.7.4-py3-none-any.whl", hash = "sha256:f8053f7aefcb60af4e91f3fab1a093b15ba0c4688ba67e6ab69e7b73e997b2cb"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -947,29 +1000,6 @@ files = [
|
|||
[package.dependencies]
|
||||
six = ">=1.7.0"
|
||||
|
||||
[[package]]
|
||||
name = "pytoolconfig"
|
||||
version = "1.2.5"
|
||||
description = "Python tool configuration"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pytoolconfig-1.2.5-py3-none-any.whl", hash = "sha256:239ba9d3e537b91d0243275a497700ea39a5e259ddb80421c366e3b288bf30fe"},
|
||||
{file = "pytoolconfig-1.2.5.tar.gz", hash = "sha256:a50f9dfe23b03a9d40414c1fdf902fefbeae12f2ac75a3c8f915944d6ffac279"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
packaging = ">=22.0"
|
||||
platformdirs = {version = ">=1.4.4", optional = true, markers = "extra == \"global\""}
|
||||
tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""}
|
||||
|
||||
[package.extras]
|
||||
doc = ["sphinx (>=4.5.0)", "tabulate (>=0.8.9)"]
|
||||
gendocs = ["pytoolconfig[doc]", "sphinx (>=4.5.0)", "sphinx-autodoc-typehints (>=1.18.1)", "sphinx-rtd-theme (>=1.0.0)"]
|
||||
global = ["platformdirs (>=1.4.4)"]
|
||||
validation = ["pydantic (>=1.7.4)"]
|
||||
|
||||
[[package]]
|
||||
name = "pyyaml"
|
||||
version = "6.0"
|
||||
|
@ -1020,25 +1050,6 @@ files = [
|
|||
{file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rope"
|
||||
version = "1.8.0"
|
||||
description = "a python refactoring library..."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "rope-1.8.0-py3-none-any.whl", hash = "sha256:0767424ed40ce237dcf1c1f5088054fef960e5b19f4a0850783a259a3600d7bd"},
|
||||
{file = "rope-1.8.0.tar.gz", hash = "sha256:3de1d1f1cf2412540c6a150067fe25298175e7c2b72455b6ca8395f61678da82"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pytoolconfig = {version = ">=1.2.2", extras = ["global"]}
|
||||
|
||||
[package.extras]
|
||||
dev = ["build (>=0.7.0)", "pip-tools (>=6.12.1)", "pre-commit (>=2.20.0)", "pytest (>=7.0.1)", "pytest-timeout (>=2.1.0)", "toml (>=0.10.2)"]
|
||||
doc = ["pytoolconfig[doc]", "sphinx (>=4.5.0)", "sphinx-autodoc-typehints (>=1.18.1)", "sphinx-rtd-theme (>=1.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "setuptools"
|
||||
version = "68.0.0"
|
||||
|
@ -1109,16 +1120,40 @@ files = [
|
|||
{file = "tomlkit-0.11.8.tar.gz", hash = "sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "types-pytz"
|
||||
version = "2023.3.0.0"
|
||||
description = "Typing stubs for pytz"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "types-pytz-2023.3.0.0.tar.gz", hash = "sha256:ecdc70d543aaf3616a7e48631543a884f74205f284cefd6649ddf44c6a820aac"},
|
||||
{file = "types_pytz-2023.3.0.0-py3-none-any.whl", hash = "sha256:4fc2a7fbbc315f0b6630e0b899fd6c743705abe1094d007b0e612d10da15e0f3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "types-pyyaml"
|
||||
version = "6.0.12.10"
|
||||
description = "Typing stubs for PyYAML"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "types-PyYAML-6.0.12.10.tar.gz", hash = "sha256:ebab3d0700b946553724ae6ca636ea932c1b0868701d4af121630e78d695fc97"},
|
||||
{file = "types_PyYAML-6.0.12.10-py3-none-any.whl", hash = "sha256:662fa444963eff9b68120d70cda1af5a5f2aa57900003c2006d7626450eaae5f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.6.3"
|
||||
version = "4.7.1"
|
||||
description = "Backported and Experimental Type Hints for Python 3.7+"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "typing_extensions-4.6.3-py3-none-any.whl", hash = "sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26"},
|
||||
{file = "typing_extensions-4.6.3.tar.gz", hash = "sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5"},
|
||||
{file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"},
|
||||
{file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1289,19 +1324,7 @@ files = [
|
|||
{file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yapf"
|
||||
version = "0.32.0"
|
||||
description = "A formatter for Python code."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "yapf-0.32.0-py2.py3-none-any.whl", hash = "sha256:8fea849025584e486fd06d6ba2bed717f396080fd3cc236ba10cb97c4c51cf32"},
|
||||
{file = "yapf-0.32.0.tar.gz", hash = "sha256:a3f5085d37ef7e3e004c4ba9f9b3e40c54ff1901cd111f05145ae313a7c67d1b"},
|
||||
]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.9"
|
||||
content-hash = "95419a1919aadc2d6bbd680b89480fa6b53f4dc29d2f7e2ea7ec7f849bfba1ba"
|
||||
content-hash = "56454bd1da936edf92442e1f87d0cdb1ace8cda9297e33f4eba8a98230cc4610"
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
[tool.black]
|
||||
line-length = 79
|
||||
[tool.pylint]
|
||||
max-line-length = 88
|
||||
load-plugins = [
|
||||
"pylint_django",
|
||||
]
|
||||
|
||||
[tool.poetry]
|
||||
name = "network_inventory"
|
||||
|
@ -11,6 +14,45 @@ packages = [
|
|||
{ include = "src" },
|
||||
]
|
||||
|
||||
[tool.mypy]
|
||||
exclude = [
|
||||
"tests/",
|
||||
]
|
||||
plugins = ["mypy_django_plugin.main"]
|
||||
mypy_path = "./src"
|
||||
# Start off with these
|
||||
warn_unused_configs = true
|
||||
warn_redundant_casts = true
|
||||
warn_unused_ignores = true
|
||||
|
||||
# Getting these passing should be easy
|
||||
strict_equality = true
|
||||
strict_concatenate = true
|
||||
|
||||
# Strongly recommend enabling this one as soon as you can
|
||||
#check_untyped_defs = true
|
||||
|
||||
# These shouldn't be too much additional work, but may be tricky to
|
||||
# get passing if you use a lot of untyped libraries
|
||||
#disallow_subclassing_any = true
|
||||
#disallow_untyped_decorators = true
|
||||
#disallow_any_generics = true
|
||||
|
||||
[tool.django-stubs]
|
||||
django_settings_module = "network_inventory.settings.local"
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = [
|
||||
"nested_admin.*",
|
||||
"django_tables2.*",
|
||||
"floppyforms.*",
|
||||
"django_filters.*",
|
||||
"crispy_forms.*",
|
||||
"mixer.*",
|
||||
"guardian.*",
|
||||
]
|
||||
ignore_missing_imports = true
|
||||
|
||||
[tool.poetry.group.main.dependencies]
|
||||
python = "^3.9"
|
||||
Django = "^4.1.3"
|
||||
|
@ -27,21 +69,19 @@ psycopg2-binary = "^2.9.5"
|
|||
PyYAML = "^6.0"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
autopep8 = "^2.0.0"
|
||||
black = "^22.10.0"
|
||||
coverage = "^6.5.0"
|
||||
flake8 = "^6.0.0"
|
||||
jedi = "^0.18.2"
|
||||
mixer = "^7.2.2"
|
||||
pep8 = "^1.7.1"
|
||||
pylint = "^2.15.8"
|
||||
pytest = "^7.2.0"
|
||||
pytest-cov = "^4.0.0"
|
||||
pytest-django = "^4.5.2"
|
||||
pytest-xdist = "^3.1.0"
|
||||
rope = "^1.5.1"
|
||||
yapf = "^0.32.0"
|
||||
python-lsp-server = "^1.7.3"
|
||||
mypy = "^1.4.1"
|
||||
django-stubs = "^4.2.3"
|
||||
pylint-django = "^2.5.3"
|
||||
execnet = "~1.9.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
|
|
|
@ -11,8 +11,6 @@ def backup_view_permission(old_fuction):
|
|||
if user.has_perm("customers.view_customer", backup.computer.customer):
|
||||
return old_fuction(request, pk)
|
||||
else:
|
||||
return HttpResponseForbidden(
|
||||
"You're not allowed to access this device."
|
||||
)
|
||||
return HttpResponseForbidden("You're not allowed to access this device.")
|
||||
|
||||
return new_function
|
||||
|
|
|
@ -20,18 +20,12 @@ class Backup(models.Model):
|
|||
computer = models.ForeignKey(
|
||||
Computer, related_name="source_computer", on_delete=models.CASCADE
|
||||
)
|
||||
method = models.ForeignKey(
|
||||
BackupMethod, models.SET_NULL, blank=True, null=True
|
||||
)
|
||||
software = models.ForeignKey(
|
||||
Software, models.SET_NULL, blank=True, null=True
|
||||
)
|
||||
method = models.ForeignKey(BackupMethod, models.SET_NULL, blank=True, null=True)
|
||||
software = models.ForeignKey(Software, models.SET_NULL, blank=True, null=True)
|
||||
source_path = models.CharField(max_length=200, blank=True)
|
||||
exec_time = models.TimeField(null=True, blank=True)
|
||||
exec_days = models.ManyToManyField(Weekday, blank=True)
|
||||
target_device = models.ManyToManyField(
|
||||
Computer, through="TargetDevice", blank=True
|
||||
)
|
||||
target_device = models.ManyToManyField(Computer, through="TargetDevice", blank=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ["name"]
|
||||
|
@ -50,9 +44,7 @@ class Backup(models.Model):
|
|||
|
||||
|
||||
class TargetDevice(models.Model):
|
||||
device = models.ForeignKey(
|
||||
Computer, models.SET_NULL, blank=True, null=True
|
||||
)
|
||||
device = models.ForeignKey(Computer, models.SET_NULL, blank=True, null=True)
|
||||
backup = models.ForeignKey(Backup, on_delete=models.CASCADE)
|
||||
target_path = models.CharField(max_length=200, blank=True)
|
||||
|
||||
|
|
|
@ -53,9 +53,7 @@ def test_backup_detail_view_with_target_device(create_admin_user):
|
|||
software=mixer.SELECT,
|
||||
method=mixer.SELECT,
|
||||
)
|
||||
mixer.blend(
|
||||
"backups.TargetDevice", device=target_computer, backup=mixer.SELECT
|
||||
)
|
||||
mixer.blend("backups.TargetDevice", device=target_computer, backup=mixer.SELECT)
|
||||
client = Client()
|
||||
client.login(username="pharma-admin", password="password")
|
||||
response = client.get("/backup/" + str(backup.id) + "/")
|
||||
|
@ -79,9 +77,7 @@ def test_backup_detail_view_with_notification(create_admin_user):
|
|||
client = Client()
|
||||
client.login(username="pharma-admin", password="password")
|
||||
response = client.get("/backup/" + str(backup.id) + "/")
|
||||
assert response.status_code == 200 and helper.in_content(
|
||||
response, notification
|
||||
)
|
||||
assert response.status_code == 200 and helper.in_content(response, notification)
|
||||
|
||||
|
||||
def test_backup_detail_view_with_day_relation(create_admin_user):
|
||||
|
|
|
@ -23,9 +23,7 @@ def test_customer_backup_table(create_admin_user):
|
|||
computer = mixer.blend("computers.Computer", customer=customer)
|
||||
backup = mixer.blend("backups.Backup", computer=computer)
|
||||
response = client.get("/customer/" + str(customer.id) + "/backups/")
|
||||
assert response.status_code == 200 and helper.in_content(
|
||||
response, backup.name
|
||||
)
|
||||
assert response.status_code == 200 and helper.in_content(response, backup.name)
|
||||
|
||||
|
||||
def test_customer_backup_table_no_backup(create_admin_user):
|
||||
|
|
|
@ -3,9 +3,7 @@ from django.urls import path
|
|||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
"customer/<int:pk>/backups/", views.backups_table_view, name="backups"
|
||||
),
|
||||
path("customer/<int:pk>/backups/", views.backups_table_view, name="backups"),
|
||||
path("backup/<int:pk>/", views.backup_detail_view, name="backup"),
|
||||
path(
|
||||
"create/backup-for-computer/<int:pk>/",
|
||||
|
|
|
@ -47,7 +47,7 @@ def backup_detail_view(request, pk):
|
|||
class BackupCreateView(LoginRequiredMixin, CreateView):
|
||||
model = Backup
|
||||
template_name = "backups/backup_create.html"
|
||||
fields = "__all__"
|
||||
fields = "__all__" # type: ignore
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse("computer", args=(self.computer.pk,))
|
||||
|
@ -63,7 +63,7 @@ class BackupCreateView(LoginRequiredMixin, CreateView):
|
|||
}
|
||||
|
||||
|
||||
class BackupDeleteView(LoginRequiredMixin, DeleteView):
|
||||
class BackupDeleteView(LoginRequiredMixin, DeleteView): # type: ignore
|
||||
model = Backup
|
||||
template_name = "backups/backup_confirm_delete.html"
|
||||
|
||||
|
@ -71,7 +71,7 @@ class BackupDeleteView(LoginRequiredMixin, DeleteView):
|
|||
return reverse("computer", args=(self.object.computer.pk,))
|
||||
|
||||
|
||||
class BackupDeleteFromTableView(LoginRequiredMixin, DeleteView):
|
||||
class BackupDeleteFromTableView(LoginRequiredMixin, DeleteView): # type: ignore
|
||||
model = Backup
|
||||
template_name = "backups/backup_confirm_delete.html"
|
||||
|
||||
|
|
|
@ -26,62 +26,64 @@ from .models import (
|
|||
)
|
||||
|
||||
|
||||
class SoftwareInLine(nested_admin.NestedStackedInline):
|
||||
class SoftwareInLine(nested_admin.NestedStackedInline): # pylint: disable=no-member
|
||||
model = ComputerSoftwareRelation
|
||||
extra = 0
|
||||
verbose_name_plural = "Software"
|
||||
|
||||
|
||||
class RamInLine(nested_admin.NestedStackedInline):
|
||||
class RamInLine(nested_admin.NestedStackedInline): # pylint: disable=no-member
|
||||
model = ComputerRamRelation
|
||||
extra = 0
|
||||
verbose_name_plural = "RAM Modules"
|
||||
|
||||
|
||||
class DiskInLine(nested_admin.NestedStackedInline):
|
||||
class DiskInLine(nested_admin.NestedStackedInline): # pylint: disable=no-member
|
||||
model = ComputerDiskRelation
|
||||
extra = 0
|
||||
verbose_name_plural = "Disks"
|
||||
|
||||
|
||||
class DisksInRaidInLine(nested_admin.NestedStackedInline):
|
||||
class DisksInRaidInLine(nested_admin.NestedStackedInline): # pylint: disable=no-member
|
||||
model = DisksInRaid
|
||||
extra = 0
|
||||
verbose_name_plural = "Disks in RAID"
|
||||
|
||||
|
||||
class CpusInLine(nested_admin.NestedStackedInline):
|
||||
class CpusInLine(nested_admin.NestedStackedInline): # pylint: disable=no-member
|
||||
model = ComputerCpuRelation
|
||||
extra = 0
|
||||
verbose_name_plural = "CPUs"
|
||||
|
||||
|
||||
class GpusInLine(nested_admin.NestedStackedInline):
|
||||
class GpusInLine(nested_admin.NestedStackedInline): # pylint: disable=no-member
|
||||
model = ComputerGpuRelation
|
||||
extra = 0
|
||||
verbose_name_plural = "GPUs"
|
||||
|
||||
|
||||
class RaidInLine(nested_admin.NestedStackedInline):
|
||||
class RaidInLine(nested_admin.NestedStackedInline): # pylint: disable=no-member
|
||||
model = Raid
|
||||
extra = 0
|
||||
verbose_name_plural = "RAID"
|
||||
inlines = (DisksInRaidInLine,)
|
||||
|
||||
|
||||
class DeviceInNetInline(nested_admin.NestedStackedInline):
|
||||
class DeviceInNetInline(nested_admin.NestedStackedInline): # pylint: disable=no-member
|
||||
model = DeviceInNet
|
||||
extra = 0
|
||||
verbose_name_plural = "Nets"
|
||||
|
||||
|
||||
class LicenseWithComputerInLine(nested_admin.NestedStackedInline):
|
||||
class LicenseWithComputerInLine(
|
||||
nested_admin.NestedStackedInline
|
||||
): # pylint: disable=no-member
|
||||
model = LicenseWithComputer
|
||||
extra = 0
|
||||
verbose_name_plural = "Licenses"
|
||||
|
||||
|
||||
class ComputerAdmin(nested_admin.NestedModelAdmin):
|
||||
class ComputerAdmin(nested_admin.NestedModelAdmin): # pylint: disable=no-member
|
||||
list_display = ("name", "host")
|
||||
inlines = (
|
||||
SoftwareInLine,
|
||||
|
|
|
@ -41,15 +41,9 @@ class ComputerUpdateForm(forms.ModelForm):
|
|||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(ComputerUpdateForm, self).__init__(*args, **kwargs)
|
||||
customers = utils.objects_for_allowed_customers(
|
||||
Customer, user=request.user
|
||||
)
|
||||
locations = utils.objects_for_allowed_customers(
|
||||
Location, user=request.user
|
||||
)
|
||||
hosts = utils.objects_for_allowed_customers(
|
||||
Computer, user=request.user
|
||||
)
|
||||
customers = utils.objects_for_allowed_customers(Customer, user=request.user)
|
||||
locations = utils.objects_for_allowed_customers(Location, user=request.user)
|
||||
hosts = utils.objects_for_allowed_customers(Computer, user=request.user)
|
||||
users = utils.objects_for_allowed_customers(User, user=request.user)
|
||||
self.fields["customer"].queryset = customers
|
||||
self.fields["location"].queryset = locations
|
||||
|
|
|
@ -23,12 +23,8 @@ class Computer(Device):
|
|||
ram = models.ManyToManyField(Ram, through="ComputerRamRelation")
|
||||
gpu = models.ManyToManyField(Gpu, through="ComputerGpuRelation")
|
||||
disks = models.ManyToManyField(Disk, through="ComputerDiskRelation")
|
||||
software = models.ManyToManyField(
|
||||
Software, through="ComputerSoftwareRelation"
|
||||
)
|
||||
host = models.ForeignKey(
|
||||
"self", null=True, blank=True, on_delete=models.CASCADE
|
||||
)
|
||||
software = models.ManyToManyField(Software, through="ComputerSoftwareRelation")
|
||||
host = models.ForeignKey("self", null=True, blank=True, on_delete=models.CASCADE)
|
||||
allocated_space = models.IntegerField(null=True, blank=True)
|
||||
|
||||
def __str__(self):
|
||||
|
|
|
@ -12,9 +12,7 @@ class RaidType(Category):
|
|||
|
||||
class Raid(models.Model):
|
||||
usable_space = models.IntegerField(blank=True, null=True)
|
||||
raid_type = models.ForeignKey(
|
||||
RaidType, models.SET_NULL, blank=True, null=True
|
||||
)
|
||||
raid_type = models.ForeignKey(RaidType, models.SET_NULL, blank=True, null=True)
|
||||
computer = models.ForeignKey(Computer, on_delete=models.CASCADE)
|
||||
|
||||
def __str__(self):
|
||||
|
|
|
@ -15,15 +15,11 @@ def test_computer_detail_view_not_logged_in():
|
|||
|
||||
def test_computer_detail_view(create_admin_user):
|
||||
create_admin_user()
|
||||
computer = mixer.blend(
|
||||
"computers.Computer", customer=mixer.SELECT, os=mixer.SELECT
|
||||
)
|
||||
computer = mixer.blend("computers.Computer", customer=mixer.SELECT, os=mixer.SELECT)
|
||||
client = Client()
|
||||
client.login(username="pharma-admin", password="password")
|
||||
response = client.get("/computer/" + str(computer.id) + "/")
|
||||
assert response.status_code == 200 and helper.in_content(
|
||||
response, computer
|
||||
)
|
||||
assert response.status_code == 200 and helper.in_content(response, computer)
|
||||
|
||||
|
||||
def test_computer_detail_view_not_found(create_admin_user):
|
||||
|
@ -43,9 +39,7 @@ def test_computer_detail_view_ram_relation(create_admin_user):
|
|||
client = Client()
|
||||
client.login(username="pharma-admin", password="password")
|
||||
response = client.get("/computer/" + str(computer.id) + "/")
|
||||
assert response.status_code == 200 and helper.in_content(
|
||||
response, "RAM Modules:"
|
||||
)
|
||||
assert response.status_code == 200 and helper.in_content(response, "RAM Modules:")
|
||||
|
||||
|
||||
def test_computer_detail_view_raid_relation(create_admin_user):
|
||||
|
@ -53,9 +47,7 @@ def test_computer_detail_view_raid_relation(create_admin_user):
|
|||
computer = mixer.blend("computers.Computer", customer=mixer.SELECT)
|
||||
raid_type = mixer.blend("computers.RaidType")
|
||||
disk = mixer.blend("computers.Disk")
|
||||
raid = mixer.blend(
|
||||
"computers.Raid", computer=computer, raid_type=raid_type
|
||||
)
|
||||
raid = mixer.blend("computers.Raid", computer=computer, raid_type=raid_type)
|
||||
mixer.blend("computers.DisksInRaid", raid=raid, disk=disk)
|
||||
client = Client()
|
||||
client.login(username="pharma-admin", password="password")
|
||||
|
|
|
@ -12,9 +12,7 @@ def test_computer_create_form(create_admin_user):
|
|||
fixture = create_admin_user()
|
||||
user = mixer.blend("core.InventoryUser", customer=fixture["customer"])
|
||||
form = forms.ComputerCreateForm(user=user, data={})
|
||||
assert (
|
||||
form.is_valid() is False
|
||||
), "Should be false because no data was given"
|
||||
assert form.is_valid() is False, "Should be false because no data was given"
|
||||
|
||||
data = {"name": "pharma-pc1", "customer": 3}
|
||||
form = forms.ComputerCreateForm(user=user, data=data)
|
||||
|
@ -32,9 +30,7 @@ def test_computer_update_form(create_admin_user):
|
|||
request = HttpRequest()
|
||||
request.user = fixture["admin"]
|
||||
form = forms.ComputerUpdateForm(request, data={})
|
||||
assert (
|
||||
form.is_valid() is False
|
||||
), "Should be false because no data was given"
|
||||
assert form.is_valid() is False, "Should be false because no data was given"
|
||||
|
||||
data = {"name": "pharma-pc1", "customer": 20356}
|
||||
form = forms.ComputerUpdateForm(request, data=data)
|
||||
|
|
|
@ -27,6 +27,4 @@ def test_computer_list_view(create_admin_user):
|
|||
client = Client()
|
||||
client.login(username="pharma-admin", password="password")
|
||||
response = client.get("/computers/all/")
|
||||
assert response.status_code == 200 and helper.in_content(
|
||||
response, computer
|
||||
)
|
||||
assert response.status_code == 200 and helper.in_content(response, computer)
|
||||
|
|
|
@ -21,9 +21,7 @@ def test_customer_computer_table(create_admin_user):
|
|||
client.login(username="pharma-admin", password="password")
|
||||
computer = mixer.blend("computers.Computer", customer=mixer.SELECT)
|
||||
response = client.get("/customer/" + str(customer.id) + "/computers/")
|
||||
assert response.status_code == 200 and helper.in_content(
|
||||
response, computer
|
||||
)
|
||||
assert response.status_code == 200 and helper.in_content(response, computer)
|
||||
|
||||
|
||||
def test_customer_computer_table_no_computer(create_admin_user):
|
||||
|
|
|
@ -41,9 +41,7 @@ from .tables import ComputersTable
|
|||
|
||||
@login_required
|
||||
def computer_detail_view(request, pk):
|
||||
device = utils.get_object_with_view_permission(
|
||||
Computer, user=request.user, pk=pk
|
||||
)
|
||||
device = utils.get_object_with_view_permission(Computer, user=request.user, pk=pk)
|
||||
disks_relations = ComputerDiskRelation.objects.filter(computer=pk)
|
||||
warranty_relations = Warranty.objects.filter(device=pk)
|
||||
ram_relations = ComputerRamRelation.objects.filter(computer=pk)
|
||||
|
@ -76,9 +74,7 @@ def computer_detail_view(request, pk):
|
|||
@login_required
|
||||
def computers_table_view(request, pk):
|
||||
table = ComputersTable(
|
||||
utils.get_objects_for_customer(
|
||||
Computer, user=request.user, customer_pk=pk
|
||||
)
|
||||
utils.get_objects_for_customer(Computer, user=request.user, customer_pk=pk)
|
||||
)
|
||||
RequestConfig(request).configure(table)
|
||||
return render(
|
||||
|
@ -139,9 +135,7 @@ def computer_update_view(request, pk):
|
|||
A view to create a customer.
|
||||
"""
|
||||
template_name = "computers/computer_update.html"
|
||||
computer = utils.get_object_with_view_permission(
|
||||
Computer, user=request.user, pk=pk
|
||||
)
|
||||
computer = utils.get_object_with_view_permission(Computer, user=request.user, pk=pk)
|
||||
if request.method == "POST":
|
||||
form = ComputerUpdateForm(request, request.POST, instance=computer)
|
||||
if form.is_valid():
|
||||
|
@ -152,7 +146,7 @@ def computer_update_view(request, pk):
|
|||
return TemplateResponse(request, template_name, {"form": form})
|
||||
|
||||
|
||||
class ComputerDeleteView(LoginRequiredMixin, DeleteView):
|
||||
class ComputerDeleteView(LoginRequiredMixin, DeleteView): # type: ignore
|
||||
model = Computer
|
||||
|
||||
def get_success_url(self):
|
||||
|
@ -178,7 +172,7 @@ class ComputerRamRelationCreateView(LoginRequiredMixin, CreateView):
|
|||
}
|
||||
|
||||
|
||||
class ComputerRamRelationDeleteView(LoginRequiredMixin, DeleteView):
|
||||
class ComputerRamRelationDeleteView(LoginRequiredMixin, DeleteView): # type: ignore
|
||||
model = ComputerRamRelation
|
||||
template_name = "computers/relation_confirm_delete.html"
|
||||
|
||||
|
@ -205,7 +199,7 @@ class ComputerCpuRelationCreateView(LoginRequiredMixin, CreateView):
|
|||
}
|
||||
|
||||
|
||||
class ComputerCpuRelationDeleteView(LoginRequiredMixin, DeleteView):
|
||||
class ComputerCpuRelationDeleteView(LoginRequiredMixin, DeleteView): # type: ignore
|
||||
model = ComputerCpuRelation
|
||||
template_name = "computers/relation_confirm_delete.html"
|
||||
|
||||
|
@ -232,7 +226,7 @@ class ComputerGpuRelationCreateView(LoginRequiredMixin, CreateView):
|
|||
}
|
||||
|
||||
|
||||
class ComputerGpuRelationDeleteView(LoginRequiredMixin, DeleteView):
|
||||
class ComputerGpuRelationDeleteView(LoginRequiredMixin, DeleteView): # type: ignore
|
||||
model = ComputerGpuRelation
|
||||
template_name = "computers/relation_confirm_delete.html"
|
||||
|
||||
|
@ -259,7 +253,7 @@ class ComputerDiskRelationCreateView(LoginRequiredMixin, CreateView):
|
|||
}
|
||||
|
||||
|
||||
class ComputerDiskRelationDeleteView(LoginRequiredMixin, DeleteView):
|
||||
class ComputerDiskRelationDeleteView(LoginRequiredMixin, DeleteView): # type: ignore
|
||||
model = ComputerDiskRelation
|
||||
template_name = "computers/relation_confirm_delete.html"
|
||||
|
||||
|
@ -286,7 +280,7 @@ class ComputerSoftwareRelationCreateView(LoginRequiredMixin, CreateView):
|
|||
}
|
||||
|
||||
|
||||
class ComputerSoftwareRelationDeleteView(LoginRequiredMixin, DeleteView):
|
||||
class ComputerSoftwareRelationDeleteView(LoginRequiredMixin, DeleteView): # type: ignore
|
||||
model = ComputerSoftwareRelation
|
||||
template_name = "computers/relation_confirm_delete.html"
|
||||
|
||||
|
@ -313,7 +307,7 @@ class RaidCreateView(LoginRequiredMixin, CreateView):
|
|||
}
|
||||
|
||||
|
||||
class RaidDeleteView(LoginRequiredMixin, DeleteView):
|
||||
class RaidDeleteView(LoginRequiredMixin, DeleteView): # type: ignore
|
||||
model = Raid
|
||||
template_name = "computers/relation_confirm_delete.html"
|
||||
|
||||
|
|
|
@ -22,9 +22,7 @@ def django_db_setup(django_db_setup, django_db_blocker):
|
|||
def create_admin_user():
|
||||
def _create_admin_user():
|
||||
User = get_user_model()
|
||||
admin = User.objects.create_user(
|
||||
"pharma-admin", "admin@pharma.com", "password"
|
||||
)
|
||||
admin = User.objects.create_user("pharma-admin", "admin@pharma.com", "password")
|
||||
customer = mixer.blend("customers.Customer")
|
||||
group = Group.objects.create(name="Pharma Corp. Admin")
|
||||
admin.groups.add(group)
|
||||
|
|
|
@ -15,9 +15,7 @@ def test_get_object_with_view_permission(create_admin_user):
|
|||
fixture = create_admin_user()
|
||||
customer = fixture["customer"]
|
||||
admin = fixture["admin"]
|
||||
object = utils.get_object_with_view_permission(
|
||||
Customer, user=admin, pk=customer.id
|
||||
)
|
||||
object = utils.get_object_with_view_permission(Customer, user=admin, pk=customer.id)
|
||||
assert object == customer
|
||||
|
||||
|
||||
|
@ -26,9 +24,7 @@ def test_get_object_with_view_permission_device(create_admin_user):
|
|||
customer = fixture["customer"]
|
||||
admin = fixture["admin"]
|
||||
device = mixer.blend(Device, customer=customer)
|
||||
object = utils.get_object_with_view_permission(
|
||||
Device, user=admin, pk=device.id
|
||||
)
|
||||
object = utils.get_object_with_view_permission(Device, user=admin, pk=device.id)
|
||||
assert object == device
|
||||
|
||||
|
||||
|
@ -37,9 +33,7 @@ def test_get_object_without_view_permission(create_admin_user):
|
|||
customer = mixer.blend(Customer)
|
||||
admin = fixture["admin"]
|
||||
with pytest.raises(Http404):
|
||||
utils.get_object_with_view_permission(
|
||||
Customer, user=admin, pk=customer.id
|
||||
)
|
||||
utils.get_object_with_view_permission(Customer, user=admin, pk=customer.id)
|
||||
|
||||
|
||||
def test_get_object_without_view_permission_device(create_admin_user):
|
||||
|
|
|
@ -16,9 +16,7 @@ def test_get_objects_for_customer_with_customer(create_admin_user):
|
|||
customer = fixture["customer"]
|
||||
admin = fixture["admin"]
|
||||
with pytest.raises(Exception):
|
||||
utils.get_objects_for_customer(
|
||||
Customer, user=admin, customer_pk=customer.id
|
||||
)
|
||||
utils.get_objects_for_customer(Customer, user=admin, customer_pk=customer.id)
|
||||
|
||||
|
||||
def test_get_objects_for_customer_device(create_admin_user):
|
||||
|
@ -37,9 +35,7 @@ def test_get_all_objects_for_unallowed_customers(create_admin_user):
|
|||
customer = mixer.blend(Customer)
|
||||
admin = fixture["admin"]
|
||||
with pytest.raises(Http404):
|
||||
utils.get_objects_for_customer(
|
||||
Customer, user=admin, customer_pk=customer.id
|
||||
)
|
||||
utils.get_objects_for_customer(Customer, user=admin, customer_pk=customer.id)
|
||||
|
||||
|
||||
def test_get_all_objects_for_unallowed_customers_device(create_admin_user):
|
||||
|
@ -48,6 +44,4 @@ def test_get_all_objects_for_unallowed_customers_device(create_admin_user):
|
|||
admin = fixture["admin"]
|
||||
mixer.blend(Device, customer=customer)
|
||||
with pytest.raises(Http404):
|
||||
utils.get_objects_for_customer(
|
||||
Device, user=admin, customer_pk=customer.id
|
||||
)
|
||||
utils.get_objects_for_customer(Device, user=admin, customer_pk=customer.id)
|
||||
|
|
|
@ -34,9 +34,7 @@ def _get_customers(user):
|
|||
|
||||
user : django.contrib.auth.models.User
|
||||
"""
|
||||
return get_objects_for_user(
|
||||
user, "customers.view_customer", klass=Customer
|
||||
)
|
||||
return get_objects_for_user(user, "customers.view_customer", klass=Customer)
|
||||
|
||||
|
||||
def get_object_with_view_permission(model, user=None, pk=None):
|
||||
|
|
|
@ -10,8 +10,6 @@ def customer_view_permission(old_function):
|
|||
if user.has_perm("customers.view_customer", customer):
|
||||
return old_function(request, pk)
|
||||
else:
|
||||
return HttpResponseForbidden(
|
||||
"You're not allowed to access this page."
|
||||
)
|
||||
return HttpResponseForbidden("You're not allowed to access this page.")
|
||||
|
||||
return new_function
|
||||
|
|
|
@ -43,4 +43,4 @@ class DummyLocation(models.Model):
|
|||
location = models.ForeignKey(Location, on_delete=models.CASCADE)
|
||||
|
||||
def __str__(self):
|
||||
return self.location
|
||||
return self.location.name
|
||||
|
|
|
@ -6,9 +6,7 @@ from core.tables import CoreTable
|
|||
|
||||
class CustomersTable(CoreTable):
|
||||
name = tables.LinkColumn("customer", args=[A("pk")])
|
||||
nets = tables.LinkColumn(
|
||||
"nets", text="Nets", args=[A("pk")], orderable=False
|
||||
)
|
||||
nets = tables.LinkColumn("nets", text="Nets", args=[A("pk")], orderable=False)
|
||||
computers = tables.LinkColumn(
|
||||
"computers", text="Computers", args=[A("pk")], orderable=False
|
||||
)
|
||||
|
@ -21,12 +19,8 @@ class CustomersTable(CoreTable):
|
|||
licenses = tables.LinkColumn(
|
||||
"licenses", text="Licenses", args=[A("pk")], orderable=False
|
||||
)
|
||||
users = tables.LinkColumn(
|
||||
"users", text="Users", args=[A("pk")], orderable=False
|
||||
)
|
||||
groups = tables.LinkColumn(
|
||||
"groups", text="Groups", args=[A("pk")], orderable=False
|
||||
)
|
||||
users = tables.LinkColumn("users", text="Users", args=[A("pk")], orderable=False)
|
||||
groups = tables.LinkColumn("groups", text="Groups", args=[A("pk")], orderable=False)
|
||||
project_manager = tables.Column(verbose_name="Project Manager")
|
||||
delete = tables.LinkColumn(
|
||||
"customer_delete",
|
||||
|
|
|
@ -42,24 +42,12 @@ def test_customer_list_view(create_admin_user):
|
|||
assert (
|
||||
response.status_code == 200
|
||||
and helper.in_content(response, customer)
|
||||
and helper.in_content(
|
||||
response, "/customer/" + str(customer.id) + "/nets/"
|
||||
)
|
||||
and helper.in_content(
|
||||
response, "/customer/" + str(customer.id) + "/computers/"
|
||||
)
|
||||
and helper.in_content(
|
||||
response, "/customer/" + str(customer.id) + "/devices/"
|
||||
)
|
||||
and helper.in_content(
|
||||
response, "/customer/" + str(customer.id) + "/backups/"
|
||||
)
|
||||
and helper.in_content(
|
||||
response, "/customer/" + str(customer.id) + "/licenses/"
|
||||
)
|
||||
and helper.in_content(
|
||||
response, "/customer/" + str(customer.id) + "/users/"
|
||||
)
|
||||
and helper.in_content(response, "/customer/" + str(customer.id) + "/nets/")
|
||||
and helper.in_content(response, "/customer/" + str(customer.id) + "/computers/")
|
||||
and helper.in_content(response, "/customer/" + str(customer.id) + "/devices/")
|
||||
and helper.in_content(response, "/customer/" + str(customer.id) + "/backups/")
|
||||
and helper.in_content(response, "/customer/" + str(customer.id) + "/licenses/")
|
||||
and helper.in_content(response, "/customer/" + str(customer.id) + "/users/")
|
||||
and helper.in_content(response, project_manager)
|
||||
)
|
||||
|
||||
|
@ -75,41 +63,21 @@ def test_customer_list_view_multiple_customers(create_admin_user):
|
|||
assert (
|
||||
response.status_code == 200
|
||||
and helper.in_content(response, customer1)
|
||||
and helper.in_content(
|
||||
response, "/customer/" + str(customer1.id) + "/nets/"
|
||||
)
|
||||
and helper.in_content(response, "/customer/" + str(customer1.id) + "/nets/")
|
||||
and helper.in_content(
|
||||
response, "/customer/" + str(customer1.id) + "/computers/"
|
||||
)
|
||||
and helper.in_content(
|
||||
response, "/customer/" + str(customer1.id) + "/devices/"
|
||||
)
|
||||
and helper.in_content(
|
||||
response, "/customer/" + str(customer1.id) + "/backups/"
|
||||
)
|
||||
and helper.in_content(
|
||||
response, "/customer/" + str(customer1.id) + "/licenses/"
|
||||
)
|
||||
and helper.in_content(
|
||||
response, "/customer/" + str(customer1.id) + "/users/"
|
||||
)
|
||||
and helper.in_content(response, "/customer/" + str(customer1.id) + "/devices/")
|
||||
and helper.in_content(response, "/customer/" + str(customer1.id) + "/backups/")
|
||||
and helper.in_content(response, "/customer/" + str(customer1.id) + "/licenses/")
|
||||
and helper.in_content(response, "/customer/" + str(customer1.id) + "/users/")
|
||||
and helper.in_content(response, customer2)
|
||||
and helper.in_content(
|
||||
response, "/customer/" + str(customer2.id) + "/nets/"
|
||||
)
|
||||
and helper.in_content(response, "/customer/" + str(customer2.id) + "/nets/")
|
||||
and helper.in_content(
|
||||
response, "/customer/" + str(customer2.id) + "/computers/"
|
||||
)
|
||||
and helper.in_content(
|
||||
response, "/customer/" + str(customer2.id) + "/devices/"
|
||||
)
|
||||
and helper.in_content(
|
||||
response, "/customer/" + str(customer2.id) + "/backups/"
|
||||
)
|
||||
and helper.in_content(
|
||||
response, "/customer/" + str(customer2.id) + "/licenses/"
|
||||
)
|
||||
and helper.in_content(
|
||||
response, "/customer/" + str(customer1.id) + "/users/"
|
||||
)
|
||||
and helper.in_content(response, "/customer/" + str(customer2.id) + "/devices/")
|
||||
and helper.in_content(response, "/customer/" + str(customer2.id) + "/backups/")
|
||||
and helper.in_content(response, "/customer/" + str(customer2.id) + "/licenses/")
|
||||
and helper.in_content(response, "/customer/" + str(customer1.id) + "/users/")
|
||||
)
|
||||
|
|
|
@ -10,9 +10,7 @@ def test_location_form(create_admin_user):
|
|||
fixture = create_admin_user()
|
||||
user = fixture["admin"]
|
||||
form = forms.LocationForm(user=user, data={})
|
||||
assert (
|
||||
form.is_valid() is False
|
||||
), "Should be false because no data was given"
|
||||
assert form.is_valid() is False, "Should be false because no data was given"
|
||||
|
||||
data = {"name": "Main Office", "customer": 3}
|
||||
form = forms.LocationForm(user=user, data=data)
|
||||
|
|
|
@ -14,9 +14,7 @@ def test_load_htmx_create_location_view(create_admin_user):
|
|||
client.login(username="pharma-admin", password="password")
|
||||
url = "/create/location/"
|
||||
response = client.get(url)
|
||||
assert response.status_code == 200 and helper.in_content(
|
||||
response, "Add Location"
|
||||
)
|
||||
assert response.status_code == 200 and helper.in_content(response, "Add Location")
|
||||
|
||||
|
||||
def test_htmx_create_location_view(create_admin_user):
|
||||
|
@ -25,9 +23,7 @@ def test_htmx_create_location_view(create_admin_user):
|
|||
client.login(username="pharma-admin", password="password")
|
||||
data = {"name": mixer.faker.name(), "save_location": 1}
|
||||
response = client.post("/create/location/", data)
|
||||
assert response.status_code == 200 and helper.in_content(
|
||||
response, data["name"]
|
||||
)
|
||||
assert response.status_code == 200 and helper.in_content(response, data["name"])
|
||||
|
||||
|
||||
def test_htmx_create_location_view_invalid_form(create_admin_user):
|
||||
|
|
|
@ -24,9 +24,7 @@ def customers_table_view(request):
|
|||
customers = utils.objects_for_allowed_customers(Customer, request.user)
|
||||
table = CustomersTable(customers)
|
||||
RequestConfig(request).configure(table)
|
||||
return render(
|
||||
request, "customers/customer_list.html", {"customers": table}
|
||||
)
|
||||
return render(request, "customers/customer_list.html", {"customers": table})
|
||||
|
||||
|
||||
@login_required
|
||||
|
@ -44,23 +42,17 @@ def create_customer(request):
|
|||
)
|
||||
form = CustomerForm()
|
||||
context = {"form": form}
|
||||
return TemplateResponse(
|
||||
request, "customers/partials/customer_create.html", context
|
||||
)
|
||||
return TemplateResponse(request, "customers/partials/customer_create.html", context)
|
||||
|
||||
|
||||
@login_required
|
||||
def customer_detail_view(request, pk):
|
||||
customer = utils.get_object_with_view_permission(
|
||||
Customer, user=request.user, pk=pk
|
||||
)
|
||||
customer = utils.get_object_with_view_permission(Customer, user=request.user, pk=pk)
|
||||
context = {"customer": customer}
|
||||
return TemplateResponse(
|
||||
request, "customers/customer_details.html", context
|
||||
)
|
||||
return TemplateResponse(request, "customers/customer_details.html", context)
|
||||
|
||||
|
||||
class CustomerDeleteView(LoginRequiredMixin, DeleteView):
|
||||
class CustomerDeleteView(LoginRequiredMixin, DeleteView): # type: ignore
|
||||
model = Customer
|
||||
|
||||
def get_success_url(self):
|
||||
|
|
|
@ -12,13 +12,13 @@ from .models import (
|
|||
)
|
||||
|
||||
|
||||
class DeviceInNetInline(nested_admin.NestedStackedInline):
|
||||
class DeviceInNetInline(nested_admin.NestedStackedInline): # pylint: disable=no-member
|
||||
model = DeviceInNet
|
||||
extra = 0
|
||||
verbose_name_plural = "Nets"
|
||||
|
||||
|
||||
class DeviceAdmin(nested_admin.NestedModelAdmin):
|
||||
class DeviceAdmin(nested_admin.NestedModelAdmin): # pylint: disable=no-member
|
||||
inlines = (DeviceInNetInline,)
|
||||
|
||||
|
||||
|
|
|
@ -11,8 +11,6 @@ def device_view_permission(old_function):
|
|||
if user.has_perm("customers.view_customer", device.customer):
|
||||
return old_function(request, pk)
|
||||
else:
|
||||
return HttpResponseForbidden(
|
||||
"You're not allowed to access this device."
|
||||
)
|
||||
return HttpResponseForbidden("You're not allowed to access this device.")
|
||||
|
||||
return new_function
|
||||
|
|
|
@ -69,12 +69,8 @@ class DeviceUpdateForm(forms.ModelForm):
|
|||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(DeviceUpdateForm, self).__init__(*args, **kwargs)
|
||||
customers = utils.objects_for_allowed_customers(
|
||||
Customer, user=request.user
|
||||
)
|
||||
locations = utils.objects_for_allowed_customers(
|
||||
Location, user=request.user
|
||||
)
|
||||
customers = utils.objects_for_allowed_customers(Customer, user=request.user)
|
||||
locations = utils.objects_for_allowed_customers(Location, user=request.user)
|
||||
users = utils.objects_for_allowed_customers(User, user=request.user)
|
||||
self.fields["customer"].queryset = customers
|
||||
self.fields["location"].queryset = locations
|
||||
|
|
|
@ -38,9 +38,7 @@ class DeviceCategory(Category):
|
|||
|
||||
class HardwareModel(models.Model):
|
||||
name = models.CharField(max_length=50)
|
||||
manufacturer = models.ForeignKey(
|
||||
DeviceManufacturer, on_delete=models.CASCADE
|
||||
)
|
||||
manufacturer = models.ForeignKey(DeviceManufacturer, on_delete=models.CASCADE)
|
||||
|
||||
class Meta:
|
||||
ordering = ["name"]
|
||||
|
@ -56,19 +54,13 @@ class Device(models.Model):
|
|||
category = models.ForeignKey(
|
||||
DeviceCategory, on_delete=models.SET_NULL, null=True, blank=True
|
||||
)
|
||||
owner = models.ForeignKey(
|
||||
Owner, on_delete=models.SET_NULL, null=True, blank=True
|
||||
)
|
||||
owner = models.ForeignKey(Owner, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
|
||||
manufacturer = models.ForeignKey(
|
||||
DeviceManufacturer, models.SET_NULL, null=True, blank=True
|
||||
)
|
||||
model = models.ForeignKey(
|
||||
HardwareModel, models.SET_NULL, null=True, blank=True
|
||||
)
|
||||
location = models.ForeignKey(
|
||||
Location, models.SET_NULL, null=True, blank=True
|
||||
)
|
||||
model = models.ForeignKey(HardwareModel, models.SET_NULL, null=True, blank=True)
|
||||
location = models.ForeignKey(Location, models.SET_NULL, null=True, blank=True)
|
||||
user = models.ForeignKey(User, models.SET_NULL, null=True, blank=True)
|
||||
installation_date = models.DateField(null=True, blank=True)
|
||||
net = models.ManyToManyField(Net, through="DeviceInNet")
|
||||
|
|
|
@ -16,9 +16,7 @@ class WarrantyType(Category):
|
|||
|
||||
|
||||
class Warranty(models.Model):
|
||||
customer = models.ForeignKey(
|
||||
Customer, on_delete=models.CASCADE, blank=True
|
||||
)
|
||||
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, blank=True)
|
||||
device = models.ForeignKey(Device, on_delete=models.CASCADE)
|
||||
valid_from = models.DateField()
|
||||
valid_until = models.DateField()
|
||||
|
|
|
@ -12,9 +12,7 @@ def test_device_create_form(create_admin_user):
|
|||
fixture = create_admin_user()
|
||||
user = mixer.blend("core.InventoryUser", customer=fixture["customer"])
|
||||
form = forms.DeviceCreateForm(user=user, data={})
|
||||
assert (
|
||||
form.is_valid() is False
|
||||
), "Should be false because no data was given"
|
||||
assert form.is_valid() is False, "Should be false because no data was given"
|
||||
|
||||
data = {"name": "pharma-device1", "customer": 3}
|
||||
form = forms.DeviceCreateForm(user=user, data=data)
|
||||
|
@ -32,9 +30,7 @@ def test_device_update_form(create_admin_user):
|
|||
request = HttpRequest()
|
||||
request.user = fixture["admin"]
|
||||
form = forms.DeviceUpdateForm(request, data={})
|
||||
assert (
|
||||
form.is_valid() is False
|
||||
), "Should be false because no data was given"
|
||||
assert form.is_valid() is False, "Should be false because no data was given"
|
||||
|
||||
data = {"name": "pharma-device1", "customer": 3}
|
||||
form = forms.DeviceUpdateForm(request, data=data)
|
||||
|
@ -50,9 +46,7 @@ def test_device_update_form(create_admin_user):
|
|||
def test_device_create_form_duplicate_device(create_admin_user):
|
||||
fixture = create_admin_user()
|
||||
user = mixer.blend("core.InventoryUser", customer=fixture["customer"])
|
||||
mixer.blend(
|
||||
"devices.Device", name="pharma-device1", customer=fixture["customer"]
|
||||
)
|
||||
mixer.blend("devices.Device", name="pharma-device1", customer=fixture["customer"])
|
||||
data = {"name": "pharma-device1", "customer": fixture["customer"].id}
|
||||
form = forms.DeviceCreateForm(user=user, data=data)
|
||||
assert (
|
||||
|
|
|
@ -35,9 +35,7 @@ def test_load_device_update_view(create_admin_user):
|
|||
client.login(username="pharma-admin", password="password")
|
||||
device = mixer.blend("devices.Device", customer=mixer.SELECT)
|
||||
response = client.get("/update/device/{}/".format(device.pk))
|
||||
assert response.status_code == 200 and helper.in_content(
|
||||
response, device.name
|
||||
)
|
||||
assert response.status_code == 200 and helper.in_content(response, device.name)
|
||||
|
||||
|
||||
def test_device_update_view(create_admin_user):
|
||||
|
@ -187,9 +185,7 @@ def test_device_in_net_update_view(create_admin_user):
|
|||
"mac_address": "",
|
||||
"ip_status": "1",
|
||||
}
|
||||
response = client.post(
|
||||
"/update/device-in-net/{}/".format(device_in_net.pk), data
|
||||
)
|
||||
response = client.post("/update/device-in-net/{}/".format(device_in_net.pk), data)
|
||||
assert response.status_code == 302
|
||||
device_in_net.refresh_from_db()
|
||||
assert device_in_net.ip == data["ip"]
|
||||
|
|
|
@ -9,9 +9,7 @@ pytestmark = pytest.mark.django_db
|
|||
def test_warranty_create_form(create_admin_user):
|
||||
create_admin_user()
|
||||
form = forms.WarrantyCreateForm(data={})
|
||||
assert (
|
||||
form.is_valid() is False
|
||||
), "Should be false because no data was given"
|
||||
assert form.is_valid() is False, "Should be false because no data was given"
|
||||
|
||||
device = mixer.blend("devices.Device")
|
||||
|
||||
|
@ -33,8 +31,7 @@ def test_warranty_create_form(create_admin_user):
|
|||
form.is_valid() is False
|
||||
), "Should be false because valid from is before valid until"
|
||||
assert (
|
||||
"Valid from date must be before valid until date"
|
||||
== form.errors["__all__"][0]
|
||||
"Valid from date must be before valid until date" == form.errors["__all__"][0]
|
||||
)
|
||||
|
||||
|
||||
|
@ -51,6 +48,5 @@ def test_warranty_update_form(create_admin_user):
|
|||
form = forms.WarrantyUpdateForm(data=data)
|
||||
assert form.is_valid() is False
|
||||
assert (
|
||||
"Valid from date must be before valid until date"
|
||||
== form.errors["__all__"][0]
|
||||
"Valid from date must be before valid until date" == form.errors["__all__"][0]
|
||||
)
|
||||
|
|
|
@ -39,9 +39,7 @@ def test_warranties_view_plenty_of_time(create_admin_user):
|
|||
user.save()
|
||||
device = mixer.blend("devices.Device", customer=fixture["customer"])
|
||||
more_than_one_year = datetime.date(datetime.today() + timedelta(400))
|
||||
mixer.blend(
|
||||
"devices.Warranty", device=device, valid_until=more_than_one_year
|
||||
)
|
||||
mixer.blend("devices.Warranty", device=device, valid_until=more_than_one_year)
|
||||
client = Client()
|
||||
client.login(username="pharma-admin", password="password")
|
||||
response = client.get("/warranties/")
|
||||
|
@ -77,9 +75,7 @@ def test_warranties_view_warranty_one_year_till_expiration(create_admin_user):
|
|||
user.save()
|
||||
device = mixer.blend("devices.Device", customer=fixture["customer"])
|
||||
not_one_year_more = datetime.date(datetime.today() + timedelta(200))
|
||||
mixer.blend(
|
||||
"devices.Warranty", device=device, valid_until=not_one_year_more
|
||||
)
|
||||
mixer.blend("devices.Warranty", device=device, valid_until=not_one_year_more)
|
||||
client = Client()
|
||||
client.login(username="pharma-admin", password="password")
|
||||
response = client.get("/warranties/")
|
||||
|
|
|
@ -4,9 +4,7 @@ from . import views
|
|||
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
"customer/<int:pk>/devices/", views.devices_table_view, name="devices"
|
||||
),
|
||||
path("customer/<int:pk>/devices/", views.devices_table_view, name="devices"),
|
||||
path("device/<int:pk>/", views.device_detail_view, name="device"),
|
||||
path(
|
||||
"manufacturer/<int:pk>/",
|
||||
|
|
|
@ -60,16 +60,12 @@ def device_detail_view(request, pk):
|
|||
def devices_table_view(request, pk):
|
||||
table = DevicesTable(Device.objects.filter(customer=pk))
|
||||
RequestConfig(request).configure(table)
|
||||
return render(
|
||||
request, "devices/device_list.html", {"devices": table, "pk": pk}
|
||||
)
|
||||
return render(request, "devices/device_list.html", {"devices": table, "pk": pk})
|
||||
|
||||
|
||||
@login_required
|
||||
def warranties_view(request):
|
||||
table = WarrantiesTable(
|
||||
utils.objects_for_allowed_customers(Warranty, request.user)
|
||||
)
|
||||
table = WarrantiesTable(utils.objects_for_allowed_customers(Warranty, request.user))
|
||||
RequestConfig(request).configure(table)
|
||||
return render(request, "devices/warranties_list.html", {"devices": table})
|
||||
|
||||
|
@ -111,9 +107,7 @@ def device_update_view(request, pk):
|
|||
"""
|
||||
template_name = "devices/device_update.html"
|
||||
request.session["device_to_update"] = pk
|
||||
device = utils.get_object_with_view_permission(
|
||||
Device, user=request.user, pk=pk
|
||||
)
|
||||
device = utils.get_object_with_view_permission(Device, user=request.user, pk=pk)
|
||||
if request.method == "POST" and "save_device" in request.POST:
|
||||
form = DeviceUpdateForm(request, request.POST, instance=device)
|
||||
if form.is_valid():
|
||||
|
@ -124,7 +118,7 @@ def device_update_view(request, pk):
|
|||
return TemplateResponse(request, template_name, {"form": form})
|
||||
|
||||
|
||||
class DeviceDeleteView(LoginRequiredMixin, DeleteView):
|
||||
class DeviceDeleteView(LoginRequiredMixin, DeleteView): # type: ignore
|
||||
model = Device
|
||||
|
||||
def get_success_url(self):
|
||||
|
@ -160,7 +154,7 @@ class WarrantyUpdateView(LoginRequiredMixin, UpdateView):
|
|||
return self.request.POST.get("previous_page")
|
||||
|
||||
|
||||
class WarrantyDeleteView(LoginRequiredMixin, DeleteView):
|
||||
class WarrantyDeleteView(LoginRequiredMixin, DeleteView): # type: ignore
|
||||
model = Warranty
|
||||
|
||||
def get_success_url(self):
|
||||
|
@ -195,7 +189,7 @@ class DeviceInNetUpdateView(LoginRequiredMixin, UpdateView):
|
|||
return self.request.POST.get("previous_page")
|
||||
|
||||
|
||||
class DeviceInNetDeleteView(LoginRequiredMixin, DeleteView):
|
||||
class DeviceInNetDeleteView(LoginRequiredMixin, DeleteView): # type: ignore
|
||||
model = DeviceInNet
|
||||
template_name = "devices/device_in_net_confirm_delete.html"
|
||||
|
||||
|
|
|
@ -48,9 +48,7 @@ class LicenseWithUser(models.Model):
|
|||
|
||||
class Meta:
|
||||
constraints = [
|
||||
models.UniqueConstraint(
|
||||
fields=["user", "license"], name="user per license"
|
||||
)
|
||||
models.UniqueConstraint(fields=["user", "license"], name="user per license")
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -61,9 +61,7 @@ def test_customer_license_table_no_license(create_admin_user):
|
|||
client = Client()
|
||||
client.login(username="pharma-admin", password="password")
|
||||
response = client.get("/customer/" + str(customer.id) + "/licenses/")
|
||||
assert response.status_code == 200 and helper.not_in_content(
|
||||
response, customer
|
||||
)
|
||||
assert response.status_code == 200 and helper.not_in_content(response, customer)
|
||||
|
||||
|
||||
def test_customer_license_table_no_permission(create_admin_user):
|
||||
|
|
|
@ -41,7 +41,7 @@ def licenses_table_view(request, pk):
|
|||
class LicenseWithComputerCreateView(LoginRequiredMixin, CreateView):
|
||||
model = LicenseWithComputer
|
||||
template_name = "licenses/license_with_computer_create.html"
|
||||
fields = "__all__"
|
||||
fields = "__all__" # type: ignore
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse("computer", args=(self.computer.pk,))
|
||||
|
@ -57,7 +57,7 @@ class LicenseWithComputerCreateView(LoginRequiredMixin, CreateView):
|
|||
}
|
||||
|
||||
|
||||
class LicenseWithComputerDeleteView(LoginRequiredMixin, DeleteView):
|
||||
class LicenseWithComputerDeleteView(LoginRequiredMixin, DeleteView): # type: ignore
|
||||
model = LicenseWithComputer
|
||||
template_name = "licenses/license_with_computer_confirm_delete.html"
|
||||
|
||||
|
@ -65,7 +65,7 @@ class LicenseWithComputerDeleteView(LoginRequiredMixin, DeleteView):
|
|||
return reverse("computer", args=(self.object.computer.pk,))
|
||||
|
||||
|
||||
class UserLicenseDeleteView(LoginRequiredMixin, DeleteView):
|
||||
class UserLicenseDeleteView(LoginRequiredMixin, DeleteView): # type: ignore
|
||||
model = UserLicense
|
||||
template_name = "licenses/license_confirm_delete.html"
|
||||
|
||||
|
@ -73,7 +73,7 @@ class UserLicenseDeleteView(LoginRequiredMixin, DeleteView):
|
|||
return reverse("licenses", args=(self.object.customer.pk,))
|
||||
|
||||
|
||||
class ComputerLicenseDeleteView(LoginRequiredMixin, DeleteView):
|
||||
class ComputerLicenseDeleteView(LoginRequiredMixin, DeleteView): # type: ignore
|
||||
model = ComputerLicense
|
||||
template_name = "licenses/license_confirm_delete.html"
|
||||
|
||||
|
|
|
@ -3,9 +3,7 @@ import os
|
|||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ.setdefault(
|
||||
"DJANGO_SETTINGS_MODULE", "network_inventory.settings"
|
||||
)
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "network_inventory.settings")
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
|
|
|
@ -11,8 +11,6 @@ def net_view_permission(old_fuction):
|
|||
if user.has_perm("customers.view_customer", net.customer):
|
||||
return old_fuction(request, pk)
|
||||
else:
|
||||
return HttpResponseForbidden(
|
||||
"You're not allowed to access this device."
|
||||
)
|
||||
return HttpResponseForbidden("You're not allowed to access this device.")
|
||||
|
||||
return new_function
|
||||
|
|
|
@ -15,9 +15,7 @@ def test_net_detail_view_no_permission(create_admin_user):
|
|||
net = mixer.blend("nets.Net")
|
||||
customer = mixer.blend("customers.Customer")
|
||||
device = mixer.blend("computers.Computer", customer=customer)
|
||||
mixer.blend(
|
||||
"devices.DeviceInNet", device=device, net=net, ip="10.7.89.101"
|
||||
)
|
||||
mixer.blend("devices.DeviceInNet", device=device, net=net, ip="10.7.89.101")
|
||||
client = Client()
|
||||
client.login(username="pharma-admin", password="password")
|
||||
response = client.get("/net/" + str(net.id) + "/")
|
||||
|
@ -28,9 +26,7 @@ def test_net_detail_view(create_admin_user):
|
|||
fixture = create_admin_user()
|
||||
net = mixer.blend("nets.Net", customer=mixer.SELECT)
|
||||
device = mixer.blend("computers.Computer", customer=fixture["customer"])
|
||||
device_in_net = DeviceInNet.objects.create(
|
||||
device=device, net=net, ip="10.7.89.101"
|
||||
)
|
||||
device_in_net = DeviceInNet.objects.create(device=device, net=net, ip="10.7.89.101")
|
||||
client = Client()
|
||||
client.login(username="pharma-admin", password="password")
|
||||
response = client.get("/net/" + str(net.id) + "/")
|
||||
|
|
|
@ -29,12 +29,10 @@ def net_detail_view(request, pk):
|
|||
net = get_object_or_404(Net, pk=pk)
|
||||
table = NetDetailTable(DeviceInNet.objects.filter(net=net))
|
||||
RequestConfig(request).configure(table)
|
||||
return render(
|
||||
request, "nets/net_details.html", {"table": table, "net": net}
|
||||
)
|
||||
return render(request, "nets/net_details.html", {"table": table, "net": net})
|
||||
|
||||
|
||||
class NetDeleteView(LoginRequiredMixin, DeleteView):
|
||||
class NetDeleteView(LoginRequiredMixin, DeleteView): # type: ignore
|
||||
model = Net
|
||||
|
||||
def get_success_url(self):
|
||||
|
|
|
@ -11,8 +11,6 @@ def user_view_permission(old_fuction):
|
|||
if user.has_perm("customers.view_customer", inventory_user.customer):
|
||||
return old_fuction(request, pk)
|
||||
else:
|
||||
return HttpResponseForbidden(
|
||||
"You're not allowed to access this device."
|
||||
)
|
||||
return HttpResponseForbidden("You're not allowed to access this device.")
|
||||
|
||||
return new_function
|
||||
|
|
|
@ -37,9 +37,7 @@ def test_customer_user_table_no_user(create_admin_user):
|
|||
client = Client()
|
||||
client.login(username="pharma-admin", password="password")
|
||||
response = client.get("/customer/" + str(customer.id) + "/users/")
|
||||
assert response.status_code == 200 and helper.not_in_content(
|
||||
response, customer
|
||||
)
|
||||
assert response.status_code == 200 and helper.not_in_content(response, customer)
|
||||
|
||||
|
||||
def test_customer_user_table_no_permission(create_admin_user):
|
||||
|
|
|
@ -61,6 +61,4 @@ def test_group_detail_view_with_child_group(create_admin_user):
|
|||
client = Client()
|
||||
client.login(username="pharma-admin", password="password")
|
||||
response = client.get("/group/" + str(group.id) + "/")
|
||||
assert response.status_code == 200 and helper.in_content(
|
||||
response, child_group
|
||||
)
|
||||
assert response.status_code == 200 and helper.in_content(response, child_group)
|
||||
|
|
|
@ -38,9 +38,7 @@ def test_user_detail_view_group(create_admin_user):
|
|||
client = Client()
|
||||
client.login(username="pharma-admin", password="password")
|
||||
response = client.get("/user/" + str(user.id) + "/")
|
||||
assert response.status_code == 200 and helper.in_content(
|
||||
response, "Groups"
|
||||
)
|
||||
assert response.status_code == 200 and helper.in_content(response, "Groups")
|
||||
|
||||
|
||||
def test_user_detail_view_mail_alias(create_admin_user):
|
||||
|
@ -50,9 +48,7 @@ def test_user_detail_view_mail_alias(create_admin_user):
|
|||
client = Client()
|
||||
client.login(username="pharma-admin", password="password")
|
||||
response = client.get("/user/" + str(user.id) + "/")
|
||||
assert response.status_code == 200 and helper.in_content(
|
||||
response, "Mail Alias"
|
||||
)
|
||||
assert response.status_code == 200 and helper.in_content(response, "Mail Alias")
|
||||
|
||||
|
||||
def test_user_detail_view_license(create_admin_user):
|
||||
|
@ -63,9 +59,7 @@ def test_user_detail_view_license(create_admin_user):
|
|||
client = Client()
|
||||
client.login(username="pharma-admin", password="password")
|
||||
response = client.get("/user/" + str(user.id) + "/")
|
||||
assert response.status_code == 200 and helper.in_content(
|
||||
response, "License"
|
||||
)
|
||||
assert response.status_code == 200 and helper.in_content(response, "License")
|
||||
|
||||
|
||||
def test_user_detail_view_computer(create_admin_user):
|
||||
|
@ -75,9 +69,7 @@ def test_user_detail_view_computer(create_admin_user):
|
|||
client = Client()
|
||||
client.login(username="pharma-admin", password="password")
|
||||
response = client.get("/user/" + str(user.id) + "/")
|
||||
assert response.status_code == 200 and helper.in_content(
|
||||
response, computer
|
||||
)
|
||||
assert response.status_code == 200 and helper.in_content(response, computer)
|
||||
|
||||
|
||||
def test_user_detail_view_no_permission(create_admin_user):
|
||||
|
|
|
@ -52,7 +52,7 @@ def user_detail_view(request, pk):
|
|||
)
|
||||
|
||||
|
||||
class UserDeleteView(LoginRequiredMixin, DeleteView):
|
||||
class UserDeleteView(LoginRequiredMixin, DeleteView): # type: ignore
|
||||
model = User
|
||||
|
||||
def get_success_url(self):
|
||||
|
@ -64,9 +64,7 @@ class UserDeleteView(LoginRequiredMixin, DeleteView):
|
|||
def groups_table_view(request, pk):
|
||||
customer = get_object_or_404(Customer, pk=pk)
|
||||
groups_table = GroupsTable(
|
||||
utils.get_objects_for_customer(
|
||||
Group, user=request.user, customer_pk=pk
|
||||
)
|
||||
utils.get_objects_for_customer(Group, user=request.user, customer_pk=pk)
|
||||
)
|
||||
RequestConfig(request).configure(groups_table)
|
||||
return TemplateResponse(
|
||||
|
@ -81,9 +79,7 @@ def groups_table_view(request, pk):
|
|||
|
||||
@login_required
|
||||
def group_detail_view(request, pk):
|
||||
group = utils.get_object_with_view_permission(
|
||||
Group, user=request.user, pk=pk
|
||||
)
|
||||
group = utils.get_object_with_view_permission(Group, user=request.user, pk=pk)
|
||||
users = group.user_set.all()
|
||||
groups = Group.objects.filter(parent_group=group)
|
||||
print(groups)
|
||||
|
@ -96,9 +92,7 @@ def group_detail_view(request, pk):
|
|||
|
||||
@login_required
|
||||
def delete_group(request, pk):
|
||||
group = utils.get_object_with_view_permission(
|
||||
Group, user=request.user, pk=pk
|
||||
)
|
||||
group = utils.get_object_with_view_permission(Group, user=request.user, pk=pk)
|
||||
if request.method == "POST":
|
||||
group.delete()
|
||||
return redirect("groups", pk=group.customer.pk)
|
||||
|
|
Loading…
Reference in New Issue