Просмотр исходного кода

Merge branch 'develop' into feature

Jeremy Stretch 2 лет назад
Родитель
Сommit
44f8a777df

+ 1 - 1
.github/ISSUE_TEMPLATE/bug_report.yaml

@@ -14,7 +14,7 @@ body:
     attributes:
       label: NetBox version
       description: What version of NetBox are you currently running?
-      placeholder: v3.5.7
+      placeholder: v3.5.8
     validations:
       required: true
   - type: dropdown

+ 1 - 1
.github/ISSUE_TEMPLATE/feature_request.yaml

@@ -14,7 +14,7 @@ body:
     attributes:
       label: NetBox version
       description: What version of NetBox are you currently running?
-      placeholder: v3.5.7
+      placeholder: v3.5.8
     validations:
       required: true
   - type: dropdown

+ 561 - 0
contrib/generated_schema.json

@@ -0,0 +1,561 @@
+{
+    "type": "object",
+    "additionalProperties": false,
+    "definitions": {
+        "airflow": {
+            "type": "string",
+            "enum": [
+                "front-to-rear",
+                "rear-to-front",
+                "left-to-right",
+                "right-to-left",
+                "side-to-rear",
+                "passive",
+                "mixed"
+            ]
+        },
+        "weight-unit": {
+            "type": "string",
+            "enum": [
+                "kg",
+                "g",
+                "lb",
+                "oz"
+            ]
+        },
+        "subdevice-role": {
+            "type": "string",
+            "enum": [
+                "parent",
+                "child"
+            ]
+        },
+        "console-port": {
+            "type": "object",
+            "properties": {
+                "type": {
+                    "type": "string",
+                    "enum": [
+                        "de-9",
+                        "db-25",
+                        "rj-11",
+                        "rj-12",
+                        "rj-45",
+                        "mini-din-8",
+                        "usb-a",
+                        "usb-b",
+                        "usb-c",
+                        "usb-mini-a",
+                        "usb-mini-b",
+                        "usb-micro-a",
+                        "usb-micro-b",
+                        "usb-micro-ab",
+                        "other"
+                    ]
+                }
+            }
+        },
+        "console-server-port": {
+            "type": "object",
+            "properties": {
+                "type": {
+                    "type": "string",
+                    "enum": [
+                        "de-9",
+                        "db-25",
+                        "rj-11",
+                        "rj-12",
+                        "rj-45",
+                        "mini-din-8",
+                        "usb-a",
+                        "usb-b",
+                        "usb-c",
+                        "usb-mini-a",
+                        "usb-mini-b",
+                        "usb-micro-a",
+                        "usb-micro-b",
+                        "usb-micro-ab",
+                        "other"
+                    ]
+                }
+            }
+        },
+        "power-port": {
+            "type": "object",
+            "properties": {
+                "type": {
+                    "type": "string",
+                    "enum": [
+                        "iec-60320-c6",
+                        "iec-60320-c8",
+                        "iec-60320-c14",
+                        "iec-60320-c16",
+                        "iec-60320-c20",
+                        "iec-60320-c22",
+                        "iec-60309-p-n-e-4h",
+                        "iec-60309-p-n-e-6h",
+                        "iec-60309-p-n-e-9h",
+                        "iec-60309-2p-e-4h",
+                        "iec-60309-2p-e-6h",
+                        "iec-60309-2p-e-9h",
+                        "iec-60309-3p-e-4h",
+                        "iec-60309-3p-e-6h",
+                        "iec-60309-3p-e-9h",
+                        "iec-60309-3p-n-e-4h",
+                        "iec-60309-3p-n-e-6h",
+                        "iec-60309-3p-n-e-9h",
+                        "iec-60906-1",
+                        "nbr-14136-10a",
+                        "nbr-14136-20a",
+                        "nema-1-15p",
+                        "nema-5-15p",
+                        "nema-5-20p",
+                        "nema-5-30p",
+                        "nema-5-50p",
+                        "nema-6-15p",
+                        "nema-6-20p",
+                        "nema-6-30p",
+                        "nema-6-50p",
+                        "nema-10-30p",
+                        "nema-10-50p",
+                        "nema-14-20p",
+                        "nema-14-30p",
+                        "nema-14-50p",
+                        "nema-14-60p",
+                        "nema-15-15p",
+                        "nema-15-20p",
+                        "nema-15-30p",
+                        "nema-15-50p",
+                        "nema-15-60p",
+                        "nema-l1-15p",
+                        "nema-l5-15p",
+                        "nema-l5-20p",
+                        "nema-l5-30p",
+                        "nema-l5-50p",
+                        "nema-l6-15p",
+                        "nema-l6-20p",
+                        "nema-l6-30p",
+                        "nema-l6-50p",
+                        "nema-l10-30p",
+                        "nema-l14-20p",
+                        "nema-l14-30p",
+                        "nema-l14-50p",
+                        "nema-l14-60p",
+                        "nema-l15-20p",
+                        "nema-l15-30p",
+                        "nema-l15-50p",
+                        "nema-l15-60p",
+                        "nema-l21-20p",
+                        "nema-l21-30p",
+                        "nema-l22-30p",
+                        "cs6361c",
+                        "cs6365c",
+                        "cs8165c",
+                        "cs8265c",
+                        "cs8365c",
+                        "cs8465c",
+                        "ita-c",
+                        "ita-e",
+                        "ita-f",
+                        "ita-ef",
+                        "ita-g",
+                        "ita-h",
+                        "ita-i",
+                        "ita-j",
+                        "ita-k",
+                        "ita-l",
+                        "ita-m",
+                        "ita-n",
+                        "ita-o",
+                        "usb-a",
+                        "usb-b",
+                        "usb-c",
+                        "usb-mini-a",
+                        "usb-mini-b",
+                        "usb-micro-a",
+                        "usb-micro-b",
+                        "usb-micro-ab",
+                        "usb-3-b",
+                        "usb-3-micro-b",
+                        "dc-terminal",
+                        "saf-d-grid",
+                        "neutrik-powercon-20",
+                        "neutrik-powercon-32",
+                        "neutrik-powercon-true1",
+                        "neutrik-powercon-true1-top",
+                        "ubiquiti-smartpower",
+                        "hardwired",
+                        "other"
+                    ]
+                }
+            }
+        },
+        "power-outlet": {
+            "type": "object",
+            "properties": {
+                "type": {
+                    "type": "string",
+                    "enum": [
+                        "iec-60320-c5",
+                        "iec-60320-c7",
+                        "iec-60320-c13",
+                        "iec-60320-c15",
+                        "iec-60320-c19",
+                        "iec-60320-c21",
+                        "iec-60309-p-n-e-4h",
+                        "iec-60309-p-n-e-6h",
+                        "iec-60309-p-n-e-9h",
+                        "iec-60309-2p-e-4h",
+                        "iec-60309-2p-e-6h",
+                        "iec-60309-2p-e-9h",
+                        "iec-60309-3p-e-4h",
+                        "iec-60309-3p-e-6h",
+                        "iec-60309-3p-e-9h",
+                        "iec-60309-3p-n-e-4h",
+                        "iec-60309-3p-n-e-6h",
+                        "iec-60309-3p-n-e-9h",
+                        "iec-60906-1",
+                        "nbr-14136-10a",
+                        "nbr-14136-20a",
+                        "nema-1-15r",
+                        "nema-5-15r",
+                        "nema-5-20r",
+                        "nema-5-30r",
+                        "nema-5-50r",
+                        "nema-6-15r",
+                        "nema-6-20r",
+                        "nema-6-30r",
+                        "nema-6-50r",
+                        "nema-10-30r",
+                        "nema-10-50r",
+                        "nema-14-20r",
+                        "nema-14-30r",
+                        "nema-14-50r",
+                        "nema-14-60r",
+                        "nema-15-15r",
+                        "nema-15-20r",
+                        "nema-15-30r",
+                        "nema-15-50r",
+                        "nema-15-60r",
+                        "nema-l1-15r",
+                        "nema-l5-15r",
+                        "nema-l5-20r",
+                        "nema-l5-30r",
+                        "nema-l5-50r",
+                        "nema-l6-15r",
+                        "nema-l6-20r",
+                        "nema-l6-30r",
+                        "nema-l6-50r",
+                        "nema-l10-30r",
+                        "nema-l14-20r",
+                        "nema-l14-30r",
+                        "nema-l14-50r",
+                        "nema-l14-60r",
+                        "nema-l15-20r",
+                        "nema-l15-30r",
+                        "nema-l15-50r",
+                        "nema-l15-60r",
+                        "nema-l21-20r",
+                        "nema-l21-30r",
+                        "nema-l22-30r",
+                        "CS6360C",
+                        "CS6364C",
+                        "CS8164C",
+                        "CS8264C",
+                        "CS8364C",
+                        "CS8464C",
+                        "ita-e",
+                        "ita-f",
+                        "ita-g",
+                        "ita-h",
+                        "ita-i",
+                        "ita-j",
+                        "ita-k",
+                        "ita-l",
+                        "ita-m",
+                        "ita-n",
+                        "ita-o",
+                        "ita-multistandard",
+                        "usb-a",
+                        "usb-micro-b",
+                        "usb-c",
+                        "dc-terminal",
+                        "hdot-cx",
+                        "saf-d-grid",
+                        "neutrik-powercon-20a",
+                        "neutrik-powercon-32a",
+                        "neutrik-powercon-true1",
+                        "neutrik-powercon-true1-top",
+                        "ubiquiti-smartpower",
+                        "hardwired",
+                        "other"
+                    ]
+                },
+                "feed-leg": {
+                    "type": "string",
+                    "enum": [
+                        "A",
+                        "B",
+                        "C"
+                    ]
+                }
+            }
+        },
+        "interface": {
+            "type": "object",
+            "properties": {
+                "type": {
+                    "type": "string",
+                    "enum": [
+                        "virtual",
+                        "bridge",
+                        "lag",
+                        "100base-fx",
+                        "100base-lfx",
+                        "100base-tx",
+                        "100base-t1",
+                        "1000base-t",
+                        "2.5gbase-t",
+                        "5gbase-t",
+                        "10gbase-t",
+                        "10gbase-cx4",
+                        "1000base-x-gbic",
+                        "1000base-x-sfp",
+                        "10gbase-x-sfpp",
+                        "10gbase-x-xfp",
+                        "10gbase-x-xenpak",
+                        "10gbase-x-x2",
+                        "25gbase-x-sfp28",
+                        "50gbase-x-sfp56",
+                        "40gbase-x-qsfpp",
+                        "50gbase-x-sfp28",
+                        "100gbase-x-cfp",
+                        "100gbase-x-cfp2",
+                        "200gbase-x-cfp2",
+                        "100gbase-x-cfp4",
+                        "100gbase-x-cxp",
+                        "100gbase-x-cpak",
+                        "100gbase-x-dsfp",
+                        "100gbase-x-sfpdd",
+                        "100gbase-x-qsfp28",
+                        "100gbase-x-qsfpdd",
+                        "200gbase-x-qsfp56",
+                        "200gbase-x-qsfpdd",
+                        "400gbase-x-qsfpdd",
+                        "400gbase-x-osfp",
+                        "400gbase-x-cdfp",
+                        "400gbase-x-cfp8",
+                        "800gbase-x-qsfpdd",
+                        "800gbase-x-osfp",
+                        "1000base-kx",
+                        "10gbase-kr",
+                        "10gbase-kx4",
+                        "25gbase-kr",
+                        "40gbase-kr4",
+                        "50gbase-kr",
+                        "100gbase-kp4",
+                        "100gbase-kr2",
+                        "100gbase-kr4",
+                        "ieee802.11a",
+                        "ieee802.11g",
+                        "ieee802.11n",
+                        "ieee802.11ac",
+                        "ieee802.11ad",
+                        "ieee802.11ax",
+                        "ieee802.11ay",
+                        "ieee802.15.1",
+                        "other-wireless",
+                        "gsm",
+                        "cdma",
+                        "lte",
+                        "sonet-oc3",
+                        "sonet-oc12",
+                        "sonet-oc48",
+                        "sonet-oc192",
+                        "sonet-oc768",
+                        "sonet-oc1920",
+                        "sonet-oc3840",
+                        "1gfc-sfp",
+                        "2gfc-sfp",
+                        "4gfc-sfp",
+                        "8gfc-sfpp",
+                        "16gfc-sfpp",
+                        "32gfc-sfp28",
+                        "64gfc-qsfpp",
+                        "128gfc-qsfp28",
+                        "infiniband-sdr",
+                        "infiniband-ddr",
+                        "infiniband-qdr",
+                        "infiniband-fdr10",
+                        "infiniband-fdr",
+                        "infiniband-edr",
+                        "infiniband-hdr",
+                        "infiniband-ndr",
+                        "infiniband-xdr",
+                        "t1",
+                        "e1",
+                        "t3",
+                        "e3",
+                        "xdsl",
+                        "docsis",
+                        "gpon",
+                        "xg-pon",
+                        "xgs-pon",
+                        "ng-pon2",
+                        "epon",
+                        "10g-epon",
+                        "cisco-stackwise",
+                        "cisco-stackwise-plus",
+                        "cisco-flexstack",
+                        "cisco-flexstack-plus",
+                        "cisco-stackwise-80",
+                        "cisco-stackwise-160",
+                        "cisco-stackwise-320",
+                        "cisco-stackwise-480",
+                        "cisco-stackwise-1t",
+                        "juniper-vcp",
+                        "extreme-summitstack",
+                        "extreme-summitstack-128",
+                        "extreme-summitstack-256",
+                        "extreme-summitstack-512",
+                        "other"
+                    ]
+                },
+                "poe_mode": {
+                    "type": "string",
+                    "enum": [
+                        "pd",
+                        "pse"
+                    ]
+                },
+                "poe_type": {
+                    "type": "string",
+                    "enum": [
+                        "type1-ieee802.3af",
+                        "type2-ieee802.3at",
+                        "type3-ieee802.3bt",
+                        "type4-ieee802.3bt",
+                        "passive-24v-2pair",
+                        "passive-24v-4pair",
+                        "passive-48v-2pair",
+                        "passive-48v-4pair"
+                    ]
+                }
+            }
+        },
+        "front-port": {
+            "type": "object",
+            "properties": {
+                "type": {
+                    "type": "string",
+                    "enum": [
+                        "8p8c",
+                        "8p6c",
+                        "8p4c",
+                        "8p2c",
+                        "6p6c",
+                        "6p4c",
+                        "6p2c",
+                        "4p4c",
+                        "4p2c",
+                        "gg45",
+                        "tera-4p",
+                        "tera-2p",
+                        "tera-1p",
+                        "110-punch",
+                        "bnc",
+                        "f",
+                        "n",
+                        "mrj21",
+                        "fc",
+                        "lc",
+                        "lc-pc",
+                        "lc-upc",
+                        "lc-apc",
+                        "lsh",
+                        "lsh-pc",
+                        "lsh-upc",
+                        "lsh-apc",
+                        "lx5",
+                        "lx5-pc",
+                        "lx5-upc",
+                        "lx5-apc",
+                        "mpo",
+                        "mtrj",
+                        "sc",
+                        "sc-pc",
+                        "sc-upc",
+                        "sc-apc",
+                        "st",
+                        "cs",
+                        "sn",
+                        "sma-905",
+                        "sma-906",
+                        "urm-p2",
+                        "urm-p4",
+                        "urm-p8",
+                        "splice",
+                        "other"
+                    ]
+                }
+            }
+        },
+        "rear-port": {
+            "type": "object",
+            "properties": {
+                "type": {
+                    "type": "string",
+                    "enum": [
+                        "8p8c",
+                        "8p6c",
+                        "8p4c",
+                        "8p2c",
+                        "6p6c",
+                        "6p4c",
+                        "6p2c",
+                        "4p4c",
+                        "4p2c",
+                        "gg45",
+                        "tera-4p",
+                        "tera-2p",
+                        "tera-1p",
+                        "110-punch",
+                        "bnc",
+                        "f",
+                        "n",
+                        "mrj21",
+                        "fc",
+                        "lc",
+                        "lc-pc",
+                        "lc-upc",
+                        "lc-apc",
+                        "lsh",
+                        "lsh-pc",
+                        "lsh-upc",
+                        "lsh-apc",
+                        "lx5",
+                        "lx5-pc",
+                        "lx5-upc",
+                        "lx5-apc",
+                        "mpo",
+                        "mtrj",
+                        "sc",
+                        "sc-pc",
+                        "sc-upc",
+                        "sc-apc",
+                        "st",
+                        "cs",
+                        "sn",
+                        "sma-905",
+                        "sma-906",
+                        "urm-p2",
+                        "urm-p4",
+                        "urm-p8",
+                        "splice",
+                        "other"
+                    ]
+                }
+            }
+        }
+    }
+}

