Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: 🚧 Replace custom Notes by Nautobot ones #324

Merged
merged 14 commits into from
Oct 15, 2024
1 change: 1 addition & 0 deletions changes/324.housekeeping
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Replace custom Note model by the Nautobot one
11 changes: 0 additions & 11 deletions nautobot_circuit_maintenance/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from nautobot_circuit_maintenance.models import (
CircuitImpact,
CircuitMaintenance,
Note,
NotificationSource,
ParsedNotification,
RawNotification,
Expand Down Expand Up @@ -42,16 +41,6 @@ class Meta:
fields = "__all__"


class NoteSerializer(NautobotModelSerializer):
"""Serializer for API."""

class Meta:
"""Meta class for MaintenanceNoteSerializer."""

model = Note
fields = "__all__"


class NotificationSourceSerializer(NautobotModelSerializer):
"""Serializer for NotificationSource records."""

Expand Down
1 change: 0 additions & 1 deletion nautobot_circuit_maintenance/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

router = routers.DefaultRouter()
router.register("circuit-maintenances", views.MaintenanceTaskView)
router.register("notes", views.MaintenanceNoteTaskView)
router.register("circuit-impacts", views.MaintenanceCircuitImpactTaskView)
router.register("notification-sources", views.NotificationSourceTaskView)
router.register("parsed-notifications", views.ParsedNotificationTaskView)
Expand Down
9 changes: 0 additions & 9 deletions nautobot_circuit_maintenance/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from nautobot_circuit_maintenance.models import (
CircuitImpact,
CircuitMaintenance,
Note,
NotificationSource,
ParsedNotification,
RawNotification,
Expand All @@ -17,7 +16,6 @@
from .serializers import (
CircuitImpactSerializer,
CircuitMaintenanceSerializer,
NoteSerializer,
NotificationSourceSerializer,
ParsedNotificationSerializer,
RawNotificationSerializer,
Expand All @@ -32,13 +30,6 @@ class MaintenanceTaskView(CustomFieldModelViewSet):
filterset_class = filters.CircuitMaintenanceFilterSet


class MaintenanceNoteTaskView(CustomFieldModelViewSet):
"""API view for Circuit Note CRUD operations."""

queryset = Note.objects.prefetch_related()
serializer_class = NoteSerializer


class MaintenanceCircuitImpactTaskView(CustomFieldModelViewSet):
"""API view for Circuit Impact CRUD operations."""

Expand Down
12 changes: 0 additions & 12 deletions nautobot_circuit_maintenance/choices.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,3 @@ class CircuitImpactChoices(ChoiceSet):
(DEGRADED, "DEGRADED"),
(OUTAGE, "OUTAGE"),
)


class NoteLevelChoices(ChoiceSet):
"""Valid values for Circuit Maintenance Note level."""

INFO = "INFO"
WARNING = "WARNING"

CHOICES = (
(INFO, "INFO"),
(WARNING, "WARNING"),
)
26 changes: 1 addition & 25 deletions nautobot_circuit_maintenance/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from nautobot.core.filters import NaturalKeyOrPKMultipleChoiceFilter
from nautobot.extras.filters import NautobotFilterSet

from .models import CircuitImpact, CircuitMaintenance, Note, NotificationSource, ParsedNotification, RawNotification
from .models import CircuitImpact, CircuitMaintenance, NotificationSource, ParsedNotification, RawNotification

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -74,30 +74,6 @@ class Meta:
fields = "__all__"


class NoteFilterSet(NautobotFilterSet):
"""Filter capabilities for Note instances."""

maintenance = NaturalKeyOrPKMultipleChoiceFilter(
field_name="maintenance",
queryset=CircuitMaintenance.objects.all(),
to_field_name="name",
label="CircuitMaintenance",
)

class Meta:
"""Meta class attributes for NoteFilterSet."""

model = Note
fields = "__all__"

def search(self, queryset, name, value): # pylint: disable=unused-argument
"""Perform the filtered search."""
if not value.strip():
return queryset
qs_filter = Q(title__icontains=value)
return queryset.filter(qs_filter)


class RawNotificationFilterSet(NautobotFilterSet):
"""Filter capabilities for Raw Notification instances."""

Expand Down
42 changes: 2 additions & 40 deletions nautobot_circuit_maintenance/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
CustomFieldModelBulkEditFormMixin,
CustomFieldModelFilterFormMixin,
CustomFieldModelFormMixin,
NoteModelFormMixin,
RelationshipModelFormMixin,
)
from nautobot.circuits.models import Circuit, Provider
Expand All @@ -27,7 +28,6 @@
from .models import (
CircuitImpact,
CircuitMaintenance,
Note,
NotificationSource,
RawNotification,
)
Expand Down Expand Up @@ -73,7 +73,7 @@ class CircuitImpactFilterForm(BootstrapMixin, CustomFieldModelFilterFormMixin):
impact = forms.CharField(max_length=50)


class CircuitMaintenanceForm(BootstrapMixin, CustomFieldModelFormMixin, RelationshipModelFormMixin):
class CircuitMaintenanceForm(BootstrapMixin, CustomFieldModelFormMixin, RelationshipModelFormMixin, NoteModelFormMixin):
"""Filter Form for CircuitMaintenance instances."""

class Meta: # noqa: D106 "Missing docstring in public nested class"
Expand Down Expand Up @@ -119,44 +119,6 @@ class Meta: # noqa: D106 "Missing docstring in public nested class"
nullable_fields = ["status", "ack", "description"]


class NoteForm(BootstrapMixin, CustomFieldModelFormMixin, RelationshipModelFormMixin):
chadell marked this conversation as resolved.
Show resolved Hide resolved
"""Form for creating new maintenance note."""

class Meta: # noqa: D106 "Missing docstring in public nested class"
"""Metaclass attributes for NoteForm."""

model = Note
fields = ["maintenance", "title", "comment", "level"]
widgets = {"maintenance": forms.HiddenInput()}


class NoteBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkEditFormMixin):
"""Form for bulk editing Notes."""

