mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 11:16:47 +00:00
fix(accounts): a user's page shows permissions as marks, says when there are no VMs, deletes keys
On a superuser's page of a user the VM permissions read True/False; they are now check marks as on the Users list. A user without VMs gets "No VMs." instead of an empty table. A superuser can delete one of the user's SSH keys, as with API tokens: the same view takes the user, the row names whose key it was. Closes #218
This commit is contained in:
parent
6c2704f97d
commit
b619cf3cd4
4 changed files with 81 additions and 8 deletions
|
|
@ -60,9 +60,9 @@
|
|||
<tr>
|
||||
<td>{{ forloop.counter }}</td>
|
||||
<td><a href="{% url 'instances:instance' inst.instance.id %}">{{ inst.instance.name }}</a></td>
|
||||
<td>{{ inst.is_vnc }}</td>
|
||||
<td>{{ inst.is_change }}</td>
|
||||
<td>{{ inst.is_delete }}</td>
|
||||
<td>{% if inst.is_vnc %}{% bs_icon 'check' %}{% endif %}</td>
|
||||
<td>{% if inst.is_change %}{% bs_icon 'check' %}{% endif %}</td>
|
||||
<td>{% if inst.is_delete %}{% bs_icon 'check' %}{% endif %}</td>
|
||||
<td style="width:5px;">
|
||||
<a href="{% url 'accounts:user_instance_update' inst.id %}" class="btn btn-sm btn-secondary" title="{% trans "edit" %}">
|
||||
{% bs_icon 'pencil' %}
|
||||
|
|
@ -74,6 +74,8 @@
|
|||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr><td colspan="7" class="text-body-secondary">{% trans "No VMs." %}</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -86,6 +88,7 @@
|
|||
<tr>
|
||||
<th scope="col">{% trans "Key name" %}</th>
|
||||
<th scope="col">{% trans "Public key" %}</th>
|
||||
<th scope="col"><span class="visually-hidden">{% trans "Action" %}</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
@ -93,6 +96,11 @@
|
|||
<tr>
|
||||
<td>{{ publickey.keyname }}</td>
|
||||
<td title="{{ publickey.keypublic }}">{{ publickey.keypublic|truncatechars:64 }}</td>
|
||||
<td style="width:5px;">
|
||||
<a class="btn btn-sm btn-secondary" href="{% url 'accounts:account_ssh_key_delete' user.id publickey.id %}" title="{% trans "Delete" %}">
|
||||
{% bs_icon 'trash' %}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
|
|
|||
53
accounts/tests/test_account_page.py
Normal file
53
accounts/tests/test_account_page.py
Normal file
|
|
@ -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, "<td>True</td>", html=True)
|
||||
self.assertNotContains(response, "<td>False</td>", 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())
|
||||
|
|
@ -14,6 +14,7 @@ urlpatterns = [
|
|||
path("profile/<int:user_id>/", views.account, name="account"),
|
||||
path("profile/<int:user_id>/api_token/<str:token_key>/delete/", views.api_token_delete,
|
||||
name="account_api_token_delete"),
|
||||
path("profile/<int:user_id>/ssh_key/<int:pk>/delete/", views.ssh_key_delete, name="account_ssh_key_delete"),
|
||||
path("change_password/", views.change_password, name="change_password"),
|
||||
path(
|
||||
"user_instance/create/<int:user_id>/",
|
||||
|
|
|
|||
|
|
@ -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."),
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue