Skip to content
Snippets Groups Projects
Commit f28e9606 authored by Benjamin Hättasch's avatar Benjamin Hättasch Committed by Nadja Geisler
Browse files

Implement admin actions for constraint violations

Add three admin actions to mark CVs as resolved, or set the level to 'warning' or 'violation' -- each including a preview/confirmation step
Introduce a generic view inheriting from the generic admin intermediate view to handle confirmations for admin actions (performing on multiple, freely selected items)
This implements #154
parent ec088aa2
No related branches found
No related tags found
1 merge request!133Add new functionality to backend
......@@ -4,8 +4,9 @@ from django.contrib import admin, messages
from django.contrib.admin import SimpleListFilter, RelatedFieldListFilter, action
from django.db.models import Count, F
from django.db.models.functions import Now
from django.http import HttpResponseRedirect
from django.shortcuts import render, redirect
from django.urls import reverse_lazy
from django.urls import reverse_lazy, path
from django.utils import timezone
from django.utils.html import format_html
from django.utils.safestring import mark_safe
......@@ -18,6 +19,7 @@ from AKModel.availability.models import Availability
from AKModel.models import Event, AKOwner, AKCategory, AKTrack, AKTag, AKRequirement, AK, AKSlot, Room, AKOrgaMessage, \
ConstraintViolation
from AKModel.urls import get_admin_urls_event_wizard, get_admin_urls_event
from AKModel.views import CVMarkResolvedView, CVSetLevelViolationView, CVSetLevelWarningView
class EventRelatedFieldListFilter(RelatedFieldListFilter):
......@@ -329,3 +331,28 @@ class ConstraintViolationAdmin(admin.ModelAdmin):
list_filter = ['event']
readonly_fields = ['timestamp']
form = ConstraintViolationAdminForm
actions = ['mark_resolved', 'set_violation', 'set_warning']
def get_urls(self):
urls = [
path('mark-resolved/', CVMarkResolvedView.as_view(), name="cv-mark-resolved"),
path('set-violation/', CVSetLevelViolationView.as_view(), name="cv-set-violation"),
path('set-warning/', CVSetLevelWarningView.as_view(), name="cv-set-warning"),
]
urls.extend(super().get_urls())
return urls
def mark_resolved(self, request, queryset):
selected = queryset.values_list('pk', flat=True)
return HttpResponseRedirect(f"{reverse_lazy('admin:cv-mark-resolved')}?pks={','.join(str(pk) for pk in selected)}")
mark_resolved.short_description = _("Mark Constraint Violations as manually resolved")
def set_violation(self, request, queryset):
selected = queryset.values_list('pk', flat=True)
return HttpResponseRedirect(f"{reverse_lazy('admin:cv-set-violation')}?pks={','.join(str(pk) for pk in selected)}")
set_violation.short_description = _('Set to Constraint Violations to level "violation"')
def set_warning(self, request, queryset):
selected = queryset.values_list('pk', flat=True)
return HttpResponseRedirect(f"{reverse_lazy('admin:cv-set-warning')}?pks={','.join(str(pk) for pk in selected)}")
set_warning.short_description = _('Set Constraint Violations to level "warning"')
......@@ -75,6 +75,10 @@ class AdminIntermediateForm(forms.Form):
pass
class AdminIntermediateActionForm(AdminIntermediateForm):
pks = forms.CharField(widget=forms.HiddenInput)
class SlideExportForm(AdminIntermediateForm):
num_next = forms.IntegerField(
min_value=0,
......
import os
import tempfile
from abc import ABC, abstractmethod
from itertools import zip_longest
from django.contrib import admin, messages
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse_lazy
from django.urls import reverse_lazy, reverse
from django.utils.translation import gettext_lazy as _
from django.views.generic import TemplateView, DetailView, ListView, DeleteView, CreateView, FormView, UpdateView
from django_tex.core import render_template_with_context, run_tex_in_directory
......@@ -12,8 +13,10 @@ from django_tex.response import PDFResponse
from rest_framework import viewsets, permissions, mixins
from AKModel.forms import NewEventWizardStartForm, NewEventWizardSettingsForm, NewEventWizardPrepareImportForm, \
NewEventWizardImportForm, NewEventWizardActivateForm, AdminIntermediateForm, SlideExportForm
from AKModel.models import Event, AK, AKSlot, Room, AKTrack, AKCategory, AKOwner, AKOrgaMessage, AKRequirement
NewEventWizardImportForm, NewEventWizardActivateForm, AdminIntermediateForm, SlideExportForm, \
AdminIntermediateActionForm
from AKModel.models import Event, AK, AKSlot, Room, AKTrack, AKCategory, AKOwner, AKOrgaMessage, AKRequirement, \
ConstraintViolation
from AKModel.serializers import AKSerializer, AKSlotSerializer, RoomSerializer, AKTrackSerializer, AKCategorySerializer, \
AKOwnerSerializer
......@@ -369,3 +372,67 @@ class ExportSlidesView(EventSlugMixin, IntermediateAdminView):
pdf = run_tex_in_directory(source, tempdir, template_name=self.template_name)
return PDFResponse(pdf, filename='slides.pdf')
class IntermediateAdminActionView(IntermediateAdminView, ABC):
form_class = AdminIntermediateActionForm
def get_queryset(self, pks=None):
if pks is None:
pks = self.request.GET['pks']
return self.model.objects.filter(pk__in=pks.split(","))
def get_initial(self):
initial = super().get_initial()
initial['pks'] = self.request.GET['pks']
return initial
def get_preview(self):
entities = self.get_queryset()
joined_entities = '\n'.join(str(e) for e in entities)
return f"{self.confirmation_message}:\n\n {joined_entities}"
def get_success_url(self):
return reverse(f"admin:{self.model._meta.app_label}_{self.model._meta.model_name}_changelist")
@abstractmethod
def perform_action(self, entity):
pass
def form_valid(self, form):
entities = self.get_queryset(pks=form.cleaned_data['pks'])
for entity in entities:
self.perform_action(entity)
entity.save()
messages.add_message(self.request, messages.SUCCESS, self.success_message)
return super().form_valid(form)
class CVMarkResolvedView(IntermediateAdminActionView):
title = _('Mark Constraint Violations as manually resolved')
model = ConstraintViolation
confirmation_message = _("The following Constraint Violations will be marked as manually resolved")
success_message = _("Constraint Violations marked as resolved")
def perform_action(self, entity):
entity.manually_resolved = True
class CVSetLevelViolationView(IntermediateAdminActionView):
title = _('Set Constraint Violations to level "violation"')
model = ConstraintViolation
confirmation_message = _("The following Constraint Violations will be set to level 'violation'")
success_message = _("Constraint Violations set to level 'violation'")
def perform_action(self, entity):
entity.level = ConstraintViolation.ViolationLevel.VIOLATION
class CVSetLevelWarningView(IntermediateAdminActionView):
title = _('Set Constraint Violations to level "warning"')
model = ConstraintViolation
confirmation_message = _("The following Constraint Violations will be set to level 'warning'")
success_message = _("Constraint Violations set to level 'warning'")
def perform_action(self, entity):
entity.level = ConstraintViolation.ViolationLevel.WARNING
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment