diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml
new file mode 100644
index 0000000..dcf3153
--- /dev/null
+++ b/.github/workflows/python.yml
@@ -0,0 +1,28 @@
+name: Python
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ types: [opened, synchronize, reopened]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4.0.0
+
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: "3.9"
+
+ - name: Install tools
+ run: pip install .[tools]
+
+ - name: Run ruff
+ run: ruff netbox_slm
+
+ - name: Run black
+ run: black netbox_slm
diff --git a/.gitignore b/.gitignore
index 0d8ca00..de12c05 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,4 @@ ci/docker-compose.override.yml
ci/reports
out/production
*.iml
+build/
diff --git a/Pipfile b/Pipfile
deleted file mode 100644
index efa2a23..0000000
--- a/Pipfile
+++ /dev/null
@@ -1,12 +0,0 @@
-[[source]]
-url = "https://pypi.org/simple"
-verify_ssl = true
-name = "pypi"
-
-[packages]
-
-[dev-packages]
-twine = "3.7.1"
-
-[requires]
-python_version = "3.9"
diff --git a/Pipfile.lock b/Pipfile.lock
deleted file mode 100644
index 62275a2..0000000
--- a/Pipfile.lock
+++ /dev/null
@@ -1,192 +0,0 @@
-{
- "_meta": {
- "hash": {
- "sha256": "f3cebe84c169ba6773cfcfae65b47e5076fa331e445f47a6ec4d13306942deb4"
- },
- "pipfile-spec": 6,
- "requires": {
- "python_version": "3.9"
- },
- "sources": [
- {
- "name": "pypi",
- "url": "https://pypi.org/simple",
- "verify_ssl": true
- }
- ]
- },
- "default": {},
- "develop": {
- "bleach": {
- "hashes": [
- "sha256:0900d8b37eba61a802ee40ac0061f8c2b5dee29c1927dd1d233e075ebf5a71da",
- "sha256:4d2651ab93271d1129ac9cbc679f524565cc8a1b791909c4a51eac4446a15994"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==4.1.0"
- },
- "certifi": {
- "hashes": [
- "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872",
- "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"
- ],
- "version": "==2021.10.8"
- },
- "charset-normalizer": {
- "hashes": [
- "sha256:876d180e9d7432c5d1dfd4c5d26b72f099d503e8fcc0feb7532c9289be60fcbd",
- "sha256:cb957888737fc0bbcd78e3df769addb41fd1ff8cf950dc9e7ad7793f1bf44455"
- ],
- "markers": "python_version >= '3'",
- "version": "==2.0.10"
- },
- "colorama": {
- "hashes": [
- "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b",
- "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
- "version": "==0.4.4"
- },
- "docutils": {
- "hashes": [
- "sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c",
- "sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
- "version": "==0.18.1"
- },
- "idna": {
- "hashes": [
- "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff",
- "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"
- ],
- "markers": "python_version >= '3'",
- "version": "==3.3"
- },
- "importlib-metadata": {
- "hashes": [
- "sha256:92a8b58ce734b2a4494878e0ecf7d79ccd7a128b5fc6014c401e0b61f006f0f6",
- "sha256:b7cf7d3fef75f1e4c80a96ca660efbd51473d7e8f39b5ab9210febc7809012a4"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==4.10.0"
- },
- "keyring": {
- "hashes": [
- "sha256:9012508e141a80bd1c0b6778d5c610dd9f8c464d75ac6774248500503f972fb9",
- "sha256:b0d28928ac3ec8e42ef4cc227822647a19f1d544f21f96457965dc01cf555261"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==23.5.0"
- },
- "packaging": {
- "hashes": [
- "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb",
- "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==21.3"
- },
- "pkginfo": {
- "hashes": [
- "sha256:542e0d0b6750e2e21c20179803e40ab50598d8066d51097a0e382cba9eb02bff",
- "sha256:c24c487c6a7f72c66e816ab1796b96ac6c3d14d49338293d2141664330b55ffc"
- ],
- "version": "==1.8.2"
- },
- "pygments": {
- "hashes": [
- "sha256:59b895e326f0fb0d733fd28c6839bd18ad0687ba20efc26d4277fd1d30b971f4",
- "sha256:9135c1af61eec0f650cd1ea1ed8ce298e54d56bcd8cc2ef46edd7702c171337c"
- ],
- "markers": "python_version >= '3.5'",
- "version": "==2.11.1"
- },
- "pyparsing": {
- "hashes": [
- "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4",
- "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==3.0.6"
- },
- "readme-renderer": {
- "hashes": [
- "sha256:a50a0f2123a4c1145ac6f420e1a348aafefcc9211c846e3d51df05fe3d865b7d",
- "sha256:b512beafa6798260c7d5af3e1b1f097e58bfcd9a575da7c4ddd5e037490a5b85"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==32.0"
- },
- "requests": {
- "hashes": [
- "sha256:8e5643905bf20a308e25e4c1dd379117c09000bf8a82ebccc462cfb1b34a16b5",
- "sha256:f71a09d7feba4a6b64ffd8e9d9bc60f9bf7d7e19fd0e04362acb1cfc2e3d98df"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
- "version": "==2.27.0"
- },
- "requests-toolbelt": {
- "hashes": [
- "sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f",
- "sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0"
- ],
- "version": "==0.9.1"
- },
- "rfc3986": {
- "hashes": [
- "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835",
- "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"
- ],
- "version": "==1.5.0"
- },
- "six": {
- "hashes": [
- "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
- "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
- "version": "==1.16.0"
- },
- "tqdm": {
- "hashes": [
- "sha256:8dd278a422499cd6b727e6ae4061c40b48fce8b76d1ccbf5d34fca9b7f925b0c",
- "sha256:d359de7217506c9851b7869f3708d8ee53ed70a1b8edbba4dbcb47442592920d"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==4.62.3"
- },
- "twine": {
- "hashes": [
- "sha256:28460a3db6b4532bde6a5db6755cf2dce6c5020bada8a641bb2c5c7a9b1f35b8",
- "sha256:8c120845fc05270f9ee3e9d7ebbed29ea840e41f48cd059e04733f7e1d401345"
- ],
- "index": "pypi",
- "version": "==3.7.1"
- },
- "urllib3": {
- "hashes": [
- "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece",
- "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
- "version": "==1.26.7"
- },
- "webencodings": {
- "hashes": [
- "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78",
- "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"
- ],
- "version": "==0.5.1"
- },
- "zipp": {
- "hashes": [
- "sha256:9f50f446828eb9d45b267433fd3e9da8d801f614129124863f9c51ebceafb87d",
- "sha256:b47250dd24f92b7dd6a0a8fc5244da14608f3ca90a5efcd37a3b1642fac9a375"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==3.7.0"
- }
- }
-}
diff --git a/README.md b/README.md
index 3a9478e..ae8faed 100644
--- a/README.md
+++ b/README.md
@@ -27,8 +27,8 @@ Next, follow these instructions (based on the Netbox docker variant
to install the Netbox SLM plugin:
1. Add ``netbox_slm`` to the ``PLUGINS`` list in
- ``configuration/extra.py``.
-2. Create a ``plugin_requirements.txt`` with ``netbox-slm==1.2`` as
+ ``configuration/plugins.py``.
+2. Create a ``plugin_requirements.txt`` with ``netbox-slm`` as
contents.
3. Create a ``Dockerfile-SLM`` with contents:
@@ -65,20 +65,17 @@ And finally, run Netbox with the SLM plugin: ``docker compose up``
To draft a release;
-update the setup.py file to reflect the new version, then from the *src*
+update the `netbox_slm/__init__.py` file to reflect the new version, then from the *src*
directory run
```
- # make sure to update the version in netbox_slm/__init__.py
- $ python setup.py sdist
+ $ python -m build
$ twine upload dist/*
```
On Github.com create a similar tag and version. These steps could be
automated with a github workflow.
-n.b. Currently the plugin is configured to use a personal pypi account,
-this should be changed.
## Developer Guide (local installation)
diff --git a/ci/Dockerfile b/ci/Dockerfile
index 57e3308..0c7a21e 100644
--- a/ci/Dockerfile
+++ b/ci/Dockerfile
@@ -7,10 +7,11 @@ ENV PATH="/opt/netbox/venv/bin:$PATH"
COPY ../ /build
-RUN python setup.py sdist
+RUN pip install -U .[build]
+RUN python -m build
RUN pip install --no-index /build
-FROM netboxcommunity/netbox:v3.4.7
+FROM netboxcommunity/netbox:v3.6.1
ARG PYTHON_VERSION=3.10
COPY --from=compile-image /opt/netbox/venv/lib/python${PYTHON_VERSION}/site-packages/netbox_slm /opt/netbox/venv/lib/python${PYTHON_VERSION}/site-packages/netbox_slm
diff --git a/ci/Dockerfile-CI b/ci/Dockerfile-CI
index 822fc40..fe7e75b 100644
--- a/ci/Dockerfile-CI
+++ b/ci/Dockerfile-CI
@@ -1,4 +1,4 @@
-FROM netboxcommunity/netbox:v3.4.7
+FROM netboxcommunity/netbox:v3.6.1
RUN mkdir /ci && chmod go+w /ci
COPY ../ci/requirements_ci.txt /ci/
diff --git a/ci/configuration/extra.py b/ci/configuration/extra.py
index c721991..25ec2ee 100644
--- a/ci/configuration/extra.py
+++ b/ci/configuration/extra.py
@@ -1,6 +1,6 @@
PLUGINS = ['netbox_slm']
DEBUG = True
-SECRET_KEY = 'dummy'
+SECRET_KEY = 'dummydummydummydummydummydummydummydummydummydummy'
DEVELOPER = True
PLUGINS_CONFIG = {
'netbox_slm': dict(
diff --git a/ci/docker-compose.yml b/ci/docker-compose.yml
index 1b5997d..f30dedf 100644
--- a/ci/docker-compose.yml
+++ b/ci/docker-compose.yml
@@ -1,7 +1,7 @@
version: '3.7'
services:
netbox: &netbox
- image: netboxcommunity/netbox:${VERSION-v3.3-2.2.0}
+ image: netboxcommunity/netbox:${VERSION-v3.6.1}
depends_on:
- postgres
- redis
diff --git a/netbox_slm/__init__.py b/netbox_slm/__init__.py
index ea0a4d6..05bb650 100644
--- a/netbox_slm/__init__.py
+++ b/netbox_slm/__init__.py
@@ -1,18 +1,18 @@
from extras.plugins import PluginConfig
+__version__ = "1.4"
+
class SLMConfig(PluginConfig):
- name = 'netbox_slm'
- verbose_name = 'Software Lifecycle Management'
- description = 'Software Lifecycle Management Netbox Plugin.'
- version = '1.4'
- author = 'ICTU'
- author_email = 'open-source-projects@ictu.nl'
- base_url = 'slm'
+ name = "netbox_slm"
+ verbose_name = "Software Lifecycle Management"
+ description = "Software Lifecycle Management Netbox Plugin."
+ version = __version__
+ author = "ICTU"
+ author_email = "open-source-projects@ictu.nl"
+ base_url = "slm"
required_settings = []
- default_settings = {
- 'version_info': False
- }
+ default_settings = {"version_info": False}
config = SLMConfig
diff --git a/netbox_slm/api/serializers.py b/netbox_slm/api/serializers.py
index c1dbaa9..5b3f61c 100644
--- a/netbox_slm/api/serializers.py
+++ b/netbox_slm/api/serializers.py
@@ -6,15 +6,19 @@ from netbox_slm.models import SoftwareProduct, SoftwareProductVersion, SoftwareP
class SoftwareProductSerializer(NetBoxModelSerializer):
display = serializers.SerializerMethodField()
- url = serializers.HyperlinkedIdentityField(
- view_name="plugins-api:netbox_slm-api:softwareproduct-detail"
- )
+ url = serializers.HyperlinkedIdentityField(view_name="plugins-api:netbox_slm-api:softwareproduct-detail")
class Meta:
model = SoftwareProduct
fields = [
- 'id', 'display', 'url', 'name',
- 'tags', 'custom_field_data', 'created', 'last_updated',
+ "id",
+ "display",
+ "url",
+ "name",
+ "tags",
+ "custom_field_data",
+ "created",
+ "last_updated",
]
def get_display(self, obj):
@@ -23,15 +27,20 @@ class SoftwareProductSerializer(NetBoxModelSerializer):
class SoftwareProductVersionSerializer(NetBoxModelSerializer):
display = serializers.SerializerMethodField()
- url = serializers.HyperlinkedIdentityField(
- view_name="plugins-api:netbox_slm-api:softwareproductversion-detail"
- )
+ url = serializers.HyperlinkedIdentityField(view_name="plugins-api:netbox_slm-api:softwareproductversion-detail")
class Meta:
model = SoftwareProductVersion
fields = [
- 'id', 'display', 'url', 'name', 'software_product',
- 'tags', 'custom_field_data', 'created', 'last_updated',
+ "id",
+ "display",
+ "url",
+ "name",
+ "software_product",
+ "tags",
+ "custom_field_data",
+ "created",
+ "last_updated",
]
def get_display(self, obj):
@@ -47,8 +56,17 @@ class SoftwareProductInstallationSerializer(NetBoxModelSerializer):
class Meta:
model = SoftwareProductInstallation
fields = [
- 'id', 'display', 'url', 'device', 'virtualmachine', 'software_product', 'version',
- 'tags', 'custom_field_data', 'created', 'last_updated',
+ "id",
+ "display",
+ "url",
+ "device",
+ "virtualmachine",
+ "software_product",
+ "version",
+ "tags",
+ "custom_field_data",
+ "created",
+ "last_updated",
]
def get_display(self, obj):
@@ -57,16 +75,27 @@ class SoftwareProductInstallationSerializer(NetBoxModelSerializer):
class SoftwareLicenseSerializer(NetBoxModelSerializer):
display = serializers.SerializerMethodField()
- url = serializers.HyperlinkedIdentityField(
- view_name="plugins-api:netbox_slm-api:softwarelicense-detail"
- )
+ url = serializers.HyperlinkedIdentityField(view_name="plugins-api:netbox_slm-api:softwarelicense-detail")
class Meta:
model = SoftwareLicense
fields = [
- 'id', 'display', 'url', 'name', 'description', 'type', 'stored_location',
- 'start_date', 'expiration_date', 'software_product', 'version', 'installation',
- 'tags', 'custom_field_data', 'created', 'last_updated',
+ "id",
+ "display",
+ "url",
+ "name",
+ "description",
+ "type",
+ "stored_location",
+ "start_date",
+ "expiration_date",
+ "software_product",
+ "version",
+ "installation",
+ "tags",
+ "custom_field_data",
+ "created",
+ "last_updated",
]
def get_display(self, obj):
diff --git a/netbox_slm/filtersets.py b/netbox_slm/filtersets.py
index a1745af..72741e5 100644
--- a/netbox_slm/filtersets.py
+++ b/netbox_slm/filtersets.py
@@ -24,17 +24,17 @@ class SoftwareProductVersionFilterSet(NetBoxModelFilterSet):
class Meta:
model = SoftwareProductVersion
- fields = (
- "software_product",
- )
+ fields = ("software_product",)
def search(self, queryset, name, value):
"""Perform the filtered search."""
if not value.strip():
return queryset
- qs_filter = Q(name__icontains=value) | \
- Q(software_product__name__icontains=value) | \
- Q(software_product__manufacturer__name__icontains=value)
+ qs_filter = (
+ Q(name__icontains=value)
+ | Q(software_product__name__icontains=value)
+ | Q(software_product__manufacturer__name__icontains=value)
+ )
return queryset.filter(qs_filter)
@@ -43,17 +43,17 @@ class SoftwareProductInstallationFilterSet(NetBoxModelFilterSet):
class Meta:
model = SoftwareProductInstallation
- fields = (
- "software_product",
- )
+ fields = ("software_product",)
def search(self, queryset, name, value):
"""Perform the filtered search."""
if not value.strip():
return queryset
- qs_filter = Q(software_product__name__icontains=value) | \
- Q(software_product__manufacturer__name__icontains=value) | \
- Q(version__name__icontains=value)
+ qs_filter = (
+ Q(software_product__name__icontains=value)
+ | Q(software_product__manufacturer__name__icontains=value)
+ | Q(version__name__icontains=value)
+ )
return queryset.filter(qs_filter)
@@ -68,9 +68,11 @@ class SoftwareLicenseFilterSet(NetBoxModelFilterSet):
"""Perform the filtered search."""
if not value.strip():
return queryset
- qs_filter = Q(name__icontains=value) | \
- Q(software_product__name__icontains=value) | \
- Q(version__name__icontains=value) | \
- Q(installation__device__name__icontains=value) | \
- Q(installation__virtualmachine__name__icontains=value)
+ qs_filter = (
+ Q(name__icontains=value)
+ | Q(software_product__name__icontains=value)
+ | Q(version__name__icontains=value)
+ | Q(installation__device__name__icontains=value)
+ | Q(installation__virtualmachine__name__icontains=value)
+ )
return queryset.filter(qs_filter)
diff --git a/netbox_slm/forms/__init__.py b/netbox_slm/forms/__init__.py
index b579da4..7ce40a8 100644
--- a/netbox_slm/forms/__init__.py
+++ b/netbox_slm/forms/__init__.py
@@ -1,4 +1,24 @@
-from .software_license import *
-from .software_product import *
-from .software_product_installation import *
-from .software_product_version import *
+from .software_license import (
+ SoftwareLicenseForm,
+ SoftwareLicenseFilterForm,
+ SoftwareLicenseImportForm,
+ SoftwareLicenseBulkEditForm,
+)
+from .software_product import (
+ SoftwareProductForm,
+ SoftwareProductFilterForm,
+ SoftwareProductImportForm,
+ SoftwareProductBulkEditForm,
+)
+from .software_product_installation import (
+ SoftwareProductInstallationForm,
+ SoftwareProductInstallationFilterForm,
+ SoftwareProductInstallationImportForm,
+ SoftwareProductInstallationBulkEditForm,
+)
+from .software_product_version import (
+ SoftwareProductVersionForm,
+ SoftwareProductVersionFilterForm,
+ SoftwareProductVersionImportForm,
+ SoftwareProductVersionBulkEditForm,
+)
diff --git a/netbox_slm/forms/software_license.py b/netbox_slm/forms/software_license.py
index 5b83b45..193f702 100644
--- a/netbox_slm/forms/software_license.py
+++ b/netbox_slm/forms/software_license.py
@@ -1,8 +1,11 @@
+from django.forms import DateField
from django.urls import reverse_lazy
+from django.utils.translation import gettext_lazy as _
from netbox.forms import NetBoxModelForm, NetBoxModelImportForm, NetBoxModelBulkEditForm, NetBoxModelFilterSetForm
from netbox_slm.models import SoftwareProduct, SoftwareProductVersion, SoftwareProductInstallation, SoftwareLicense
-from utilities.forms import DynamicModelChoiceField, APISelect, TagFilterField
+from utilities.forms.fields import DynamicModelChoiceField, TagFilterField
+from utilities.forms.widgets import APISelect, DatePicker
class SoftwareLicenseForm(NetBoxModelForm):
@@ -11,19 +14,15 @@ class SoftwareLicenseForm(NetBoxModelForm):
software_product = DynamicModelChoiceField(
queryset=SoftwareProduct.objects.all(),
required=True,
- widget=APISelect(
- attrs={"data-url": reverse_lazy("plugins-api:netbox_slm-api:softwareproduct-list")}
- ),
+ widget=APISelect(attrs={"data-url": reverse_lazy("plugins-api:netbox_slm-api:softwareproduct-list")}),
)
version = DynamicModelChoiceField(
queryset=SoftwareProductVersion.objects.all(),
required=False,
- widget=APISelect(
- attrs={"data-url": reverse_lazy("plugins-api:netbox_slm-api:softwareproductversion-list")}
- ),
+ widget=APISelect(attrs={"data-url": reverse_lazy("plugins-api:netbox_slm-api:softwareproductversion-list")}),
query_params={
- 'software_product': '$software_product',
- }
+ "software_product": "$software_product",
+ },
)
installation = DynamicModelChoiceField(
queryset=SoftwareProductInstallation.objects.all(),
@@ -32,20 +31,38 @@ class SoftwareLicenseForm(NetBoxModelForm):
attrs={"data-url": reverse_lazy("plugins-api:netbox_slm-api:softwareproductinstallation-list")}
),
query_params={
- 'software_product': '$software_product',
- }
+ "software_product": "$software_product",
+ },
)
+ start_date = DateField(label=_("Start date"), required=False, widget=DatePicker())
+ expiration_date = DateField(label=_("Expiration date"), required=False, widget=DatePicker())
class Meta:
model = SoftwareLicense
- fields = ("name", "description", "type", "stored_location", "start_date", "expiration_date",
- "software_product", "version", "installation", "tags")
+ fields = (
+ "name",
+ "description",
+ "type",
+ "stored_location",
+ "start_date",
+ "expiration_date",
+ "software_product",
+ "version",
+ "installation",
+ "tags",
+ )
class SoftwareLicenseFilterForm(NetBoxModelFilterSetForm):
model = SoftwareLicense
fieldsets = (
- (None, ('q', 'tag',)),
+ (
+ None,
+ (
+ "q",
+ "tag",
+ ),
+ ),
)
tag = TagFilterField(model)
@@ -54,23 +71,28 @@ class SoftwareLicenseFilterForm(NetBoxModelFilterSetForm):
class SoftwareLicenseImportForm(NetBoxModelImportForm):
class Meta:
model = SoftwareLicense
- fields = ("name", "description", "type", "stored_location", "start_date", "expiration_date",)
+ fields = (
+ "name",
+ "description",
+ "type",
+ "stored_location",
+ "start_date",
+ "expiration_date",
+ )
class SoftwareLicenseBulkEditForm(NetBoxModelBulkEditForm):
- software_product = DynamicModelChoiceField(
- queryset=SoftwareProduct.objects.all(),
- required=False
- )
- version = DynamicModelChoiceField(
- queryset=SoftwareProductVersion.objects.all(),
- required=False
- )
- installation = DynamicModelChoiceField(
- queryset=SoftwareProductInstallation.objects.all(),
- required=False
- )
+ software_product = DynamicModelChoiceField(queryset=SoftwareProduct.objects.all(), required=False)
+ version = DynamicModelChoiceField(queryset=SoftwareProductVersion.objects.all(), required=False)
+ installation = DynamicModelChoiceField(queryset=SoftwareProductInstallation.objects.all(), required=False)
model = SoftwareLicense
fieldsets = (
- (None, ('software_product', 'version', 'installation',)),
+ (
+ None,
+ (
+ "software_product",
+ "version",
+ "installation",
+ ),
+ ),
)
diff --git a/netbox_slm/forms/software_product.py b/netbox_slm/forms/software_product.py
index c5dc56d..086e0be 100644
--- a/netbox_slm/forms/software_product.py
+++ b/netbox_slm/forms/software_product.py
@@ -3,7 +3,7 @@ from django import forms
from dcim.models import Manufacturer
from netbox.forms import NetBoxModelForm, NetBoxModelImportForm, NetBoxModelBulkEditForm, NetBoxModelFilterSetForm
from netbox_slm.models import SoftwareProduct
-from utilities.forms import DynamicModelChoiceField, TagFilterField
+from utilities.forms.fields import DynamicModelChoiceField, TagFilterField
class SoftwareProductForm(NetBoxModelForm):
@@ -21,9 +21,7 @@ class SoftwareProductForm(NetBoxModelForm):
class SoftwareProductFilterForm(NetBoxModelFilterSetForm):
model = SoftwareProduct
- fieldsets = (
- (None, ('q', 'tag')),
- )
+ fieldsets = ((None, ("q", "tag")),)
tag = TagFilterField(model)
@@ -31,7 +29,10 @@ class SoftwareProductFilterForm(NetBoxModelFilterSetForm):
class SoftwareProductImportForm(NetBoxModelImportForm):
class Meta:
model = SoftwareProduct
- fields = ("name", "manufacturer",)
+ fields = (
+ "name",
+ "manufacturer",
+ )
class SoftwareProductBulkEditForm(NetBoxModelBulkEditForm):
diff --git a/netbox_slm/forms/software_product_installation.py b/netbox_slm/forms/software_product_installation.py
index 47de64b..dc107f3 100644
--- a/netbox_slm/forms/software_product_installation.py
+++ b/netbox_slm/forms/software_product_installation.py
@@ -5,37 +5,28 @@ from django.utils.translation import gettext as _
from dcim.models import Device
from netbox.forms import NetBoxModelForm, NetBoxModelImportForm, NetBoxModelBulkEditForm, NetBoxModelFilterSetForm
from netbox_slm.models import SoftwareProductInstallation, SoftwareProduct, SoftwareProductVersion
-from utilities.forms import DynamicModelChoiceField, APISelect, TagFilterField
+from utilities.forms.fields import DynamicModelChoiceField, TagFilterField
+from utilities.forms.widgets import APISelect
from virtualization.models import VirtualMachine
class SoftwareProductInstallationForm(NetBoxModelForm):
"""Form for creating a new SoftwareProductInstallation object."""
- device = DynamicModelChoiceField(
- queryset=Device.objects.all(),
- required=False,
- )
- virtualmachine = DynamicModelChoiceField(
- queryset=VirtualMachine.objects.all(),
- required=False,
- )
+ device = DynamicModelChoiceField(queryset=Device.objects.all(), required=False)
+ virtualmachine = DynamicModelChoiceField(queryset=VirtualMachine.objects.all(), required=False)
software_product = DynamicModelChoiceField(
queryset=SoftwareProduct.objects.all(),
required=True,
- widget=APISelect(
- attrs={"data-url": reverse_lazy("plugins-api:netbox_slm-api:softwareproduct-list")}
- ),
+ widget=APISelect(attrs={"data-url": reverse_lazy("plugins-api:netbox_slm-api:softwareproduct-list")}),
)
version = DynamicModelChoiceField(
queryset=SoftwareProductVersion.objects.all(),
required=True,
- widget=APISelect(
- attrs={"data-url": reverse_lazy("plugins-api:netbox_slm-api:softwareproductversion-list")}
- ),
+ widget=APISelect(attrs={"data-url": reverse_lazy("plugins-api:netbox_slm-api:softwareproductversion-list")}),
query_params={
- 'software_product': '$software_product',
- }
+ "software_product": "$software_product",
+ },
)
class Meta:
@@ -43,15 +34,19 @@ class SoftwareProductInstallationForm(NetBoxModelForm):
fields = ("device", "virtualmachine", "software_product", "version", "tags")
def clean_version(self):
- version = self.cleaned_data['version']
- software_product = self.cleaned_data['software_product']
+ version = self.cleaned_data["version"]
+ software_product = self.cleaned_data["software_product"]
if version not in software_product.softwareproductversion_set.all():
- raise forms.ValidationError(_(f"Version `{version}` doesn't exist on {software_product}, make sure you've "
- f"selected a compatible version or first select the software product."))
+ raise forms.ValidationError(
+ _(
+ f"Version `{version}` doesn't exist on {software_product}, make sure you've "
+ f"selected a compatible version or first select the software product."
+ )
+ )
return version
def clean(self):
- if not any([self.cleaned_data['device'], self.cleaned_data['virtualmachine']]):
+ if not any([self.cleaned_data["device"], self.cleaned_data["virtualmachine"]]):
raise forms.ValidationError(_("Installation requires atleast one virtualmachine or device destination."))
return super(SoftwareProductInstallationForm, self).clean()
@@ -59,7 +54,13 @@ class SoftwareProductInstallationForm(NetBoxModelForm):
class SoftwareProductInstallationFilterForm(NetBoxModelFilterSetForm):
model = SoftwareProductInstallation
fieldsets = (
- (None, ('q', 'tag',)),
+ (
+ None,
+ (
+ "q",
+ "tag",
+ ),
+ ),
)
tag = TagFilterField(model)
@@ -72,15 +73,15 @@ class SoftwareProductInstallationImportForm(NetBoxModelImportForm):
class SoftwareProductInstallationBulkEditForm(NetBoxModelBulkEditForm):
- software_product = DynamicModelChoiceField(
- queryset=SoftwareProduct.objects.all(),
- required=False
- )
- version = DynamicModelChoiceField(
- queryset=SoftwareProductVersion.objects.all(),
- required=False
- )
+ software_product = DynamicModelChoiceField(queryset=SoftwareProduct.objects.all(), required=False)
+ version = DynamicModelChoiceField(queryset=SoftwareProductVersion.objects.all(), required=False)
model = SoftwareProductInstallation
fieldsets = (
- (None, ('software_product', 'version',)),
+ (
+ None,
+ (
+ "software_product",
+ "version",
+ ),
+ ),
)
diff --git a/netbox_slm/forms/software_product_version.py b/netbox_slm/forms/software_product_version.py
index 6eb61d5..138f5c2 100644
--- a/netbox_slm/forms/software_product_version.py
+++ b/netbox_slm/forms/software_product_version.py
@@ -4,18 +4,18 @@ from django.utils.translation import gettext as _
from netbox.forms import NetBoxModelForm, NetBoxModelImportForm, NetBoxModelBulkEditForm, NetBoxModelFilterSetForm
from netbox_slm.models import SoftwareProduct, SoftwareProductVersion
-from utilities.forms import DynamicModelChoiceField, APISelect, TagFilterField
+from utilities.forms.fields import DynamicModelChoiceField, TagFilterField
+from utilities.forms.widgets import APISelect
class SoftwareProductVersionForm(NetBoxModelForm):
"""Form for creating a new SoftwareProductVersion object."""
+
name = forms.CharField(label=_("Version"))
software_product = DynamicModelChoiceField(
queryset=SoftwareProduct.objects.all(),
- widget=APISelect(
- attrs={"data-url": reverse_lazy("plugins-api:netbox_slm-api:softwareproduct-list")}
- ),
+ widget=APISelect(attrs={"data-url": reverse_lazy("plugins-api:netbox_slm-api:softwareproduct-list")}),
)
class Meta:
@@ -25,9 +25,7 @@ class SoftwareProductVersionForm(NetBoxModelForm):
class SoftwareProductVersionFilterForm(NetBoxModelFilterSetForm):
model = SoftwareProductVersion
- fieldsets = (
- (None, ('q', 'tag')),
- )
+ fieldsets = ((None, ("q", "tag")),)
tag = TagFilterField(model)
diff --git a/netbox_slm/models.py b/netbox_slm/models.py
index c264dae..7a70605 100644
--- a/netbox_slm/models.py
+++ b/netbox_slm/models.py
@@ -10,11 +10,7 @@ class SoftwareProduct(NetBoxModel):
name = models.CharField(max_length=128)
description = models.CharField(max_length=255, null=True, blank=True)
- manufacturer = models.ForeignKey(
- to='dcim.Manufacturer',
- on_delete=models.PROTECT,
- null=True, blank=True
- )
+ manufacturer = models.ForeignKey(to="dcim.Manufacturer", on_delete=models.PROTECT, null=True, blank=True)
objects = RestrictedQuerySet.as_manager()
@@ -26,17 +22,23 @@ class SoftwareProduct(NetBoxModel):
def get_installation_count(self):
count = SoftwareProductInstallation.objects.filter(software_product_id=self.pk).count()
- return safestring.mark_safe("{count}".format(
- url=reverse_lazy("plugins:netbox_slm:softwareproductinstallation_list") + f"?q={self.name}",
- count=count
- )) if count else "0"
+ return (
+ safestring.mark_safe(
+ '{count}'.format(
+ url=reverse_lazy("plugins:netbox_slm:softwareproductinstallation_list") + f"?q={self.name}",
+ count=count,
+ )
+ )
+ if count
+ else "0"
+ )
class SoftwareProductVersion(NetBoxModel):
name = models.CharField(max_length=64)
software_product = models.ForeignKey(
- to='netbox_slm.SoftwareProduct',
+ to="netbox_slm.SoftwareProduct",
on_delete=models.PROTECT,
)
@@ -50,33 +52,25 @@ class SoftwareProductVersion(NetBoxModel):
def get_installation_count(self):
count = SoftwareProductInstallation.objects.filter(version_id=self.pk).count()
- return safestring.mark_safe("{count}".format(
- url=reverse_lazy("plugins:netbox_slm:softwareproductinstallation_list") + f"?q={self.name}",
- count=count
- )) if count else "0"
+ return (
+ safestring.mark_safe(
+ '{count}'.format(
+ url=reverse_lazy("plugins:netbox_slm:softwareproductinstallation_list") + f"?q={self.name}",
+ count=count,
+ )
+ )
+ if count
+ else "0"
+ )
class SoftwareProductInstallation(NetBoxModel):
- device = models.ForeignKey(
- to='dcim.Device',
- on_delete=models.PROTECT,
- null=True,
- blank=True
- )
+ device = models.ForeignKey(to="dcim.Device", on_delete=models.PROTECT, null=True, blank=True)
virtualmachine = models.ForeignKey(
- to='virtualization.VirtualMachine',
- on_delete=models.PROTECT,
- null=True,
- blank=True
- )
- software_product = models.ForeignKey(
- to='netbox_slm.SoftwareProduct',
- on_delete=models.PROTECT,
- )
- version = models.ForeignKey(
- to='netbox_slm.SoftwareProductVersion',
- on_delete=models.PROTECT,
+ to="virtualization.VirtualMachine", on_delete=models.PROTECT, null=True, blank=True
)
+ software_product = models.ForeignKey(to="netbox_slm.SoftwareProduct", on_delete=models.PROTECT)
+ version = models.ForeignKey(to="netbox_slm.SoftwareProductVersion", on_delete=models.PROTECT)
objects = RestrictedQuerySet.as_manager()
@@ -91,7 +85,7 @@ class SoftwareProductInstallation(NetBoxModel):
return self.device or self.virtualmachine
def render_type(self):
- return 'device' if self.device else 'virtualmachine'
+ return "device" if self.device else "virtualmachine"
class SoftwareLicense(NetBoxModel):
@@ -103,21 +97,10 @@ class SoftwareLicense(NetBoxModel):
start_date = models.DateField(null=True, blank=True)
expiration_date = models.DateField(null=True, blank=True)
- software_product = models.ForeignKey(
- to='netbox_slm.SoftwareProduct',
- on_delete=models.PROTECT,
- )
- version = models.ForeignKey(
- to='netbox_slm.SoftwareProductVersion',
- on_delete=models.PROTECT,
- null=True,
- blank=True
- )
+ software_product = models.ForeignKey(to="netbox_slm.SoftwareProduct", on_delete=models.PROTECT)
+ version = models.ForeignKey(to="netbox_slm.SoftwareProductVersion", on_delete=models.PROTECT, null=True, blank=True)
installation = models.ForeignKey(
- to='netbox_slm.SoftwareProductInstallation',
- on_delete=models.PROTECT,
- null=True,
- blank=True
+ to="netbox_slm.SoftwareProductInstallation", on_delete=models.PROTECT, null=True, blank=True
)
objects = RestrictedQuerySet.as_manager()
diff --git a/netbox_slm/navigation.py b/netbox_slm/navigation.py
index a0e77d9..13b1423 100644
--- a/netbox_slm/navigation.py
+++ b/netbox_slm/navigation.py
@@ -3,8 +3,8 @@ from utilities.choices import ButtonColorChoices
menu_items = (
PluginMenuItem(
- link='plugins:netbox_slm:softwareproduct_list',
- link_text='Software Products',
+ link="plugins:netbox_slm:softwareproduct_list",
+ link_text="Software Products",
buttons=(
PluginMenuButton(
"plugins:netbox_slm:softwareproduct_add",
@@ -20,11 +20,11 @@ menu_items = (
ButtonColorChoices.CYAN,
permissions=["netbox_slm.add_softwareproduct"],
),
- )
+ ),
),
PluginMenuItem(
- link='plugins:netbox_slm:softwareproductversion_list',
- link_text='Versions',
+ link="plugins:netbox_slm:softwareproductversion_list",
+ link_text="Versions",
buttons=(
PluginMenuButton(
"plugins:netbox_slm:softwareproductversion_add",
@@ -40,11 +40,11 @@ menu_items = (
ButtonColorChoices.CYAN,
permissions=["netbox_slm.add_softwareproductversion"],
),
- )
+ ),
),
PluginMenuItem(
- link='plugins:netbox_slm:softwareproductinstallation_list',
- link_text='Installations',
+ link="plugins:netbox_slm:softwareproductinstallation_list",
+ link_text="Installations",
buttons=(
PluginMenuButton(
"plugins:netbox_slm:softwareproductinstallation_add",
@@ -60,11 +60,11 @@ menu_items = (
ButtonColorChoices.CYAN,
permissions=["netbox_slm.add_softwareproductinstallation"],
),
- )
+ ),
),
PluginMenuItem(
- link='plugins:netbox_slm:softwarelicense_list',
- link_text='Licenses',
+ link="plugins:netbox_slm:softwarelicense_list",
+ link_text="Licenses",
buttons=(
PluginMenuButton(
"plugins:netbox_slm:softwarelicense_add",
@@ -80,6 +80,6 @@ menu_items = (
ButtonColorChoices.CYAN,
permissions=["netbox_slm.add_softwarelicense"],
),
- )
+ ),
),
)
diff --git a/netbox_slm/tables.py b/netbox_slm/tables.py
index 7d0731b..374b6f8 100644
--- a/netbox_slm/tables.py
+++ b/netbox_slm/tables.py
@@ -11,15 +11,10 @@ class SoftwareProductTable(NetBoxTable):
pk = ToggleColumn()
name = tables.LinkColumn()
- manufacturer = tables.Column(
- accessor=Accessor('manufacturer'),
- linkify=True
- )
- installations = tables.Column(accessor='get_installation_count', verbose_name='Installations')
+ manufacturer = tables.Column(accessor=Accessor("manufacturer"), linkify=True)
+ installations = tables.Column(accessor="get_installation_count", verbose_name="Installations")
- tags = columns.TagColumn(
- url_name="plugins:netbox_slm:softwareproduct_list",
- )
+ tags = columns.TagColumn(url_name="plugins:netbox_slm:softwareproduct_list")
class Meta(NetBoxTable.Meta):
model = SoftwareProduct
@@ -47,9 +42,9 @@ class SoftwareProductTable(NetBoxTable):
)
def order_installations(self, queryset, is_descending):
- queryset = queryset.annotate(
- count=Count('softwareproductinstallation__id')
- ).order_by(("-" if is_descending else "") + "count")
+ queryset = queryset.annotate(count=Count("softwareproductinstallation__id")).order_by(
+ ("-" if is_descending else "") + "count"
+ )
return queryset, True
@@ -57,20 +52,12 @@ class SoftwareProductVersionTable(NetBoxTable):
"""Table for displaying SoftwareProductVersion objects."""
pk = ToggleColumn()
- name = tables.LinkColumn(verbose_name='Version')
- software_product = tables.Column(
- accessor=Accessor('software_product'),
- linkify=True
- )
- manufacturer = tables.Column(
- accessor=Accessor('software_product__manufacturer'),
- linkify=True
- )
- installations = tables.Column(accessor='get_installation_count', verbose_name='Installations')
+ name = tables.LinkColumn(verbose_name="Version")
+ software_product = tables.Column(accessor=Accessor("software_product"), linkify=True)
+ manufacturer = tables.Column(accessor=Accessor("software_product__manufacturer"), linkify=True)
+ installations = tables.Column(accessor="get_installation_count", verbose_name="Installations")
- tags = columns.TagColumn(
- url_name="plugins:netbox_slm:softwareproductversion_list",
- )
+ tags = columns.TagColumn(url_name="plugins:netbox_slm:softwareproductversion_list")
class Meta(NetBoxTable.Meta):
model = SoftwareProductVersion
@@ -98,9 +85,9 @@ class SoftwareProductVersionTable(NetBoxTable):
)
def order_installations(self, queryset, is_descending):
- queryset = queryset.annotate(
- count=Count('softwareproductinstallation__id')
- ).order_by(("-" if is_descending else "") + "count")
+ queryset = queryset.annotate(count=Count("softwareproductinstallation__id")).order_by(
+ ("-" if is_descending else "") + "count"
+ )
return queryset, True
@@ -109,31 +96,14 @@ class SoftwareProductInstallationTable(NetBoxTable):
pk = ToggleColumn()
name = tables.LinkColumn()
- device = tables.Column(
- accessor=Accessor('device'),
- linkify=True
- )
- virtualmachine = tables.Column(
- accessor=Accessor('virtualmachine'),
- linkify=True
- )
- platform = tables.Column(
- accessor=Accessor('platform'),
- linkify=True
- )
- type = tables.Column(accessor='render_type')
- software_product = tables.Column(
- accessor=Accessor('software_product'),
- linkify=True
- )
- version = tables.Column(
- accessor=Accessor('version'),
- linkify=True
- )
+ device = tables.Column(accessor=Accessor("device"), linkify=True)
+ virtualmachine = tables.Column(accessor=Accessor("virtualmachine"), linkify=True)
+ platform = tables.Column(accessor=Accessor("platform"), linkify=True)
+ type = tables.Column(accessor="render_type")
+ software_product = tables.Column(accessor=Accessor("software_product"), linkify=True)
+ version = tables.Column(accessor=Accessor("version"), linkify=True)
- tags = columns.TagColumn(
- url_name="plugins:netbox_slm:softwareproductinstallation_list",
- )
+ tags = columns.TagColumn(url_name="plugins:netbox_slm:softwareproductinstallation_list")
class Meta(NetBoxTable.Meta):
model = SoftwareProductInstallation
@@ -173,23 +143,12 @@ class SoftwareLicenseTable(NetBoxTable):
pk = ToggleColumn()
name = tables.LinkColumn()
- type = tables.Column(accessor='render_type')
- software_product = tables.Column(
- accessor=Accessor('software_product'),
- linkify=True
- )
- version = tables.Column(
- accessor=Accessor('version'),
- linkify=True
- )
- installation = tables.Column(
- accessor=Accessor('installation'),
- linkify=True
- )
+ type = tables.Column(accessor="render_type")
+ software_product = tables.Column(accessor=Accessor("software_product"), linkify=True)
+ version = tables.Column(accessor=Accessor("version"), linkify=True)
+ installation = tables.Column(accessor=Accessor("installation"), linkify=True)
- tags = columns.TagColumn(
- url_name="plugins:netbox_slm:softwarelicense_list",
- )
+ tags = columns.TagColumn(url_name="plugins:netbox_slm:softwarelicense_list")
class Meta(NetBoxTable.Meta):
model = SoftwareLicense
diff --git a/netbox_slm/tests/test_models.py b/netbox_slm/tests/test_models.py
index 41fdf75..9d156ff 100644
--- a/netbox_slm/tests/test_models.py
+++ b/netbox_slm/tests/test_models.py
@@ -17,8 +17,10 @@ class ModelTestCase(TestCase):
software_product=self.software_product, version=self.software_product_version
)
self.software_license = SoftwareLicense.objects.create(
- name=self.l_name, software_product=self.software_product,
- version=self.software_product_version, installation=self.software_product_installation
+ name=self.l_name,
+ software_product=self.software_product,
+ version=self.software_product_version,
+ installation=self.software_product_installation,
)
def test_model_name(self):
diff --git a/netbox_slm/urls.py b/netbox_slm/urls.py
index 02cb9ae..43ba8b0 100644
--- a/netbox_slm/urls.py
+++ b/netbox_slm/urls.py
@@ -6,94 +6,105 @@ from netbox_slm.models import SoftwareProduct, SoftwareProductVersion, SoftwareP
urlpatterns = [
# SoftwareProduct
- path("software-products/", views.SoftwareProductListView.as_view(),
- name='softwareproduct_list'),
- path("software-products/add/", views.SoftwareProductEditView.as_view(),
- name='softwareproduct_add'),
- path("software-products/import/", views.SoftwareProductBulkImportView.as_view(),
- name="softwareproduct_import"),
- path("software-products/edit/", views.SoftwareProductBulkEditView.as_view(),
- name="softwareproduct_bulk_edit"),
- path("software-products/delete/", views.SoftwareProductBulkDeleteView.as_view(),
- name="softwareproduct_bulk_delete"),
- path("software-products//", views.SoftwareProductView.as_view(),
- name="softwareproduct"),
- path("software-products//delete/", views.SoftwareProductDeleteView.as_view(),
- name="softwareproduct_delete"),
- path("software-products//edit/", views.SoftwareProductEditView.as_view(),
- name="softwareproduct_edit"),
+ path("software-products/", views.SoftwareProductListView.as_view(), name="softwareproduct_list"),
+ path("software-products/add/", views.SoftwareProductEditView.as_view(), name="softwareproduct_add"),
+ path("software-products/import/", views.SoftwareProductBulkImportView.as_view(), name="softwareproduct_import"),
+ path("software-products/edit/", views.SoftwareProductBulkEditView.as_view(), name="softwareproduct_bulk_edit"),
+ path(
+ "software-products/delete/", views.SoftwareProductBulkDeleteView.as_view(), name="softwareproduct_bulk_delete"
+ ),
+ path("software-products//", views.SoftwareProductView.as_view(), name="softwareproduct"),
+ path(
+ "software-products//delete/", views.SoftwareProductDeleteView.as_view(), name="softwareproduct_delete"
+ ),
+ path("software-products//edit/", views.SoftwareProductEditView.as_view(), name="softwareproduct_edit"),
path(
"software-products//changelog/",
ObjectChangeLogView.as_view(),
name="softwareproduct_changelog",
kwargs={"model": SoftwareProduct},
),
-
# SoftwareProductVersion
- path("versions/", views.SoftwareProductVersionListView.as_view(),
- name='softwareproductversion_list'),
- path("versions/add/", views.SoftwareProductVersionEditView.as_view(),
- name='softwareproductversion_add'),
- path("versions/import/", views.SoftwareProductVersionBulkImportView.as_view(),
- name="softwareproductversion_import"),
- path("versions/edit/", views.SoftwareProductVersionBulkEditView.as_view(),
- name="softwareproductversion_bulk_edit"),
- path("versions/delete/", views.SoftwareProductVersionBulkDeleteView.as_view(),
- name="softwareproductversion_bulk_delete"),
- path("versions//", views.SoftwareProductVersionView.as_view(),
- name="softwareproductversion"),
- path("versions//delete/", views.SoftwareProductVersionDeleteView.as_view(),
- name="softwareproductversion_delete"),
- path("versions//edit/", views.SoftwareProductVersionEditView.as_view(),
- name="softwareproductversion_edit"),
+ path("versions/", views.SoftwareProductVersionListView.as_view(), name="softwareproductversion_list"),
+ path("versions/add/", views.SoftwareProductVersionEditView.as_view(), name="softwareproductversion_add"),
+ path(
+ "versions/import/", views.SoftwareProductVersionBulkImportView.as_view(), name="softwareproductversion_import"
+ ),
+ path("versions/edit/", views.SoftwareProductVersionBulkEditView.as_view(), name="softwareproductversion_bulk_edit"),
+ path(
+ "versions/delete/",
+ views.SoftwareProductVersionBulkDeleteView.as_view(),
+ name="softwareproductversion_bulk_delete",
+ ),
+ path("versions//", views.SoftwareProductVersionView.as_view(), name="softwareproductversion"),
+ path(
+ "versions//delete/",
+ views.SoftwareProductVersionDeleteView.as_view(),
+ name="softwareproductversion_delete",
+ ),
+ path("versions//edit/", views.SoftwareProductVersionEditView.as_view(), name="softwareproductversion_edit"),
path(
"versions//changelog/",
ObjectChangeLogView.as_view(),
name="softwareproductversion_changelog",
kwargs={"model": SoftwareProductVersion},
),
-
# SoftwareProductInstallation
- path("installations/", views.SoftwareProductInstallationListView.as_view(),
- name='softwareproductinstallation_list'),
- path("installations/add/", views.SoftwareProductInstallationEditView.as_view(),
- name='softwareproductinstallation_add'),
- path("installations/import/", views.SoftwareProductInstallationBulkImportView.as_view(),
- name="softwareproductinstallation_import"),
- path("installations/edit/", views.SoftwareProductInstallationBulkEditView.as_view(),
- name="softwareproductinstallation_bulk_edit"),
- path("installations/delete/", views.SoftwareProductInstallationBulkDeleteView.as_view(),
- name="softwareproductinstallation_bulk_delete"),
- path("installations//", views.SoftwareProductInstallationView.as_view(),
- name="softwareproductinstallation"),
- path("installations//delete/", views.SoftwareProductInstallationDeleteView.as_view(),
- name="softwareproductinstallation_delete"),
- path("installations//edit/", views.SoftwareProductInstallationEditView.as_view(),
- name="softwareproductinstallation_edit"),
+ path(
+ "installations/",
+ views.SoftwareProductInstallationListView.as_view(),
+ name="softwareproductinstallation_list",
+ ),
+ path(
+ "installations/add/",
+ views.SoftwareProductInstallationEditView.as_view(),
+ name="softwareproductinstallation_add",
+ ),
+ path(
+ "installations/import/",
+ views.SoftwareProductInstallationBulkImportView.as_view(),
+ name="softwareproductinstallation_import",
+ ),
+ path(
+ "installations/edit/",
+ views.SoftwareProductInstallationBulkEditView.as_view(),
+ name="softwareproductinstallation_bulk_edit",
+ ),
+ path(
+ "installations/delete/",
+ views.SoftwareProductInstallationBulkDeleteView.as_view(),
+ name="softwareproductinstallation_bulk_delete",
+ ),
+ path(
+ "installations//",
+ views.SoftwareProductInstallationView.as_view(),
+ name="softwareproductinstallation",
+ ),
+ path(
+ "installations//delete/",
+ views.SoftwareProductInstallationDeleteView.as_view(),
+ name="softwareproductinstallation_delete",
+ ),
+ path(
+ "installations//edit/",
+ views.SoftwareProductInstallationEditView.as_view(),
+ name="softwareproductinstallation_edit",
+ ),
path(
"installations//changelog/",
ObjectChangeLogView.as_view(),
name="softwareproductinstallation_changelog",
kwargs={"model": SoftwareProductInstallation},
),
-
# SoftwareLicense
- path("licenses/", views.SoftwareLicenseListView.as_view(),
- name='softwarelicense_list'),
- path("licenses/add/", views.SoftwareLicenseEditView.as_view(),
- name='softwarelicense_add'),
- path("licenses/import/", views.SoftwareLicenseBulkImportView.as_view(),
- name="softwarelicense_import"),
- path("licenses/edit/", views.SoftwareLicenseBulkEditView.as_view(),
- name="softwarelicense_bulk_edit"),
- path("licenses/delete/", views.SoftwareLicenseBulkDeleteView.as_view(),
- name="softwarelicense_bulk_delete"),
- path("licenses//", views.SoftwareLicenseView.as_view(),
- name="softwarelicense"),
- path("licenses//delete/", views.SoftwareLicenseDeleteView.as_view(),
- name="softwarelicense_delete"),
- path("licenses//edit/", views.SoftwareLicenseEditView.as_view(),
- name="softwarelicense_edit"),
+ path("licenses/", views.SoftwareLicenseListView.as_view(), name="softwarelicense_list"),
+ path("licenses/add/", views.SoftwareLicenseEditView.as_view(), name="softwarelicense_add"),
+ path("licenses/import/", views.SoftwareLicenseBulkImportView.as_view(), name="softwarelicense_import"),
+ path("licenses/edit/", views.SoftwareLicenseBulkEditView.as_view(), name="softwarelicense_bulk_edit"),
+ path("licenses/delete/", views.SoftwareLicenseBulkDeleteView.as_view(), name="softwarelicense_bulk_delete"),
+ path("licenses//", views.SoftwareLicenseView.as_view(), name="softwarelicense"),
+ path("licenses//delete/", views.SoftwareLicenseDeleteView.as_view(), name="softwarelicense_delete"),
+ path("licenses//edit/", views.SoftwareLicenseEditView.as_view(), name="softwarelicense_edit"),
path(
"licenses//changelog/",
ObjectChangeLogView.as_view(),
diff --git a/netbox_slm/views/__init__.py b/netbox_slm/views/__init__.py
index b579da4..4a76efa 100644
--- a/netbox_slm/views/__init__.py
+++ b/netbox_slm/views/__init__.py
@@ -1,4 +1,36 @@
-from .software_license import *
-from .software_product import *
-from .software_product_installation import *
-from .software_product_version import *
+from .software_license import (
+ SoftwareLicenseListView,
+ SoftwareLicenseView,
+ SoftwareLicenseEditView,
+ SoftwareLicenseDeleteView,
+ SoftwareLicenseBulkImportView,
+ SoftwareLicenseBulkEditView,
+ SoftwareLicenseBulkDeleteView,
+)
+from .software_product import (
+ SoftwareProductListView,
+ SoftwareProductView,
+ SoftwareProductEditView,
+ SoftwareProductDeleteView,
+ SoftwareProductBulkImportView,
+ SoftwareProductBulkEditView,
+ SoftwareProductBulkDeleteView,
+)
+from .software_product_installation import (
+ SoftwareProductInstallationListView,
+ SoftwareProductInstallationView,
+ SoftwareProductInstallationEditView,
+ SoftwareProductInstallationDeleteView,
+ SoftwareProductInstallationBulkImportView,
+ SoftwareProductInstallationBulkEditView,
+ SoftwareProductInstallationBulkDeleteView,
+)
+from .software_product_version import (
+ SoftwareProductVersionListView,
+ SoftwareProductVersionView,
+ SoftwareProductVersionEditView,
+ SoftwareProductVersionDeleteView,
+ SoftwareProductVersionBulkImportView,
+ SoftwareProductVersionBulkEditView,
+ SoftwareProductVersionBulkDeleteView,
+)
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..f062736
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,73 @@
+[build-system]
+requires = ["setuptools"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "netbox-slm"
+dynamic = ["version"]
+description = "Software Lifecycle Management Netbox Plugin"
+readme = "README.md"
+requires-python = ">=3.9"
+license = { text = "Apache-2.0" }
+authors = [
+ {name = "ICTU", email = "open-source-projects@ictu.nl"},
+]
+classifiers = [
+ "Environment :: Web Environment",
+ "Framework :: Django",
+ "Intended Audience :: Developers",
+ "License :: OSI Approved :: Apache Software License",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3 :: Only",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+ "Topic :: Internet :: WWW/HTTP",
+ "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
+]
+dependencies = []
+
+[project.optional-dependencies]
+build = [
+ "build == 1.0.3",
+ "setuptools == 68.2.0",
+ "twine == 3.7.1",
+]
+tools = [
+ "black == 23.3.0",
+ "ruff == 0.0.275",
+]
+
+[tool.setuptools.dynamic]
+version = {attr = "netbox_slm.__version__"}
+
+[tool.setuptools.packages.find]
+include = ["netbox_slm"]
+
+[tool.black]
+line-length = 120
+target-version = ["py39"]
+color = true
+check = true
+diff = true
+fast = true
+extend-exclude = '''
+netbox_slm/migrations/.*.py
+'''
+
+[tool.ruff]
+line-length = 120
+target-version = "py39"
+format = "github"
+src = ["netbox_slm"]
+
+[tool.ruff.per-file-ignores]
+"__init__.py" = [
+ "D104", # https://beta.ruff.rs/docs/rules/#pydocstyle-d - don't require doc strings in __init__.py files
+ "F401", # https://beta.ruff.rs/docs/rules/#pyflakes-f - don't complain about unused imports in __init__.py files
+]
+"netbox_slm/migrations/*.py" = [
+ "E501", # https://beta.ruff.rs/docs/rules/line-too-long/ - don't check on Django generated migration files
+]
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index 43b5b59..0000000
--- a/setup.cfg
+++ /dev/null
@@ -1,26 +0,0 @@
-[metadata]
-name = netbox-slm
-version = 1.4
-description = Software Lifecycle Management Netbox Plugin.
-author = ICTU
-author_email = open-source-projects@ictu.nl
-license = Apache 2.0
-classifiers =
- Environment :: Web Environment
- Framework :: Django
- Intended Audience :: Developers
- License :: OSI Approved :: Apache Software License
- Operating System :: OS Independent
- Programming Language :: Python
- Programming Language :: Python :: 3
- Programming Language :: Python :: 3 :: Only
- Programming Language :: Python :: 3.9
- Programming Language :: Python :: 3.10
- Programming Language :: Python :: 3.11
- Topic :: Internet :: WWW/HTTP
- Topic :: Internet :: WWW/HTTP :: Dynamic Content
-
-[options]
-include_package_data = true
-packages = find:
-python_requires = >=3.9
diff --git a/setup.py b/setup.py
deleted file mode 100644
index 6068493..0000000
--- a/setup.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from setuptools import setup
-
-setup()