mirror of
https://github.com/netbox-community/netbox.git
synced 2026-01-17 01:02:18 -06:00
Compare commits
5 Commits
c2d3363930
...
fix-19669-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef7880a013 | ||
|
|
8fd8493d11 | ||
|
|
db805053d9 | ||
|
|
cf4db67e0b | ||
|
|
f48e1cb534 |
@@ -1,28 +1,29 @@
|
||||
from django.http import Http404, HttpResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_rq.queues import get_redis_connection
|
||||
from django_rq.settings import QUEUES_LIST
|
||||
from django_rq.utils import get_statistics
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework import viewsets
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.exceptions import PermissionDenied
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.routers import APIRootView
|
||||
from rest_framework.viewsets import ReadOnlyModelViewSet
|
||||
from rq.job import Job as RQ_Job
|
||||
from rq.worker import Worker
|
||||
|
||||
from core import filtersets
|
||||
from core.choices import DataSourceStatusChoices
|
||||
from core.jobs import SyncDataSourceJob
|
||||
from core.models import *
|
||||
from core.utils import delete_rq_job, enqueue_rq_job, get_rq_jobs, requeue_rq_job, stop_rq_job
|
||||
from django_rq.queues import get_redis_connection
|
||||
from django_rq.utils import get_statistics
|
||||
from django_rq.settings import QUEUES_LIST
|
||||
from netbox.api.metadata import ContentTypeMetadata
|
||||
from netbox.api.pagination import LimitOffsetListPagination
|
||||
from netbox.api.viewsets import NetBoxModelViewSet, NetBoxReadOnlyModelViewSet
|
||||
from rest_framework import viewsets
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
from rq.job import Job as RQ_Job
|
||||
from rq.worker import Worker
|
||||
from . import serializers
|
||||
|
||||
|
||||
@@ -49,8 +50,10 @@ class DataSourceViewSet(NetBoxModelViewSet):
|
||||
if not request.user.has_perm('core.sync_datasource', obj=datasource):
|
||||
raise PermissionDenied(_("This user does not have permission to synchronize this data source."))
|
||||
|
||||
# Enqueue the sync job
|
||||
# Enqueue the sync job & update the DataSource's status
|
||||
SyncDataSourceJob.enqueue(instance=datasource, user=request.user)
|
||||
datasource.status = DataSourceStatusChoices.QUEUED
|
||||
DataSource.objects.filter(pk=datasource.pk).update(status=datasource.status)
|
||||
|
||||
serializer = serializers.DataSourceSerializer(datasource, context={'request': request})
|
||||
|
||||
|
||||
@@ -21,17 +21,6 @@ class SyncDataSourceJob(JobRunner):
|
||||
class Meta:
|
||||
name = 'Synchronization'
|
||||
|
||||
@classmethod
|
||||
def enqueue(cls, *args, **kwargs):
|
||||
job = super().enqueue(*args, **kwargs)
|
||||
|
||||
# Update the DataSource's synchronization status to queued
|
||||
if datasource := job.object:
|
||||
datasource.status = DataSourceStatusChoices.QUEUED
|
||||
DataSource.objects.filter(pk=datasource.pk).update(status=datasource.status)
|
||||
|
||||
return job
|
||||
|
||||
def run(self, *args, **kwargs):
|
||||
datasource = DataSource.objects.get(pk=self.job.object_id)
|
||||
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import logging
|
||||
from threading import local
|
||||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db.models.fields.reverse_related import ManyToManyRel, ManyToOneRel
|
||||
from django.db.models.signals import m2m_changed, post_save, pre_delete
|
||||
from django.dispatch import receiver, Signal
|
||||
from django.core.signals import request_finished
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_prometheus.models import model_deletes, model_inserts, model_updates
|
||||
|
||||
@@ -44,10 +42,6 @@ clear_events = Signal()
|
||||
# Change logging & event handling
|
||||
#
|
||||
|
||||
# Used to track received signals per object
|
||||
_signals_received = local()
|
||||
|
||||
|
||||
@receiver((post_save, m2m_changed))
|
||||
def handle_changed_object(sender, instance, **kwargs):
|
||||
"""
|
||||
@@ -136,16 +130,6 @@ def handle_deleted_object(sender, instance, **kwargs):
|
||||
if request is None:
|
||||
return
|
||||
|
||||
# Check whether we've already processed a pre_delete signal for this object. (This can
|
||||
# happen e.g. when both a parent object and its child are deleted simultaneously, due
|
||||
# to cascading deletion.)
|
||||
if not hasattr(_signals_received, 'pre_delete'):
|
||||
_signals_received.pre_delete = set()
|
||||
signature = (ContentType.objects.get_for_model(instance), instance.pk)
|
||||
if signature in _signals_received.pre_delete:
|
||||
return
|
||||
_signals_received.pre_delete.add(signature)
|
||||
|
||||
# Record an ObjectChange if applicable
|
||||
if hasattr(instance, 'to_objectchange'):
|
||||
if hasattr(instance, 'snapshot') and not getattr(instance, '_prechange_snapshot', None):
|
||||
@@ -195,14 +179,6 @@ def handle_deleted_object(sender, instance, **kwargs):
|
||||
model_deletes.labels(instance._meta.model_name).inc()
|
||||
|
||||
|
||||
@receiver(request_finished)
|
||||
def clear_signal_history(sender, **kwargs):
|
||||
"""
|
||||
Clear out the signals history once the request is finished.
|
||||
"""
|
||||
_signals_received.pre_delete = set()
|
||||
|
||||
|
||||
@receiver(clear_events)
|
||||
def clear_events_queue(sender, **kwargs):
|
||||
"""
|
||||
|
||||
@@ -346,38 +346,6 @@ class ChangeLogViewTest(ModelViewTestCase):
|
||||
self.assertEqual(changes[1].changed_object_type, ContentType.objects.get_for_model(Interface))
|
||||
self.assertEqual(changes[2].changed_object_type, ContentType.objects.get_for_model(Device))
|
||||
|
||||
def test_duplicate_deletions(self):
|
||||
"""
|
||||
Check that a cascading deletion event does not generate multiple "deleted" ObjectChange records for
|
||||
the same object.
|
||||
"""
|
||||
role1 = DeviceRole(name='Role 1', slug='role-1')
|
||||
role1.save()
|
||||
role2 = DeviceRole(name='Role 2', slug='role-2', parent=role1)
|
||||
role2.save()
|
||||
pk_list = [role1.pk, role2.pk]
|
||||
|
||||
# Delete both objects simultaneously
|
||||
form_data = {
|
||||
'pk': pk_list,
|
||||
'confirm': True,
|
||||
'_confirm': True,
|
||||
}
|
||||
request = {
|
||||
'path': reverse('dcim:devicerole_bulk_delete'),
|
||||
'data': post_data(form_data),
|
||||
}
|
||||
self.add_permissions('dcim.delete_devicerole')
|
||||
self.assertHttpStatus(self.client.post(**request), 302)
|
||||
|
||||
# This should result in exactly one change record per object
|
||||
objectchanges = ObjectChange.objects.filter(
|
||||
changed_object_type=ContentType.objects.get_for_model(DeviceRole),
|
||||
changed_object_id__in=pk_list,
|
||||
action=ObjectChangeActionChoices.ACTION_DELETE
|
||||
)
|
||||
self.assertEqual(objectchanges.count(), 2)
|
||||
|
||||
|
||||
class ChangeLogAPITest(APITestCase):
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ from utilities.json import ConfigJSONEncoder
|
||||
from utilities.query import count_related
|
||||
from utilities.views import ContentTypePermissionRequiredMixin, GetRelatedModelsMixin, register_model_view
|
||||
from . import filtersets, forms, tables
|
||||
from .choices import DataSourceStatusChoices
|
||||
from .jobs import SyncDataSourceJob
|
||||
from .models import *
|
||||
from .plugins import get_catalog_plugins, get_local_plugins
|
||||
@@ -77,8 +78,12 @@ class DataSourceSyncView(BaseObjectView):
|
||||
|
||||
def post(self, request, pk):
|
||||
datasource = get_object_or_404(self.queryset, pk=pk)
|
||||
# Enqueue the sync job
|
||||
|
||||
# Enqueue the sync job & update the DataSource's status
|
||||
job = SyncDataSourceJob.enqueue(instance=datasource, user=request.user)
|
||||
datasource.status = DataSourceStatusChoices.QUEUED
|
||||
DataSource.objects.filter(pk=datasource.pk).update(status=datasource.status)
|
||||
|
||||
messages.success(
|
||||
request,
|
||||
_("Queued job #{id} to sync {datasource}").format(id=job.pk, datasource=datasource)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from django.conf import settings
|
||||
from django.http import Http404
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.views.static import serve
|
||||
from django_rq.queues import get_connection
|
||||
from drf_spectacular.utils import extend_schema, extend_schema_view
|
||||
from rest_framework import status
|
||||
@@ -200,6 +202,17 @@ class ImageAttachmentViewSet(NetBoxModelViewSet):
|
||||
serializer_class = serializers.ImageAttachmentSerializer
|
||||
filterset_class = filtersets.ImageAttachmentFilterSet
|
||||
|
||||
@action(
|
||||
methods=['GET'],
|
||||
detail=True,
|
||||
url_path='download',
|
||||
url_name='download',
|
||||
)
|
||||
def download(self, request, pk, *args, **kwargs):
|
||||
obj = get_object_or_404(self.queryset, pk=pk)
|
||||
# Render and return the elevation as an SVG drawing with the correct content type
|
||||
return serve(request, obj.image.name, document_root=settings.MEDIA_ROOT)
|
||||
|
||||
|
||||
#
|
||||
# Journal entries
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import datetime
|
||||
|
||||
from PIL import Image
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.files.base import File
|
||||
from django.urls import reverse
|
||||
from django.utils.timezone import make_aware, now
|
||||
from rest_framework import status
|
||||
@@ -616,6 +618,38 @@ class ImageAttachmentTest(
|
||||
)
|
||||
ImageAttachment.objects.bulk_create(image_attachments)
|
||||
|
||||
def test_image_download(self):
|
||||
self.add_permissions('extras.view_imageattachment')
|
||||
ct = ContentType.objects.get_for_model(Site)
|
||||
site = Site.objects.get(name='Site 1', slug='site-1')
|
||||
|
||||
image = Image.new('RGB', size=(1, 1), color=(255, 0, 0))
|
||||
image.save('test_image_download.png', format='PNG')
|
||||
image_file = File(open('test_image_download.png', 'rb'))
|
||||
content = image_file.read()
|
||||
|
||||
attachment = ImageAttachment(
|
||||
object_type=ct,
|
||||
object_id=site.pk,
|
||||
name='Image Attachment 4',
|
||||
image_height=1,
|
||||
image_width=1
|
||||
)
|
||||
attachment.image.save('test_image_download.png', image_file, save=True)
|
||||
attachment.save()
|
||||
|
||||
image = ImageAttachment.objects.get(name='Image Attachment 4')
|
||||
url = reverse('extras-api:imageattachment-download', kwargs={'pk': image.pk})
|
||||
response = self.client.get(url, **self.header)
|
||||
downloaded_content = b''.join(response.streaming_content)
|
||||
|
||||
self.assertEqual(response.headers.get('Content-Type'), 'image/png')
|
||||
self.assertEqual(response.headers.get('Content-Length'), '69')
|
||||
self.assertEqual(
|
||||
response.headers.get('Content-Disposition'), f'inline; filename="site_{site.pk}_Image_Attachment_4.png"'
|
||||
)
|
||||
self.assertEqual(content, downloaded_content)
|
||||
|
||||
|
||||
class JournalEntryTest(APIViewTestCases.APIViewTestCase):
|
||||
model = JournalEntry
|
||||
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-07-25 05:07+0000\n"
|
||||
"POT-Creation-Date: 2025-07-24 05:05+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -215,8 +215,8 @@ msgstr ""
|
||||
#: netbox/dcim/forms/bulk_edit.py:344 netbox/dcim/forms/bulk_edit.py:730
|
||||
#: netbox/dcim/forms/bulk_edit.py:935 netbox/dcim/forms/bulk_import.py:134
|
||||
#: netbox/dcim/forms/bulk_import.py:236 netbox/dcim/forms/bulk_import.py:337
|
||||
#: netbox/dcim/forms/bulk_import.py:598 netbox/dcim/forms/bulk_import.py:1539
|
||||
#: netbox/dcim/forms/bulk_import.py:1567 netbox/dcim/forms/filtersets.py:89
|
||||
#: netbox/dcim/forms/bulk_import.py:598 netbox/dcim/forms/bulk_import.py:1512
|
||||
#: netbox/dcim/forms/bulk_import.py:1540 netbox/dcim/forms/filtersets.py:89
|
||||
#: netbox/dcim/forms/filtersets.py:227 netbox/dcim/forms/filtersets.py:344
|
||||
#: netbox/dcim/forms/filtersets.py:441 netbox/dcim/forms/filtersets.py:773
|
||||
#: netbox/dcim/forms/filtersets.py:992 netbox/dcim/forms/filtersets.py:1065
|
||||
@@ -656,13 +656,13 @@ msgstr ""
|
||||
#: netbox/circuits/forms/filtersets.py:321 netbox/dcim/forms/bulk_edit.py:216
|
||||
#: netbox/dcim/forms/bulk_edit.py:656 netbox/dcim/forms/bulk_edit.py:866
|
||||
#: netbox/dcim/forms/bulk_edit.py:1235 netbox/dcim/forms/bulk_edit.py:1262
|
||||
#: netbox/dcim/forms/bulk_edit.py:1796 netbox/dcim/forms/bulk_import.py:1414
|
||||
#: netbox/dcim/forms/filtersets.py:1132 netbox/dcim/forms/filtersets.py:1390
|
||||
#: netbox/dcim/forms/filtersets.py:1543 netbox/dcim/forms/filtersets.py:1567
|
||||
#: netbox/dcim/tables/devices.py:748 netbox/dcim/tables/devices.py:804
|
||||
#: netbox/dcim/tables/devices.py:1045 netbox/dcim/tables/devicetypes.py:256
|
||||
#: netbox/dcim/tables/devicetypes.py:271 netbox/dcim/tables/racks.py:33
|
||||
#: netbox/extras/forms/bulk_edit.py:303 netbox/extras/tables/tables.py:487
|
||||
#: netbox/dcim/forms/bulk_edit.py:1796 netbox/dcim/forms/filtersets.py:1132
|
||||
#: netbox/dcim/forms/filtersets.py:1390 netbox/dcim/forms/filtersets.py:1543
|
||||
#: netbox/dcim/forms/filtersets.py:1567 netbox/dcim/tables/devices.py:748
|
||||
#: netbox/dcim/tables/devices.py:804 netbox/dcim/tables/devices.py:1045
|
||||
#: netbox/dcim/tables/devicetypes.py:256 netbox/dcim/tables/devicetypes.py:271
|
||||
#: netbox/dcim/tables/racks.py:33 netbox/extras/forms/bulk_edit.py:303
|
||||
#: netbox/extras/tables/tables.py:487
|
||||
#: netbox/templates/circuits/circuittype.html:30
|
||||
#: netbox/templates/circuits/virtualcircuittype.html:30
|
||||
#: netbox/templates/dcim/cable.html:40 netbox/templates/dcim/devicerole.html:38
|
||||
@@ -694,7 +694,7 @@ msgstr ""
|
||||
#: netbox/dcim/forms/bulk_import.py:818 netbox/dcim/forms/bulk_import.py:838
|
||||
#: netbox/dcim/forms/bulk_import.py:924 netbox/dcim/forms/bulk_import.py:1018
|
||||
#: netbox/dcim/forms/bulk_import.py:1060 netbox/dcim/forms/bulk_import.py:1395
|
||||
#: netbox/dcim/forms/bulk_import.py:1604 netbox/dcim/forms/filtersets.py:1023
|
||||
#: netbox/dcim/forms/bulk_import.py:1577 netbox/dcim/forms/filtersets.py:1023
|
||||
#: netbox/dcim/forms/filtersets.py:1122 netbox/dcim/forms/filtersets.py:1243
|
||||
#: netbox/dcim/forms/filtersets.py:1315 netbox/dcim/forms/filtersets.py:1340
|
||||
#: netbox/dcim/forms/filtersets.py:1364 netbox/dcim/forms/filtersets.py:1384
|
||||
@@ -765,7 +765,7 @@ msgstr ""
|
||||
#: netbox/dcim/forms/bulk_import.py:150 netbox/dcim/forms/bulk_import.py:254
|
||||
#: netbox/dcim/forms/bulk_import.py:563 netbox/dcim/forms/bulk_import.py:717
|
||||
#: netbox/dcim/forms/bulk_import.py:1168 netbox/dcim/forms/bulk_import.py:1389
|
||||
#: netbox/dcim/forms/bulk_import.py:1599 netbox/dcim/forms/bulk_import.py:1663
|
||||
#: netbox/dcim/forms/bulk_import.py:1572 netbox/dcim/forms/bulk_import.py:1636
|
||||
#: netbox/dcim/forms/filtersets.py:180 netbox/dcim/forms/filtersets.py:239
|
||||
#: netbox/dcim/forms/filtersets.py:361 netbox/dcim/forms/filtersets.py:819
|
||||
#: netbox/dcim/forms/filtersets.py:944 netbox/dcim/forms/filtersets.py:1026
|
||||
@@ -843,7 +843,7 @@ msgstr ""
|
||||
#: netbox/dcim/forms/bulk_import.py:110 netbox/dcim/forms/bulk_import.py:155
|
||||
#: netbox/dcim/forms/bulk_import.py:247 netbox/dcim/forms/bulk_import.py:362
|
||||
#: netbox/dcim/forms/bulk_import.py:537 netbox/dcim/forms/bulk_import.py:1401
|
||||
#: netbox/dcim/forms/bulk_import.py:1656 netbox/dcim/forms/filtersets.py:175
|
||||
#: netbox/dcim/forms/bulk_import.py:1629 netbox/dcim/forms/filtersets.py:175
|
||||
#: netbox/dcim/forms/filtersets.py:207 netbox/dcim/forms/filtersets.py:325
|
||||
#: netbox/dcim/forms/filtersets.py:401 netbox/dcim/forms/filtersets.py:422
|
||||
#: netbox/dcim/forms/filtersets.py:742 netbox/dcim/forms/filtersets.py:936
|
||||
@@ -1149,7 +1149,7 @@ msgstr ""
|
||||
#: netbox/circuits/forms/bulk_import.py:229 netbox/dcim/forms/bulk_import.py:93
|
||||
#: netbox/dcim/forms/bulk_import.py:152 netbox/dcim/forms/bulk_import.py:256
|
||||
#: netbox/dcim/forms/bulk_import.py:565 netbox/dcim/forms/bulk_import.py:719
|
||||
#: netbox/dcim/forms/bulk_import.py:1170 netbox/dcim/forms/bulk_import.py:1601
|
||||
#: netbox/dcim/forms/bulk_import.py:1170 netbox/dcim/forms/bulk_import.py:1574
|
||||
#: netbox/ipam/forms/bulk_import.py:197 netbox/ipam/forms/bulk_import.py:265
|
||||
#: netbox/ipam/forms/bulk_import.py:301 netbox/ipam/forms/bulk_import.py:498
|
||||
#: netbox/ipam/forms/bulk_import.py:511
|
||||
@@ -1165,8 +1165,8 @@ msgstr ""
|
||||
#: netbox/circuits/forms/bulk_import.py:236
|
||||
#: netbox/dcim/forms/bulk_import.py:114 netbox/dcim/forms/bulk_import.py:159
|
||||
#: netbox/dcim/forms/bulk_import.py:366 netbox/dcim/forms/bulk_import.py:541
|
||||
#: netbox/dcim/forms/bulk_import.py:1405 netbox/dcim/forms/bulk_import.py:1596
|
||||
#: netbox/dcim/forms/bulk_import.py:1660 netbox/ipam/forms/bulk_import.py:45
|
||||
#: netbox/dcim/forms/bulk_import.py:1405 netbox/dcim/forms/bulk_import.py:1569
|
||||
#: netbox/dcim/forms/bulk_import.py:1633 netbox/ipam/forms/bulk_import.py:45
|
||||
#: netbox/ipam/forms/bulk_import.py:74 netbox/ipam/forms/bulk_import.py:102
|
||||
#: netbox/ipam/forms/bulk_import.py:122 netbox/ipam/forms/bulk_import.py:142
|
||||
#: netbox/ipam/forms/bulk_import.py:171 netbox/ipam/forms/bulk_import.py:260
|
||||
@@ -1246,8 +1246,8 @@ msgstr ""
|
||||
#: netbox/dcim/forms/bulk_edit.py:466 netbox/dcim/forms/bulk_edit.py:735
|
||||
#: netbox/dcim/forms/bulk_edit.py:790 netbox/dcim/forms/bulk_edit.py:944
|
||||
#: netbox/dcim/forms/bulk_import.py:241 netbox/dcim/forms/bulk_import.py:343
|
||||
#: netbox/dcim/forms/bulk_import.py:604 netbox/dcim/forms/bulk_import.py:1545
|
||||
#: netbox/dcim/forms/bulk_import.py:1579 netbox/dcim/forms/filtersets.py:97
|
||||
#: netbox/dcim/forms/bulk_import.py:604 netbox/dcim/forms/bulk_import.py:1518
|
||||
#: netbox/dcim/forms/bulk_import.py:1552 netbox/dcim/forms/filtersets.py:97
|
||||
#: netbox/dcim/forms/filtersets.py:324 netbox/dcim/forms/filtersets.py:358
|
||||
#: netbox/dcim/forms/filtersets.py:398 netbox/dcim/forms/filtersets.py:449
|
||||
#: netbox/dcim/forms/filtersets.py:739 netbox/dcim/forms/filtersets.py:782
|
||||
@@ -1949,7 +1949,7 @@ msgstr ""
|
||||
#: netbox/dcim/forms/bulk_import.py:1007 netbox/dcim/forms/bulk_import.py:1055
|
||||
#: netbox/dcim/forms/bulk_import.py:1072 netbox/dcim/forms/bulk_import.py:1084
|
||||
#: netbox/dcim/forms/bulk_import.py:1132 netbox/dcim/forms/bulk_import.py:1254
|
||||
#: netbox/dcim/forms/bulk_import.py:1650 netbox/dcim/forms/connections.py:24
|
||||
#: netbox/dcim/forms/bulk_import.py:1623 netbox/dcim/forms/connections.py:24
|
||||
#: netbox/dcim/forms/filtersets.py:133 netbox/dcim/forms/filtersets.py:941
|
||||
#: netbox/dcim/forms/filtersets.py:973 netbox/dcim/forms/filtersets.py:1119
|
||||
#: netbox/dcim/forms/filtersets.py:1310 netbox/dcim/forms/filtersets.py:1335
|
||||
@@ -4194,8 +4194,8 @@ msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_edit.py:465 netbox/dcim/forms/bulk_edit.py:972
|
||||
#: netbox/dcim/forms/bulk_import.py:350 netbox/dcim/forms/bulk_import.py:353
|
||||
#: netbox/dcim/forms/bulk_import.py:611 netbox/dcim/forms/bulk_import.py:1586
|
||||
#: netbox/dcim/forms/bulk_import.py:1590 netbox/dcim/forms/filtersets.py:106
|
||||
#: netbox/dcim/forms/bulk_import.py:611 netbox/dcim/forms/bulk_import.py:1559
|
||||
#: netbox/dcim/forms/bulk_import.py:1563 netbox/dcim/forms/filtersets.py:106
|
||||
#: netbox/dcim/forms/filtersets.py:326 netbox/dcim/forms/filtersets.py:407
|
||||
#: netbox/dcim/forms/filtersets.py:421 netbox/dcim/forms/filtersets.py:459
|
||||
#: netbox/dcim/forms/filtersets.py:792 netbox/dcim/forms/filtersets.py:1005
|
||||
@@ -4405,17 +4405,17 @@ msgstr ""
|
||||
msgid "Domain"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_edit.py:967 netbox/dcim/forms/bulk_import.py:1573
|
||||
#: netbox/dcim/forms/bulk_edit.py:967 netbox/dcim/forms/bulk_import.py:1546
|
||||
#: netbox/dcim/forms/filtersets.py:1226 netbox/dcim/forms/model_forms.py:855
|
||||
msgid "Power panel"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_edit.py:989 netbox/dcim/forms/bulk_import.py:1609
|
||||
#: netbox/dcim/forms/bulk_edit.py:989 netbox/dcim/forms/bulk_import.py:1582
|
||||
#: netbox/dcim/forms/filtersets.py:1248 netbox/templates/dcim/powerfeed.html:83
|
||||
msgid "Supply"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_edit.py:995 netbox/dcim/forms/bulk_import.py:1614
|
||||
#: netbox/dcim/forms/bulk_edit.py:995 netbox/dcim/forms/bulk_import.py:1587
|
||||
#: netbox/dcim/forms/filtersets.py:1253 netbox/templates/dcim/powerfeed.html:95
|
||||
msgid "Phase"
|
||||
msgstr ""
|
||||
@@ -4653,7 +4653,7 @@ msgid "available options"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:137 netbox/dcim/forms/bulk_import.py:601
|
||||
#: netbox/dcim/forms/bulk_import.py:1570 netbox/ipam/forms/bulk_import.py:479
|
||||
#: netbox/dcim/forms/bulk_import.py:1543 netbox/ipam/forms/bulk_import.py:479
|
||||
#: netbox/virtualization/forms/bulk_import.py:64
|
||||
#: netbox/virtualization/forms/bulk_import.py:95
|
||||
msgid "Assigned site"
|
||||
@@ -4716,7 +4716,7 @@ msgstr ""
|
||||
msgid "Parent site"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:347 netbox/dcim/forms/bulk_import.py:1583
|
||||
#: netbox/dcim/forms/bulk_import.py:347 netbox/dcim/forms/bulk_import.py:1556
|
||||
msgid "Rack's location (if any)"
|
||||
msgstr ""
|
||||
|
||||
@@ -4767,7 +4767,7 @@ msgstr ""
|
||||
msgid "Limit platform assignments to this manufacturer"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:534 netbox/dcim/forms/bulk_import.py:1653
|
||||
#: netbox/dcim/forms/bulk_import.py:534 netbox/dcim/forms/bulk_import.py:1626
|
||||
#: netbox/tenancy/forms/bulk_import.py:105
|
||||
msgid "Assigned role"
|
||||
msgstr ""
|
||||
@@ -5100,77 +5100,66 @@ msgstr ""
|
||||
msgid "Connection status"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1417
|
||||
msgid "Color name (e.g. \"Red\") or hex code (e.g. \"f44336\")"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1469
|
||||
#: netbox/dcim/forms/bulk_import.py:1463
|
||||
#, python-brace-format
|
||||
msgid "Side {side_upper}: {device} {termination_object} is already connected"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1475
|
||||
#: netbox/dcim/forms/bulk_import.py:1469
|
||||
#, python-brace-format
|
||||
msgid "{side_upper} side termination not found: {device} {name}"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1496
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"{color} did not match any used color name and was longer than six "
|
||||
"characters: invalid hex."
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1521 netbox/dcim/forms/model_forms.py:891
|
||||
#: netbox/dcim/forms/bulk_import.py:1494 netbox/dcim/forms/model_forms.py:891
|
||||
#: netbox/dcim/tables/devices.py:1069 netbox/templates/dcim/device.html:138
|
||||
#: netbox/templates/dcim/virtualchassis.html:27
|
||||
#: netbox/templates/dcim/virtualchassis.html:67
|
||||
msgid "Master"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1525
|
||||
#: netbox/dcim/forms/bulk_import.py:1498
|
||||
msgid "Master device"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1542
|
||||
#: netbox/dcim/forms/bulk_import.py:1515
|
||||
msgid "Name of parent site"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1576
|
||||
#: netbox/dcim/forms/bulk_import.py:1549
|
||||
msgid "Upstream power panel"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1606
|
||||
#: netbox/dcim/forms/bulk_import.py:1579
|
||||
msgid "Primary or redundant"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1611
|
||||
#: netbox/dcim/forms/bulk_import.py:1584
|
||||
msgid "Supply type (AC/DC)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1616
|
||||
#: netbox/dcim/forms/bulk_import.py:1589
|
||||
msgid "Single or three-phase"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1667 netbox/dcim/forms/model_forms.py:1847
|
||||
#: netbox/dcim/forms/bulk_import.py:1640 netbox/dcim/forms/model_forms.py:1847
|
||||
#: netbox/templates/dcim/device.html:196
|
||||
#: netbox/templates/dcim/virtualdevicecontext.html:30
|
||||
#: netbox/templates/virtualization/virtualmachine.html:52
|
||||
msgid "Primary IPv4"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1671
|
||||
#: netbox/dcim/forms/bulk_import.py:1644
|
||||
msgid "IPv4 address with mask, e.g. 1.2.3.4/24"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1674 netbox/dcim/forms/model_forms.py:1856
|
||||
#: netbox/dcim/forms/bulk_import.py:1647 netbox/dcim/forms/model_forms.py:1856
|
||||
#: netbox/templates/dcim/device.html:212
|
||||
#: netbox/templates/dcim/virtualdevicecontext.html:41
|
||||
#: netbox/templates/virtualization/virtualmachine.html:68
|
||||
msgid "Primary IPv6"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/forms/bulk_import.py:1678
|
||||
#: netbox/dcim/forms/bulk_import.py:1651
|
||||
msgid "IPv6 address with prefix length, e.g. 2001:db8::1/64"
|
||||
msgstr ""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user