Merge pull request #15631 from netbox-community/develop

Release v3.7.5
This commit is contained in:
Jeremy Stretch 2024-04-04 16:20:14 -04:00 committed by GitHub
commit 1c76034069
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
44 changed files with 3561 additions and 3482 deletions

View File

@ -1,7 +1,7 @@
---
name: 🐛 Bug Report
description: Report a reproducible bug in the current release of NetBox
labels: ["type: bug"]
labels: ["type: bug", "needs triage"]
body:
- type: markdown
attributes:
@ -26,7 +26,7 @@ body:
attributes:
label: NetBox Version
description: What version of NetBox are you currently running?
placeholder: v3.7.4
placeholder: v3.7.5
validations:
required: true
- type: dropdown

View File

@ -1,7 +1,7 @@
---
name: 📖 Documentation Change
description: Suggest an addition or modification to the NetBox documentation
labels: ["type: documentation"]
labels: ["type: documentation", "needs triage"]
body:
- type: dropdown
attributes:

View File

@ -1,7 +1,7 @@
---
name: ✨ Feature Request
description: Propose a new NetBox feature or enhancement
labels: ["type: feature"]
labels: ["type: feature", "needs triage"]
body:
- type: markdown
attributes:
@ -14,7 +14,7 @@ body:
attributes:
label: NetBox version
description: What version of NetBox are you currently running?
placeholder: v3.7.4
placeholder: v3.7.5
validations:
required: true
- type: dropdown

21
.github/workflows/auto-assign-issue.yml vendored Normal file
View File

@ -0,0 +1,21 @@
# auto-assign-issue (https://github.com/marketplace/actions/auto-assign-issue)
name: Issue assignment
on:
issues:
types: [opened]
permissions:
issues: write
jobs:
auto-assign:
runs-on: ubuntu-latest
steps:
- uses: pozil/auto-assign-issue@v1
if: "contains(github.event.issue.labels.*.name, 'needs triage')"
with:
# Weighted assignments
assignees: arthanson:3, jeffgdotorg:3, jeremystretch:3, abhi1693, DanSheps
numOfAssignee: 1
abortIfPreviousAssignees: true

View File

@ -1,5 +1,5 @@
# close-stale-issues (https://github.com/marketplace/actions/close-stale-issues)
name: 'Close stale issues/PRs'
name: Close stale issues/PRs
on:
schedule:
@ -12,10 +12,9 @@ permissions:
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v8
- uses: actions/stale@v9
with:
close-issue-message: >
This issue has been automatically closed due to lack of activity. In an

View File

@ -1,5 +1,5 @@
# lock-threads (https://github.com/marketplace/actions/lock-threads)
name: 'Lock threads'
name: Lock threads
on:
schedule:

View File

@ -84,7 +84,7 @@ NetBox automatically logs the creation, modification, and deletion of all manage
<p align="center">
<a href="https://netboxlabs.com/netbox-cloud/"><img src="docs/media/misc/netbox_cloud.png" alt="NetBox Cloud" /></a><br />
Looking for an enterprise solution? Check out <strong><a href="https://netboxlabs.com/netbox-cloud/">NetBox Cloud</a></strong>!
Looking for a managed solution? Check out <strong><a href="https://netboxlabs.com/netbox-cloud/">NetBox Cloud</a></strong> or <strong><a href="https://netboxlabs.com/netbox-enterprise/">NetBox Enterprise</a></strong>!
</p>
## Get Involved

View File

