From 7adfc6d34de3415183a99a87473e09ac3c2f9fe4 Mon Sep 17 00:00:00 2001 From: AnsibleGuy Date: Sun, 11 Feb 2024 00:37:55 +0100 Subject: [PATCH] refactoring job-manage view => ajax --- src/ansible-webui/aw/api_endpoints/base.py | 11 ++ src/ansible-webui/aw/api_endpoints/job.py | 7 -- .../aw/api_endpoints/job_util.py | 13 ++- .../aw/api_endpoints/permission.py | 26 +++-- src/ansible-webui/aw/model/job.py | 3 +- src/ansible-webui/aw/static/js/aw.js | 35 +++++- src/ansible-webui/aw/static/js/jobs/logs.js | 5 +- src/ansible-webui/aw/static/js/jobs/manage.js | 110 ++++++++++++++++++ .../aw/static/js/settings/api_key.js | 4 +- .../aw/static/js/settings/permission.js | 18 +-- src/ansible-webui/aw/templates/jobs/logs.html | 2 - .../aw/templates/jobs/manage.html | 53 ++++++--- .../aw/templates/jobs/manage_job.html | 54 --------- .../templates/jobs/manage_job_executions.html | 1 - src/ansible-webui/aw/templatetags/job_util.py | 106 ----------------- src/ansible-webui/aw/views/settings.py | 52 +++++---- src/ansible-webui/aw/views/system.py | 2 +- src/ansible-webui/db.py | 1 - 18 files changed, 259 insertions(+), 244 deletions(-) create mode 100644 src/ansible-webui/aw/static/js/jobs/manage.js delete mode 100644 src/ansible-webui/aw/templates/jobs/manage_job.html delete mode 100644 src/ansible-webui/aw/templatetags/job_util.py diff --git a/src/ansible-webui/aw/api_endpoints/base.py b/src/ansible-webui/aw/api_endpoints/base.py index 747d60e..5ac92de 100644 --- a/src/ansible-webui/aw/api_endpoints/base.py +++ b/src/ansible-webui/aw/api_endpoints/base.py @@ -1,6 +1,7 @@ from django.conf import settings from django.contrib.auth.models import AnonymousUser from django.core.exceptions import ObjectDoesNotExist +from django.contrib.auth.models import User, Group from rest_framework import serializers from rest_framework.permissions import IsAuthenticated from rest_framework_api_key.permissions import BaseHasAPIKey @@ -40,3 +41,13 @@ def update(self, instance, validated_data): class GenericResponse(BaseResponse): msg = serializers.CharField() + + +class GroupSerializer(serializers.ModelSerializer): + class Meta: + model = Group + + +class UserSerializer(serializers.ModelSerializer): + class Meta: + model = User diff --git a/src/ansible-webui/aw/api_endpoints/job.py b/src/ansible-webui/aw/api_endpoints/job.py index 7bff078..3e4f344 100644 --- a/src/ansible-webui/aw/api_endpoints/job.py +++ b/src/ansible-webui/aw/api_endpoints/job.py @@ -446,7 +446,6 @@ class APIJobExecution(APIView): request=None, responses={ 200: OpenApiResponse(JobExecutionReadResponse, description='Return job-execution information'), - 404: OpenApiResponse(JobExecutionReadResponse, description='No viewable jobs or executions found'), }, summary='Return list of job-executions the current user is privileged to view.', operation_id='job_exec_list', @@ -461,9 +460,6 @@ class APIJobExecution(APIView): def get(self, request): # pylint: disable=E1101 jobs = get_viewable_jobs(get_api_user(request)) - if len(jobs) == 0: - return Response(data={'msg': 'No viewable jobs found'}, status=404) - exec_count = _job_execution_count(request) if exec_count is None: exec_count = JOB_EXECUTION_LIMIT @@ -472,7 +468,4 @@ def get(self, request): for execution in JobExecution.objects.filter(job__in=jobs).order_by('updated')[:exec_count]: serialized.append(get_job_execution_serialized(execution)) - if len(serialized) == 0: - return Response(data={'msg': 'No viewable job-executions found'}, status=404) - return Response(data=serialized, status=200) diff --git a/src/ansible-webui/aw/api_endpoints/job_util.py b/src/ansible-webui/aw/api_endpoints/job_util.py index df96ae7..442e01b 100644 --- a/src/ansible-webui/aw/api_endpoints/job_util.py +++ b/src/ansible-webui/aw/api_endpoints/job_util.py @@ -4,7 +4,7 @@ from aw.config.hardcoded import SHORT_TIME_FORMAT, JOB_EXECUTION_LIMIT from aw.model.job import Job, CHOICES_JOB_EXEC_STATUS, JobExecution from aw.utils.permission import get_viewable_jobs -from aw.utils.util import datetime_from_db +from aw.utils.util import datetime_from_db, get_next_cron_execution_str class JobReadResponse(serializers.ModelSerializer): @@ -12,6 +12,8 @@ class Meta: model = Job fields = Job.api_fields_read + next_run = serializers.CharField(required=False) + class JobExecutionReadResponse(serializers.ModelSerializer): class Meta: @@ -40,7 +42,7 @@ def get_job_execution_serialized(execution: JobExecution) -> dict: 'job': execution.job.id, 'job_name': execution.job.name, 'job_comment': execution.job.comment, - 'user': execution.user.id, + 'user': execution.user.id if execution.user is not None else None, 'user_name': execution.user.username if execution.user is not None else 'Scheduled', 'status': execution.status, 'status_name': CHOICES_JOB_EXEC_STATUS[execution.status][1], @@ -81,6 +83,13 @@ def get_viewable_jobs_serialized( for job in get_viewable_jobs(user): job_serialized = JobReadResponse(instance=job).data + + try: + job_serialized['next_run'] = get_next_cron_execution_str(job.schedule) + + except ValueError: + job_serialized['next_run'] = None + if executions: job_serialized['executions'] = get_job_executions_serialized(job=job, execution_count=execution_count) diff --git a/src/ansible-webui/aw/api_endpoints/permission.py b/src/ansible-webui/aw/api_endpoints/permission.py index bae21c8..3e24ff0 100644 --- a/src/ansible-webui/aw/api_endpoints/permission.py +++ b/src/ansible-webui/aw/api_endpoints/permission.py @@ -27,23 +27,25 @@ class Meta: jobs_name = serializers.ListSerializer(child=serializers.CharField(), required=False) +class JobSerializer(serializers.ModelSerializer): + class Meta: + model = Job + + class PermissionWriteRequest(serializers.ModelSerializer): class Meta: model = JobPermission fields = JobPermission.api_fields_write - jobs = serializers.MultipleChoiceField( - choices=[job.id for job in Job.objects.all()], - allow_blank=True, - ) - users = serializers.MultipleChoiceField( - choices=[user.id for user in User.objects.all()], - allow_blank=True, - ) - groups = serializers.MultipleChoiceField( - choices=[group.id for group in Group.objects.all()], - allow_blank=True, - ) + jobs = serializers.MultipleChoiceField(allow_blank=True, choices=[]) + users = serializers.MultipleChoiceField(allow_blank=True, choices=[]) + groups = serializers.MultipleChoiceField(allow_blank=True, choices=[]) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields['jobs'] = serializers.MultipleChoiceField(choices=[job.id for job in Job.objects.all()]) + self.fields['users'] = serializers.MultipleChoiceField(choices=[user.id for user in User.objects.all()]) + self.fields['groups'] = serializers.MultipleChoiceField(choices=[group.id for group in Group.objects.all()]) @staticmethod def create_or_update(validated_data: dict, perm: JobPermission = None): diff --git a/src/ansible-webui/aw/model/job.py b/src/ansible-webui/aw/model/job.py index de200e8..018897f 100644 --- a/src/ansible-webui/aw/model/job.py +++ b/src/ansible-webui/aw/model/job.py @@ -163,6 +163,7 @@ class Job(BaseJob): api_fields_read = ['id'] api_fields_read.extend(CHANGE_FIELDS) api_fields_write = api_fields_read.copy() + api_fields_read.append('next_run') api_fields_write.extend(['vault_pass', 'become_pass', 'connect_pass']) name = models.CharField(max_length=150) @@ -330,7 +331,7 @@ def __str__(self) -> str: class JobExecution(BaseJob): api_fields_read = [ 'id', 'job', 'job_name', 'user', 'user_name', 'result', 'status', 'status_name', 'time_start', 'time_fin', - 'failed', 'error_s', 'error_m', 'log_stdout', 'log_stdout_url', 'log_stderr', 'log_stderr_url', + 'failed', 'error_s', 'error_m', 'log_stdout', 'log_stdout_url', 'log_stderr', 'log_stderr_url', 'job_comment', ] # NOTE: scheduled execution will have no user diff --git a/src/ansible-webui/aw/static/js/aw.js b/src/ansible-webui/aw/static/js/aw.js index 39de227..6ba83fb 100644 --- a/src/ansible-webui/aw/static/js/aw.js +++ b/src/ansible-webui/aw/static/js/aw.js @@ -78,6 +78,12 @@ function toggleHidden(elementID) { } } +function shortExecutionStatus(execution) { + return execution.time_start + '
' + execution.user_name + + '
' + + execution.status_name + '
'; +} + // API CALLS const CSRF_TOKEN = getCookie('csrftoken'); @@ -174,10 +180,21 @@ function apiBrowseDir(inputElement, choicesElement, selector, base, searchType) }); } -function fetchApiTableData(apiEndpoint, updateFunction, secondRow = false) { +function fetchApiTableDataPlaceholder(dataTable, placeholderId) { + tableHead = dataTable.rows[0]; + tmpRow = dataTable.insertRow(1); + tmpRow.setAttribute("aw-api-entry", placeholderId); + for (i = 0, len = tableHead.cells.length; i < len; i++) { + tmpRow.insertCell(i).innerText = '-'; + } +} + +function fetchApiTableData(apiEndpoint, updateFunction, secondRow = false, placeholderFunction = null) { // NOTE: data needs to be list of dict and include an 'id' attribute dataTable = document.getElementById("aw-api-data-table"); secondRowAppendix = '_2'; + placeholderExists = false; + placeholderId = 'placeholder'; $.get(apiEndpoint, function(data) { existingEntryIds = []; @@ -242,7 +259,12 @@ function fetchApiTableData(apiEndpoint, updateFunction, secondRow = false) { if (typeof(existingRowId) == 'undefined' || existingRowId == null) { continue } - if (!existingEntryIds.includes(String(existingRowId))) { + if (existingRowId == placeholderId) { + placeholderExists = true; + if (data.length > 0) { + rowsToDelete.push(rowIdx); + } + } else if (!existingEntryIds.includes(String(existingRowId))) { rowsToDelete.push(rowIdx); } } @@ -251,6 +273,14 @@ function fetchApiTableData(apiEndpoint, updateFunction, secondRow = false) { console.log("Removing entry row", rowIdx); dataTable.deleteRow(rowIdx); } + // add placeholder row if empty + if (data.length == 0 && !placeholderExists) { + if (placeholderFunction == null) { + fetchApiTableDataPlaceholder(dataTable, placeholderId); + } else { + placeholderFunction(dataTable, placeholderId); + } + } }); } @@ -331,7 +361,6 @@ $( document ).ready(function() { } if (this.checkValidity() == false) { - let userInput = $(this).val(); if (typeof(userInput) == 'undefined' || userInput == null) { userInput = ""; diff --git a/src/ansible-webui/aw/static/js/jobs/logs.js b/src/ansible-webui/aw/static/js/jobs/logs.js index db8676e..bdc90ac 100644 --- a/src/ansible-webui/aw/static/js/jobs/logs.js +++ b/src/ansible-webui/aw/static/js/jobs/logs.js @@ -52,10 +52,7 @@ function addLogLines($this) { } function updateApiTableDataJobLogs(row, row2, entry) { - console.log(entry); - row.insertCell(0).innerHTML = entry.time_start + '
' + entry.user_name + - '
' + - entry.status_name + '
'; + row.insertCell(0).innerHTML = shortExecutionStatus(entry); row.insertCell(1).innerText = entry.job_name; if (entry.job_comment == "") { row.insertCell(2).innerText = "-"; diff --git a/src/ansible-webui/aw/static/js/jobs/manage.js b/src/ansible-webui/aw/static/js/jobs/manage.js new file mode 100644 index 0000000..1a20410 --- /dev/null +++ b/src/ansible-webui/aw/static/js/jobs/manage.js @@ -0,0 +1,110 @@ +function updateApiTableDataJob(row, row2, entry) { + // job + row.insertCell(0).innerText = entry.name; + c2 = row.insertCell(1); + c2.setAttribute("class", "aw-responsive-lg"); + c2.innerText = entry.inventory_file; + c3 = row.insertCell(2); + c3.setAttribute("class", "aw-responsive-lg"); + c3.innerText = entry.playbook_file; + + c4 = row.insertCell(3); + c4.setAttribute("class", "aw-responsive-lg"); + if (entry.comment == "") { + c4.innerText = '-'; + } else { + c4.innerText = entry.comment; + } + if (entry.schedule == "") { + row.insertCell(4).innerText = '-'; + } else { + scheduleHtml = entry.schedule; + if (!entry.enabled) { + scheduleHtml += '
(disabled)'; + } + row.insertCell(4).innerHTML = scheduleHtml; + } + + if (entry.executions.length == 0) { + lastExecution = null; + row.insertCell(5).innerText = '-'; + + c7 = row.insertCell(6); + c7.setAttribute("class", "aw-responsive-med"); + c7.innerHTML = '-'; + } else { + lastExecution = entry.executions[0]; + c6 = row.insertCell(5); + c6.innerHTML = shortExecutionStatus(lastExecution); + + c7 = row.insertCell(6); + c7.setAttribute("class", "aw-responsive-med"); + if (entry.next_run == null) { + c7.innerText = '-'; + } else { + c7.innerText = entry.next_run; + } + } + + actionsTemplate = document.getElementById("aw-api-data-tmpl-actions").innerHTML; + actionsTemplate = actionsTemplate.replaceAll('${ID}', entry.id); + if (lastExecution != null) { + actionsTemplate = actionsTemplate.replaceAll('${EXEC_ID_1}', lastExecution.id); + } + row.insertCell(7).innerHTML = actionsTemplate; + + // execution stati + executionsTemplate = document.getElementById("aw-api-data-tmpl-executions").innerHTML; + executionsTemplate = executionsTemplate.replaceAll('${ID}', entry.id); + row2.setAttribute("hidden", "hidden"); + row2.setAttribute("id", "aw-spoiler-" + entry.id); + row2Col = row2.insertCell(0); + row2Col.setAttribute("colspan", "100%"); + execs = '
'; + for (i = 0, len = entry.executions.length; i < len; i++) { + exec = entry.executions[i]; + execs += ('
Start time: ' + exec.time_start) + execs += ('
Finish time: ' + exec.time_fin) + execs += ('
Executed by: ' + exec.user_name) + execs += ('
Status: ' + exec.status_name + '') + execs += ('
Logs: Output, ') + execs += ('Error') + if (exec.error_s != null) { + execs += ('

Error: ' + exec.error_s + '') + if (exec.error_m != null) { + execs += ('
Error full:
' + exec.error_m + '
') + } + } + } + execs += '
'; + executionsTemplate = executionsTemplate.replaceAll('${EXECS}', execs); + row2Col.innerHTML = executionsTemplate; +} + +function updateApiTableDataJobPlaceholder(dataTable, placeholderId) { + tableHead = dataTable.rows[0]; + tmpRow = dataTable.insertRow(1); + tmpRow.setAttribute("aw-api-entry", placeholderId); + tmpRow.insertCell(0).innerText = '-'; + c2 = tmpRow.insertCell(1); + c2.innerText = '-'; + c2.setAttribute("class", "aw-responsive-lg"); + c3 = tmpRow.insertCell(2); + c3.innerText = '-'; + c3.setAttribute("class", "aw-responsive-lg"); + c4 = tmpRow.insertCell(3); + c4.innerText = '-'; + c4.setAttribute("class", "aw-responsive-lg"); + tmpRow.insertCell(4).innerText = '-'; + c6 = tmpRow.insertCell(5); + c6.innerText = '-'; + c6.setAttribute("class", "aw-responsive-med"); + tmpRow.insertCell(6).innerText = '-'; +} + + +$( document ).ready(function() { + apiEndpoint = "/api/job?executions=true"; + fetchApiTableData(apiEndpoint, updateApiTableDataJob, true, updateApiTableDataJobPlaceholder); + setInterval('fetchApiTableData(apiEndpoint, updateApiTableDataJob, true, updateApiTableDataJobPlaceholder)', (DATA_REFRESH_SEC * 1000)); +}); diff --git a/src/ansible-webui/aw/static/js/settings/api_key.js b/src/ansible-webui/aw/static/js/settings/api_key.js index cd5a759..3e225b0 100644 --- a/src/ansible-webui/aw/static/js/settings/api_key.js +++ b/src/ansible-webui/aw/static/js/settings/api_key.js @@ -1,7 +1,7 @@ function updateApiTableDataKey(row, entry) { - entryRow.insertCell(0).innerText = entry.token; + row.insertCell(0).innerText = entry.token; actionsTemplate = document.getElementById("aw-api-data-tmpl-actions").innerHTML; - entryRow.insertCell(1).innerHTML = actionsTemplate.replaceAll('${TOKEN}', entry.token); + row.insertCell(1).innerHTML = actionsTemplate.replaceAll('${TOKEN}', entry.token); } $( document ).ready(function() { diff --git a/src/ansible-webui/aw/static/js/settings/permission.js b/src/ansible-webui/aw/static/js/settings/permission.js index 11bf7da..fde5346 100644 --- a/src/ansible-webui/aw/static/js/settings/permission.js +++ b/src/ansible-webui/aw/static/js/settings/permission.js @@ -1,24 +1,24 @@ function updateApiTableDataPermission(row, entry) { - entryRow.insertCell(0).innerText = entry.name; - entryRow.insertCell(1).innerText = entry.permission_name; + row.insertCell(0).innerText = entry.name; + row.insertCell(1).innerText = entry.permission_name; if (entry.jobs_name.length == 0) { - entryRow.insertCell(2).innerText = '-'; + row.insertCell(2).innerText = '-'; } else { - entryRow.insertCell(2).innerText = entry.jobs_name.join(', '); + row.insertCell(2).innerText = entry.jobs_name.join(', '); } if (entry.users_name.length == 0) { - entryRow.insertCell(3).innerText = '-'; + row.insertCell(3).innerText = '-'; } else { - entryRow.insertCell(3).innerText = entry.users_name.join(', '); + row.insertCell(3).innerText = entry.users_name.join(', '); } if (entry.groups_name.length == 0) { - entryRow.insertCell(4).innerText = '-'; + row.insertCell(4).innerText = '-'; } else { - entryRow.insertCell(4).innerText = entry.groups_name.join(', '); + row.insertCell(4).innerText = entry.groups_name.join(', '); } actionsTemplate = document.getElementById("aw-api-data-tmpl-actions").innerHTML; - entryRow.insertCell(5).innerHTML = actionsTemplate.replaceAll('${ID}', entry.id); + row.insertCell(5).innerHTML = actionsTemplate.replaceAll('${ID}', entry.id); } $( document ).ready(function() { diff --git a/src/ansible-webui/aw/templates/jobs/logs.html b/src/ansible-webui/aw/templates/jobs/logs.html index 208dbe1..99b1341 100644 --- a/src/ansible-webui/aw/templates/jobs/logs.html +++ b/src/ansible-webui/aw/templates/jobs/logs.html @@ -1,10 +1,8 @@ {% extends "../body.html" %} {% load static %} {% load util %} -{% load job_util %} {% block content %} -{# todo: build table using ajax to allow dynamic search #} + + + + + + + + + + + + {% endblock %} \ No newline at end of file diff --git a/src/ansible-webui/aw/templates/jobs/manage_job.html b/src/ansible-webui/aw/templates/jobs/manage_job.html deleted file mode 100644 index b796886..0000000 --- a/src/ansible-webui/aw/templates/jobs/manage_job.html +++ /dev/null @@ -1,54 +0,0 @@ -{% load util %} -{% load job_util %} -{% for job in jobs %} -{% set_var executions|get_value:job.id as job_executions %} - - {{ job.name }} - {{ job.inventory_file }} - {{ job.playbook_file }} - {{ job.comment|get_fallback:"-" }} - {{ job.schedule|get_fallback:"-" }} -{% if job.schedule|exists and not job.enabled %} -
(disabled) -{% endif %} - - {{ job_executions|first|execution_info_brief|get_fallback:"-"|safe }} - {{ next_executions|get_value:job.id }} - - - - - - - - - - - - - -{% if job_executions|length > 0 %} -{% include "./manage_job_executions.html" %} -{% endif %} -{% endfor %} diff --git a/src/ansible-webui/aw/templates/jobs/manage_job_executions.html b/src/ansible-webui/aw/templates/jobs/manage_job_executions.html index 2bbf847..ed690ff 100644 --- a/src/ansible-webui/aw/templates/jobs/manage_job_executions.html +++ b/src/ansible-webui/aw/templates/jobs/manage_job_executions.html @@ -1,5 +1,4 @@ {% load util %} -{% load job_util %}

