diff --git a/api/desecapi/migrations/0041_remove_token_token_auto_policy_and_more.py b/api/desecapi/migrations/0041_remove_token_token_auto_policy_and_more.py new file mode 100644 index 000000000..6dbd9737f --- /dev/null +++ b/api/desecapi/migrations/0041_remove_token_token_auto_policy_and_more.py @@ -0,0 +1,55 @@ +# Generated by Django 5.1.3 on 2024-12-02 10:59 + +import pgtrigger.compiler +import pgtrigger.migrations +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("desecapi", "0040_token_auto_policy_token_token_auto_policy_and_more"), + ] + + operations = [ + pgtrigger.migrations.RemoveTrigger( + model_name="token", + name="token_auto_policy", + ), + pgtrigger.migrations.RemoveTrigger( + model_name="tokendomainpolicy", + name="default_policy_when_auto_policy", + ), + pgtrigger.migrations.AddTrigger( + model_name="token", + trigger=pgtrigger.compiler.Trigger( + name="token_auto_policy", + sql=pgtrigger.compiler.UpsertTriggerSql( + constraint="CONSTRAINT", + func="\n IF\n NEW.auto_policy = true AND NOT EXISTS(\n SELECT * FROM desecapi_tokendomainpolicy WHERE token_id = NEW.id AND domain_id IS NULL AND subname IS NULL AND type IS NULL\n )\n THEN\n RAISE EXCEPTION 'Token auto policy without a default policy is not allowed. (token.id=%s)', NEW.id;\n END IF;\n RETURN NULL;\n ", + hash="a940f3a622b7ffdb0dbf5e3de88e28932d6d4c6c", + operation='INSERT OR UPDATE OF "auto_policy"', + pgid="pgtrigger_token_auto_policy_8e6d9", + table="desecapi_token", + timing="DEFERRABLE INITIALLY DEFERRED", + when="AFTER", + ), + ), + ), + pgtrigger.migrations.AddTrigger( + model_name="tokendomainpolicy", + trigger=pgtrigger.compiler.Trigger( + name="default_policy_when_auto_policy", + sql=pgtrigger.compiler.UpsertTriggerSql( + constraint="CONSTRAINT", + func="\n IF\n OLD.domain_id IS NULL AND OLD.subname IS NULL AND OLD.type IS NULL AND (SELECT auto_policy FROM desecapi_token WHERE id = OLD.token_id) = true\n THEN\n RAISE EXCEPTION 'Cannot delete default policy while auto_policy is in effect. (tokendomainpolicy.id=%s)', OLD.id;\n END IF;\n RETURN OLD;\n ", + hash="5d67fce7a4904080ee952d30ab1d4373923558ee", + operation="DELETE", + pgid="pgtrigger_default_policy_when_auto_policy_a1fd2", + table="desecapi_tokendomainpolicy", + timing="DEFERRABLE INITIALLY DEFERRED", + when="AFTER", + ), + ), + ), + ] diff --git a/api/desecapi/models/tokens.py b/api/desecapi/models/tokens.py index 3480384f9..7ec20dc11 100644 --- a/api/desecapi/models/tokens.py +++ b/api/desecapi/models/tokens.py @@ -65,7 +65,7 @@ class Meta: # Ensure that a default policy is defined when auto_policy=true pgtrigger.Trigger( name="token_auto_policy", - operation=pgtrigger.Update | pgtrigger.Insert, + operation=pgtrigger.Insert | pgtrigger.UpdateOf("auto_policy"), when=pgtrigger.After, timing=pgtrigger.Deferred, func=pgtrigger.Func( @@ -234,7 +234,8 @@ class Meta: pgtrigger.Trigger( name="default_policy_when_auto_policy", operation=pgtrigger.Delete, - when=pgtrigger.Before, + when=pgtrigger.After, + timing=pgtrigger.Deferred, func=pgtrigger.Func( """ IF diff --git a/api/desecapi/tests/test_token_domain_policy.py b/api/desecapi/tests/test_token_domain_policy.py index efe635348..454c76cbc 100644 --- a/api/desecapi/tests/test_token_domain_policy.py +++ b/api/desecapi/tests/test_token_domain_policy.py @@ -752,3 +752,15 @@ def test_create_domain(self): self.assertTrue(self.token.get_policy(rrset).perm_write) rrset = models.RRset(domain=models.Domain.objects.get(name=name_other)) self.assertFalse(self.token.get_policy(rrset).perm_write) + + def test_delete_domain_with_autopolicy(self): + self.token_manage.auto_policy = True + self.token_manage.save() + connection.check_constraints() # simulate transaction commit + + response = self.client._request( + self.client.delete, + self.reverse("v1:token-detail", pk=self.token_manage.id), + using=self.token_manage, + ) + self.assertStatus(response, status.HTTP_204_NO_CONTENT)