Skip to content

Commit

Permalink
Merge pull request #25 from jasonyates/calendar
Browse files Browse the repository at this point in the history
Adding maintenance calendar
  • Loading branch information
jasonyates authored Sep 19, 2024
2 parents 70e2e8a + c7bfa32 commit ccb956d
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 14 deletions.
6 changes: 3 additions & 3 deletions netbox_circuitmaintenance/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ class CircuitMaintenanceTypeChoices(ChoiceSet):
CHOICES = [
('TENTATIVE', 'Tentative', 'yellow'),
('CONFIRMED', 'Confirmed', 'green'),
('CANCELLED', 'Cancelled', 'gray'),
('IN-PROCESS', 'In-Process', 'orange'),
('CANCELLED', 'Cancelled', 'blue'),
('IN-PROCESS', 'In-Progress', 'orange'),
('COMPLETED', 'Completed', 'indigo'),
('RE-SCHEDULED', 'Rescheduled', 'green'),
('UNKNOWN', 'Unknown', 'gray'),
('UNKNOWN', 'Unknown', 'blue'),
]

class CircuitMaintenanceImpactTypeChoices(ChoiceSet):
Expand Down
8 changes: 4 additions & 4 deletions netbox_circuitmaintenance/navigation.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
)
]
),
#PluginMenuItem(
# link='plugins:netbox_circuitmaintenance:maintenanceschedule',
# link_text='Maintenance Schedule',
#),
PluginMenuItem(
link='plugins:netbox_circuitmaintenance:maintenanceschedule',
link_text='Maintenance Schedule',
),
]