+ 10 - 0
docs/development/release-checklist.md

@@ -70,6 +70,16 @@ Before each release, update each of NetBox's Python dependencies to its most rec
 
 In cases where upgrading a dependency to its most recent release is breaking, it should be constrained to its current minor version in `base_requirements.txt` with an explanatory comment and revisited for the next major NetBox release (see the [Address Constrained Dependencies](#address-constrained-dependencies) section above).
 
+### Rebuild the Device Type Definition Schema
+
+Run the following command to update the device type definition validation schema:
+
+```nohighlight
+./manage.py buildschema --write
+```
+
+This will automatically update the schema file at `contrib/generated_schema.json`.
+
 ### Update Version and Changelog
 
 * Update the `VERSION` constant in `settings.py` to the new release version.

+ 11 - 1
docs/release-notes/version-3.5.md

@@ -1,23 +1,33 @@
 # NetBox v3.5
 
-## v3.5.8 (FUTURE)
+## v3.5.9 (FUTURE)
+
+---
+
+## v3.5.8 (2023-08-15)
 
 ### Enhancements
 
+* [#10030](https://github.com/netbox-community/netbox/issues/10030) - Ship a validation schema for the device type library with each release
 * [#11675](https://github.com/netbox-community/netbox/issues/11675) - Add support for specifying import/export route targets during VRF bulk import
 * [#11922](https://github.com/netbox-community/netbox/issues/11922) - Automatically populate any VDC assignments from the parent when adding a child interface via the UI
 * [#12889](https://github.com/netbox-community/netbox/issues/12889) - Add 400GE CFP2 interface type
 * [#13033](https://github.com/netbox-community/netbox/issues/13033) - Add human-friendly speed column to interfaces table
 * [#13151](https://github.com/netbox-community/netbox/issues/13151) - Add "assigned" filter for IP addresses
 * [#13368](https://github.com/netbox-community/netbox/issues/13368) - List installed plugins on the server error report page
+* [#13442](https://github.com/netbox-community/netbox/issues/13442) - Add 200 and 400 Gbps speeds to dropdown choices on interface form
 
 ### Bug Fixes
 
+* [#11578](https://github.com/netbox-community/netbox/issues/11578) - Fix schema definition for available IP & VLAN REST API endpoints
+* [#12639](https://github.com/netbox-community/netbox/issues/12639) - Raise validation error for invalid alphanumeric ranges when creating objects
 * [#12665](https://github.com/netbox-community/netbox/issues/12665) - Avoid escaping semicolons when rendering custom links
 * [#12750](https://github.com/netbox-community/netbox/issues/12750) - Automatically delete an AutoSyncRecord when its object is deleted
 * [#13343](https://github.com/netbox-community/netbox/issues/13343) - Fix filtering of circuits under provider network view
 * [#13369](https://github.com/netbox-community/netbox/issues/13369) - Fix job termination status for failed reports
 * [#13414](https://github.com/netbox-community/netbox/issues/13414) - Fix support for "hide-if-unset" custom fields on bulk import forms
+* [#13446](https://github.com/netbox-community/netbox/issues/13446) - Don't disable bulk edit/delete buttons after deselecting "select all" checkbox
+* [#13451](https://github.com/netbox-community/netbox/issues/13451) - Disable table ordering for custom link columns
 
 ---
 

+ 2 - 0
netbox/dcim/choices.py

@@ -1143,6 +1143,8 @@ class InterfaceSpeedChoices(ChoiceSet):
         (25000000, '25 Gbps'),
         (40000000, '40 Gbps'),
         (100000000, '100 Gbps'),
+        (200000000, '200 Gbps'),
+        (400000000, '400 Gbps'),
     ]
 
 

+ 4 - 1
netbox/dcim/forms/object_create.py

@@ -55,7 +55,10 @@ class ComponentCreateForm(forms.Form):
         super().clean()
 
         # Validate that all replication fields generate an equal number of values
-        pattern_count = len(self.cleaned_data[self.replication_fields[0]])
+        if not (patterns := self.cleaned_data.get(self.replication_fields[0])):
+            return
+
+        pattern_count = len(patterns)
         for field_name in self.replication_fields:
             value_count = len(self.cleaned_data[field_name])
             if self.cleaned_data[field_name] and value_count != pattern_count:

+ 62 - 0
netbox/dcim/management/commands/buildschema.py

@@ -0,0 +1,62 @@
+import json
+import os
+
+from django.conf import settings
+from django.core.management.base import BaseCommand
+from jinja2 import FileSystemLoader, Environment
+
+from dcim.choices import *
+
+TEMPLATE_FILENAME = 'devicetype_schema.jinja2'
+OUTPUT_FILENAME = 'contrib/generated_schema.json'
+
+CHOICES_MAP = {
+    'airflow_choices': DeviceAirflowChoices,
+    'weight_unit_choices': WeightUnitChoices,
+    'subdevice_role_choices': SubdeviceRoleChoices,
+    'console_port_type_choices': ConsolePortTypeChoices,
+    'console_server_port_type_choices': ConsolePortTypeChoices,
+    'power_port_type_choices': PowerPortTypeChoices,
+    'power_outlet_type_choices': PowerOutletTypeChoices,
+    'power_outlet_feedleg_choices': PowerOutletFeedLegChoices,
+    'interface_type_choices': InterfaceTypeChoices,
+    'interface_poe_mode_choices': InterfacePoEModeChoices,
+    'interface_poe_type_choices': InterfacePoETypeChoices,
+    'front_port_type_choices': PortTypeChoices,
+    'rear_port_type_choices': PortTypeChoices,
+}
+
+
+class Command(BaseCommand):
+    help = "Generate JSON schema for validating NetBox device type definitions"
+
+    def add_arguments(self, parser):
+        parser.add_argument(
+            '--write',
+            action='store_true',
+            help="Write the generated schema to file"
+        )
+
+    def handle(self, *args, **kwargs):
+        # Initialize template
+        template_loader = FileSystemLoader(searchpath=f'{settings.TEMPLATES_DIR}/extras/schema/')
+        template_env = Environment(loader=template_loader)
+        template = template_env.get_template(TEMPLATE_FILENAME)
+
+        # Render template
+        context = {
+            key: json.dumps(choices.values())
+            for key, choices in CHOICES_MAP.items()
+        }
+        rendered = template.render(**context)
+
+        if kwargs['write']:
+            # $root/contrib/generated_schema.json
+            filename = os.path.join(os.path.split(settings.BASE_DIR)[0], OUTPUT_FILENAME)
+            with open(filename, mode='w', encoding='UTF-8') as f:
+                f.write(json.dumps(json.loads(rendered), indent=4))
+                f.write('\n')
+                f.close()
+            self.stdout.write(self.style.SUCCESS(f"Schema written to {filename}."))
+        else:
+            self.stdout.write(rendered)

+ 21 - 7
netbox/ipam/api/views.py

@@ -1,7 +1,5 @@
 from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
 from django.db import transaction
-from django.db.models import F
-from django.db.models.functions import Round
 from django.shortcuts import get_object_or_404
 from django_pglocks import advisory_lock
 from drf_spectacular.utils import extend_schema
@@ -16,6 +14,7 @@ from circuits.models import Provider
 from dcim.models import Site
 from ipam import filtersets
 from ipam.models import *
+from ipam.models import L2VPN, L2VPNTermination
 from ipam.utils import get_next_available_prefix
 from netbox.api.viewsets import NetBoxModelViewSet
 from netbox.api.viewsets.mixins import ObjectValidationMixin
@@ -24,7 +23,6 @@ from netbox.constants import ADVISORY_LOCK_KEYS
 from utilities.api import get_serializer_for_model
 from utilities.utils import count_related
 from . import serializers
-from ipam.models import L2VPN, L2VPNTermination
 
 
 class IPAMRootView(APIRootView):
@@ -346,7 +344,11 @@ class AvailableASNsView(AvailableObjectsView):
     def get(self, request, pk):
         return super().get(request, pk)
 
-    @extend_schema(methods=["post"], responses={201: serializers.AvailableASNSerializer(many=True)})
+    @extend_schema(
+        methods=["post"],
+        responses={201: serializers.ASNSerializer(many=True)},
+        request=serializers.ASNSerializer(many=True),
+    )
     def post(self, request, pk):
         return super().post(request, pk)
 
@@ -395,7 +397,11 @@ class AvailablePrefixesView(AvailableObjectsView):
     def get(self, request, pk):
         return super().get(request, pk)
 
-    @extend_schema(methods=["post"], responses={201: serializers.PrefixSerializer(many=True)})
+    @extend_schema(
+        methods=["post"],
+        responses={201: serializers.PrefixSerializer(many=True)},
+        request=serializers.PrefixSerializer(many=True),
+    )
     def post(self, request, pk):
         return super().post(request, pk)
 
@@ -435,7 +441,11 @@ class AvailableIPAddressesView(AvailableObjectsView):
     def get(self, request, pk):
         return super().get(request, pk)
 
-    @extend_schema(methods=["post"], responses={201: serializers.IPAddressSerializer(many=True)})
+    @extend_schema(
+        methods=["post"],
+        responses={201: serializers.IPAddressSerializer(many=True)},
+        request=serializers.IPAddressSerializer(many=True),
+    )
     def post(self, request, pk):
         return super().post(request, pk)
 
@@ -482,6 +492,10 @@ class AvailableVLANsView(AvailableObjectsView):
     def get(self, request, pk):
         return super().get(request, pk)
 
-    @extend_schema(methods=["post"], responses={201: serializers.VLANSerializer(many=True)})
+    @extend_schema(
+        methods=["post"],
+        responses={201: serializers.VLANSerializer(many=True)},
+        request=serializers.VLANSerializer(many=True),
+    )
     def post(self, request, pk):
         return super().post(request, pk)

+ 1 - 1
netbox/ipam/forms/filtersets.py

@@ -256,7 +256,7 @@ class IPRangeFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = IPRange
     fieldsets = (
         (None, ('q', 'filter_id', 'tag')),
-        (_('Attriubtes'), ('family', 'vrf_id', 'status', 'role_id', 'mark_utilized')),
+        (_('Attributes'), ('family', 'vrf_id', 'status', 'role_id', 'mark_utilized')),
         (_('Tenant'), ('tenant_group_id', 'tenant_id')),
     )
     family = forms.ChoiceField(

+ 1 - 1
netbox/netbox/settings.py

@@ -25,7 +25,7 @@ from netbox.constants import RQ_QUEUE_DEFAULT, RQ_QUEUE_HIGH, RQ_QUEUE_LOW
 # Environment setup
 #
 
-VERSION = '3.6-beta1'
+VERSION = '3.6-beta2'
 
 # Hostname
 HOSTNAME = platform.node()

+ 3 - 3
netbox/netbox/tables/columns.py

@@ -511,9 +511,9 @@ class CustomLinkColumn(tables.Column):
     """
     def __init__(self, customlink, *args, **kwargs):
         self.customlink = customlink
-        kwargs['accessor'] = Accessor('pk')
-        if 'verbose_name' not in kwargs:
-            kwargs['verbose_name'] = customlink.name
+        kwargs.setdefault('accessor', Accessor('pk'))
+        kwargs.setdefault('orderable', False)
+        kwargs.setdefault('verbose_name', customlink.name)
 
         super().__init__(*args, **kwargs)
 

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
netbox/project-static/dist/netbox.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
netbox/project-static/dist/netbox.js.map


+ 1 - 29
netbox/project-static/src/buttons/selectAll.ts

@@ -1,4 +1,4 @@
-import { getElement, getElements, findFirstAdjacent } from '../util';
+import { getElements, findFirstAdjacent } from '../util';
 
 /**
  * If any PK checkbox is checked, uncheck the select all table checkbox and the select all
@@ -63,29 +63,6 @@ function handleSelectAllToggle(event: Event): void {
   }
 }
 
-/**
- * Synchronize the select all confirmation checkbox state with the select all confirmation button
- * disabled state. If the select all confirmation checkbox is checked, the buttons should be
- * enabled. If not, the buttons should be disabled.
- *
- * @param event Change Event
- */
-function handleSelectAll(event: Event): void {
-  const target = event.currentTarget as HTMLInputElement;
-  const selectAllBox = getElement<HTMLDivElement>('select-all-box');
-  if (selectAllBox !== null) {
-    for (const button of selectAllBox.querySelectorAll<HTMLButtonElement>(
-      'button[type="submit"]',
-    )) {
-      if (target.checked) {
-        button.disabled = false;
-      } else {
-        button.disabled = true;
-      }
-    }
-  }
-}
-
 /**
  * Initialize table select all elements.
  */
@@ -98,9 +75,4 @@ export function initSelectAll(): void {
   for (const element of getElements<HTMLInputElement>('input[type="checkbox"][name="pk"]')) {
     element.addEventListener('change', handlePkCheck);
   }
-  const selectAll = getElement<HTMLInputElement>('select-all');
-
-  if (selectAll !== null) {
-    selectAll.addEventListener('change', handleSelectAll);
-  }
 }

+ 4 - 0
netbox/templates/extras/imageattachment.html

@@ -0,0 +1,4 @@
+{% extends 'generic/object.html' %}
+
+{% block tabs %}
+{% endblock %}

+ 93 - 0
netbox/templates/extras/schema/devicetype_schema.jinja2

@@ -0,0 +1,93 @@
+{
+  "type": "object",
+  "additionalProperties": false,
+  "definitions": {
+    "airflow": {
+      "type": "string",
+      "enum": {{ airflow_choices }}
+    },
+    "weight-unit": {
+      "type": "string",
+      "enum": {{ weight_unit_choices }}
+    },
+    "subdevice-role": {
+      "type": "string",
+      "enum": {{ subdevice_role_choices }}
+    },
+    "console-port": {
+      "type": "object",
+      "properties": {
+        "type": {
+          "type": "string",
+          "enum": {{ console_port_type_choices }}
+        }
+      }
+    },
+    "console-server-port": {
+      "type": "object",
+      "properties": {
+        "type": {
+          "type": "string",
+          "enum": {{ console_server_port_type_choices }}
+        }
+      }
+    },
+    "power-port": {
+      "type": "object",
+      "properties": {
+        "type": {
+          "type": "string",
+          "enum": {{ power_port_type_choices }}
+        }
+      }
+    },
+    "power-outlet": {
+      "type": "object",
+      "properties": {
+        "type": {
+          "type": "string",
+          "enum": {{ power_outlet_type_choices }}
+        },
+        "feed-leg": {
+          "type": "string",
+          "enum": {{ power_outlet_feedleg_choices }}
+        }
+      }
+    },
+    "interface": {
+      "type": "object",
+      "properties": {
+        "type": {
+          "type": "string",
+          "enum": {{ interface_type_choices }}
+        },
+        "poe_mode": {
+          "type": "string",
+          "enum": {{ interface_poe_mode_choices }}
+        },
+        "poe_type": {
+          "type": "string",
+          "enum": {{ interface_poe_type_choices }}
+        }
+      }
+    },
+    "front-port": {
+      "type": "object",
+      "properties": {
+        "type": {
+          "type": "string",
+          "enum": {{ front_port_type_choices }}
+        }
+      }
+    },
+    "rear-port": {
+      "type": "object",
+      "properties": {
+        "type": {
+          "type": "string",
+          "enum": {{ rear_port_type_choices}}
+        }
+      }
+    }
+  }
+}

+ 7 - 0
netbox/utilities/forms/utils.py

@@ -60,6 +60,9 @@ def parse_alphanumeric_range(string):
         except ValueError:
             begin, end = dash_range, dash_range
         if begin.isdigit() and end.isdigit():
+            if int(begin) >= int(end):
+                raise forms.ValidationError(f'Range "{dash_range}" is invalid.')
+
             for n in list(range(int(begin), int(end) + 1)):
                 values.append(n)
         else:
@@ -71,6 +74,10 @@ def parse_alphanumeric_range(string):
                 # Not a valid range (more than a single character)
                 if not len(begin) == len(end) == 1:
                     raise forms.ValidationError(f'Range "{dash_range}" is invalid.')
+
+                if ord(begin) >= ord(end):
+                    raise forms.ValidationError(f'Range "{dash_range}" is invalid.')
+
                 for n in list(range(ord(begin), ord(end) + 1)):
                     values.append(chr(n))
     return values

+ 3 - 2
netbox/utilities/tests/test_forms.py

@@ -264,8 +264,9 @@ class ExpandAlphanumeric(TestCase):
         self.assertEqual(sorted(expand_alphanumeric_pattern('r[a-9]a')), [])
 
     def test_invalid_range_bounds(self):
-        self.assertEqual(sorted(expand_alphanumeric_pattern('r[9-8]a')), [])
-        self.assertEqual(sorted(expand_alphanumeric_pattern('r[b-a]a')), [])
+        with self.assertRaises(forms.ValidationError):
+            sorted(expand_alphanumeric_pattern('r[9-8]a'))
+            sorted(expand_alphanumeric_pattern('r[b-a]a'))
 
     def test_invalid_range_len(self):
         with self.assertRaises(forms.ValidationError):

+ 5 - 4
requirements.txt

@@ -1,6 +1,7 @@
 bleach==6.0.0
+Django==4.2.4
 django-cors-headers==4.2.0
-django-debug-toolbar==4.1.0
+django-debug-toolbar==4.2.0
 django-filter==23.2
 django-graphiql-debug-toolbar==0.2.0
 django-mptt==0.14
@@ -14,7 +15,7 @@ django-taggit==4.0.0
 django-timezone-field==5.1
 djangorestframework==3.14.0
 drf-spectacular==0.26.4
-drf-spectacular-sidecar==2023.7.1
+drf-spectacular-sidecar==2023.8.1
 feedparser==6.0.10
 graphene-django==3.0.0
 gunicorn==21.2.0
@@ -24,9 +25,9 @@ mkdocs-material==9.1.21
 mkdocstrings[python-legacy]==0.22.0
 netaddr==0.8.0
 Pillow==10.0.0
-psycopg[binary,pool]==3.1.9
+psycopg[binary,pool]==3.1.10
 PyYAML==6.0.1
-sentry-sdk==1.28.1
+sentry-sdk==1.29.2
 social-auth-app-django==5.2.0
 social-auth-core[openidconnect]==4.4.2
 svgwrite==1.4.3

Некоторые файлы не были показаны из-за большого количества измененных файлов