pk = forms.ModelMultipleChoiceField(queryset=Note.objects.all(), widget=forms.MultipleHiddenInput)
title = forms.CharField(max_length=200)
level = forms.CharField(max_length=50, required=False)
comment = forms.CharField(max_length=200)

class Meta: # noqa: D106 "Missing docstring in public nested class"
nullable_fields = ["level"]


class NoteFilterForm(BootstrapMixin, CustomFieldModelFilterFormMixin):
"""Filter Form for creating new maintenance note."""

model = Note
q = forms.CharField(required=False, label="Search")
maintenance = DynamicModelMultipleChoiceField(
queryset=CircuitMaintenance.objects.all(),
to_field_name="pk",
required=False,
)
title = forms.CharField(max_length=200)
level = forms.CharField(max_length=50, required=False)
comment = forms.CharField(max_length=200)


class RawNotificationFilterSetForm(BootstrapMixin, CustomFieldModelFilterFormMixin):
"""Form for filtering Raw Notification instances."""

Expand Down
18 changes: 8 additions & 10 deletions nautobot_circuit_maintenance/handle_notifications/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@
from circuit_maintenance_parser import Maintenance, NotificationData, ProviderError, init_provider
from dateutil import parser
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction
from nautobot.circuits.models import Circuit, Provider
from nautobot.extras.jobs import DryRunVar, Job
from nautobot.extras.models import Note

from nautobot_circuit_maintenance.choices import CircuitMaintenanceStatusChoices
from nautobot_circuit_maintenance.enum import MessageProcessingStatus
from nautobot_circuit_maintenance.models import (
MAX_MAINTENANCE_NAME_LENGTH,
MAX_NOTE_TITLE_LENGTH,
MAX_NOTIFICATION_SENDER_LENGTH,
MAX_NOTIFICATION_SUBJECT_LENGTH,
CircuitImpact,
CircuitMaintenance,
Note,
NotificationSource,
ParsedNotification,
RawNotification,
Expand Down Expand Up @@ -71,13 +71,12 @@ def create_circuit_maintenance(
)
else:
note_entry, created = Note.objects.get_or_create(
maintenance=circuit_maintenance_entry,
title=f"Nonexistent circuit ID {circuit.circuit_id}"[:MAX_NOTE_TITLE_LENGTH],
comment=(
assigned_object_id=circuit_maintenance_entry.id,
assigned_object_type=ContentType.objects.get_for_model(CircuitMaintenance),
glennmatthews marked this conversation as resolved.
Show resolved Hide resolved
note=(
f"Circuit ID {circuit.circuit_id} referenced was not found in the database, so omitted from the "
"maintenance."
),
level="WARNING",
)
if created:
job.logger.warning(
Expand Down Expand Up @@ -146,13 +145,12 @@ def update_circuit_maintenance(
)
else:
note_entry, created = Note.objects.get_or_create(
maintenance=circuit_maintenance_entry,
title=f"Nonexistent circuit ID {circuit.circuit_id}"[:MAX_NOTE_TITLE_LENGTH],
comment=(
assigned_object_id=circuit_maintenance_entry.id,
assigned_object_type=ContentType.objects.get_for_model(CircuitMaintenance),
note=(
f"Circuit ID {circuit.circuit_id} referenced was not found in the database, so omitted from the "
"maintenance."
),
level="WARNING",
)
if created:
job.logger.warning(
Expand Down
41 changes: 41 additions & 0 deletions nautobot_circuit_maintenance/migrations/0014_migrate_notes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Generated by Django 4.2.16 on 2024-09-13 08:49

from django.db import migrations


def move_data_to_new_model(apps, schema_editor):
CircuitMaintenance = apps.get_model("nautobot_circuit_maintenance", "CircuitMaintenance")
ContentType = apps.get_model("contenttypes", "ContentType")
OldModel = apps.get_model("nautobot_circuit_maintenance", "Note")
NewModel = apps.get_model("extras", "Note")

for old_obj in OldModel.objects.all():
NewModel.objects.create(
note=f"### {old_obj.title}\n\n{old_obj.comment}",
assigned_object_type=ContentType.objects.get_for_model(CircuitMaintenance),
assigned_object_id=old_obj.maintenance.id,
user_name="migration",
)


def reverse_move_data(apps, schema_editor):
OldModel = apps.get_model("nautobot_circuit_maintenance", "Note")
NewModel = apps.get_model("extras", "Note")

for new_obj in NewModel.objects.all():
OldModel.objects.create(
title=new_obj.note[:20], # truncate to 20
content=new_obj.note,
maintenance=new_obj.assigned_object,
)


class Migration(migrations.Migration):
dependencies = [
("nautobot_circuit_maintenance", "0013_rename_site_search_job"),
glennmatthews marked this conversation as resolved.
Show resolved Hide resolved
("extras", "0043_note"),
]

operations = [
migrations.RunPython(move_data_to_new_model, reverse_move_data),
]
15 changes: 15 additions & 0 deletions nautobot_circuit_maintenance/migrations/0015_delete_note.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Generated by Django 4.2.16 on 2024-09-13 08:49

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("nautobot_circuit_maintenance", "0014_migrate_notes"),
]

operations = [
migrations.DeleteModel(
name="Note",
),
]
37 changes: 1 addition & 36 deletions nautobot_circuit_maintenance/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from nautobot.core.models.generics import OrganizationalModel, PrimaryModel
from nautobot.extras.utils import extras_features

from .choices import CircuitImpactChoices, CircuitMaintenanceStatusChoices, NoteLevelChoices
from .choices import CircuitImpactChoices, CircuitMaintenanceStatusChoices

logger = logging.getLogger(__name__)

Expand All @@ -24,7 +24,6 @@
MAX_NOTIFICATION_SENDER_LENGTH = 200
MAX_NOTIFICATION_SUBJECT_LENGTH = 200
MAX_NOTIFICATION_TOTAL_LENGTH = 16384
MAX_NOTE_TITLE_LENGTH = 200


@extras_features(
Expand Down Expand Up @@ -119,40 +118,6 @@ def get_absolute_url(self, api=False):
return reverse("plugins:nautobot_circuit_maintenance:circuitimpact", args=[self.pk])


@extras_features(
"custom_fields",
"custom_links",
"custom_validators",
"export_templates",
"relationships",
"webhooks",
)
class Note(OrganizationalModel):
"""Model for maintenance notes."""

maintenance = models.ForeignKey(CircuitMaintenance, on_delete=models.CASCADE, default=None)
title = models.CharField(max_length=MAX_NOTE_TITLE_LENGTH)
level = models.CharField(
default=NoteLevelChoices.INFO,
max_length=50,
choices=NoteLevelChoices,
)
comment = models.TextField()

class Meta: # noqa: D106 "Missing docstring in public nested class"
ordering = ["last_updated"]
unique_together = ["maintenance", "title"]

def __str__(self):
"""String value for HTML rendering."""
# str(self) is used in change logging, and ObjectChange.object_repr field is limited to 200 characters.
return f"{self.title}"[:200]

def get_absolute_url(self, api=False):
"""Returns reverse loop up URL."""
return reverse("plugins:nautobot_circuit_maintenance:note", args=[self.pk])


@extras_features(
"custom_fields",
"custom_links",
Expand Down
16 changes: 1 addition & 15 deletions nautobot_circuit_maintenance/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import django_tables2 as tables
from nautobot.core.tables import BaseTable, ToggleColumn

from .models import CircuitImpact, CircuitMaintenance, Note, NotificationSource, RawNotification
from .models import CircuitImpact, CircuitMaintenance, NotificationSource, RawNotification


class CircuitMaintenanceTable(BaseTable):
Expand Down Expand Up @@ -70,20 +70,6 @@ class Meta(BaseTable.Meta):
fields = ("pk", "maintenance", "circuit", "impact") # pylint:disable=nb-use-fields-all


class NoteTable(BaseTable):
"""Table to display Note model."""

pk = ToggleColumn()
maintenance = tables.Column(linkify=True)
title = tables.Column(linkify=True)

class Meta(BaseTable.Meta):
"""Meta for class NoteTable."""

model = Note
fields = ("pk", "maintenance", "title", "level", "comment", "last_updated") # pylint:disable=nb-use-fields-all


class NotificationSourceTable(BaseTable):
"""Table to display Circuit Impact model."""

Expand Down
Loading