nautobot 3.0.0rc2__py3-none-any.whl → 3.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nautobot might be problematic. Click here for more details.
- nautobot/apps/views.py +2 -0
- nautobot/core/celery/__init__.py +46 -1
- nautobot/core/cli/bootstrap_v3_to_v5.py +125 -44
- nautobot/core/jobs/bulk_actions.py +12 -6
- nautobot/core/settings.py +13 -0
- nautobot/core/settings.yaml +22 -0
- nautobot/core/templates/components/panel/body_wrapper_generic_table.html +1 -1
- nautobot/core/templates/nautobot_config.py.j2 +14 -1
- nautobot/core/templates/redoc_ui.html +3 -0
- nautobot/core/testing/filters.py +2 -2
- nautobot/core/testing/views.py +1 -1
- nautobot/core/tests/test_jobs.py +118 -0
- nautobot/core/tests/test_views.py +24 -0
- nautobot/core/ui/bulk_buttons.py +2 -3
- nautobot/core/ui/object_detail.py +2 -2
- nautobot/core/views/generic.py +1 -0
- nautobot/core/views/mixins.py +6 -7
- nautobot/core/views/renderers.py +1 -0
- nautobot/core/views/utils.py +3 -3
- nautobot/dcim/tables/devices.py +1 -1
- nautobot/dcim/views.py +1 -1
- nautobot/extras/jobs.py +48 -2
- nautobot/extras/models/jobs.py +1 -0
- nautobot/extras/models/models.py +19 -0
- nautobot/extras/tables.py +9 -6
- nautobot/extras/templates/extras/approval_workflow/approve.html +9 -2
- nautobot/extras/templates/extras/approval_workflow/deny.html +9 -3
- nautobot/extras/tests/test_customfields_filters.py +84 -4
- nautobot/extras/tests/test_views.py +40 -4
- nautobot/extras/views.py +63 -38
- nautobot/project-static/dist/css/graphql-libraries.css.map +1 -1
- nautobot/project-static/dist/css/materialdesignicons.css.map +1 -1
- nautobot/project-static/dist/css/nautobot.css +1 -1
- nautobot/project-static/dist/css/nautobot.css.map +1 -1
- nautobot/project-static/dist/js/graphql-libraries.js +1 -1
- nautobot/project-static/dist/js/graphql-libraries.js.map +1 -1
- nautobot/project-static/dist/js/libraries.js.map +1 -1
- nautobot/project-static/dist/js/nautobot-graphiql.js.map +1 -1
- nautobot/project-static/dist/js/nautobot.js.map +1 -1
- nautobot/project-static/img/dark-theme.png +0 -0
- nautobot/project-static/img/light-theme.png +0 -0
- nautobot/project-static/img/system-theme.png +0 -0
- nautobot/ui/package-lock.json +25 -25
- nautobot/ui/package.json +6 -6
- nautobot/ui/src/scss/nautobot.scss +2 -1
- {nautobot-3.0.0rc2.dist-info → nautobot-3.0.2.dist-info}/METADATA +6 -6
- {nautobot-3.0.0rc2.dist-info → nautobot-3.0.2.dist-info}/RECORD +51 -51
- {nautobot-3.0.0rc2.dist-info → nautobot-3.0.2.dist-info}/LICENSE.txt +0 -0
- {nautobot-3.0.0rc2.dist-info → nautobot-3.0.2.dist-info}/NOTICE +0 -0
- {nautobot-3.0.0rc2.dist-info → nautobot-3.0.2.dist-info}/WHEEL +0 -0
- {nautobot-3.0.0rc2.dist-info → nautobot-3.0.2.dist-info}/entry_points.txt +0 -0
nautobot/extras/views.py
CHANGED
|
@@ -420,27 +420,33 @@ class ApprovalWorkflowStageUIViewSet(
|
|
|
420
420
|
],
|
|
421
421
|
)
|
|
422
422
|
|
|
423
|
-
@action(
|
|
423
|
+
@action(
|
|
424
|
+
detail=True,
|
|
425
|
+
url_path="approve",
|
|
426
|
+
methods=["get", "post"],
|
|
427
|
+
custom_view_base_action="change",
|
|
428
|
+
custom_view_additional_permissions=["extras.view_approvalworkflowstage"],
|
|
429
|
+
)
|
|
424
430
|
def approve(self, request, *args, **kwargs):
|
|
425
431
|
"""
|
|
426
432
|
Approve the approval workflow stage response.
|
|
427
433
|
"""
|
|
428
434
|
instance = self.get_object()
|
|
429
435
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
)
|
|
435
|
-
|
|
436
|
-
approval_workflow_stage_response = ApprovalWorkflowStageResponse.objects.create(
|
|
437
|
-
approval_workflow_stage=instance,
|
|
438
|
-
user=request.user,
|
|
439
|
-
)
|
|
436
|
+
if not (
|
|
437
|
+
request.user.is_superuser
|
|
438
|
+
or instance.approval_workflow_stage_definition.approver_group.user_set.filter(id=request.user.id).exists()
|
|
439
|
+
):
|
|
440
|
+
messages.error(request, "You are not permitted to approve this workflow stage.")
|
|
441
|
+
return redirect(self.get_return_url(request, instance))
|
|
440
442
|
|
|
441
443
|
if request.method == "GET":
|
|
442
|
-
|
|
443
|
-
|
|
444
|
+
if existing_response := ApprovalWorkflowStageResponse.objects.filter(
|
|
445
|
+
approval_workflow_stage=instance, user=request.user
|
|
446
|
+
).first():
|
|
447
|
+
form = ApprovalForm(initial={"comments": existing_response.comments})
|
|
448
|
+
else:
|
|
449
|
+
form = ApprovalForm()
|
|
444
450
|
|
|
445
451
|
object_under_review = instance.approval_workflow.object_under_review
|
|
446
452
|
template_name = getattr(object_under_review, "get_approval_template", lambda: None)()
|
|
@@ -451,15 +457,19 @@ class ApprovalWorkflowStageUIViewSet(
|
|
|
451
457
|
request,
|
|
452
458
|
template_name,
|
|
453
459
|
{
|
|
454
|
-
"obj":
|
|
455
|
-
"object_under_review":
|
|
460
|
+
"obj": instance,
|
|
461
|
+
"object_under_review": instance.approval_workflow.object_under_review,
|
|
456
462
|
"form": form,
|
|
457
463
|
"obj_type": ApprovalWorkflowStage._meta.verbose_name,
|
|
458
|
-
"return_url": self.get_return_url(request,
|
|
464
|
+
"return_url": self.get_return_url(request, instance),
|
|
459
465
|
"card_class": "success",
|
|
460
466
|
"button_class": "success",
|
|
461
467
|
},
|
|
462
468
|
)
|
|
469
|
+
|
|
470
|
+
approval_workflow_stage_response, _ = ApprovalWorkflowStageResponse.objects.get_or_create(
|
|
471
|
+
approval_workflow_stage=instance, user=request.user
|
|
472
|
+
)
|
|
463
473
|
approval_workflow_stage_response.comments = request.data.get("comments")
|
|
464
474
|
approval_workflow_stage_response.state = ApprovalWorkflowStateChoices.APPROVED
|
|
465
475
|
approval_workflow_stage_response.save()
|
|
@@ -467,40 +477,49 @@ class ApprovalWorkflowStageUIViewSet(
|
|
|
467
477
|
messages.success(request, f"You approved {instance}.")
|
|
468
478
|
return redirect(self.get_return_url(request))
|
|
469
479
|
|
|
470
|
-
@action(
|
|
480
|
+
@action(
|
|
481
|
+
detail=True,
|
|
482
|
+
url_path="deny",
|
|
483
|
+
methods=["get", "post"],
|
|
484
|
+
custom_view_base_action="change",
|
|
485
|
+
custom_view_additional_permissions=["extras.view_approvalworkflowstage"],
|
|
486
|
+
)
|
|
471
487
|
def deny(self, request, *args, **kwargs):
|
|
472
488
|
"""
|
|
473
489
|
Deny the approval workflow stage response.
|
|
474
490
|
"""
|
|
475
491
|
instance = self.get_object()
|
|
476
492
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
)
|
|
482
|
-
|
|
483
|
-
approval_workflow_stage_response = ApprovalWorkflowStageResponse.objects.create(
|
|
484
|
-
approval_workflow_stage=instance,
|
|
485
|
-
user=request.user,
|
|
486
|
-
state=ApprovalWorkflowStateChoices.PENDING,
|
|
487
|
-
)
|
|
493
|
+
if not (
|
|
494
|
+
request.user.is_superuser
|
|
495
|
+
or instance.approval_workflow_stage_definition.approver_group.user_set.filter(id=request.user.id).exists()
|
|
496
|
+
):
|
|
497
|
+
messages.error(request, "You are not permitted to deny this workflow stage.")
|
|
498
|
+
return redirect(self.get_return_url(request, instance))
|
|
488
499
|
|
|
489
500
|
if request.method == "GET":
|
|
490
|
-
|
|
491
|
-
|
|
501
|
+
if existing_response := ApprovalWorkflowStageResponse.objects.filter(
|
|
502
|
+
approval_workflow_stage=instance, user=request.user
|
|
503
|
+
).first():
|
|
504
|
+
form = ApprovalForm(initial={"comments": existing_response.comments})
|
|
505
|
+
else:
|
|
506
|
+
form = ApprovalForm()
|
|
492
507
|
|
|
493
508
|
return render(
|
|
494
509
|
request,
|
|
495
510
|
"extras/approval_workflow/deny.html",
|
|
496
511
|
{
|
|
497
|
-
"obj":
|
|
498
|
-
"object_under_review":
|
|
512
|
+
"obj": instance,
|
|
513
|
+
"object_under_review": instance.approval_workflow.object_under_review,
|
|
499
514
|
"form": form,
|
|
500
515
|
"obj_type": ApprovalWorkflowStage._meta.verbose_name,
|
|
501
|
-
"return_url": self.get_return_url(request,
|
|
516
|
+
"return_url": self.get_return_url(request, instance),
|
|
502
517
|
},
|
|
503
518
|
)
|
|
519
|
+
|
|
520
|
+
approval_workflow_stage_response, _ = ApprovalWorkflowStageResponse.objects.get_or_create(
|
|
521
|
+
approval_workflow_stage=instance, user=request.user
|
|
522
|
+
)
|
|
504
523
|
approval_workflow_stage_response.comments = request.data.get("comments")
|
|
505
524
|
approval_workflow_stage_response.state = ApprovalWorkflowStateChoices.DENIED
|
|
506
525
|
approval_workflow_stage_response.save()
|
|
@@ -508,7 +527,13 @@ class ApprovalWorkflowStageUIViewSet(
|
|
|
508
527
|
messages.success(request, f"You denied {instance}.")
|
|
509
528
|
return redirect(self.get_return_url(request))
|
|
510
529
|
|
|
511
|
-
@action(
|
|
530
|
+
@action(
|
|
531
|
+
detail=True,
|
|
532
|
+
url_path="comment",
|
|
533
|
+
methods=["get", "post"],
|
|
534
|
+
custom_view_base_action="change",
|
|
535
|
+
custom_view_additional_permissions=["extras.view_approvalworkflowstage"],
|
|
536
|
+
)
|
|
512
537
|
def comment(self, request, *args, **kwargs):
|
|
513
538
|
"""
|
|
514
539
|
Comment the approval workflow stage response.
|
|
@@ -521,11 +546,12 @@ class ApprovalWorkflowStageUIViewSet(
|
|
|
521
546
|
)
|
|
522
547
|
return redirect(self.get_return_url(request, instance))
|
|
523
548
|
|
|
549
|
+
# We don't enforce approver-group/superuser check here, anyone can comment, not just an approver.
|
|
550
|
+
|
|
524
551
|
if request.method == "GET":
|
|
525
|
-
existing_response
|
|
552
|
+
if existing_response := ApprovalWorkflowStageResponse.objects.filter(
|
|
526
553
|
approval_workflow_stage=instance, user=request.user
|
|
527
|
-
).first()
|
|
528
|
-
if existing_response is not None:
|
|
554
|
+
).first():
|
|
529
555
|
form = ApprovalForm(initial={"comments": existing_response.comments})
|
|
530
556
|
else:
|
|
531
557
|
form = ApprovalForm()
|
|
@@ -547,7 +573,6 @@ class ApprovalWorkflowStageUIViewSet(
|
|
|
547
573
|
approval_workflow_stage_response, _ = ApprovalWorkflowStageResponse.objects.get_or_create(
|
|
548
574
|
approval_workflow_stage=instance, user=request.user
|
|
549
575
|
)
|
|
550
|
-
|
|
551
576
|
approval_workflow_stage_response.comments = request.data.get("comments")
|
|
552
577
|
# we don't want to change a state if is approved, denied or canceled
|
|
553
578
|
if approval_workflow_stage_response.state == ApprovalWorkflowStateChoices.PENDING:
|