mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 11:16:47 +00:00
fix(templates): each delete page says what deleting its object does
The shared delete page asked only whether to delete the object. Each view now gives its consequence: a deleted compute's VMs keep running but the panel forgets them and their owners, a deleted user's VMs stay, a group's members keep their accounts, a VM's owner loses only the access, a removed VM's record no longer brings its owners back, an SSH key stays on the VMs that have it, a flavor only goes as a size template. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f9c8c36a6b
commit
fbe93d9aee
6 changed files with 54 additions and 7 deletions
|
|
@ -93,6 +93,7 @@ def ssh_key_delete(request, pk):
|
|||
{
|
||||
"object": ssh_key,
|
||||
"title": _("Delete SSH key"),
|
||||
"consequence": _("VMs that already have it keep it; VMs created from now on do not get it."),
|
||||
},
|
||||
)
|
||||
|
||||
|
|
@ -200,7 +201,8 @@ def user_instance_delete(request, pk):
|
|||
return render(
|
||||
request,
|
||||
"common/confirm_delete.html",
|
||||
{"object": user_instance},
|
||||
{"object": user_instance,
|
||||
"consequence": _("The user loses access to this VM; the VM itself is not changed.")},
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ def group_delete(request, pk):
|
|||
return render(
|
||||
request,
|
||||
"common/confirm_delete.html",
|
||||
{"object": group},
|
||||
{"object": group, "consequence": _("Its members stay but lose the permissions it gave them.")},
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -182,7 +182,8 @@ def user_delete(request, pk):
|
|||
return render(
|
||||
request,
|
||||
"common/confirm_delete.html",
|
||||
{"object": user},
|
||||
{"object": user,
|
||||
"consequence": _("Their access to VMs, SSH keys and settings go; the VMs themselves stay.")},
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -237,7 +238,8 @@ def tombstone_delete(request, pk):
|
|||
return render(
|
||||
request,
|
||||
"common/confirm_delete.html",
|
||||
{"object": tombstone},
|
||||
{"object": tombstone,
|
||||
"consequence": _("Its owners no longer get the VM back if its UUID shows up again.")},
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ from django.http import HttpResponse
|
|||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from instances.models import Instance
|
||||
from libvirt import libvirtError
|
||||
from operations import claims
|
||||
|
|
@ -127,7 +128,9 @@ def compute_delete(request, compute_id):
|
|||
return render(
|
||||
request,
|
||||
"common/confirm_delete.html",
|
||||
{"object": compute},
|
||||
{"object": compute,
|
||||
"consequence": _("Its VMs keep running on the host, but the panel forgets them and who owns them; "
|
||||
"added again, the host's VMs come back without owners.")},
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2202,5 +2202,5 @@ def flavor_delete(request, pk):
|
|||
return render(
|
||||
request,
|
||||
"common/confirm_delete.html",
|
||||
{"object": flavor},
|
||||
{"object": flavor, "consequence": _("Only the size template goes; VMs made from it keep their size.")},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="alert alert-warning">
|
||||
{%trans "Are you sure you want to delete" %} "{{ object }}"?
|
||||
{% blocktrans %}Delete "{{ object }}"?{% endblocktrans %} {{ consequence }}
|
||||
</div>
|
||||
<div class="mb-0 float-end">
|
||||
<a class="btn btn-primary" href="javascript:history.back()">
|
||||
|
|
|
|||
40
webvirtcloud/tests/test_delete_pages.py
Normal file
40
webvirtcloud/tests/test_delete_pages.py
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
"""Each delete page says what deleting its object does, besides naming it."""
|
||||
|
||||
from accounts.models import UserInstance, UserSSHKey
|
||||
from computes.models import Compute
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import Group
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
from instances.models import Flavor, Instance, InstanceTombstone
|
||||
from lxml import html
|
||||
|
||||
KEY = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGJ5dGVzLWZvci10aGUtZGVsZXRlLXBhZ2UtdGVzdA== page@example.com"
|
||||
|
||||
|
||||
class DeletePageTests(TestCase):
|
||||
def test_every_delete_page_says_what_deleting_does(self):
|
||||
admin = get_user_model().objects.create_superuser("del-admin", "da@example.com", "pw")
|
||||
user = get_user_model().objects.create_user("del-user", password="pw")
|
||||
compute = Compute.objects.create(name="del-host", hostname="192.0.2.9", login="u", password="p", type=1)
|
||||
vm = Instance.objects.create(compute=compute, name="del-vm", uuid="d0000000-0000-4000-8000-000000000001")
|
||||
pages = {
|
||||
reverse("compute_delete", args=[compute.id]): "the panel forgets them and who owns them",
|
||||
reverse("admin:user_delete", args=[user.id]): "the VMs themselves stay",
|
||||
reverse("admin:group_delete", args=[Group.objects.create(name="del-group").id]): "lose the permissions",
|
||||
reverse("admin:tombstone_delete", args=[InstanceTombstone.objects.create(uuid=vm.uuid, name="gone").id]):
|
||||
"no longer get the VM back",
|
||||
reverse("accounts:user_instance_delete", args=[UserInstance.objects.create(user=user, instance=vm).id]):
|
||||
"the VM itself is not changed",
|
||||
reverse("instances:flavor_delete", args=[Flavor.objects.create(label="del-flavor", memory=512, vcpu=1, disk=1).id]):
|
||||
"VMs made from it keep their size",
|
||||
}
|
||||
key = UserSSHKey.objects.create(user=admin, keyname="del-key", keypublic=KEY)
|
||||
pages[reverse("accounts:ssh_key_delete", args=[key.id])] = "VMs that already have it keep it"
|
||||
self.client.force_login(admin)
|
||||
for url, consequence in pages.items():
|
||||
with self.subTest(url=url):
|
||||
alert = html.fromstring(self.client.get(url).content).xpath("//div[contains(@class, 'alert-warning')]")
|
||||
self.assertEqual(len(alert), 1)
|
||||
self.assertIn(consequence, alert[0].text_content())
|
||||
self.assertNotIn("Are you sure", alert[0].text_content())
|
||||
Loading…
Add table
Add a link
Reference in a new issue