restart front

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
This commit is contained in:
Marc 'risson' Schmitt
2025-06-11 17:25:21 +02:00
parent 1a9c529e92
commit 7ef547b357
11 changed files with 317 additions and 194 deletions

View File

@ -1,3 +1,6 @@
from django_filters.filters import BooleanFilter
from django_filters.filterset import FilterSet
from rest_framework.fields import ReadOnlyField
from rest_framework.mixins import (
ListModelMixin,
RetrieveModelMixin,
@ -11,6 +14,9 @@ from authentik.tenants.utils import get_current_tenant
class TaskSerializer(ModelSerializer):
rel_obj_app_label = ReadOnlyField(source="rel_obj_content_type.app_label")
rel_obj_model = ReadOnlyField(source="rel_obj_content_type.model")
messages = LogEventSerializer(many=True, source="_messages")
class Meta:
@ -21,7 +27,8 @@ class TaskSerializer(ModelSerializer):
"actor_name",
"state",
"mtime",
"rel_obj_content_type",
"rel_obj_app_label",
"rel_obj_model",
"rel_obj_id",
"uid",
"messages",
@ -29,6 +36,23 @@ class TaskSerializer(ModelSerializer):
]
class TaskFilter(FilterSet):
rel_obj_id__isnull = BooleanFilter("rel_obj_id", "isnull")
class Meta:
model = Task
fields = (
"queue_name",
"actor_name",
"state",
"rel_obj_content_type__app_label",
"rel_obj_content_type__model",
"rel_obj_id",
"rel_obj_id__isnull",
"aggregated_status",
)
class TaskViewSet(
RetrieveModelMixin,
ListModelMixin,
@ -41,16 +65,16 @@ class TaskViewSet(
"queue_name",
"actor_name",
"state",
"rel_obj_app_label",
"rel_obj_model",
"rel_obj_id",
"_uid",
"aggregated_status",
)
filterset_fields = (
"queue_name",
"actor_name",
"state",
"aggregated_status",
)
filterset_class = TaskFilter
ordering = ("-mtime",)
def get_queryset(self):
return Task.objects.filter(tenant=get_current_tenant())
return Task.objects.select_related("rel_obj_content_type").filter(
tenant=get_current_tenant()
)

View File

@ -1,9 +1,12 @@
from django_filters.filters import BooleanFilter
from django_filters.filterset import FilterSet
from dramatiq.actor import Actor
from dramatiq.broker import get_broker
from dramatiq.errors import ActorNotFound
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiResponse, extend_schema
from rest_framework.decorators import action
from rest_framework.fields import ReadOnlyField
from rest_framework.mixins import (
ListModelMixin,
RetrieveModelMixin,
@ -20,19 +23,25 @@ from authentik.tasks.schedules.models import Schedule
class ScheduleSerializer(ModelSerializer):
rel_obj_app_label = ReadOnlyField(source="rel_obj_content_type.app_label")
rel_obj_model = ReadOnlyField(source="rel_obj_content_type.model")
description = SerializerMethodField()
class Meta:
model = Schedule
fields = [
fields = (
"id",
"uid",
"actor_name",
"rel_obj_app_label",
"rel_obj_model",
"rel_obj_id",
"crontab",
"paused",
"next_run",
"description",
]
)
def get_description(self, instance: Schedule) -> str | None:
if instance.rel_obj:
@ -43,22 +52,48 @@ class ScheduleSerializer(ModelSerializer):
actor: Actor = get_broker().get_actor(instance.actor_name)
except ActorNotFound:
return "FIXME this shouldn't happen"
if not actor.fn.__doc__:
return "no doc"
return actor.fn.__doc__.strip()
class ScheduleFilter(FilterSet):
rel_obj_id__isnull = BooleanFilter("rel_obj_id", "isnull")
class Meta:
model = Schedule
fields = (
"actor_name",
"rel_obj_content_type__app_label",
"rel_obj_content_type__model",
"rel_obj_id",
"rel_obj_id__isnull",
"paused",
)
class ScheduleViewSet(
RetrieveModelMixin,
UpdateModelMixin,
ListModelMixin,
GenericViewSet,
):
queryset = Schedule.objects.all()
queryset = Schedule.objects.select_related("rel_obj_content_type").all()
serializer_class = ScheduleSerializer
search_fields = (
"id",
"uid",
"actor_name",
"rel_obj_content_type__app_label",
"rel_obj_content_type__model",
"rel_obj_id",
"description",
)
filterset_class = ScheduleFilter
ordering = (
"next_run",
"uid",
)
ordering = ("next_run", "uid")
@permission_required("authentik_tasks_schedules.send_schedule")
@extend_schema(

View File

@ -0,0 +1,30 @@
# Generated by Django 5.1.10 on 2025-06-11 12:57
import pgtrigger.compiler
import pgtrigger.migrations
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("authentik_tasks_schedules", "0001_initial"),
]
operations = [
pgtrigger.migrations.AddTrigger(
model_name="schedule",
trigger=pgtrigger.compiler.Trigger(
name="set_next_run_on_paused",
sql=pgtrigger.compiler.UpsertTriggerSql(
condition='WHEN (NEW."paused" AND NOT OLD."paused")',
func="\n NEW.next_run = to_timestamp(0);\n RETURN NEW;\n ",
hash="7fe580a86de70723522cfcbac712785984000f92",
operation="UPDATE",
pgid="pgtrigger_set_next_run_on_paused_95c6d",
table="authentik_tasks_schedules_schedule",
when="BEFORE",
),
),
),
]

View File

@ -1,6 +1,7 @@
import pickle # nosec
from uuid import uuid4
import pgtrigger
from cron_converter import Cron
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
@ -55,6 +56,18 @@ class Schedule(SerializerModel):
("send_schedule", _("Manually trigger a schedule")),
]
indexes = (models.Index(fields=("rel_obj_content_type", "rel_obj_id")),)
triggers = (
pgtrigger.Trigger(
name="set_next_run_on_paused",
operation=pgtrigger.Update,
when=pgtrigger.Before,
condition=pgtrigger.Q(new__paused=True) & pgtrigger.Q(old__paused=False),
func="""
NEW.next_run = to_timestamp(0);
RETURN NEW;
""",
),
)
def __str__(self):
return self.uid