feat: add German localization
Internationalize plugin navigation, forms, tables, model labels, detail templates, choices, and validation messages. Ship a compiled German Django message catalog and bump the plugin version to 1.10.0.
This commit is contained in:
@@ -15,15 +15,16 @@ limitations under the License.
|
||||
"""
|
||||
|
||||
from netbox.plugins import PluginConfig
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
__version__ = "1.9.1"
|
||||
__version__ = "1.10.0"
|
||||
|
||||
|
||||
class SLMConfig(PluginConfig):
|
||||
name = "netbox_slm"
|
||||
verbose_name = "Software Lifecycle Management"
|
||||
verbose_name = _("Software Lifecycle Management")
|
||||
version = __version__
|
||||
description = "Software Lifecycle Management Netbox Plugin."
|
||||
description = _("Software Lifecycle Management NetBox Plugin.")
|
||||
author = "ICTU"
|
||||
author_email = "open-source-projects@ictu.nl"
|
||||
base_url = "slm"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from rest_framework import serializers
|
||||
from rest_framework.serializers import SerializerMethodField, HyperlinkedIdentityField
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from netbox.api.serializers import NetBoxModelSerializer
|
||||
from netbox_slm.models import SoftwareProduct, SoftwareProductVersion, SoftwareProductInstallation, SoftwareLicense
|
||||
@@ -46,7 +47,7 @@ class SoftwareLicenseSerializer(NetBoxModelSerializer):
|
||||
tenant = attrs.get("tenant", getattr(self.instance, "tenant", None))
|
||||
if tenant_group and tenant and tenant.group_id != tenant_group.pk:
|
||||
raise serializers.ValidationError(
|
||||
{"tenant": "The selected tenant does not belong to the selected tenant group."}
|
||||
{"tenant": _("The selected tenant does not belong to the selected tenant group.")}
|
||||
)
|
||||
return attrs
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from django.db.models import Q
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_filters import CharFilter, ModelMultipleChoiceFilter, MultipleChoiceFilter
|
||||
|
||||
from dcim.models import Device, Manufacturer
|
||||
@@ -55,7 +56,7 @@ class SoftwareProductVersionFilterSet(NetBoxModelFilterSet):
|
||||
|
||||
software_product_id = ModelMultipleChoiceFilter(
|
||||
queryset=SoftwareProduct.objects.all(),
|
||||
label="Software Product",
|
||||
label=_("Software Product"),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
@@ -82,12 +83,12 @@ class SoftwareProductInstallationFilterSet(NetBoxModelFilterSet):
|
||||
device_id = ModelMultipleChoiceFilter(queryset=Device.objects.all())
|
||||
virtualmachine_id = ModelMultipleChoiceFilter(
|
||||
queryset=VirtualMachine.objects.all(),
|
||||
label="Virtual Machine",
|
||||
label=_("Virtual Machine"),
|
||||
)
|
||||
cluster_id = ModelMultipleChoiceFilter(queryset=Cluster.objects.all())
|
||||
software_product_id = ModelMultipleChoiceFilter(
|
||||
queryset=SoftwareProduct.objects.all(),
|
||||
label="Software Product",
|
||||
label=_("Software Product"),
|
||||
)
|
||||
version_id = ModelMultipleChoiceFilter(queryset=SoftwareProductVersion.objects.all())
|
||||
|
||||
@@ -114,17 +115,17 @@ class SoftwareLicenseFilterSet(NetBoxModelFilterSet):
|
||||
name = CharFilter(lookup_expr="icontains")
|
||||
description = CharFilter(lookup_expr="icontains")
|
||||
type = CharFilter(lookup_expr="icontains")
|
||||
spdx_expression = CharFilter(lookup_expr="icontains", label="SPDX expression")
|
||||
spdx_expression = CharFilter(lookup_expr="icontains", label=_("SPDX expression"))
|
||||
stored_location = CharFilter(lookup_expr="icontains")
|
||||
|
||||
software_product_id = ModelMultipleChoiceFilter(
|
||||
queryset=SoftwareProduct.objects.all(),
|
||||
label="Software Product",
|
||||
label=_("Software Product"),
|
||||
)
|
||||
version_id = ModelMultipleChoiceFilter(queryset=SoftwareProductVersion.objects.all())
|
||||
installation_id = ModelMultipleChoiceFilter(queryset=SoftwareProductInstallation.objects.all())
|
||||
tenant_group_id = ModelMultipleChoiceFilter(queryset=TenantGroup.objects.all(), label="Tenant Group")
|
||||
tenant_id = ModelMultipleChoiceFilter(queryset=Tenant.objects.all(), label="Tenant")
|
||||
tenant_group_id = ModelMultipleChoiceFilter(queryset=TenantGroup.objects.all(), label=_("Tenant Group"))
|
||||
tenant_id = ModelMultipleChoiceFilter(queryset=Tenant.objects.all(), label=_("Tenant"))
|
||||
|
||||
class Meta:
|
||||
model = SoftwareLicense
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from django.forms import CharField, DateField, ChoiceField, IntegerField, NullBooleanField
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from netbox.forms import NetBoxModelForm, NetBoxModelFilterSetForm, NetBoxModelImportForm, NetBoxModelBulkEditForm
|
||||
from netbox_slm.models import (
|
||||
@@ -31,9 +32,9 @@ class SoftwareLicenseForm(NetBoxModelForm):
|
||||
"software_product",
|
||||
"version",
|
||||
"installation",
|
||||
name="Software License",
|
||||
name=_("Software License"),
|
||||
),
|
||||
FieldSet("tenant_group", "tenant", name="Tenancy"),
|
||||
FieldSet("tenant_group", "tenant", name=_("Tenancy")),
|
||||
FieldSet(
|
||||
"type",
|
||||
"spdx_expression",
|
||||
@@ -43,12 +44,12 @@ class SoftwareLicenseForm(NetBoxModelForm):
|
||||
"expiration_date",
|
||||
"support",
|
||||
"license_amount",
|
||||
name="License Details",
|
||||
name=_("License Details"),
|
||||
),
|
||||
FieldSet("tags", name="Tags"),
|
||||
FieldSet("tags", name=_("Tags")),
|
||||
)
|
||||
|
||||
spdx_expression = ChoiceField(required=False, choices=spdx_license_names(), label="SPDX expression")
|
||||
spdx_expression = ChoiceField(required=False, choices=spdx_license_names(), label=_("SPDX expression"))
|
||||
stored_location_url = LaxURLField(required=False)
|
||||
start_date = DateField(required=False, widget=DatePicker())
|
||||
expiration_date = DateField(required=False, widget=DatePicker())
|
||||
@@ -56,7 +57,7 @@ class SoftwareLicenseForm(NetBoxModelForm):
|
||||
software_product = DynamicModelChoiceField(
|
||||
queryset=SoftwareProduct.objects.all(),
|
||||
required=True,
|
||||
label="Software Product",
|
||||
label=_("Software Product"),
|
||||
)
|
||||
version = DynamicModelChoiceField(
|
||||
queryset=SoftwareProductVersion.objects.all(),
|
||||
@@ -75,13 +76,13 @@ class SoftwareLicenseForm(NetBoxModelForm):
|
||||
tenant_group = DynamicModelChoiceField(
|
||||
queryset=TenantGroup.objects.all(),
|
||||
required=False,
|
||||
label="Tenant Group",
|
||||
label=_("Tenant Group"),
|
||||
)
|
||||
tenant = DynamicModelChoiceField(
|
||||
queryset=Tenant.objects.all(),
|
||||
required=False,
|
||||
query_params={"group_id": "$tenant_group"},
|
||||
label="Tenant",
|
||||
label=_("Tenant"),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
@@ -132,40 +133,42 @@ class SoftwareLicenseFilterForm(NetBoxModelFilterSetForm):
|
||||
name = CharField(required=False)
|
||||
description = CharField(required=False)
|
||||
type = CharField(required=False)
|
||||
spdx_expression = CharField(required=False, label="SPDX expression")
|
||||
spdx_expression = CharField(required=False, label=_("SPDX expression"))
|
||||
stored_location = CharField(required=False)
|
||||
support = ChoiceField(required=False, choices=BOOLEAN_WITH_BLANK_CHOICES)
|
||||
|
||||
software_product_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SoftwareProduct.objects.all(),
|
||||
required=False,
|
||||
label="Software Product",
|
||||
label=_("Software Product"),
|
||||
)
|
||||
version_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SoftwareProductVersion.objects.all(),
|
||||
required=False,
|
||||
label="Version",
|
||||
label=_("Version"),
|
||||
)
|
||||
installation_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SoftwareProductInstallation.objects.all(),
|
||||
required=False,
|
||||
label="Installation",
|
||||
label=_("Installation"),
|
||||
)
|
||||
tenant_group_id = DynamicModelMultipleChoiceField(
|
||||
queryset=TenantGroup.objects.all(),
|
||||
required=False,
|
||||
label="Tenant Group",
|
||||
label=_("Tenant Group"),
|
||||
)
|
||||
tenant_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Tenant.objects.all(),
|
||||
required=False,
|
||||
query_params={"group_id": "$tenant_group_id"},
|
||||
label="Tenant",
|
||||
label=_("Tenant"),
|
||||
)
|
||||
|
||||
|
||||
class SoftwareLicenseBulkImportForm(NetBoxModelImportForm):
|
||||
support = NullBooleanField(required=False, help_text="Support (values other than 'True' and 'False' are ignored)")
|
||||
support = NullBooleanField(
|
||||
required=False, help_text=_("Support (values other than 'True' and 'False' are ignored)")
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = SoftwareLicense
|
||||
@@ -226,7 +229,7 @@ class SoftwareLicenseBulkEditForm(NetBoxModelBulkEditForm):
|
||||
comments = CommentField()
|
||||
|
||||
type = CharField(required=False)
|
||||
spdx_expression = ChoiceField(required=False, choices=spdx_license_names(), label="SPDX expression")
|
||||
spdx_expression = ChoiceField(required=False, choices=spdx_license_names(), label=_("SPDX expression"))
|
||||
stored_location = CharField(required=False)
|
||||
stored_location_url = LaxURLField(required=False)
|
||||
start_date = DateField(required=False, widget=DatePicker())
|
||||
@@ -237,7 +240,7 @@ class SoftwareLicenseBulkEditForm(NetBoxModelBulkEditForm):
|
||||
software_product = DynamicModelChoiceField(
|
||||
queryset=SoftwareProduct.objects.all(),
|
||||
required=False,
|
||||
label="Software Product",
|
||||
label=_("Software Product"),
|
||||
)
|
||||
version = DynamicModelChoiceField(
|
||||
queryset=SoftwareProductVersion.objects.all(),
|
||||
@@ -256,11 +259,11 @@ class SoftwareLicenseBulkEditForm(NetBoxModelBulkEditForm):
|
||||
tenant_group = DynamicModelChoiceField(
|
||||
queryset=TenantGroup.objects.all(),
|
||||
required=False,
|
||||
label="Tenant Group",
|
||||
label=_("Tenant Group"),
|
||||
)
|
||||
tenant = DynamicModelChoiceField(
|
||||
queryset=Tenant.objects.all(),
|
||||
required=False,
|
||||
query_params={"group_id": "$tenant_group"},
|
||||
label="Tenant",
|
||||
label=_("Tenant"),
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from django.forms import CharField
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from dcim.models import Manufacturer
|
||||
from netbox.forms import NetBoxModelForm, NetBoxModelFilterSetForm, NetBoxModelImportForm, NetBoxModelBulkEditForm
|
||||
@@ -46,7 +47,7 @@ class SoftwareProductFilterForm(NetBoxModelFilterSetForm):
|
||||
manufacturer_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Manufacturer.objects.all(),
|
||||
required=False,
|
||||
label="Manufacturer",
|
||||
label=_("Manufacturer"),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from django.forms import ValidationError
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from dcim.models import Device
|
||||
from netbox.forms import NetBoxModelForm, NetBoxModelFilterSetForm, NetBoxModelImportForm, NetBoxModelBulkEditForm
|
||||
@@ -22,13 +23,13 @@ class SoftwareProductInstallationForm(NetBoxModelForm):
|
||||
virtualmachine = DynamicModelChoiceField(
|
||||
queryset=VirtualMachine.objects.all(),
|
||||
required=False,
|
||||
label="Virtual Machine",
|
||||
label=_("Virtual Machine"),
|
||||
)
|
||||
cluster = DynamicModelChoiceField(queryset=Cluster.objects.all(), required=False)
|
||||
software_product = DynamicModelChoiceField(
|
||||
queryset=SoftwareProduct.objects.all(),
|
||||
required=True,
|
||||
label="Software Product",
|
||||
label=_("Software Product"),
|
||||
)
|
||||
version = DynamicModelChoiceField(
|
||||
queryset=SoftwareProductVersion.objects.all(),
|
||||
@@ -54,8 +55,8 @@ class SoftwareProductInstallationForm(NetBoxModelForm):
|
||||
software_product = self.cleaned_data["software_product"]
|
||||
if version not in software_product.softwareproductversion_set.all():
|
||||
raise 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."
|
||||
_("Version '%(version)s' does not belong to %(product)s. Select a compatible version.")
|
||||
% {"version": version, "product": software_product}
|
||||
)
|
||||
return version
|
||||
|
||||
@@ -73,27 +74,27 @@ class SoftwareProductInstallationFilterForm(NetBoxModelFilterSetForm):
|
||||
device_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Device.objects.all(),
|
||||
required=False,
|
||||
label="Device",
|
||||
label=_("Device"),
|
||||
)
|
||||
virtualmachine_id = DynamicModelMultipleChoiceField(
|
||||
queryset=VirtualMachine.objects.all(),
|
||||
required=False,
|
||||
label="Virtual Machine",
|
||||
label=_("Virtual Machine"),
|
||||
)
|
||||
cluster_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Cluster.objects.all(),
|
||||
required=False,
|
||||
label="Cluster",
|
||||
label=_("Cluster"),
|
||||
)
|
||||
software_product_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SoftwareProduct.objects.all(),
|
||||
required=False,
|
||||
label="Software Product",
|
||||
label=_("Software Product"),
|
||||
)
|
||||
version_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SoftwareProductVersion.objects.all(),
|
||||
required=False,
|
||||
label="Version",
|
||||
label=_("Version"),
|
||||
)
|
||||
|
||||
|
||||
@@ -122,13 +123,13 @@ class SoftwareProductInstallationBulkEditForm(NetBoxModelBulkEditForm):
|
||||
virtualmachine = DynamicModelChoiceField(
|
||||
queryset=VirtualMachine.objects.all(),
|
||||
required=False,
|
||||
label="Virtual Machine",
|
||||
label=_("Virtual Machine"),
|
||||
)
|
||||
cluster = DynamicModelChoiceField(queryset=Cluster.objects.all(), required=False)
|
||||
software_product = DynamicModelChoiceField(
|
||||
queryset=SoftwareProduct.objects.all(),
|
||||
required=False,
|
||||
label="Software Product",
|
||||
label=_("Software Product"),
|
||||
)
|
||||
version = DynamicModelChoiceField(
|
||||
queryset=SoftwareProductVersion.objects.all(),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from django.forms import DateField, CharField, MultipleChoiceField
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from dcim.models import Manufacturer
|
||||
from netbox.forms import NetBoxModelForm, NetBoxModelFilterSetForm, NetBoxModelImportForm, NetBoxModelBulkEditForm
|
||||
@@ -23,7 +24,7 @@ class SoftwareProductVersionForm(NetBoxModelForm):
|
||||
software_product = DynamicModelChoiceField(
|
||||
queryset=SoftwareProduct.objects.all(),
|
||||
required=True,
|
||||
label="Software Product",
|
||||
label=_("Software Product"),
|
||||
widget=APISelect(attrs={"data-url": reverse_lazy("plugins-api:netbox_slm-api:softwareproduct-list")}),
|
||||
)
|
||||
|
||||
@@ -64,17 +65,19 @@ class SoftwareProductVersionFilterForm(NetBoxModelFilterSetForm):
|
||||
manufacturer_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Manufacturer.objects.all(),
|
||||
required=False,
|
||||
label="Manufacturer",
|
||||
label=_("Manufacturer"),
|
||||
)
|
||||
software_product_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SoftwareProduct.objects.all(),
|
||||
required=False,
|
||||
label="Software Product",
|
||||
label=_("Software Product"),
|
||||
)
|
||||
|
||||
|
||||
class SoftwareProductVersionBulkImportForm(NetBoxModelImportForm):
|
||||
release_type = CharField(help_text=f"Release type (possible values: {SoftwareReleaseTypes.values})")
|
||||
release_type = CharField(
|
||||
help_text=_("Release type (possible values: %(values)s)") % {"values": SoftwareReleaseTypes.values}
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = SoftwareProductVersion
|
||||
@@ -122,5 +125,5 @@ class SoftwareProductVersionBulkEditForm(NetBoxModelBulkEditForm):
|
||||
software_product = DynamicModelChoiceField(
|
||||
queryset=SoftwareProduct.objects.all(),
|
||||
required=False,
|
||||
label="Software Product",
|
||||
label=_("Software Product"),
|
||||
)
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,263 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: netbox-slm 1.9.1\n"
|
||||
"Language: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Add"
|
||||
msgstr "Hinzufügen"
|
||||
|
||||
msgid "Import"
|
||||
msgstr "Importieren"
|
||||
|
||||
msgid "Software Lifecycle"
|
||||
msgstr "Software-Lebenszyklus"
|
||||
|
||||
msgid "Software Products"
|
||||
msgstr "Softwareprodukte"
|
||||
|
||||
msgid "Software Product"
|
||||
msgstr "Softwareprodukt"
|
||||
|
||||
msgid "Software Product Version"
|
||||
msgstr "Softwareproduktversion"
|
||||
|
||||
msgid "Software Product Installation"
|
||||
msgstr "Softwareproduktinstallation"
|
||||
|
||||
msgid "Software License"
|
||||
msgstr "Softwarelizenz"
|
||||
|
||||
msgid "License Details"
|
||||
msgstr "Lizenzdetails"
|
||||
|
||||
msgid "Versions"
|
||||
msgstr "Versionen"
|
||||
|
||||
msgid "Version"
|
||||
msgstr "Version"
|
||||
|
||||
msgid "Installations"
|
||||
msgstr "Installationen"
|
||||
|
||||
msgid "Installation"
|
||||
msgstr "Installation"
|
||||
|
||||
msgid "Add an installation"
|
||||
msgstr "Installation hinzufügen"
|
||||
|
||||
msgid "Licenses"
|
||||
msgstr "Lizenzen"
|
||||
|
||||
msgid "Tenancy"
|
||||
msgstr "Mandantenzuordnung"
|
||||
|
||||
msgid "Tenant Group"
|
||||
msgstr "Mandantengruppe"
|
||||
|
||||
msgid "Tenant"
|
||||
msgstr "Mandant"
|
||||
|
||||
msgid "Manufacturer"
|
||||
msgstr "Hersteller"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "Gerät"
|
||||
|
||||
msgid "Virtual Machine"
|
||||
msgstr "Virtuelle Maschine"
|
||||
|
||||
msgid "Cluster"
|
||||
msgstr "Cluster"
|
||||
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
msgid "Description"
|
||||
msgstr "Beschreibung"
|
||||
|
||||
msgid "Type"
|
||||
msgstr "Typ"
|
||||
|
||||
msgid "SPDX expression"
|
||||
msgstr "SPDX-Ausdruck"
|
||||
|
||||
msgid "Stored location"
|
||||
msgstr "Ablageort"
|
||||
|
||||
msgid "Start date"
|
||||
msgstr "Startdatum"
|
||||
|
||||
msgid "Expiration date"
|
||||
msgstr "Ablaufdatum"
|
||||
|
||||
msgid "Support"
|
||||
msgstr "Support"
|
||||
|
||||
msgid "License amount"
|
||||
msgstr "Lizenzanzahl"
|
||||
|
||||
msgid "Release date"
|
||||
msgstr "Veröffentlichungsdatum"
|
||||
|
||||
msgid "Documentation URL"
|
||||
msgstr "Dokumentations-URL"
|
||||
|
||||
msgid "End of support"
|
||||
msgstr "Supportende"
|
||||
|
||||
msgid "Filename"
|
||||
msgstr "Dateiname"
|
||||
|
||||
msgid "File checksum"
|
||||
msgstr "Dateiprüfsumme"
|
||||
|
||||
msgid "Release type"
|
||||
msgstr "Veröffentlichungstyp"
|
||||
|
||||
msgid "Release candidate"
|
||||
msgstr "Veröffentlichungskandidat"
|
||||
|
||||
msgid "Stable release"
|
||||
msgstr "Stabile Veröffentlichung"
|
||||
|
||||
msgid "Alpha"
|
||||
msgstr "Alpha"
|
||||
|
||||
msgid "Beta"
|
||||
msgstr "Beta"
|
||||
|
||||
msgid "Tags"
|
||||
msgstr "Tags"
|
||||
|
||||
msgid "None"
|
||||
msgstr "Keine"
|
||||
|
||||
msgid "Link"
|
||||
msgstr "Link"
|
||||
|
||||
msgid "Support (values other than 'True' and 'False' are ignored)"
|
||||
msgstr "Support (andere Werte als ‚True‘ und ‚False‘ werden ignoriert)"
|
||||
|
||||
msgid "Release type (possible values: %(values)s)"
|
||||
msgstr "Veröffentlichungstyp (mögliche Werte: %(values)s)"
|
||||
|
||||
msgid "Version '%(version)s' does not belong to %(product)s. Select a compatible version."
|
||||
msgstr "Version ‚%(version)s‘ gehört nicht zu %(product)s. Wähle eine kompatible Version aus."
|
||||
|
||||
msgid "Installation requires exactly one platform destination."
|
||||
msgstr "Eine Installation benötigt genau ein Plattformziel."
|
||||
|
||||
msgid "%(value)s is not a known SPDX license expression"
|
||||
msgstr "%(value)s ist kein bekannter SPDX-Lizenzausdruck"
|
||||
|
||||
msgid "The selected tenant does not belong to the selected tenant group."
|
||||
msgstr "Der ausgewählte Mandant gehört nicht zur ausgewählten Mandantengruppe."
|
||||
|
||||
msgid "Software Lifecycle Management"
|
||||
msgstr "Software-Lebenszyklusverwaltung"
|
||||
|
||||
msgid "Software Lifecycle Management NetBox Plugin."
|
||||
msgstr "NetBox-Plugin zur Verwaltung des Software-Lebenszyklus."
|
||||
|
||||
msgid "name"
|
||||
msgstr "Name"
|
||||
|
||||
msgid "comments"
|
||||
msgstr "Kommentare"
|
||||
|
||||
msgid "description"
|
||||
msgstr "Beschreibung"
|
||||
|
||||
msgid "manufacturer"
|
||||
msgstr "Hersteller"
|
||||
|
||||
msgid "software product"
|
||||
msgstr "Softwareprodukt"
|
||||
|
||||
msgid "software products"
|
||||
msgstr "Softwareprodukte"
|
||||
|
||||
msgid "release date"
|
||||
msgstr "Veröffentlichungsdatum"
|
||||
|
||||
msgid "documentation URL"
|
||||
msgstr "Dokumentations-URL"
|
||||
|
||||
msgid "end of support"
|
||||
msgstr "Supportende"
|
||||
|
||||
msgid "filename"
|
||||
msgstr "Dateiname"
|
||||
|
||||
msgid "file checksum"
|
||||
msgstr "Dateiprüfsumme"
|
||||
|
||||
msgid "file link"
|
||||
msgstr "Dateilink"
|
||||
|
||||
msgid "release type"
|
||||
msgstr "Veröffentlichungstyp"
|
||||
|
||||
msgid "software product version"
|
||||
msgstr "Softwareproduktversion"
|
||||
|
||||
msgid "software product versions"
|
||||
msgstr "Softwareproduktversionen"
|
||||
|
||||
msgid "device"
|
||||
msgstr "Gerät"
|
||||
|
||||
msgid "virtual machine"
|
||||
msgstr "Virtuelle Maschine"
|
||||
|
||||
msgid "cluster"
|
||||
msgstr "Cluster"
|
||||
|
||||
msgid "version"
|
||||
msgstr "Version"
|
||||
|
||||
msgid "software product installation"
|
||||
msgstr "Softwareproduktinstallation"
|
||||
|
||||
msgid "software product installations"
|
||||
msgstr "Softwareproduktinstallationen"
|
||||
|
||||
msgid "type"
|
||||
msgstr "Typ"
|
||||
|
||||
msgid "stored location"
|
||||
msgstr "Ablageort"
|
||||
|
||||
msgid "stored location URL"
|
||||
msgstr "Ablageort-URL"
|
||||
|
||||
msgid "start date"
|
||||
msgstr "Startdatum"
|
||||
|
||||
msgid "expiration date"
|
||||
msgstr "Ablaufdatum"
|
||||
|
||||
msgid "support"
|
||||
msgstr "Support"
|
||||
|
||||
msgid "license amount"
|
||||
msgstr "Lizenzanzahl"
|
||||
|
||||
msgid "installation"
|
||||
msgstr "Installation"
|
||||
|
||||
msgid "tenant group"
|
||||
msgstr "Mandantengruppe"
|
||||
|
||||
msgid "tenant"
|
||||
msgstr "Mandant"
|
||||
|
||||
msgid "software license"
|
||||
msgstr "Softwarelizenz"
|
||||
|
||||
msgid "software licenses"
|
||||
msgstr "Softwarelizenzen"
|
||||
+91
-42
@@ -2,6 +2,7 @@ from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from license_expression import Licensing, get_spdx_licensing
|
||||
|
||||
from netbox.models import NetBoxModel
|
||||
@@ -21,14 +22,20 @@ class LaxURLField(models.URLField):
|
||||
|
||||
|
||||
class SoftwareProduct(NetBoxModel):
|
||||
name = models.CharField(max_length=128)
|
||||
comments = models.TextField(blank=True)
|
||||
name = models.CharField(_("name"), max_length=128)
|
||||
comments = models.TextField(_("comments"), blank=True)
|
||||
|
||||
description = models.CharField(max_length=255, null=True, blank=True)
|
||||
manufacturer = models.ForeignKey(to="dcim.Manufacturer", on_delete=models.PROTECT, null=True, blank=True)
|
||||
description = models.CharField(_("description"), max_length=255, null=True, blank=True)
|
||||
manufacturer = models.ForeignKey(
|
||||
to="dcim.Manufacturer", verbose_name=_("manufacturer"), on_delete=models.PROTECT, null=True, blank=True
|
||||
)
|
||||
|
||||
objects = RestrictedQuerySet.as_manager()
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("software product")
|
||||
verbose_name_plural = _("software products")
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@@ -44,25 +51,26 @@ class SoftwareProduct(NetBoxModel):
|
||||
|
||||
|
||||
class SoftwareReleaseTypes(models.TextChoices):
|
||||
ALPHA = "A", "Alpha"
|
||||
BETA = "B", "Beta"
|
||||
RELEASE_CANDIDATE = "RC", "Release candidate"
|
||||
STABLE = "S", "Stable release"
|
||||
ALPHA = "A", _("Alpha")
|
||||
BETA = "B", _("Beta")
|
||||
RELEASE_CANDIDATE = "RC", _("Release candidate")
|
||||
STABLE = "S", _("Stable release")
|
||||
|
||||
|
||||
class SoftwareProductVersion(NetBoxModel):
|
||||
name = models.CharField(max_length=64)
|
||||
comments = models.TextField(blank=True)
|
||||
name = models.CharField(_("name"), max_length=64)
|
||||
comments = models.TextField(_("comments"), blank=True)
|
||||
|
||||
description = models.CharField(max_length=255, null=True, blank=True)
|
||||
release_date = models.DateField(null=True, blank=True)
|
||||
documentation_url = LaxURLField(max_length=1024, null=True, blank=True)
|
||||
end_of_support = models.DateField(null=True, blank=True)
|
||||
filename = models.CharField(max_length=64, null=True, blank=True)
|
||||
file_checksum = models.CharField(max_length=128, null=True, blank=True)
|
||||
file_link = LaxURLField(max_length=1024, null=True, blank=True)
|
||||
description = models.CharField(_("description"), max_length=255, null=True, blank=True)
|
||||
release_date = models.DateField(_("release date"), null=True, blank=True)
|
||||
documentation_url = LaxURLField(_("documentation URL"), max_length=1024, null=True, blank=True)
|
||||
end_of_support = models.DateField(_("end of support"), null=True, blank=True)
|
||||
filename = models.CharField(_("filename"), max_length=64, null=True, blank=True)
|
||||
file_checksum = models.CharField(_("file checksum"), max_length=128, null=True, blank=True)
|
||||
file_link = LaxURLField(_("file link"), max_length=1024, null=True, blank=True)
|
||||
|
||||
release_type = models.CharField(
|
||||
_("release type"),
|
||||
max_length=3,
|
||||
choices=SoftwareReleaseTypes.choices,
|
||||
default=SoftwareReleaseTypes.STABLE,
|
||||
@@ -70,11 +78,16 @@ class SoftwareProductVersion(NetBoxModel):
|
||||
|
||||
software_product = models.ForeignKey(
|
||||
to="netbox_slm.SoftwareProduct",
|
||||
verbose_name=_("software product"),
|
||||
on_delete=models.PROTECT,
|
||||
)
|
||||
|
||||
objects = RestrictedQuerySet.as_manager()
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("software product version")
|
||||
verbose_name_plural = _("software product versions")
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@@ -88,15 +101,27 @@ class SoftwareProductVersion(NetBoxModel):
|
||||
|
||||
|
||||
class SoftwareProductInstallation(NetBoxModel):
|
||||
comments = models.TextField(blank=True)
|
||||
comments = models.TextField(_("comments"), 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
|
||||
device = models.ForeignKey(
|
||||
to="dcim.Device", verbose_name=_("device"), on_delete=models.PROTECT, null=True, blank=True
|
||||
)
|
||||
virtualmachine = models.ForeignKey(
|
||||
to="virtualization.VirtualMachine",
|
||||
verbose_name=_("virtual machine"),
|
||||
on_delete=models.PROTECT,
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
cluster = models.ForeignKey(
|
||||
to="virtualization.Cluster", verbose_name=_("cluster"), on_delete=models.PROTECT, null=True, blank=True
|
||||
)
|
||||
software_product = models.ForeignKey(
|
||||
to="netbox_slm.SoftwareProduct", verbose_name=_("software product"), on_delete=models.PROTECT
|
||||
)
|
||||
version = models.ForeignKey(
|
||||
to="netbox_slm.SoftwareProductVersion", verbose_name=_("version"), on_delete=models.PROTECT
|
||||
)
|
||||
cluster = models.ForeignKey(to="virtualization.Cluster", 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()
|
||||
|
||||
@@ -104,6 +129,8 @@ class SoftwareProductInstallation(NetBoxModel):
|
||||
return f"{self.pk} ({self.platform})"
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("software product installation")
|
||||
verbose_name_plural = _("software product installations")
|
||||
constraints = [
|
||||
models.CheckConstraint(
|
||||
name="%(app_label)s_%(class)s_platform",
|
||||
@@ -112,7 +139,7 @@ class SoftwareProductInstallation(NetBoxModel):
|
||||
| models.Q(device__isnull=True, virtualmachine__isnull=False, cluster__isnull=True)
|
||||
| models.Q(device__isnull=True, virtualmachine__isnull=True, cluster__isnull=False)
|
||||
),
|
||||
violation_error_message="Installation requires exactly one platform destination.",
|
||||
violation_error_message=_("Installation requires exactly one platform destination."),
|
||||
)
|
||||
]
|
||||
|
||||
@@ -141,30 +168,45 @@ def spdx_license_names():
|
||||
def validate_spdx_expression(value):
|
||||
expression_info = spdx_licensing.validate(value)
|
||||
if expression_info.errors:
|
||||
raise ValidationError(f"{value} is not a known SPDX license expression")
|
||||
raise ValidationError(_("%(value)s is not a known SPDX license expression") % {"value": value})
|
||||
|
||||
|
||||
class SoftwareLicense(NetBoxModel):
|
||||
name = models.CharField(max_length=128)
|
||||
comments = models.TextField(blank=True)
|
||||
name = models.CharField(_("name"), max_length=128)
|
||||
comments = models.TextField(_("comments"), blank=True)
|
||||
|
||||
description = models.CharField(max_length=255, null=True, blank=True)
|
||||
type = models.CharField(max_length=128)
|
||||
spdx_expression = models.CharField(max_length=64, null=True, blank=True, validators=[validate_spdx_expression])
|
||||
stored_location = models.CharField(max_length=255, null=True, blank=True)
|
||||
stored_location_url = LaxURLField(max_length=1024, null=True, blank=True)
|
||||
start_date = models.DateField(null=True, blank=True)
|
||||
expiration_date = models.DateField(null=True, blank=True)
|
||||
support = models.BooleanField(default=None, null=True, blank=True)
|
||||
license_amount = models.PositiveIntegerField(default=None, null=True, blank=True)
|
||||
description = models.CharField(_("description"), max_length=255, null=True, blank=True)
|
||||
type = models.CharField(_("type"), max_length=128)
|
||||
spdx_expression = models.CharField(
|
||||
_("SPDX expression"), max_length=64, null=True, blank=True, validators=[validate_spdx_expression]
|
||||
)
|
||||
stored_location = models.CharField(_("stored location"), max_length=255, null=True, blank=True)
|
||||
stored_location_url = LaxURLField(_("stored location URL"), max_length=1024, null=True, blank=True)
|
||||
start_date = models.DateField(_("start date"), null=True, blank=True)
|
||||
expiration_date = models.DateField(_("expiration date"), null=True, blank=True)
|
||||
support = models.BooleanField(_("support"), default=None, null=True, blank=True)
|
||||
license_amount = models.PositiveIntegerField(_("license amount"), default=None, 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", verbose_name=_("software product"), on_delete=models.PROTECT
|
||||
)
|
||||
version = models.ForeignKey(
|
||||
to="netbox_slm.SoftwareProductVersion",
|
||||
verbose_name=_("version"),
|
||||
on_delete=models.PROTECT,
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
installation = models.ForeignKey(
|
||||
to="netbox_slm.SoftwareProductInstallation", on_delete=models.SET_NULL, null=True, blank=True
|
||||
to="netbox_slm.SoftwareProductInstallation",
|
||||
verbose_name=_("installation"),
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
tenant_group = models.ForeignKey(
|
||||
to="tenancy.TenantGroup",
|
||||
verbose_name=_("tenant group"),
|
||||
on_delete=models.PROTECT,
|
||||
null=True,
|
||||
blank=True,
|
||||
@@ -172,6 +214,7 @@ class SoftwareLicense(NetBoxModel):
|
||||
)
|
||||
tenant = models.ForeignKey(
|
||||
to="tenancy.Tenant",
|
||||
verbose_name=_("tenant"),
|
||||
on_delete=models.PROTECT,
|
||||
null=True,
|
||||
blank=True,
|
||||
@@ -180,6 +223,10 @@ class SoftwareLicense(NetBoxModel):
|
||||
|
||||
objects = RestrictedQuerySet.as_manager()
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("software license")
|
||||
verbose_name_plural = _("software licenses")
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@@ -189,10 +236,12 @@ class SoftwareLicense(NetBoxModel):
|
||||
def clean(self):
|
||||
super().clean()
|
||||
if self.tenant_group and self.tenant and self.tenant.group_id != self.tenant_group_id:
|
||||
raise ValidationError({"tenant": "The selected tenant does not belong to the selected tenant group."})
|
||||
raise ValidationError(
|
||||
{"tenant": _("The selected tenant does not belong to the selected tenant group.")}
|
||||
)
|
||||
|
||||
@property
|
||||
def stored_location_txt(self):
|
||||
if self.stored_location_url and not self.stored_location:
|
||||
return "Link"
|
||||
return _("Link")
|
||||
return self.stored_location
|
||||
|
||||
+14
-13
@@ -1,21 +1,22 @@
|
||||
from netbox.plugins import PluginMenuButton, PluginMenuItem, PluginMenu, get_plugin_config
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from . import SLMConfig
|
||||
|
||||
slm_items = (
|
||||
PluginMenuItem(
|
||||
link="plugins:netbox_slm:softwareproduct_list",
|
||||
link_text="Software Products",
|
||||
link_text=_("Software Products"),
|
||||
permissions=["netbox_slm.add_softwareproduct"],
|
||||
buttons=(
|
||||
PluginMenuButton(
|
||||
"plugins:netbox_slm:softwareproduct_add",
|
||||
"Add",
|
||||
_("Add"),
|
||||
"mdi mdi-plus-thick",
|
||||
permissions=["netbox_slm.add_softwareproduct"],
|
||||
),
|
||||
PluginMenuButton(
|
||||
"plugins:netbox_slm:softwareproduct_bulk_import",
|
||||
"Import",
|
||||
_("Import"),
|
||||
"mdi mdi-upload",
|
||||
permissions=["netbox_slm.import_softwareproduct"],
|
||||
),
|
||||
@@ -23,18 +24,18 @@ slm_items = (
|
||||
),
|
||||
PluginMenuItem(
|
||||
link="plugins:netbox_slm:softwareproductversion_list",
|
||||
link_text="Versions",
|
||||
link_text=_("Versions"),
|
||||
permissions=["netbox_slm.add_softwareproductversion"],
|
||||
buttons=(
|
||||
PluginMenuButton(
|
||||
"plugins:netbox_slm:softwareproductversion_add",
|
||||
"Add",
|
||||
_("Add"),
|
||||
"mdi mdi-plus-thick",
|
||||
permissions=["netbox_slm.add_softwareproductversion"],
|
||||
),
|
||||
PluginMenuButton(
|
||||
"plugins:netbox_slm:softwareproductversion_bulk_import",
|
||||
"Import",
|
||||
_("Import"),
|
||||
"mdi mdi-upload",
|
||||
permissions=["netbox_slm.import_softwareproductversion"],
|
||||
),
|
||||
@@ -42,18 +43,18 @@ slm_items = (
|
||||
),
|
||||
PluginMenuItem(
|
||||
link="plugins:netbox_slm:softwareproductinstallation_list",
|
||||
link_text="Installations",
|
||||
link_text=_("Installations"),
|
||||
permissions=["netbox_slm.add_softwareproductinstallation"],
|
||||
buttons=(
|
||||
PluginMenuButton(
|
||||
"plugins:netbox_slm:softwareproductinstallation_add",
|
||||
"Add",
|
||||
_("Add"),
|
||||
"mdi mdi-plus-thick",
|
||||
permissions=["netbox_slm.add_softwareproductinstallation"],
|
||||
),
|
||||
PluginMenuButton(
|
||||
"plugins:netbox_slm:softwareproductinstallation_bulk_import",
|
||||
"Import",
|
||||
_("Import"),
|
||||
"mdi mdi-upload",
|
||||
permissions=["netbox_slm.import_softwareproductinstallation"],
|
||||
),
|
||||
@@ -61,18 +62,18 @@ slm_items = (
|
||||
),
|
||||
PluginMenuItem(
|
||||
link="plugins:netbox_slm:softwarelicense_list",
|
||||
link_text="Licenses",
|
||||
link_text=_("Licenses"),
|
||||
permissions=["netbox_slm.add_softwarelicense"],
|
||||
buttons=(
|
||||
PluginMenuButton(
|
||||
"plugins:netbox_slm:softwarelicense_add",
|
||||
"Add",
|
||||
_("Add"),
|
||||
"mdi mdi-plus-thick",
|
||||
permissions=["netbox_slm.add_softwarelicense"],
|
||||
),
|
||||
PluginMenuButton(
|
||||
"plugins:netbox_slm:softwarelicense_bulk_import",
|
||||
"Import",
|
||||
_("Import"),
|
||||
"mdi mdi-upload",
|
||||
permissions=["netbox_slm.import_softwarelicense"],
|
||||
),
|
||||
@@ -82,7 +83,7 @@ slm_items = (
|
||||
|
||||
if get_plugin_config("netbox_slm", "top_level_menu"):
|
||||
menu = PluginMenu(
|
||||
label="Software Lifecycle",
|
||||
label=_("Software Lifecycle"),
|
||||
groups=((SLMConfig.verbose_name, slm_items),),
|
||||
icon_class="mdi mdi-content-save",
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import django_tables2 as tables
|
||||
from django.db.models import Count, F, Value
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from netbox.tables import NetBoxTable, ToggleColumn, columns
|
||||
from netbox_slm.models import SoftwareProduct, SoftwareProductVersion, SoftwareProductInstallation, SoftwareLicense
|
||||
@@ -45,7 +46,7 @@ class SoftwareProductVersionTable(NetBoxTable):
|
||||
|
||||
pk = ToggleColumn()
|
||||
name = tables.LinkColumn()
|
||||
software_product = tables.Column(accessor="software_product", verbose_name="Software Product", linkify=True)
|
||||
software_product = tables.Column(accessor="software_product", verbose_name=_("Software Product"), linkify=True)
|
||||
manufacturer = tables.Column(accessor="software_product__manufacturer", linkify=True)
|
||||
installations = tables.Column(accessor="get_installation_count")
|
||||
|
||||
@@ -89,7 +90,7 @@ class SoftwareProductInstallationTable(NetBoxTable):
|
||||
platform = tables.Column(accessor="platform", linkify=True)
|
||||
type = tables.Column(accessor="render_type")
|
||||
manufacturer = tables.Column(accessor="software_product__manufacturer", linkify=True)
|
||||
software_product = tables.Column(accessor="software_product", verbose_name="Software Product", linkify=True)
|
||||
software_product = tables.Column(accessor="software_product", verbose_name=_("Software Product"), linkify=True)
|
||||
version = tables.Column(accessor="version", linkify=True)
|
||||
|
||||
tags = columns.TagColumn(url_name="plugins:netbox_slm:softwareproductinstallation_list")
|
||||
@@ -137,14 +138,14 @@ class SoftwareLicenseTable(NetBoxTable):
|
||||
name = tables.LinkColumn()
|
||||
|
||||
type = tables.Column()
|
||||
spdx_expression = tables.Column(verbose_name="SPDX expression")
|
||||
spdx_expression = tables.Column(verbose_name=_("SPDX expression"))
|
||||
stored_location = tables.Column(accessor="stored_location_txt", linkify=lambda record: record.stored_location_url)
|
||||
|
||||
manufacturer = tables.Column(accessor="software_product__manufacturer", linkify=True)
|
||||
software_product = tables.Column(accessor="software_product", verbose_name="Software Product", linkify=True)
|
||||
software_product = tables.Column(accessor="software_product", verbose_name=_("Software Product"), linkify=True)
|
||||
version = tables.Column(accessor="version", linkify=True)
|
||||
installation = tables.Column(accessor="installation", linkify=True)
|
||||
tenant_group = tables.Column(accessor="tenant_group", verbose_name="Tenant Group", linkify=True)
|
||||
tenant_group = tables.Column(accessor="tenant_group", verbose_name=_("Tenant Group"), linkify=True)
|
||||
tenant = tables.Column(accessor="tenant", linkify=True)
|
||||
|
||||
tags = columns.TagColumn(url_name="plugins:netbox_slm:softwarelicense_list")
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
{% load helpers %}
|
||||
{% load i18n %}
|
||||
|
||||
<div class="card">
|
||||
<h2 class="card-header">
|
||||
Installations
|
||||
{% trans "Installations" %}
|
||||
{% if perms.netbox_slm.add_softwareproductinstallation %}
|
||||
<div class="card-actions">
|
||||
<a href="{% url 'plugins:netbox_slm:softwareproductinstallation_add' %}?{{ search_obj }}={{ object.pk }}" class="btn btn-ghost-primary btn-sm">
|
||||
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add an installation
|
||||
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> {% trans "Add an installation" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@@ -3,53 +3,54 @@
|
||||
{% load static %}
|
||||
{% load helpers %}
|
||||
{% load plugins %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row my-3">
|
||||
<div class="col col-md-6">
|
||||
<div class="card">
|
||||
<h5 class="card-header">
|
||||
Software License
|
||||
{% trans "Software License" %}
|
||||
</h5>
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
<th scope="row">Name</th>
|
||||
<th scope="row">{% trans "Name" %}</th>
|
||||
<td>{{ object.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Description</th>
|
||||
<th scope="row">{% trans "Description" %}</th>
|
||||
<td>{{ object.description }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Type</th>
|
||||
<th scope="row">{% trans "Type" %}</th>
|
||||
<td>{{ object.type }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">SPDX expression</th>
|
||||
<th scope="row">{% trans "SPDX expression" %}</th>
|
||||
<td>{{ object.spdx_expression }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Software Product</th>
|
||||
<th scope="row">{% trans "Software Product" %}</th>
|
||||
<td>{{ object.software_product|linkify }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Version</th>
|
||||
<th scope="row">{% trans "Version" %}</th>
|
||||
<td>{{ object.version|linkify }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Installation</th>
|
||||
<th scope="row">{% trans "Installation" %}</th>
|
||||
<td>{{ object.installation|linkify }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Tenant Group</th>
|
||||
<th scope="row">{% trans "Tenant Group" %}</th>
|
||||
<td>{{ object.tenant_group|linkify }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Tenant</th>
|
||||
<th scope="row">{% trans "Tenant" %}</th>
|
||||
<td>{{ object.tenant|linkify }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Stored location</th>
|
||||
<th scope="row">{% trans "Stored location" %}</th>
|
||||
{% if object.stored_location_url %}
|
||||
<td><a href="{{ object.stored_location_url }}">{{ object.stored_location_txt }}</a></td>
|
||||
{% else %}
|
||||
@@ -57,19 +58,19 @@
|
||||
{% endif %}
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Start date</th>
|
||||
<th scope="row">{% trans "Start date" %}</th>
|
||||
<td>{{ object.start_date }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Expiration date</th>
|
||||
<th scope="row">{% trans "Expiration date" %}</th>
|
||||
<td>{{ object.expiration_date }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Support</th>
|
||||
<th scope="row">{% trans "Support" %}</th>
|
||||
<td>{{ object.support }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">License amount</th>
|
||||
<th scope="row">{% trans "License amount" %}</th>
|
||||
<td>{{ object.license_amount }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -3,60 +3,61 @@
|
||||
{% load static %}
|
||||
{% load helpers %}
|
||||
{% load plugins %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row my-3">
|
||||
<div class="col col-md-6">
|
||||
<div class="card">
|
||||
<h5 class="card-header">
|
||||
Software Product
|
||||
{% trans "Software Product" %}
|
||||
</h5>
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
<th scope="row">Name</th>
|
||||
<th scope="row">{% trans "Name" %}</th>
|
||||
<td>{{ object.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Description</th>
|
||||
<th scope="row">{% trans "Description" %}</th>
|
||||
<td>{{ object.description }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Manufacturer</th>
|
||||
<th scope="row">{% trans "Manufacturer" %}</th>
|
||||
<td>{{ object.manufacturer|linkify }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Versions</th>
|
||||
<th scope="row">{% trans "Versions" %}</th>
|
||||
<td>
|
||||
{% for version in object.softwareproductversion_set.all %}
|
||||
<a href="{% url 'plugins:netbox_slm:softwareproductversion' pk=version.pk %}" class="btn btn-sm">
|
||||
{{ version }}
|
||||
</a>
|
||||
{% empty %}
|
||||
None
|
||||
{% trans "None" %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Installations</th>
|
||||
<th scope="row">{% trans "Installations" %}</th>
|
||||
<td>
|
||||
{% for installation in object.softwareproductinstallation_set.all %}
|
||||
<a href="{% url 'plugins:netbox_slm:softwareproductinstallation' pk=installation.pk %}" class="btn btn-sm">
|
||||
{{ installation }}
|
||||
</a>
|
||||
{% empty %}
|
||||
None
|
||||
{% trans "None" %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Licenses</th>
|
||||
<th scope="row">{% trans "Licenses" %}</th>
|
||||
<td>
|
||||
{% for license in object.softwarelicense_set.all %}
|
||||
<a href="{% url 'plugins:netbox_slm:softwarelicense' pk=license.pk %}" class="btn btn-sm">
|
||||
{{ license }}
|
||||
</a>
|
||||
{% empty %}
|
||||
None
|
||||
{% trans "None" %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -3,48 +3,49 @@
|
||||
{% load static %}
|
||||
{% load helpers %}
|
||||
{% load plugins %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row my-3">
|
||||
<div class="col col-md-6">
|
||||
<div class="card">
|
||||
<h5 class="card-header">
|
||||
Software Product Installation
|
||||
{% trans "Software Product Installation" %}
|
||||
</h5>
|
||||
<table class="table table-hover attr-table">
|
||||
{% if object.device %}
|
||||
<tr>
|
||||
<th scope="row">Device</th>
|
||||
<th scope="row">{% trans "Device" %}</th>
|
||||
<td>{{ object.device|linkify }}</td>
|
||||
</tr>
|
||||
{% elif object.virtualmachine %}
|
||||
<tr>
|
||||
<th scope="row">Virtual Machine</th>
|
||||
<th scope="row">{% trans "Virtual Machine" %}</th>
|
||||
<td>{{ object.virtualmachine|linkify }}</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<th scope="row">Cluster</th>
|
||||
<th scope="row">{% trans "Cluster" %}</th>
|
||||
<td>{{ object.cluster|linkify }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<th scope="row">Software Product</th>
|
||||
<th scope="row">{% trans "Software Product" %}</th>
|
||||
<td>{{ object.software_product|linkify }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Version</th>
|
||||
<th scope="row">{% trans "Version" %}</th>
|
||||
<td>{{ object.version|linkify }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Licenses</th>
|
||||
<th scope="row">{% trans "Licenses" %}</th>
|
||||
<td>
|
||||
{% for license in object.softwarelicense_set.all %}
|
||||
<a href="{% url 'plugins:netbox_slm:softwarelicense' pk=license.pk %}" class="btn btn-sm">
|
||||
{{ license }}
|
||||
</a>
|
||||
{% empty %}
|
||||
None
|
||||
{% trans "None" %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -3,37 +3,38 @@
|
||||
{% load static %}
|
||||
{% load helpers %}
|
||||
{% load plugins %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row my-3">
|
||||
<div class="col col-md-6">
|
||||
<div class="card">
|
||||
<h5 class="card-header">
|
||||
Software Product Version
|
||||
{% trans "Software Product Version" %}
|
||||
</h5>
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
<th scope="row">Name</th>
|
||||
<th scope="row">{% trans "Name" %}</th>
|
||||
<td>{{ object.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Description</th>
|
||||
<th scope="row">{% trans "Description" %}</th>
|
||||
<td>{{ object.description }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Manufacturer</th>
|
||||
<th scope="row">{% trans "Manufacturer" %}</th>
|
||||
<td>{{ object.software_product.manufacturer|linkify }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Software Product</th>
|
||||
<th scope="row">{% trans "Software Product" %}</th>
|
||||
<td>{{ object.software_product|linkify }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Release date</th>
|
||||
<th scope="row">{% trans "Release date" %}</th>
|
||||
<td>{{ object.release_date }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Documentation url</th>
|
||||
<th scope="row">{% trans "Documentation URL" %}</th>
|
||||
{% if object.documentation_url %}
|
||||
<td><a href="{{ object.documentation_url }}">{{ object.documentation_url }}</a></td>
|
||||
{% else %}
|
||||
@@ -41,11 +42,11 @@
|
||||
{% endif %}
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">End of support</th>
|
||||
<th scope="row">{% trans "End of support" %}</th>
|
||||
<td>{{ object.end_of_support }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Filename</th>
|
||||
<th scope="row">{% trans "Filename" %}</th>
|
||||
{% if object.file_link %}
|
||||
<td><a href="{{ object.file_link }}">{{ object.filename }}</a></td>
|
||||
{% else %}
|
||||
@@ -53,34 +54,34 @@
|
||||
{% endif %}
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">File checksum</th>
|
||||
<th scope="row">{% trans "File checksum" %}</th>
|
||||
<td>{{ object.file_checksum }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Release type</th>
|
||||
<th scope="row">{% trans "Release type" %}</th>
|
||||
<td>{{ object.get_release_type_display }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Installations</th>
|
||||
<th scope="row">{% trans "Installations" %}</th>
|
||||
<td>
|
||||
{% for installation in object.softwareproductinstallation_set.all %}
|
||||
<a href="{% url 'plugins:netbox_slm:softwareproductinstallation' pk=installation.pk %}" class="btn btn-sm">
|
||||
{{ installation }}
|
||||
</a>
|
||||
{% empty %}
|
||||
None
|
||||
{% trans "None" %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Licenses</th>
|
||||
<th scope="row">{% trans "Licenses" %}</th>
|
||||
<td>
|
||||
{% for license in object.softwarelicense_set.all %}
|
||||
<a href="{% url 'plugins:netbox_slm:softwarelicense' pk=license.pk %}" class="btn btn-sm">
|
||||
{{ license }}
|
||||
</a>
|
||||
{% empty %}
|
||||
None
|
||||
{% trans "None" %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import gettext, override
|
||||
from netbox_slm.forms import SoftwareLicenseForm
|
||||
from tenancy.models import Tenant, TenantGroup
|
||||
|
||||
@@ -73,6 +74,12 @@ class ModelTestCase(SlmBaseTestCase):
|
||||
any("tenant_group" in fieldset.items and "tenant" in fieldset.items for fieldset in form.fieldsets)
|
||||
)
|
||||
|
||||
def test_german_translation(self):
|
||||
with override("de"):
|
||||
self.assertEqual("Softwarelizenz", gettext("Software License"))
|
||||
self.assertEqual("Mandantengruppe", gettext("Tenant Group"))
|
||||
self.assertEqual("Lizenzen", gettext("Licenses"))
|
||||
|
||||
def test_software_license_rejects_tenant_from_other_group(self):
|
||||
other_group = TenantGroup.objects.create(name="other group", slug="other-group")
|
||||
other_tenant = Tenant.objects.create(name="other tenant", slug="other-tenant", group=other_group)
|
||||
|
||||
Reference in New Issue
Block a user