Compare commits

...

3 Commits

Author SHA1 Message Date
929e42d3f2 fix other issues
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2024-10-15 14:51:20 +02:00
863958b4d6 make sure we don't break something else
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2024-10-15 14:22:25 +02:00
2249b9307e core: expiring model: don't synchronously delete
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2024-10-15 14:15:24 +02:00
4 changed files with 33 additions and 28 deletions

View File

@ -802,12 +802,25 @@ class ExpiringModel(models.Model):
return self.delete(*args, **kwargs) return self.delete(*args, **kwargs)
@classmethod @classmethod
def filter_not_expired(cls, **kwargs) -> QuerySet["Token"]: def _not_expired_filter(cls):
return Q(expires__gt=now(), expiring=True) | Q(expiring=False)
@classmethod
def filter_not_expired(cls, delete_expired=False, **kwargs) -> QuerySet["ExpiringModel"]:
"""Filer for tokens which are not expired yet or are not expiring, """Filer for tokens which are not expired yet or are not expiring,
and match filters in `kwargs`""" and match filters in `kwargs`"""
for obj in cls.objects.filter(**kwargs).filter(Q(expires__lt=now(), expiring=True)): if delete_expired:
obj.delete() cls.delete_expired(**kwargs)
return cls.objects.filter(**kwargs) return cls.objects.filter(cls._not_expired_filter()).filter(**kwargs)
@classmethod
def delete_expired(cls, **kwargs) -> int:
objects = cls.objects.all().exclude(cls._not_expired_filter()).filter(**kwargs)
amount = 0
for obj in objects:
obj.expire_action()
amount += 1
return amount
@property @property
def is_expired(self) -> bool: def is_expired(self) -> bool:

View File

@ -30,12 +30,7 @@ def clean_expired_models(self: SystemTask):
messages = [] messages = []
for cls in ExpiringModel.__subclasses__(): for cls in ExpiringModel.__subclasses__():
cls: ExpiringModel cls: ExpiringModel
objects = ( amount = cls.delete_expired()
cls.objects.all().exclude(expiring=False).exclude(expiring=True, expires__gt=now())
)
amount = objects.count()
for obj in objects:
obj.expire_action()
LOGGER.debug("Expired models", model=cls, amount=amount) LOGGER.debug("Expired models", model=cls, amount=amount)
messages.append(f"Expired {amount} {cls._meta.verbose_name_plural}") messages.append(f"Expired {amount} {cls._meta.verbose_name_plural}")
# Special case # Special case

View File

@ -9,7 +9,7 @@ from uuid import uuid4
from dacite.core import from_dict from dacite.core import from_dict
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from django.core.cache import cache from django.core.cache import cache
from django.db import IntegrityError, models, transaction from django.db import models, transaction
from django.db.models.base import Model from django.db.models.base import Model
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from guardian.models import UserObjectPermission from guardian.models import UserObjectPermission
@ -380,26 +380,22 @@ class Outpost(SerializerModel, ManagedModel):
"""Get/create token for auto-generated user""" """Get/create token for auto-generated user"""
managed = f"goauthentik.io/outpost/{self.token_identifier}" managed = f"goauthentik.io/outpost/{self.token_identifier}"
tokens = Token.filter_not_expired( tokens = Token.filter_not_expired(
delete_expired=True,
identifier=self.token_identifier, identifier=self.token_identifier,
intent=TokenIntents.INTENT_API, intent=TokenIntents.INTENT_API,
managed=managed, managed=managed,
) )
if tokens.exists(): token: Token | None = tokens.first()
return tokens.first() if token:
try: return token
return Token.objects.create( return Token.objects.create(
user=self.user, user=self.user,
identifier=self.token_identifier, identifier=self.token_identifier,
intent=TokenIntents.INTENT_API, intent=TokenIntents.INTENT_API,
description=f"Autogenerated by authentik for Outpost {self.name}", description=f"Autogenerated by authentik for Outpost {self.name}",
expiring=False, expiring=False,
managed=managed, managed=managed,
) )
except IntegrityError:
# Integrity error happens mostly when managed is reused
Token.objects.filter(managed=managed).delete()
Token.objects.filter(identifier=self.token_identifier).delete()
return self.token
def get_required_objects(self) -> Iterable[models.Model | str]: def get_required_objects(self) -> Iterable[models.Model | str]:
"""Get an iterator of all objects the user needs read access to""" """Get an iterator of all objects the user needs read access to"""

View File

@ -96,8 +96,9 @@ class ConsentStageView(ChallengeStageView):
if PLAN_CONTEXT_PENDING_USER in self.executor.plan.context: if PLAN_CONTEXT_PENDING_USER in self.executor.plan.context:
user = self.executor.plan.context[PLAN_CONTEXT_PENDING_USER] user = self.executor.plan.context[PLAN_CONTEXT_PENDING_USER]
# Remove expired consents to prevent database unique constraints errors
consent: UserConsent | None = UserConsent.filter_not_expired( consent: UserConsent | None = UserConsent.filter_not_expired(
user=user, application=application delete_expired=True, user=user, application=application
).first() ).first()
self.executor.plan.context[PLAN_CONTEXT_CONSENT] = consent self.executor.plan.context[PLAN_CONTEXT_CONSENT] = consent