Skip to content

Commit

Permalink
Merge branch '5.4.x' into 5.5.x
Browse files Browse the repository at this point in the history
  • Loading branch information
lunkwill42 committed Nov 22, 2022
2 parents 34c78b1 + 5de9a3d commit fa5425a
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 42 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
This changelog format was introduced in NAV 5.4.0. Older changelogs can be
found in the [HISTORY](HISTORY) file.

## [Unreleased]

## Fixed

- Merge two fixes from the 5.4.x stable series that never actually made it into the 5.5 series:
- Metric values of 0.0 are evaluated correctly by threshold rules [#2447](https://github.com/Uninett/nav/issues/2447)
- Validate maintenance calendar input form to avoid e-mail spam from bots scanning for vulnerabilities [#2420](https://github.com/Uninett/nav/issues/2420)


## [5.5.2] - 2022-11-10

### Fixed
Expand Down
62 changes: 61 additions & 1 deletion python/nav/web/maintenance/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
# details. You should have received a copy of the GNU General Public License
# along with NAV. If not, see <http://www.gnu.org/licenses/>.
#
from datetime import date

from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms_foundation.layout import Layout, Row, Column, Field

from nav.models.fields import INFINITY


Expand Down Expand Up @@ -72,3 +72,63 @@ class MaintenanceAddSingleNetbox(forms.Form):
a custom variable-checker"""

netboxid = forms.IntegerField(required=True)


def _get_current_year():
return date.today().year


def _get_current_month():
return date.today().month


class MaintenanceCalendarForm(forms.Form):
"""A form used for displaying a maintenance calendar"""

year = forms.IntegerField(
initial=_get_current_year, required=True, min_value=2000, max_value=2100
)
month = forms.IntegerField(
initial=_get_current_month, required=True, min_value=1, max_value=12
)

@property
def cleaned_year(self):
"""Returns the cleaned year value if valid, current year otherwise"""
return self.cleaned_data['year'] if self.is_valid() else _get_current_year()

@property
def cleaned_month(self):
"""Returns the cleaned month if valid, current month otherwise"""
return self.cleaned_data['month'] if self.is_valid() else _get_current_month()

@property
def this_month_start(self):
"""Returns the first date of the month represented by this form instance"""
return date(self.cleaned_year, self.cleaned_month, 1)

@property
def next_month_start(self):
"""Returns the first date of the month after the one represented by this form
instance
"""
year = self.cleaned_year
month = self.cleaned_month + 1

if month > 12:
year += 1
month = 1
return date(year, month, 1)

@property
def previous_month_start(self):
"""Returns the first date of the month before the one represented by this form
instance
"""
year = self.cleaned_year
month = self.cleaned_month - 1

if month < 1:
year -= 1
month = 12
return date(year, month, 1)
55 changes: 20 additions & 35 deletions python/nav/web/maintenance/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
from nav.web.maintenance.utils import structure_component_data
from nav.web.maintenance.utils import task_form_initial, infodict_by_state
from nav.web.maintenance.utils import MaintenanceCalendar, NAVPATH, TITLE
from nav.web.maintenance.forms import MaintenanceTaskForm
from nav.web.maintenance.forms import MaintenanceTaskForm, MaintenanceCalendarForm
from nav.web.maintenance.forms import MaintenanceAddSingleNetbox
import nav.maintengine

Expand All @@ -55,56 +55,41 @@ def redirect_to_calendar(_request):
def calendar(request, year=None, month=None):
# If the form was used to get here, redirect to the appropriate page
if "year" in request.GET and "month" in request.GET:
return redirect(
"maintenance-calendar",
year=request.GET.get("year"),
month=request.GET.get("month"),
form = MaintenanceCalendarForm(data=request.GET.dict())
if form.is_valid():
return redirect(
"maintenance-calendar",
year=request.GET.get("year"),
month=request.GET.get("month"),
)
elif year and month:
form = MaintenanceCalendarForm(
data={'year': year, 'month': month},
)
else:
form = MaintenanceCalendarForm()

heading = "Maintenance schedule"
try:
year = int(year)
month = int(month)
this_month_start = date(year, month, 1)
except (TypeError, ValueError):
year = date.today().year
month = date.today().month
this_month_start = date(year, month, 1)

next_month = month + 1
next_year = year
if next_month > 12:
next_year = year + 1
next_month = 1

prev_month = month - 1
prev_year = year
if prev_month < 1:
prev_year = year - 1
prev_month = 12

prev_month_start = date(prev_year, prev_month, 1)
next_month_start = date(next_year, next_month, 1)
tasks = (
MaintenanceTask.objects.filter(
start_time__lt=next_month_start, end_time__gt=this_month_start
start_time__lt=form.next_month_start, end_time__gt=form.this_month_start
)
.exclude(state=MaintenanceTask.STATE_CANCELED)
.order_by('start_time')
)
cal = MaintenanceCalendar(tasks).formatmonth(year, month)
cal = MaintenanceCalendar(tasks).formatmonth(form.cleaned_year, form.cleaned_month)
return render(
request,
'maintenance/calendar.html',
{
'active': {'calendar': True},
'calendarform': form,
'navpath': NAVPATH,
'title': TITLE,
'heading': heading,
'heading': "Maintenance schedule",
'calendar': mark_safe(cal),
'prev_month': prev_month_start,
'this_month': this_month_start,
'next_month': next_month_start,
'prev_month': form.previous_month_start,
'this_month': form.this_month_start,
'next_month': form.next_month_start,
'curr_month': datetime.today(),
},
)
Expand Down
24 changes: 18 additions & 6 deletions python/nav/web/templates/maintenance/calendar.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,18 @@
</a>

<form action="{% url 'maintenance-calendar' %}" method="get" class="inline-form">
<input type="text" name="year" value="{{ this_month.year }}" size="4" maxlength="4"/>
<input type="text" name="month" value="{{ this_month.month }}" size="2" maxlength="2"/>
<input type="number" name="year"
value="{{ calendarform.year.value }}"
min="{{ calendarform.year.field.min_value }}"
max="{{ calendarform.year.field.max_value }}"
required
id="id_year"/>
<input type="number" name="month"
value="{{ calendarform.month.value }}"
min="{{ calendarform.month.field.min_value }}"
max="{{ calendarform.month.field.max_value }}"
required
id="id_month"/>
<button type="submit" class="small secondary"><i class="fa fa-search"></i></button>
</form>

Expand All @@ -26,9 +36,11 @@
<i class="fa fa-step-forward fa-lg" title="Next month"></i>
</a>
</div>

{{ calendar }}
{% if calendarform.errors %}
{{ calendarform.errors }}
{% else %}
{{ calendar }}
{% endif %}
</div>

{% endblock %}

{% endblock %}
Empty file.
25 changes: 25 additions & 0 deletions tests/integration/web/maintenance/views_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#
# Copyright (C) 2022 Sikt
#
# This file is part of Network Administration Visualized (NAV).
#
# NAV is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License version 3 as published by
# the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details. You should have received a copy of the GNU General Public
# License along with NAV. If not, see <http://www.gnu.org/licenses/>.
#


class TestMaintenanceCalendarView:
def test_calendar_renders_when_no_arguments_given(self, client):
response = client.get('/maintenance/', follow=True)
assert response.status_code == 200

def test_calendar_still_renders_when_invalid_arguments_given(self, client):
response = client.get('/maintenance/?year=invalid&month=invalid', follow=True)
assert response.status_code == 200
Empty file.
64 changes: 64 additions & 0 deletions tests/unittests/web/maintenance/forms_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#
# Copyright (C) 2022 Sikt
#
# This file is part of Network Administration Visualized (NAV).
#
# NAV is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License version 3 as published by
# the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details. You should have received a copy of the GNU General Public
# License along with NAV. If not, see <http://www.gnu.org/licenses/>.
#
from datetime import date

import pytest

from nav.web.maintenance.forms import MaintenanceCalendarForm


class TestMaintenanceCalendarForm:
def test_cleaned_year_returns_integer(self, valid_form):
assert valid_form.cleaned_year == 2022

def test_cleaned_month_returns_integer(self, valid_form):
assert valid_form.cleaned_month == 7

def test_this_month_start_returns_the_first_day_of_the_month(self, valid_form):
assert valid_form.this_month_start == date(2022, 7, 1)

def test_next_month_start_returns_the_first_day_of_the_next_month(self, valid_form):
assert valid_form.next_month_start == date(2022, 8, 1)

def test_previous_month_start_returns_the_first_day_of_the_previous_month(
self, valid_form
):
assert valid_form.previous_month_start == date(2022, 6, 1)

def test_when_month_is_december_next_month_start_returns_january(
self, december_form
):
assert december_form.next_month_start == date(2023, 1, 1)

def test_when_month_is_january_previous_month_start_returns_december(
self, january_form
):
assert january_form.previous_month_start == date(2021, 12, 1)


@pytest.fixture
def valid_form() -> MaintenanceCalendarForm:
return MaintenanceCalendarForm(data={'year': '2022', 'month': '7'})


@pytest.fixture
def december_form() -> MaintenanceCalendarForm:
return MaintenanceCalendarForm(data={'year': '2022', 'month': '12'})


@pytest.fixture
def january_form() -> MaintenanceCalendarForm:
return MaintenanceCalendarForm(data={'year': '2022', 'month': '1'})

0 comments on commit fa5425a

Please sign in to comment.