menu = PluginMenu(
Expand Down
6 changes: 3 additions & 3 deletions netbox_circuitmaintenance/template_content.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class CircuitMaintenanceList(PluginTemplateExtension):
def left_page(self):

return self.render('netbox_circuitmaintenance/circuitmaintenance_include.html', extra_context={
'circuitmaintenance': CircuitMaintenanceImpact.objects.filter(circuit__cid=self.context['object'].cid, circuitmaintenance__status__in=['TENTATIVE', 'CONFIRMED', 'IN-PROCESS', 'RESCHEDULED', 'UNKNOWN']),
'circuitmaintenance': CircuitMaintenanceImpact.objects.filter(circuit__cid=self.context['object'].cid, circuitmaintenance__status__in=['TENTATIVE', 'CONFIRMED', 'IN-PROCESS', 'RE-SCHEDULED', 'UNKNOWN']),
})

class ProviderMaintenanceList(PluginTemplateExtension):
Expand All @@ -17,7 +17,7 @@ class ProviderMaintenanceList(PluginTemplateExtension):
def left_page(self):

return self.render('netbox_circuitmaintenance/providermaintenance_include.html', extra_context={
'circuitmaintenance': CircuitMaintenanceImpact.objects.filter(circuitmaintenance__provider=self.context['object'], circuitmaintenance__status__in=['TENTATIVE', 'CONFIRMED', 'IN-PROCESS', 'RESCHEDULED', 'UNKNOWN']),
'circuitmaintenance': CircuitMaintenanceImpact.objects.filter(circuitmaintenance__provider=self.context['object'], circuitmaintenance__status__in=['TENTATIVE', 'CONFIRMED', 'IN-PROCESS', 'RE-SCHEDULED', 'UNKNOWN']),
})

class SiteMaintenanceList(PluginTemplateExtension):
Expand All @@ -26,7 +26,7 @@ class SiteMaintenanceList(PluginTemplateExtension):
def left_page(self):

return self.render('netbox_circuitmaintenance/providermaintenance_include.html', extra_context={
'circuitmaintenance': CircuitMaintenanceImpact.objects.filter(Q(circuit__termination_a__site=self.context['object']) | Q(circuit__termination_z__site=self.context['object']), circuitmaintenance__status__in=['TENTATIVE', 'CONFIRMED', 'IN-PROCESS', 'RESCHEDULED', 'UNKNOWN']),
'circuitmaintenance': CircuitMaintenanceImpact.objects.filter(Q(circuit__termination_a__site=self.context['object']) | Q(circuit__termination_z__site=self.context['object']), circuitmaintenance__status__in=['TENTATIVE', 'CONFIRMED', 'IN-PROCESS', 'RE-SCHEDULED', 'UNKNOWN']),
})


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{% extends 'generic/_base.html' %}
{% load buttons %}
{% load render_table from django_tables2 %}
{% load static %}
{% load perms %}
{% load helpers %}

{% block title %}Circuit Maintenance Schedule{% endblock %}

{% block controls %}
<div class="controls">
<div class="control-group">
<a id="btnPrevMonth" class="btn btn-info" href="{{basepath}}?month={{prev_month}}&year={{prev_year}}">
<i class="mdi mdi-arrow-left"></i>
Previous Month
</a>
{% if month != this_month or year != this_year%}
<a id="btnPrevMonth" class="btn btn-info" href="{{basepath}}?month={{this_month}}&year={{this_year}}">
Today
</a>
{% endif %}
<a id="btnNextMonth" class="btn btn-info" href="{{basepath}}?month={{next_month}}&year={{next_year}}">
<i class="mdi mdi-arrow-right"></i>
Next Month
</a>
</div>
</div>
{% endblock controls %}

{% block content %}
{{ calendar }}
{% endblock content %}

{% block javascript %}

{% endblock javascript %}
3 changes: 2 additions & 1 deletion netbox_circuitmaintenance/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

path('circuitmaintenance/<int:pk>/', views.CircuitMaintenanceView.as_view(), name='circuitmaintenance'),
path('circuitnotification/<int:pk>/', views.CircuitMaintenanceNotificationView.as_view(), name='circuitnotification'),
path('maintenanceschedule/', views.CircuitMaintenanceScheduleView.as_view(), name='maintenanceschedule'),

path('circuitmaintenance/<int:pk>/edit/', views.CircuitMaintenanceEditView.as_view(), name='circuitmaintenance_edit'),
path('circuitimpact/<int:pk>/edit/', views.CircuitMaintenanceImpactEditView.as_view(), name='circuitimpact_edit'),
Expand All @@ -31,5 +30,7 @@
'model': models.CircuitMaintenanceImpact
}),

path('maintenanceschedule/', views.CircuitMaintenanceScheduleView.as_view(), name='maintenanceschedule'),


)
145 changes: 143 additions & 2 deletions netbox_circuitmaintenance/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
from netbox.views import generic
from django.db.models import Count
from . import forms, models, tables, filtersets
from django.views.generic import View
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.shortcuts import render
import datetime
import calendar
from django.utils.safestring import mark_safe
from django.db.models import Q
from django.conf import settings

# Circuit Maintenance Views
class CircuitMaintenanceView(generic.ObjectView):
Expand Down Expand Up @@ -55,6 +63,139 @@ class CircuitMaintenanceNotificationsDeleteView(generic.ObjectDeleteView):
class CircuitMaintenanceNotificationView(generic.ObjectView):
queryset = models.CircuitMaintenanceNotifications.objects.all()


class Calendar(calendar.HTMLCalendar):
def __init__(self, year=None, month=None):
self.year = year
self.month = month
super(Calendar, self).__init__()

def suffix(self, day):
if 4 <= day <= 20 or 24 <= day <= 30:
return "th"
else:
return ["st", "nd", "rd"][day % 10 - 1]

def custom_strftime(self, format, t):
return t.strftime(format).replace('SU', str(t.day) + self.suffix(t.day))

def formatmonthname(self, theyear, themonth) :
return f"<h1>{calendar.month_name[themonth]} {theyear}</h1>"

def prev_month(self,month):
if month == 1:
return 12
else:
return month-1

def next_month(self, month):
if month == 12:
return 1
else:
return month+1

