Skip to content

Conversation

@johannaengland
Copy link
Contributor

@johannaengland johannaengland commented Oct 1, 2025

Scope and purpose

Fixes #2927.

This is very inspired by

@transaction.atomic()
def edit(request, task_id=None, start_time=None, **_):
account = get_account(request)
components = task = None
component_keys_errors = []
component_keys = {}
if task_id:
task = get_object_or_404(MaintenanceTask, pk=task_id)
task_form = MaintenanceTaskForm(initial=task_form_initial(task, start_time))
if request.method == 'POST':
component_keys, component_keys_errors = get_component_keys(request.POST)
elif task:
components = get_components(task)
else:
component_keys, component_keys_errors = get_component_keys(request.GET)
if component_keys:
components, component_data_errors = get_components_from_keydict(component_keys)
for error in component_data_errors:
new_message(request, error, Messages.ERROR)
component_trail = [component_to_trail(c) for c in components]
for error in component_keys_errors:
new_message(request, error, Messages.ERROR)
if request.method == 'POST':
if 'save' in request.POST:
task_form = MaintenanceTaskForm(request.POST)
if component_keys and not components:
new_message(request, "No components selected.", Messages.ERROR)
elif not component_keys_errors and task_form.is_valid():
start_time = task_form.cleaned_data['start_time']
end_time = task_form.cleaned_data['end_time']
no_end_time = task_form.cleaned_data['no_end_time']
state = MaintenanceTask.STATE_SCHEDULED
if (
start_time < datetime.now()
and end_time
and end_time <= datetime.now()
):
state = MaintenanceTask.STATE_SCHEDULED
new_task = MaintenanceTask()
new_task.start_time = task_form.cleaned_data['start_time']
if no_end_time:
new_task.end_time = INFINITY
elif not no_end_time and end_time:
new_task.end_time = task_form.cleaned_data['end_time']
new_task.description = task_form.cleaned_data['description']
new_task.state = state
new_task.author = account.login
if task:
new_task.id = task.id
new_task.save()
if task:
cursor = connection.cursor()
sql = """DELETE FROM maint_component
WHERE maint_taskid = %s"""
cursor.execute(sql, (new_task.id,))
for component in components:
table = component._meta.db_table
descr = (
str(component) if table in COMPONENTS_WITH_INTEGER_PK else None
)
task_component = MaintenanceComponent(
maintenance_task=new_task,
key=table,
value=component.pk,
description=descr,
)
task_component.save()
new_message(
request, "Saved task %s" % new_task.description, Messages.SUCCESS
)
return HttpResponseRedirect(
reverse('maintenance-view', args=[new_task.id])
)
else:
task_form = MaintenanceTaskForm(initial=request.POST)
, there is a lot of cleanup that would be nice in the maintenance code, but that's a whole new can of worms.

This pull request

  • add an endpoint maintenance to the API

Contributor Checklist

Every pull request should have this checklist filled out, no matter how small it is.
More information about contributing to NAV can be found in the
Hacker's guide to NAV.

  • Added a changelog fragment for towncrier
  • Added/amended tests for new/changed code
  • Added/changed documentation
  • Linted/formatted the code with ruff, easiest by using pre-commit
  • Wrote the commit message so that the first line continues the sentence "If applied, this commit will ...", starts with a capital letter, does not end with punctuation and is 50 characters or less long. See https://cbea.ms/git-commit/
  • Based this pull request on the correct upstream branch: For a patch/bugfix affecting the latest stable version, it should be based on that version's branch (<major>.<minor>.x). For a new feature or other additions, it should be based on master.
  • If applicable: Created new issues if this PR does not fix the issue completely/there is further work to be done
  • If it's not obvious from a linked issue, described how to interact with NAV in order for a reviewer to observe the effects of this change first-hand (commands, URLs, UI interactions)
  • If this results in changes in the UI: Added screenshots of the before and after
  • If this adds a new Python source code file: Added the boilerplate header to that file

@johannaengland johannaengland requested a review from a team October 1, 2025 09:26
@johannaengland johannaengland self-assigned this Oct 1, 2025
@codecov
Copy link

codecov bot commented Oct 1, 2025

Codecov Report

❌ Patch coverage is 77.02703% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 62.15%. Comparing base (5adb5d3) to head (6262dd0).

Files with missing lines Patch % Lines
python/nav/web/api/v1/views.py 75.00% 17 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3570      +/-   ##
==========================================
+ Coverage   62.11%   62.15%   +0.03%     
==========================================
  Files         611      611              
  Lines       44880    44938      +58     
  Branches       43       43              
==========================================
+ Hits        27876    27930      +54     
- Misses      16994    16998       +4     
  Partials       10       10              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@johannaengland johannaengland force-pushed the feature/maintenance-api branch from 6a38056 to 6262dd0 Compare October 1, 2025 10:09
@sonarqubecloud
Copy link

sonarqubecloud bot commented Oct 1, 2025

Quality Gate Passed Quality Gate passed

Issues
0 New issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarQube Cloud

Copy link
Member

@lunkwill42 lunkwill42 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not going to delve too deeply into this quite yet. Suffice to say that if we are implementing a new endpoint for the MaintenanceTask model, it should be feature-complete: I.e. it should support GET for fetching existing tasks (both lists of tasks and individual tasks by id), POST for making new ones, and PATCH for modifying existing ones.

Comment on lines +1422 to +1447
Example POST request:
`/api/1/maintenance/` with body
`{
"start_time": "2025-09-29T11:11:11",
"end_time": "2025-09-29T13:11:11",
"no_end_time": false,
"description": "Changing out old equipment in serverroom",
"location": [1, 2],
"room": ["myroom", "secondroom"],
"netbox": [1, 2],
"service": [1, 2],
"netboxgroup": [1, 2]
}`
Example POST response:
`{
"id": 59,
"maintenance_components": "[<Netbox: buick.lab.uninett.no>,
<Netbox: oldsmobile.lab.uninett.no>]",
"start_time": "2025-10-01T09:17:00",
"end_time": "9999-12-31T23:59:59.999999",
"description": "Changing out old equipment in serverroom",
"author": "admin",
"state": "scheduled"
}`
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The POST body and the response body should preferably be symmetric when dealing with model API calls. These are definitely not symmetric (e.g. I can't take the response body, remove the id attribute and post it again as new record).

@johannaengland
Copy link
Contributor Author

I'm not going to delve too deeply into this quite yet. Suffice to say that if we are implementing a new endpoint for the MaintenanceTask model, it should be feature-complete: I.e. it should support GET for fetching existing tasks (both lists of tasks and individual tasks by id), POST for making new ones, and PATCH for modifying existing ones.

I was just following the spec of the issue :D
In that case I would say this issue will take much more time, because then a refactoring of the whole maintenance system might be necessary to not have to adapt our code strangely to the existing utils methods

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

API endpoints for maintenance

2 participants