mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Merge branch 'develop' into feature
This commit is contained in:
2
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@ -14,7 +14,7 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: NetBox version
|
label: NetBox version
|
||||||
description: What version of NetBox are you currently running?
|
description: What version of NetBox are you currently running?
|
||||||
placeholder: v3.5.7
|
placeholder: v3.5.8
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
|
2
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
@ -14,7 +14,7 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: NetBox version
|
label: NetBox version
|
||||||
description: What version of NetBox are you currently running?
|
description: What version of NetBox are you currently running?
|
||||||
placeholder: v3.5.7
|
placeholder: v3.5.8
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
|
561
contrib/generated_schema.json
Normal file
561
contrib/generated_schema.json
Normal file
@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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).
|
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 Version and Changelog
|
||||||
|
|
||||||
* Update the `VERSION` constant in `settings.py` to the new release version.
|
* Update the `VERSION` constant in `settings.py` to the new release version.
|
||||||
|
@ -1,23 +1,33 @@
|
|||||||
# NetBox v3.5
|
# NetBox v3.5
|
||||||
|
|
||||||
## v3.5.8 (FUTURE)
|
## v3.5.9 (FUTURE)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v3.5.8 (2023-08-15)
|
||||||
|
|
||||||
### Enhancements
|
### 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
|
* [#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
|
* [#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
|
* [#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
|
* [#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
|
* [#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
|
* [#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
|
### 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
|
* [#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
|
* [#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
|
* [#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
|
* [#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
|
* [#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
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -1143,6 +1143,8 @@ class InterfaceSpeedChoices(ChoiceSet):
|
|||||||
(25000000, '25 Gbps'),
|
(25000000, '25 Gbps'),
|
||||||
(40000000, '40 Gbps'),
|
(40000000, '40 Gbps'),
|
||||||
(100000000, '100 Gbps'),
|
(100000000, '100 Gbps'),
|
||||||
|
(200000000, '200 Gbps'),
|
||||||
|
(400000000, '400 Gbps'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,7 +55,10 @@ class ComponentCreateForm(forms.Form):
|
|||||||
super().clean()
|
super().clean()
|
||||||
|
|
||||||
# Validate that all replication fields generate an equal number of values
|
# 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:
|
for field_name in self.replication_fields:
|
||||||
value_count = len(self.cleaned_data[field_name])
|
value_count = len(self.cleaned_data[field_name])
|
||||||
if self.cleaned_data[field_name] and value_count != pattern_count:
|
if self.cleaned_data[field_name] and value_count != pattern_count:
|
||||||
|
62
netbox/dcim/management/commands/buildschema.py
Normal file
62
netbox/dcim/management/commands/buildschema.py
Normal file
@ -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)
|
@ -1,7 +1,5 @@
|
|||||||
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
|
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
|
||||||
from django.db import transaction
|
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.shortcuts import get_object_or_404
|
||||||
from django_pglocks import advisory_lock
|
from django_pglocks import advisory_lock
|
||||||
from drf_spectacular.utils import extend_schema
|
from drf_spectacular.utils import extend_schema
|
||||||
@ -16,6 +14,7 @@ from circuits.models import Provider
|
|||||||
from dcim.models import Site
|
from dcim.models import Site
|
||||||
from ipam import filtersets
|
from ipam import filtersets
|
||||||
from ipam.models import *
|
from ipam.models import *
|
||||||
|
from ipam.models import L2VPN, L2VPNTermination
|
||||||
from ipam.utils import get_next_available_prefix
|
from ipam.utils import get_next_available_prefix
|
||||||
from netbox.api.viewsets import NetBoxModelViewSet
|
from netbox.api.viewsets import NetBoxModelViewSet
|
||||||
from netbox.api.viewsets.mixins import ObjectValidationMixin
|
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.api import get_serializer_for_model
|
||||||
from utilities.utils import count_related
|
from utilities.utils import count_related
|
||||||
from . import serializers
|
from . import serializers
|
||||||
from ipam.models import L2VPN, L2VPNTermination
|
|
||||||
|
|
||||||
|
|
||||||
class IPAMRootView(APIRootView):
|
class IPAMRootView(APIRootView):
|
||||||
@ -346,7 +344,11 @@ class AvailableASNsView(AvailableObjectsView):
|
|||||||
def get(self, request, pk):
|
def get(self, request, pk):
|
||||||
return super().get(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):
|
def post(self, request, pk):
|
||||||
return super().post(request, pk)
|
return super().post(request, pk)
|
||||||
|
|
||||||
@ -395,7 +397,11 @@ class AvailablePrefixesView(AvailableObjectsView):
|
|||||||
def get(self, request, pk):
|
def get(self, request, pk):
|
||||||
return super().get(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):
|
def post(self, request, pk):
|
||||||
return super().post(request, pk)
|
return super().post(request, pk)
|
||||||
|
|
||||||
@ -435,7 +441,11 @@ class AvailableIPAddressesView(AvailableObjectsView):
|
|||||||
def get(self, request, pk):
|
def get(self, request, pk):
|
||||||
return super().get(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):
|
def post(self, request, pk):
|
||||||
return super().post(request, pk)
|
return super().post(request, pk)
|
||||||
|
|
||||||
@ -482,6 +492,10 @@ class AvailableVLANsView(AvailableObjectsView):
|
|||||||
def get(self, request, pk):
|
def get(self, request, pk):
|
||||||
return super().get(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):
|
def post(self, request, pk):
|
||||||
return super().post(request, pk)
|
return super().post(request, pk)
|
||||||
|
@ -256,7 +256,7 @@ class IPRangeFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
|||||||
model = IPRange
|
model = IPRange
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'filter_id', 'tag')),
|
(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')),
|
(_('Tenant'), ('tenant_group_id', 'tenant_id')),
|
||||||
)
|
)
|
||||||
family = forms.ChoiceField(
|
family = forms.ChoiceField(
|
||||||
|
@ -25,7 +25,7 @@ from netbox.constants import RQ_QUEUE_DEFAULT, RQ_QUEUE_HIGH, RQ_QUEUE_LOW
|
|||||||
# Environment setup
|
# Environment setup
|
||||||
#
|
#
|
||||||
|
|
||||||
VERSION = '3.6-beta1'
|
VERSION = '3.6-beta2'
|
||||||
|
|
||||||
# Hostname
|
# Hostname
|
||||||
HOSTNAME = platform.node()
|
HOSTNAME = platform.node()
|
||||||
|
@ -511,9 +511,9 @@ class CustomLinkColumn(tables.Column):
|
|||||||
"""
|
"""
|
||||||
def __init__(self, customlink, *args, **kwargs):
|
def __init__(self, customlink, *args, **kwargs):
|
||||||
self.customlink = customlink
|
self.customlink = customlink
|
||||||
kwargs['accessor'] = Accessor('pk')
|
kwargs.setdefault('accessor', Accessor('pk'))
|
||||||
if 'verbose_name' not in kwargs:
|
kwargs.setdefault('orderable', False)
|
||||||
kwargs['verbose_name'] = customlink.name
|
kwargs.setdefault('verbose_name', customlink.name)
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
18
netbox/project-static/dist/netbox.js
vendored
18
netbox/project-static/dist/netbox.js
vendored
File diff suppressed because one or more lines are too long
2
netbox/project-static/dist/netbox.js.map
vendored
2
netbox/project-static/dist/netbox.js.map
vendored
File diff suppressed because one or more lines are too long
@ -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
|
* 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.
|
* Initialize table select all elements.
|
||||||
*/
|
*/
|
||||||
@ -98,9 +75,4 @@ export function initSelectAll(): void {
|
|||||||
for (const element of getElements<HTMLInputElement>('input[type="checkbox"][name="pk"]')) {
|
for (const element of getElements<HTMLInputElement>('input[type="checkbox"][name="pk"]')) {
|
||||||
element.addEventListener('change', handlePkCheck);
|
element.addEventListener('change', handlePkCheck);
|
||||||
}
|
}
|
||||||
const selectAll = getElement<HTMLInputElement>('select-all');
|
|
||||||
|
|
||||||
if (selectAll !== null) {
|
|
||||||
selectAll.addEventListener('change', handleSelectAll);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
4
netbox/templates/extras/imageattachment.html
Normal file
4
netbox/templates/extras/imageattachment.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{% extends 'generic/object.html' %}
|
||||||
|
|
||||||
|
{% block tabs %}
|
||||||
|
{% endblock %}
|
93
netbox/templates/extras/schema/devicetype_schema.jinja2
Normal file
93
netbox/templates/extras/schema/devicetype_schema.jinja2
Normal file
@ -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}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -60,6 +60,9 @@ def parse_alphanumeric_range(string):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
begin, end = dash_range, dash_range
|
begin, end = dash_range, dash_range
|
||||||
if begin.isdigit() and end.isdigit():
|
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)):
|
for n in list(range(int(begin), int(end) + 1)):
|
||||||
values.append(n)
|
values.append(n)
|
||||||
else:
|
else:
|
||||||
@ -71,6 +74,10 @@ def parse_alphanumeric_range(string):
|
|||||||
# Not a valid range (more than a single character)
|
# Not a valid range (more than a single character)
|
||||||
if not len(begin) == len(end) == 1:
|
if not len(begin) == len(end) == 1:
|
||||||
raise forms.ValidationError(f'Range "{dash_range}" is invalid.')
|
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)):
|
for n in list(range(ord(begin), ord(end) + 1)):
|
||||||
values.append(chr(n))
|
values.append(chr(n))
|
||||||
return values
|
return values
|
||||||
|
@ -264,8 +264,9 @@ class ExpandAlphanumeric(TestCase):
|
|||||||
self.assertEqual(sorted(expand_alphanumeric_pattern('r[a-9]a')), [])
|
self.assertEqual(sorted(expand_alphanumeric_pattern('r[a-9]a')), [])
|
||||||
|
|
||||||
def test_invalid_range_bounds(self):
|
def test_invalid_range_bounds(self):
|
||||||
self.assertEqual(sorted(expand_alphanumeric_pattern('r[9-8]a')), [])
|
with self.assertRaises(forms.ValidationError):
|
||||||
self.assertEqual(sorted(expand_alphanumeric_pattern('r[b-a]a')), [])
|
sorted(expand_alphanumeric_pattern('r[9-8]a'))
|
||||||
|
sorted(expand_alphanumeric_pattern('r[b-a]a'))
|
||||||
|
|
||||||
def test_invalid_range_len(self):
|
def test_invalid_range_len(self):
|
||||||
with self.assertRaises(forms.ValidationError):
|
with self.assertRaises(forms.ValidationError):
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
bleach==6.0.0
|
bleach==6.0.0
|
||||||
|
Django==4.2.4
|
||||||
django-cors-headers==4.2.0
|
django-cors-headers==4.2.0
|
||||||
django-debug-toolbar==4.1.0
|
django-debug-toolbar==4.2.0
|
||||||
django-filter==23.2
|
django-filter==23.2
|
||||||
django-graphiql-debug-toolbar==0.2.0
|
django-graphiql-debug-toolbar==0.2.0
|
||||||
django-mptt==0.14
|
django-mptt==0.14
|
||||||
@ -14,7 +15,7 @@ django-taggit==4.0.0
|
|||||||
django-timezone-field==5.1
|
django-timezone-field==5.1
|
||||||
djangorestframework==3.14.0
|
djangorestframework==3.14.0
|
||||||
drf-spectacular==0.26.4
|
drf-spectacular==0.26.4
|
||||||
drf-spectacular-sidecar==2023.7.1
|
drf-spectacular-sidecar==2023.8.1
|
||||||
feedparser==6.0.10
|
feedparser==6.0.10
|
||||||
graphene-django==3.0.0
|
graphene-django==3.0.0
|
||||||
gunicorn==21.2.0
|
gunicorn==21.2.0
|
||||||
@ -24,9 +25,9 @@ mkdocs-material==9.1.21
|
|||||||
mkdocstrings[python-legacy]==0.22.0
|
mkdocstrings[python-legacy]==0.22.0
|
||||||
netaddr==0.8.0
|
netaddr==0.8.0
|
||||||
Pillow==10.0.0
|
Pillow==10.0.0
|
||||||
psycopg[binary,pool]==3.1.9
|
psycopg[binary,pool]==3.1.10
|
||||||
PyYAML==6.0.1
|
PyYAML==6.0.1
|
||||||
sentry-sdk==1.28.1
|
sentry-sdk==1.29.2
|
||||||
social-auth-app-django==5.2.0
|
social-auth-app-django==5.2.0
|
||||||
social-auth-core[openidconnect]==4.4.2
|
social-auth-core[openidconnect]==4.4.2
|
||||||
svgwrite==1.4.3
|
svgwrite==1.4.3
|
||||||
|
Reference in New Issue
Block a user