Last executions


diff --git a/src/ansible-webui/aw/templatetags/job_util.py b/src/ansible-webui/aw/templatetags/job_util.py deleted file mode 100644 index a4990dc..0000000 --- a/src/ansible-webui/aw/templatetags/job_util.py +++ /dev/null @@ -1,106 +0,0 @@ -from pathlib import Path - -from django import template - -from aw.model.job import JobExecution, CHOICES_JOB_EXEC_STATUS -from aw.config.hardcoded import SHORT_TIME_FORMAT -from aw.utils.util import datetime_from_db, is_null -from aw.utils.permission import get_permission_name - -register = template.Library() - - -def _execution_info(execution: JobExecution) -> dict: - base = { - 'user': f'by {execution.user.username}' if execution.user is not None else 'Scheduled', - 'status': CHOICES_JOB_EXEC_STATUS[execution.status][1], - 'time_start': datetime_from_db(execution.created).strftime(SHORT_TIME_FORMAT), - } - - if execution.result is not None and execution.result.error is not None: - error_m = '' - if execution.result.error.med is not None: - error_m = f"
Error full:
{execution.result.error.med}
" - - return { - 'time_start': datetime_from_db(execution.result.time_start).strftime(SHORT_TIME_FORMAT), - 'time_fin': datetime_from_db(execution.result.time_fin).strftime(SHORT_TIME_FORMAT), - 'failed': execution.result.failed, - 'error_s': execution.result.error.short, - 'error_m': error_m, - **base, - } - - if execution.result is not None: - return { - 'time_start': datetime_from_db(execution.result.time_start).strftime(SHORT_TIME_FORMAT), - 'time_fin': datetime_from_db(execution.result.time_fin).strftime(SHORT_TIME_FORMAT), - 'failed': execution.result.failed, - **base, - } - - return { - 'time_fin': 'Unknown', - 'failed': 'Unknown', - **base, - } - - -@register.filter -def execution_info_brief(execution: JobExecution) -> (str, None): - if is_null(execution): - return None - - info = _execution_info(execution) - return (f"{info['time_start']}
{info['user']}
{info['status']}
") - - -@register.filter -def execution_info_verbose(execution: JobExecution) -> (str, None): - if is_null(execution): - return None - - info = _execution_info(execution) - - if execution.result is not None and execution.result.error is not None: - error = f"

