diff --git a/accounts/templates/account.html b/accounts/templates/account.html
index 083fe494..2becbb6d 100644
--- a/accounts/templates/account.html
+++ b/accounts/templates/account.html
@@ -60,9 +60,9 @@
| {{ forloop.counter }} |
{{ inst.instance.name }} |
- {{ inst.is_vnc }} |
- {{ inst.is_change }} |
- {{ inst.is_delete }} |
+ {% if inst.is_vnc %}{% bs_icon 'check' %}{% endif %} |
+ {% if inst.is_change %}{% bs_icon 'check' %}{% endif %} |
+ {% if inst.is_delete %}{% bs_icon 'check' %}{% endif %} |
{% bs_icon 'pencil' %}
@@ -74,6 +74,8 @@
|
+ {% empty %}
+ | {% trans "No VMs." %} |
{% endfor %}
@@ -86,6 +88,7 @@
| {% trans "Key name" %} |
{% trans "Public key" %} |
+ {% trans "Action" %} |
@@ -93,6 +96,11 @@
| {{ publickey.keyname }} |
{{ publickey.keypublic|truncatechars:64 }} |
+
+
+ {% bs_icon 'trash' %}
+
+ |
{% endfor %}
diff --git a/accounts/tests/test_account_page.py b/accounts/tests/test_account_page.py
new file mode 100644
index 00000000..039179c0
--- /dev/null
+++ b/accounts/tests/test_account_page.py
@@ -0,0 +1,53 @@
+"""A superuser's page of a user: the VMs and their permissions, the SSH keys."""
+
+from django.contrib.auth.models import User
+from django.test import TestCase
+from django.urls import reverse
+
+from accounts.models import UserInstance, UserSSHKey
+from computes.models import Compute
+from instances.models import Instance
+from logs.models import Logs
+
+KEY = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGbXMJlKTOlUOvwzdjDs3ac3ivHQoOxAUZEwi3WsJHfs alice@example"
+
+
+class AccountPageTests(TestCase):
+ def setUp(self):
+ self.admin = User.objects.create_superuser("ap-admin", "ap@example.com", "pw")
+ self.alice = User.objects.create_user("alice", password="pw")
+ self.key = UserSSHKey.objects.create(user=self.alice, keyname="laptop", keypublic=KEY)
+ self.client.force_login(self.admin)
+
+ def page(self):
+ return self.client.get(reverse("accounts:account", args=[self.alice.pk]))
+
+ def test_the_permissions_are_marks_not_true_or_false(self):
+ compute = Compute.objects.create(name="ap-host", hostname="localhost", login="", password="", details="", type=4)
+ vm = Instance.objects.create(compute=compute, name="ap-vm", uuid="00000000-0000-0000-0000-000000000001")
+ UserInstance.objects.create(user=self.alice, instance=vm, is_vnc=True, is_change=False, is_delete=False)
+ response = self.page()
+ self.assertContains(response, "ap-vm")
+ self.assertNotContains(response, "True | ", html=True)
+ self.assertNotContains(response, "False | ", html=True)
+
+ def test_a_user_without_vms_is_told_so(self):
+ self.assertContains(self.page(), "No VMs.")
+
+ def test_a_superuser_deletes_a_users_key(self):
+ url = reverse("accounts:account_ssh_key_delete", args=[self.alice.pk, self.key.pk])
+ self.assertContains(self.page(), f'href="{url}"')
+ self.assertContains(self.client.get(url), "laptop")
+ response = self.client.post(url)
+ self.assertRedirects(response, reverse("accounts:account", args=[self.alice.pk]) + "#public-keys",
+ fetch_redirect_response=False)
+ self.assertFalse(UserSSHKey.objects.exists())
+ self.assertTrue(Logs.objects.filter(message="SSH key laptop of alice: delete").exists())
+
+ def test_only_a_superuser_and_only_that_users_key(self):
+ bob = User.objects.create_user("bob", password="pw")
+ self.assertEqual(self.client.post(reverse("accounts:account_ssh_key_delete", args=[bob.pk, self.key.pk])).status_code, 404)
+ self.client.force_login(bob)
+ url = reverse("accounts:account_ssh_key_delete", args=[self.alice.pk, self.key.pk])
+ self.assertEqual(self.client.post(url).status_code, 403)
+ self.assertTrue(UserSSHKey.objects.exists())
diff --git a/accounts/urls.py b/accounts/urls.py
index 7c009f62..a794af7c 100644
--- a/accounts/urls.py
+++ b/accounts/urls.py
@@ -14,6 +14,7 @@ urlpatterns = [
path("profile//", views.account, name="account"),
path("profile//api_token//delete/", views.api_token_delete,
name="account_api_token_delete"),
+ path("profile//ssh_key//delete/", views.ssh_key_delete, name="account_ssh_key_delete"),
path("change_password/", views.change_password, name="change_password"),
path(
"user_instance/create//",
diff --git a/accounts/views.py b/accounts/views.py
index 52a87cb5..de0b6c50 100644
--- a/accounts/views.py
+++ b/accounts/views.py
@@ -124,19 +124,30 @@ def ssh_key_create(request):
)
-def ssh_key_delete(request, pk):
- ssh_key = get_object_or_404(UserSSHKey, pk=pk, user=request.user)
+def ssh_key_delete(request, pk, user_id=None):
+ """Delete one of the user's own keys or, given user_id, a superuser
+ deletes one of that user's."""
+ if user_id is None:
+ ssh_key = get_object_or_404(UserSSHKey, pk=pk, user=request.user)
+ subject = f"SSH key {ssh_key.keyname}"
+ back = reverse("accounts:profile")
+ elif request.user.is_superuser:
+ ssh_key = get_object_or_404(UserSSHKey, pk=pk, user_id=user_id)
+ subject = f"SSH key {ssh_key.keyname} of {ssh_key.user.username}"
+ back = reverse("accounts:account", args=[user_id]) + "#public-keys"
+ else:
+ raise PermissionDenied
if request.method == "POST":
- with audit(request, None, f"SSH key {ssh_key.keyname}", "delete"):
+ with audit(request, None, subject, "delete"):
ssh_key.delete()
messages.success(request, _("SSH key deleted"))
- return redirect("accounts:profile")
+ return redirect(back)
return render(
request,
"common/confirm_delete.html",
{
- "object": ssh_key,
+ "object": subject,
"title": _("Delete SSH key"),
"consequence": _("VMs that already have it keep it; VMs created from now on do not get it."),
},