def prev_year(self, month, year):
if month == 1:
return year-1
elif month == 12:
return year+1
else:
return year

def next_year(self, month, year):
if month == 1:
return year-1
elif month == 12:
return year+1
else:
return year

def formatday(self, day, weekday, events):
"""
Return a day as a table cell.
"""
events_from_day = events.filter(Q(start__day=day) | Q(end__day=day))
events_html = "<ul>"
for event in events_from_day:
if events_html != '<ul>':
events_html += '<br><br>'

# Format time of the event
if self.custom_strftime('SU', event.start) == self.custom_strftime('SU', event.end):
event_time = f'{self.custom_strftime('%H:%M', event.start)} - {self.custom_strftime('%H:%M', event.end)}'
else:
event_time = f'{self.custom_strftime('SU %H:%M', event.start)} - {self.custom_strftime('SU %H:%M', event.end)}'

# Add the event to the day
events_html += f'<span class="badge text-bg-{event.get_status_color()}"><a href="{event.get_absolute_url()}">{event_time}<br>{event.name} <br>{event.provider} - {event.status}<br>{event.impact_count} Impacted</a></span>'
events_html += "</ul>"

if day == 0:
return '<td>&nbsp;</td>'
else:
return '<td class="%s"><strong>%d</strong>%s</td>' % (self.cssclasses[weekday], day, events_html)

def formatweek(self, theweek, events):
"""
Return a complete week as a table row.
"""
week = ''.join(self.formatday(d, wd, events) for (d, wd) in theweek)
return '<tr>%s</tr>' % week

def formatmonth(self, theyear, themonth):
events = models.CircuitMaintenance.objects.filter(Q(start__month=themonth) | Q(end__month=themonth)).annotate(impact_count=Count('impact'))
v = []
a = v.append
a('<table class="table">')
a('\n')
a(self.formatmonthname(theyear, themonth))
a('\n')
a(self.formatweekheader())
a('\n')
for week in self.monthdays2calendar(theyear, themonth):
a(self.formatweek(week, events))
a('\n')
a('</table>')
a('\n')
return ''.join(v)


# CircuitMaintenanceSchedule
class CircuitMaintenanceScheduleView(generic.ObjectView):
queryset = models.CircuitMaintenance.objects.all()
class CircuitMaintenanceScheduleView(View):
template_name = 'netbox_circuitmaintenance/calendar.html'


def get(self, request):

curr_month = datetime.date.today()

# Check if we have a month and year in the URL
if request.GET and 'month' in request.GET:
month = int(request.GET["month"])
year = int(request.GET["year"])

else:
month = curr_month.month
year = curr_month.year

# Load calendar
cal = Calendar()
html_calendar = cal.formatmonth(year, month)
html_calendar = html_calendar.replace('<td ', '<td width="300" height="150"')

return render(
request,
self.template_name,
{
"calendar": mark_safe(html_calendar),
"this_month": curr_month.month,
"this_year": curr_month.year,
"month": month,
"year": year,
"next_month": cal.next_month(month),
"next_year": cal.next_year(month, year),
"prev_month": cal.prev_month(month),
"prev_year": cal.prev_year(month, year),
"basepath": settings.BASE_PATH,
}
)
2 changes: 1 addition & 1 deletion netbox_circuitmaintenance/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class ReminderWidget(DashboardWidget):
def render(self, request):

return render_to_string(self.template_name, {
'circuitmaintenance': CircuitMaintenance.objects.filter(status__in=['TENTATIVE', 'CONFIRMED', 'IN-PROCESS', 'RESCHEDULED', 'UNKNOWN']).annotate(
'circuitmaintenance': CircuitMaintenance.objects.filter(status__in=['TENTATIVE', 'CONFIRMED', 'IN-PROCESS', 'RE-SCHEDULED', 'UNKNOWN']).annotate(
impact_count=Count('impact')
),
})

0 comments on commit ccb956d

Please sign in to comment.