Error: {info['error_s']}{info['error_m']}" - else: - error = '' - - if not execution_logfile_exists(execution): - stdout = None - else: - stdout = 'Output' - - if not execution_logfile_exists(execution, 'log_stderr'): - stderr = None - else: - stderr = 'Error' - - logs = '' - if stdout is not None or stderr is not None: - logs = '
Logs:' - if stdout is not None: - logs += f' {stdout}' - if stderr is not None: - logs += f' {stderr}' - - return (f"
Start time: {info['time_start']}
Finish time: {info['time_fin']}
" - f"Executed by: '{info['user']}'
Status: " - f"{info['status']}" - f"{logs}{error}") - - -@register.filter -def execution_logfile_exists(execution: JobExecution, attr: str = 'log_stdout') -> bool: - log_attr = getattr(execution, attr) - if is_null(log_attr): - return False - - return Path(log_attr).is_file() - - -@register.filter -def permission_name(perm: int) -> str: - return get_permission_name(perm) diff --git a/src/ansible-webui/aw/views/settings.py b/src/ansible-webui/aw/views/settings.py index a5848a0..47a9988 100644 --- a/src/ansible-webui/aw/views/settings.py +++ b/src/ansible-webui/aw/views/settings.py @@ -1,10 +1,9 @@ from django.urls import path from django.contrib.auth.models import User, Group -from django.db.utils import OperationalError from django.shortcuts import HttpResponse from django.shortcuts import render, redirect from django.contrib.auth.decorators import login_required -from django.forms import ModelForm, MultipleChoiceField, SelectMultiple +from django.forms import ModelForm, SelectMultiple, MultipleChoiceField from aw.utils.http import ui_endpoint_wrapper, ui_endpoint_wrapper_kwargs from aw.model.job import Job, JobPermission @@ -23,6 +22,19 @@ def setting_permission(request) -> HttpResponse: return render(request, status=200, template_name='settings/permission.html') +def _job_choices() -> list[tuple]: + # pylint: disable=E1101 + return [(job.id, job.name) for job in Job.objects.all()] + + +def _user_choices() -> list[tuple]: + return [(user.id, user.username) for user in User.objects.all()] + + +def _group_choices() -> list[tuple]: + return [(group.id, group.name) for group in Group.objects.all()] + + class SettingPermissionForm(ModelForm): class Meta: model = JobPermission @@ -31,27 +43,21 @@ class Meta: labels = FORM_LABEL['settings']['permissions'] help_texts = FORM_HELP['settings']['permissions'] - # pylint: disable=E1101 - try: - jobs = MultipleChoiceField( - required=False, - widget=SelectMultiple, - choices=((job.id, job.name) for job in Job.objects.all()), - ) - users = MultipleChoiceField( - required=False, - widget=SelectMultiple, - choices=((user.id, user.username) for user in User.objects.all()) - ) - groups = MultipleChoiceField( - required=False, - widget=SelectMultiple, - choices=((group.id, group.name) for group in Group.objects.all()) - ) - - except OperationalError: - # before db migration/initialization - pass + jobs = MultipleChoiceField( + required=False, + widget=SelectMultiple, + choices=_job_choices, + ) + users = MultipleChoiceField( + required=False, + widget=SelectMultiple, + choices=_user_choices, + ) + groups = MultipleChoiceField( + required=False, + widget=SelectMultiple, + choices=_group_choices, + ) @login_required diff --git a/src/ansible-webui/aw/views/system.py b/src/ansible-webui/aw/views/system.py index 5c00da6..309c49c 100644 --- a/src/ansible-webui/aw/views/system.py +++ b/src/ansible-webui/aw/views/system.py @@ -42,7 +42,7 @@ def _parsed_ansible_collections() -> dict: def _parsed_ansible_config() -> dict: - config_raw = get_ansible_config(action='dump')[0].split('\n') + config_raw = get_ansible_config(action='dump', quiet=True)[0].split('\n') config = {} for line in config_raw: diff --git a/src/ansible-webui/db.py b/src/ansible-webui/db.py index d83189d..4a94e35 100644 --- a/src/ansible-webui/db.py +++ b/src/ansible-webui/db.py @@ -61,7 +61,6 @@ def _clean_old_db_backups(): if file.startswith(DB_FILE.name) and file.endswith(DB_BACKUP_EXT): backup_file = DB_FILE.parent / file backup_age = time() - backup_file.stat().st_mtime - print(backup_file, backup_age, DB_BACKUP_RETENTION) if backup_age > DB_BACKUP_RETENTION: log(msg=f"Cleaning old backup file: '{backup_file}'", level=4) remove(backup_file)