@ -1,5 +1,7 @@
{
"type": "object",
"$id": "urn:devicetype-library:generated-schema",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"additionalProperties": false,
"definitions": {
"airflow": {

View File

@ -85,13 +85,19 @@ Each model generally has two views associated with it: a list view and a detail
* `/api/dcim/devices/` - List existing devices or create a new device
* `/api/dcim/devices/123/` - Retrieve, update, or delete the device with ID 123
Lists of objects can be filtered using a set of query parameters. For example, to find all interfaces belonging to the device with ID 123:
Lists of objects can be filtered and ordered using a set of query parameters. For example, to find all interfaces belonging to the device with ID 123:
```
GET /api/dcim/interfaces/?device_id=123
```
See the [filtering documentation](../reference/filtering.md) for more details.
An optional `ordering` parameter can be used to define how to sort the results. Building off the previous example, to sort all the interfaces in reverse order of creation (newest to oldest) for a device with ID 123:
```
GET /api/dcim/interfaces/?device_id=123&ordering=-created
```
See the [filtering documentation](../reference/filtering.md) for more details on topics related to filtering, ordering and lookup expressions.
## Serialization
@ -647,18 +653,20 @@ Note that we are _not_ passing an existing REST API token with this request. If
{
"id": 6,
"url": "https://netbox/api/users/tokens/6/",
"display": "3c9cb9 (hankhill)",
"display": "**********************************3c9cb9",
"user": {
"id": 2,
"url": "https://netbox/api/users/users/2/",
"display": "hankhill",
"username": "hankhill"
},
"created": "2021-06-11T20:09:13.339367Z",
"created": "2024-03-11T20:09:13.339367Z",
"expires": null,
"last_used": null,
"key": "9fc9b897abec9ada2da6aec9dbc34596293c9cb9",
"write_enabled": true,
"description": ""
"description": "",
"allowed_ips": []
}
```

View File

@ -82,10 +82,10 @@ Plugins may package static files to be served directly by the HTTP front end. En
### Restart WSGI Service
Restart the WSGI service to load the new plugin:
Restart the WSGI service and RQ workers to load the new plugin:
```no-highlight
# sudo systemctl restart netbox
# sudo systemctl restart netbox netbox-rq
```
## Removing Plugins

View File

@ -1,353 +1,254 @@
---
hide:
- toc
---
# Markdown
NetBox supports markdown rendering for certain text fields.
NetBox supports Markdown rendering for certain text fields. Some common examples are provided below. For a complete Markdown reference, please see [Markdownguide.org](https://www.markdownguide.org/basic-syntax/).
## Syntax
##### Table of Contents
[Headers](#headers)
[Emphasis](#emphasis)
[Lists](#lists)
[Links](#links)
[Images](#images)
[Code Blocks](#code)
[Tables](#tables)
[Blockquotes](#blockquotes)
[Inline HTML](#html)
[Horizontal Rule](#hr)
[Line Breaks](#lines)
<a name="headers"></a>
## Headers
## Headings
```no-highlight
# H1
## H2
### H3
#### H4
##### H5
###### H6
# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
###### Heading 6
```
<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<h4>Heading 4</h4>
<h5>Heading 5</h5>
<h6>Heading 6</h6>
Alternatively, for H1 and H2, an underline-ish style:
Alt-H1
======
```no-highlight
Heading 1
=========
Alt-H2
------
Heading 2
---------
```
# H1
## H2
### H3
#### H4
##### H5
###### H6
<h1>Heading 1</h1>
<h2>Heading 2</h2>
<a name="emphasis"></a>
## Emphasis
## Text
```no-highlight
Emphasis, aka italics, with *asterisks* or _underscores_.
Strong emphasis, aka bold, with **asterisks** or __underscores__.
Combined emphasis with **asterisks and _underscores_**.
Strikethrough uses two tildes. ~~Scratch this.~~
Italicize text with *asterisks* or _underscores_.
```
Emphasis, aka italics, with *asterisks* or _underscores_.
Strong emphasis, aka bold, with **asterisks** or __underscores__.
Combined emphasis with **asterisks and _underscores_**.
Strikethrough uses two tildes. ~~Scratch this.~~
<a name="lists"></a>
## Lists
(In this example, leading and trailing spaces are shown with with dots: ⋅)
Italicize text with *asterisks* or _underscores_.
```no-highlight
1. First ordered list item
2. Another item
⋅⋅* Unordered sub-list.
1. Actual numbers don't matter, just that it's a number
⋅⋅1. Ordered sub-list
4. And another item.
⋅⋅⋅You can have properly indented paragraphs within list items. Notice the blank line above, and the leading spaces (at least one, but we'll use three here to also align the raw Markdown).
⋅⋅⋅To have a line break without a paragraph, you will need to use two trailing spaces.⋅⋅
⋅⋅⋅Note that this line is separate, but within the same paragraph.⋅⋅
⋅⋅⋅(This is contrary to the typical GFM line break behaviour, where trailing spaces are not required.)
* Unordered list can use asterisks
- Or minuses
+ Or pluses
Bold text with two **asterisks** or __underscores__.
```
1. First ordered list item
2. Another item
* Unordered sub-list.
1. Actual numbers don't matter, just that it's a number
1. Ordered sub-list
4. And another item.
You can have properly indented paragraphs within list items. Notice the blank line above, and the leading spaces (at least one, but we'll use three here to also align the raw Markdown).
To have a line break without a paragraph, you will need to use two trailing spaces.
Note that this line is separate, but within the same paragraph.
(This is contrary to the typical GFM line break behaviour, where trailing spaces are not required.)
* Unordered list can use asterisks
- Or minuses
+ Or pluses
<a name="links"></a>
## Links
There are two ways to create links.
Bold text with two **asterisks** or __underscores__.
```no-highlight
[I'm an inline-style link](https://www.google.com)
[I'm an inline-style link with title](https://www.google.com "Google's Homepage")
[I'm a reference-style link][Arbitrary case-insensitive reference text]
[You can use numbers for reference-style link definitions][1]
Or leave it empty and use the [link text itself].
URLs and URLs in angle brackets will automatically get turned into links.
http://www.example.com or <http://www.example.com> and sometimes
example.com (but not on Github, for example).
Some text to show that the reference links can follow later.
[arbitrary case-insensitive reference text]: https://www.mozilla.org
[1]: http://slashdot.org
[link text itself]: http://www.reddit.com
Strike text with two tildes. ~~Deleted text.~~
```
[I'm an inline-style link](https://www.google.com)
[I'm an inline-style link with title](https://www.google.com "Google's Homepage")
[I'm a reference-style link][Arbitrary case-insensitive reference text]
[You can use numbers for reference-style link definitions][1]
Or leave it empty and use the [link text itself].
URLs and URLs in angle brackets will automatically get turned into links.
http://www.example.com or <http://www.example.com> and sometimes
example.com (but not on Github, for example).
Some text to show that the reference links can follow later.
[arbitrary case-insensitive reference text]: https://www.mozilla.org
[1]: http://slashdot.org
[link text itself]: http://www.reddit.com
<a name="images"></a>
## Images
```
Here's the NetBox logo (hover to see the title text):
Inline-style:
![alt text](/media/misc/netbox_logo.png "Logo Title Text 1")
Reference-style:
![alt text][logo]
[logo]: /media/misc/netbox_logo.png "Logo Title Text 2"
```
Here's the NetBox logo (hover to see the title text):
Inline-style:
![alt text](../media/misc/netbox_logo.png "Logo Title Text 1")
Reference-style:
![alt text][logo]
[logo]: ../media/misc/netbox_logo.png "Logo Title Text 2"
<a name="code"></a>
## Code blocks
```
Inline `code` has `back-ticks around` it.
```
Inline `code` has `back-ticks around` it.
Blocks of code are fenced by lines with three back-ticks <code>```</code>
````
```
var s = "Code block";
alert(s);
```
````
```
var s = "Code block";
alert(s);
```
<a name="tables"></a>
## Tables
```no-highlight
Colons can be used to align columns.
| Tables | Are | Cool |
| ------------- |:-------------:| -----:|
| col 3 is | right-aligned | $1600 |
| col 2 is | centered | $12 |
| zebra stripes | are neat | $1 |
There must be at least 3 dashes separating each header cell.
The outer pipes (|) are optional, and you don't need to make the
raw Markdown line up prettily. You can also use inline Markdown.
Markdown | Less | Pretty
--- | --- | ---
*Still* | `renders` | **nicely**
1 | 2 | 3
```
Colons can be used to align columns.
| Tables | Are | Cool |
| ------------- |:-------------:| -----:|
| col 3 is | right-aligned | $1600 |
| col 2 is | centered | $12 |
| zebra stripes | are neat | $1 |
There must be at least 3 dashes separating each header cell. The outer pipes (|) are optional, and you don't need to make the raw Markdown line up prettily. You can also use inline Markdown.
Markdown | Less | Pretty
--- | --- | ---
*Still* | `renders` | **nicely**
1 | 2 | 3
<a name="blockquotes"></a>
## Blockquotes
```no-highlight
> Blockquotes are very handy in email to emulate reply text.
> This line is part of the same quote.
Quote break.
> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can *put* **Markdown** into a blockquote.
```
> Blockquotes are very handy in email to emulate reply text.
> This line is part of the same quote.
Quote break.
> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can *put* **Markdown** into a blockquote.
<a name="html"></a>
## Inline HTML
You can also use raw HTML in your Markdown, and it'll mostly work pretty well.
```no-highlight
<dl>
<dt>Definition list</dt>
<dd>Is something people use sometimes.</dd>
<dt>Markdown in HTML</dt>
<dd>Does *not* work **very** well. Use HTML <em>tags</em>.</dd>
</dl>
```
<dl>
<dt>Definition list</dt>
<dd>Is something people use sometimes.</dd>
<dt>Markdown in HTML</dt>
<dd>Does *not* work **very** well. Use HTML <em>tags</em>.</dd>
</dl>
<a name="hr"></a>
## Horizontal Rule
```
Three or more...
---
Hyphens
***
Asterisks
___
Underscores
```
Three or more...
---
Hyphens
***
Asterisks
___
Underscores
<a name="lines"></a>
Strike text with two tildes. ~~Deleted text.~~
## Line Breaks
By default, Markdown will remove line breaks between successive lines of text. For example:
```
Here's a line for us to start with.
This line is separated from the one above by two newlines, so it will be a *separate paragraph*.
This line is also a separate paragraph, but...
This line is only separated by a single newline, so it's a separate line in the *same paragraph*.
```no-highlight
This is one line.
And this is another line.
One more line here.
```
Here's a line for us to start with.
This is one line.
And this is another line.
One more line here.
This line is separated from the one above by two newlines, so it will be a *separate paragraph*.
To preserve line breaks, append two spaces to each line (represented below with the `⋅` character).
This line is also begins a separate paragraph, but...
This line is only separated by a single newline, so it's a separate line in the *same paragraph*.
```no-highlight
This is one line.⋅⋅
And this is another line.⋅⋅
One more line here.
```
Based on [Markdown-Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) by [adam-p](https://github.com/adam-p) licensed under [CC-BY](https://creativecommons.org/licenses/by/3.0/)
This is one line.
And this is another line.
One more line here.
## Lists
Use asterisks or hyphens for unordered lists. Indent items by four spaces to start a child list.
```no-highlight
* Alpha
* Bravo
* Charlie
* Child item 1
* Child item 2
* Delta
```
* Alpha
* Bravo
* Charlie
* Child item 1
* Child item 2
* Delta
Use digits followed by periods for ordered (numbered) lists.
```no-highlight
1. Red
2. Green
3. Blue
1. Light blue
2. Dark blue
4. Orange
```
1. Red
2. Green
3. Blue
1. Light blue
2. Dark blue
4. Orange
## Links
Text can be rendered as a hyperlink by encasing it in square brackets, followed by a URL in parentheses. A title (text displayed on hover) may optionally be included as well.
```no-highlight
Here's an [example](https://www.example.com) of a link.
And here's [another link](https://www.example.com "Click me!"), this time with a title.
```
Here's an [example](https://www.example.com) of a link.
And here's [another link](https://www.example.com "Click me!"), with a title.
## Images
The syntax for embedding an image is very similar to that used for a hyperlink. Alternate text should always be provided; this will be displayed if the image fails to load. As with hyperlinks, title text is optional.
```no-highlight
![Alternate text](/path/to/image.png "Image title text")
```
## Code Blocks
Single backticks can be used to annotate code inline. Text enclosed by lines of three backticks will be displayed as a code block.
```no-highlight
Paragraphs are rendered in HTML using `<p>` and `</p>` tags.
```
Paragraphs are rendered in HTML using `<p>` and `</p>` tags.
````
```
def my_func(foo, bar):
# Do something
return foo * bar
```
````
```no-highlight
def my_func(foo, bar):
# Do something
return foo * bar
```
## Tables
Simple tables can be constructed using the pipe character (`|`) to denote columns, and hyphens (`-`) to denote the heading. Inline Markdown can be used to style text within columns.
```no-highlight
| Heading 1 | Heading 2 | Heading 3 |
|-----------|-----------|-----------|
| Row 1 | Alpha | Red |
| Row 2 | **Bravo** | Green |
| Row 3 | Charlie | ~~Blue~~ |
```
| Heading 1 | Heading 2 | Heading 3 |
|-----------|-----------|-----------|
| _Row 1_ | Alpha | Red |
| Row 2 | **Bravo** | Green |
| Row 3 | Charlie | ~~Blue~~ |
Colons can be used to align text to the left or right side of a column.
```no-highlight
| Left-aligned | Centered | Right-aligned |
|:-------------|:--------:|--------------:|
| Text | Text | Text |
| Text | Text | Text |
| Text | Text | Text |
```
| Left-aligned | Centered | Right-aligned |
|:-------------|:--------:|--------------:|
| Text | Text | Text |
| Text | Text | Text |
| Text | Text | Text |
## Blockquotes
Text can be wrapped in a blockquote by prepending a right angle bracket (`>`) before each line.
```no-highlight
> I think that I shall never see
> a graph more lovely than a tree.
> A tree whose crucial property
> is loop-free connectivity.
```
> I think that I shall never see
> a graph more lovely than a tree.
> A tree whose crucial property
> is loop-free connectivity.
Markdown removes line breaks by default. To preserve line breaks, append two spaces to each line (represented below with the `⋅` character).
```no-highlight
> I think that I shall never see⋅⋅
> a graph more lovely than a tree.⋅⋅
> A tree whose crucial property⋅⋅
> is loop-free connectivity.
```
> I think that I shall never see
> a graph more lovely than a tree.
> A tree whose crucial property
> is loop-free connectivity.
## Horizontal Rule
A horizontal rule is a single line rendered across the width of the page using a series of three or more hyphens or asterisks. It can be useful for separating sections of content.
```no-highlight
Content
---
More content
***
Final content
```
Content
---
More content
***
Final content

View File

@ -1,5 +1,26 @@
# NetBox v3.7
## v3.7.5 (2024-04-04)
### Enhancements
* [#14707](https://github.com/netbox-community/netbox/issues/14707) - Clarify interface designation when creating tunnel terminations
* [#15039](https://github.com/netbox-community/netbox/issues/15039) - Allow API tokens to be cloned
### Bug Fixes
* [#14799](https://github.com/netbox-community/netbox/issues/14799) - Avoid caching modified reports & scripts
* [#15029](https://github.com/netbox-community/netbox/issues/15029) - Raise a clean validation error when attempting to make duplicate FHRP group assignments
* [#15102](https://github.com/netbox-community/netbox/issues/15102) - Fix usage of selector widget for form fields referencing users/groups
* [#15435](https://github.com/netbox-community/netbox/issues/15435) - Correct permissions name to allow adding a module bay to a device via the UI
* [#15502](https://github.com/netbox-community/netbox/issues/15502) - Fix KeyError exception when modifying an IP address assigned to a virtual machine
* [#15597](https://github.com/netbox-community/netbox/issues/15597) - Restore help modal for `button_class` field on custom link bulk import form
* [#15598](https://github.com/netbox-community/netbox/issues/15598) - Fix exception when creating a device from a device type with one or more child inventory items
* [#15608](https://github.com/netbox-community/netbox/issues/15608) - Avoid caching values of null fields in search index
* [#15609](https://github.com/netbox-community/netbox/issues/15609) - Fix filtering of the providers list by assigned ASN
---
## v3.7.4 (2024-03-13)
### Enhancements

View File

@ -64,6 +64,12 @@ class ProviderFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
queryset=ASN.objects.all(),
label=_('ASN (ID)'),
)
asn = django_filters.ModelMultipleChoiceFilter(
field_name='asns__asn',
queryset=ASN.objects.all(),
to_field_name='asn',
label=_('ASN'),
)
class Meta:
model = Provider

View File

@ -24,7 +24,7 @@ class ProviderFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
fieldsets = (
(None, ('q', 'filter_id', 'tag')),
(_('Location'), ('region_id', 'site_group_id', 'site_id')),
(_('ASN'), ('asn',)),
(_('ASN'), ('asn_id',)),
(_('Contacts'), ('contact', 'contact_role', 'contact_group')),
)
region_id = DynamicModelMultipleChoiceField(
@ -46,10 +46,6 @@ class ProviderFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
},
label=_('Site')
)
asn = forms.IntegerField(
required=False,
label=_('ASN (legacy)')
)
asn_id = DynamicModelMultipleChoiceField(
queryset=ASN.objects.all(),
required=False,

View File

@ -90,10 +90,12 @@ class ProviderTestCase(TestCase, ChangeLoggedFilterSetTests):
params = {'description': ['foobar1', 'foobar2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_asn_id(self): # ASN object assignment
def test_asn(self):
asns = ASN.objects.all()[:2]
params = {'asn_id': [asns[0].pk, asns[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'asn': [asns[0].asn, asns[1].asn]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_region(self):
regions = Region.objects.all()[:2]

View File

@ -996,17 +996,16 @@ class Device(
bulk_create: If True, bulk_create() will be called to create all components in a single query
(default). Otherwise, save() will be called on each instance individually.
"""
components = [obj.instantiate(device=self) for obj in queryset]
if not components:
return
# Set default values for any applicable custom fields
model = queryset.model.component_model
if cf_defaults := CustomField.objects.get_defaults_for_model(model):
for component in components:
component.custom_field_data = cf_defaults
if bulk_create:
components = [obj.instantiate(device=self) for obj in queryset]
if not components:
return
# Set default values for any applicable custom fields
if cf_defaults := CustomField.objects.get_defaults_for_model(model):
for component in components:
component.custom_field_data = cf_defaults
model.objects.bulk_create(components)
# Manually send the post_save signal for each of the newly created components
for component in components:
@ -1019,7 +1018,11 @@ class Device(
update_fields=None
)
else:
for component in components:
for obj in queryset:
component = obj.instantiate(device=self)
# Set default values for any applicable custom fields
if cf_defaults := CustomField.objects.get_defaults_for_model(model):
component.custom_field_data = cf_defaults
component.save()
def save(self, *args, **kwargs):

View File

@ -116,6 +116,12 @@ class CustomLinkImportForm(CSVModelForm):
queryset=ContentType.objects.with_feature('custom_links'),
help_text=_("One or more assigned object types")
)
button_class = CSVChoiceField(
label=_('button class'),
required=False,
choices=CustomLinkButtonClassChoices,
help_text=_('The class of the first link in a group will be used for the dropdown button')
)
class Meta:
model = CustomLink

View File

@ -52,7 +52,7 @@ class ReportModule(PythonModuleMixin, JobsMixin, ManagedFile):
def __str__(self):
return self.python_name
@cached_property
@property
def reports(self):
def _get_name(cls):

View File

@ -37,7 +37,7 @@ class Tag(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel, TagBase):
to='contenttypes.ContentType',
related_name='+',
blank=True,
help_text=_("The object type(s) to which this this tag can be applied.")
help_text=_("The object type(s) to which this tag can be applied.")
)
clone_fields = (

View File

@ -378,7 +378,7 @@ class IPAddressImportForm(NetBoxModelImportForm):
# Set as primary for device/VM
if self.cleaned_data.get('is_primary'):
parent = self.cleaned_data['device'] or self.cleaned_data['virtual_machine']
parent = self.cleaned_data.get('device') or self.cleaned_data.get('virtual_machine')
if self.instance.address.version == 4:
parent.primary_ip4 = ipaddress
elif self.instance.address.version == 6:

View File

@ -507,6 +507,24 @@ class FHRPGroupAssignmentForm(BootstrapMixin, forms.ModelForm):
for ipaddress in ipaddresses:
self.fields['group'].widget.add_query_param('related_ip', ipaddress.pk)
def clean_group(self):
group = self.cleaned_data['group']
conflicting_assignments = FHRPGroupAssignment.objects.filter(
interface_type=self.instance.interface_type,
interface_id=self.instance.interface_id,
group=group
)
if self.instance.id:
conflicting_assignments = conflicting_assignments.exclude(id=self.instance.id)
if conflicting_assignments.exists():
raise forms.ValidationError(
_('Assignment already exists')
)
return group
class VLANGroupForm(NetBoxModelForm):
scope_type = ContentTypeChoiceField(

View File

@ -59,9 +59,10 @@ class SearchIndex:
@staticmethod
def get_field_value(instance, field_name):
"""
Return the value of the specified model field as a string.
Return the value of the specified model field as a string (or None).
"""
return str(getattr(instance, field_name))
if value := getattr(instance, field_name):
return str(value)
@classmethod
def get_category(cls):

View File

@ -28,7 +28,7 @@ from netbox.plugins import PluginConfig
# Environment setup
#
VERSION = '3.7.4'
VERSION = '3.7.5'
# Hostname
HOSTNAME = platform.node()

View File

@ -42,7 +42,7 @@
{% if perms.dcim.add_rearport %}
<li><a class="dropdown-item" href="{% url 'dcim:rearport_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_rearports' pk=object.pk %}">{% trans "Rear Ports" %}</a></li>
{% endif %}
{% if perms.dcim.add_devicebay %}
{% if perms.dcim.add_modulebay %}
<li><a class="dropdown-item" href="{% url 'dcim:modulebay_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_modulebays' pk=object.pk %}">{% trans "Module Bays" %}</a></li>
{% endif %}
{% if perms.dcim.add_devicebay %}

View File

@ -1,5 +1,7 @@
{
"type": "object",
"$id": "urn:devicetype-library:generated-schema",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"additionalProperties": false,
"definitions": {
"airflow": {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -11,21 +11,21 @@ from utilities.forms.fields import DynamicModelMultipleChoiceField
from utilities.forms.widgets import DateTimePicker
__all__ = (
'GroupFilterForm',
'NetBoxGroupFilterForm',
'ObjectPermissionFilterForm',
'UserFilterForm',
'NetBoxUserFilterForm',
'TokenFilterForm',
)
class GroupFilterForm(NetBoxModelFilterSetForm):
class NetBoxGroupFilterForm(NetBoxModelFilterSetForm):
model = NetBoxGroup
fieldsets = (
(None, ('q', 'filter_id',)),
)
class UserFilterForm(NetBoxModelFilterSetForm):
class NetBoxUserFilterForm(NetBoxModelFilterSetForm):
model = NetBoxUser
fieldsets = (
(None, ('q', 'filter_id',)),

View File

@ -17,6 +17,7 @@ from netaddr import IPNetwork
from core.models import ContentType
from ipam.fields import IPNetworkField
from netbox.config import get_config
from netbox.models.features import CloningMixin
from utilities.querysets import RestrictedQuerySet
from utilities.utils import flatten_dict
from .constants import *
@ -234,7 +235,7 @@ def create_userconfig(instance, created, raw=False, **kwargs):
# REST API
#
class Token(models.Model):
class Token(CloningMixin, models.Model):
"""
An API token used for user authentication. This extends the stock model to allow each user to have multiple tokens.
It also supports setting an expiration time and toggling write ability.
@ -285,6 +286,10 @@ class Token(models.Model):
),
)
clone_fields = (
'user', 'expires', 'write_enabled', 'description', 'allowed_ips',
)
objects = RestrictedQuerySet.as_manager()
class Meta:

View File

@ -58,7 +58,7 @@ class TokenBulkDeleteView(generic.BulkDeleteView):
class UserListView(generic.ObjectListView):
queryset = NetBoxUser.objects.all()
filterset = filtersets.UserFilterSet
filterset_form = forms.UserFilterForm
filterset_form = forms.NetBoxUserFilterForm
table = tables.UserTable
@ -112,7 +112,7 @@ class UserBulkDeleteView(generic.BulkDeleteView):
class GroupListView(generic.ObjectListView):
queryset = NetBoxGroup.objects.annotate(users_count=Count('user'))
filterset = filtersets.GroupFilterSet
filterset_form = forms.GroupFilterForm
filterset_form = forms.NetBoxGroupFilterForm
table = tables.GroupTable

View File

@ -91,7 +91,7 @@ class TunnelCreateForm(TunnelForm):
termination1_termination = DynamicModelChoiceField(
queryset=Interface.objects.all(),
required=False,
label=_('Interface'),
label=_('Tunnel interface'),
query_params={
'device_id': '$termination1_parent',
}
@ -126,7 +126,7 @@ class TunnelCreateForm(TunnelForm):
termination2_termination = DynamicModelChoiceField(
queryset=Interface.objects.all(),
required=False,
label=_('Interface'),
label=_('Tunnel interface'),
query_params={
'device_id': '$termination2_parent',
}
@ -238,7 +238,7 @@ class TunnelTerminationForm(NetBoxModelForm):
)
termination = DynamicModelChoiceField(
queryset=Interface.objects.all(),
label=_('Interface'),
label=_('Tunnel interface'),
query_params={
'device_id': '$parent',
}

View File

@ -88,7 +88,7 @@ class TunnelTerminationTable(TenancyColumnsMixin, NetBoxTable):
verbose_name=_('Host')
)
termination = tables.Column(
verbose_name=_('Interface'),
verbose_name=_('Tunnel interface'),
linkify=True
)
ip_addresses = tables.ManyToManyColumn(

View File

@ -2,34 +2,34 @@ bleach==6.1.0
Django==4.2.11
django-cors-headers==4.3.1
django-debug-toolbar==4.3.0
django-filter==24.1
django-filter==24.2
django-graphiql-debug-toolbar==0.2.0
django-mptt==0.14.0
django-pglocks==1.0.4
django-prometheus==2.3.1
django-redis==5.4.0
django-rich==1.8.0
django-rq==2.10.1
django-rq==2.10.2
django-taggit==5.0.1
django-tables2==2.7.0
django-timezone-field==6.1.0
djangorestframework==3.14.0
drf-spectacular==0.27.1
drf-spectacular-sidecar==2024.3.4
drf-spectacular==0.27.2
drf-spectacular-sidecar==2024.4.1
feedparser==6.0.11
graphene-django==3.0.0
gunicorn==21.2.0
Jinja2==3.1.3
Markdown==3.5.2
mkdocs-material==9.5.13
mkdocstrings[python-legacy]==0.24.1
Markdown==3.6
mkdocs-material==9.5.17
mkdocstrings[python-legacy]==0.24.2
netaddr==1.2.1
Pillow==10.2.0
Pillow==10.3.0
psycopg[binary,pool]==3.1.18
PyYAML==6.0.1
requests==2.31.0
social-auth-app-django==5.4.0
social-auth-core[openidconnect]==4.5.3
svgwrite==1.4.3
tablib==3.5.0
tablib==3.6.1
tzdata==2024.1