From 0d21770c72b3aea692293d4003df5caa236c3e30 Mon Sep 17 00:00:00 2001 From: Elijah Date: Sun, 18 Feb 2024 21:47:41 +0100 Subject: [PATCH 1/4] Filtered events for the user and admin dashboards --- idhub/admin/tables.py | 1 + idhub/admin/views.py | 30 ++++++++++++++++++++++++++++++ idhub/user/tables.py | 1 + idhub/user/views.py | 17 ++++++++++++++++- 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/idhub/admin/tables.py b/idhub/admin/tables.py index c783993..74dcc6f 100644 --- a/idhub/admin/tables.py +++ b/idhub/admin/tables.py @@ -150,6 +150,7 @@ class DashboardTable(tables.Table): model = Event template_name = "idhub/custom_table.html" fields = ("type", "message", "created") + empty_text = "No events available" class CredentialTable(tables.Table): diff --git a/idhub/admin/views.py b/idhub/admin/views.py index 25ac28d..9eb204d 100644 --- a/idhub/admin/views.py +++ b/idhub/admin/views.py @@ -109,6 +109,36 @@ class DashboardView(AdminView, SingleTableView): section = "Home" model = Event + def get_queryset(self): + """ + Override the get_queryset method to filter events based on the user type. + """ + events_for_admins = self.get_admin_events() + return Event.objects.filter(type__in=events_for_admins) + + def get_admin_events(self): + return [ + Event.Types.EV_USR_REGISTERED, # User registered + Event.Types.EV_USR_UPDATED_BY_ADMIN, # User's data updated by admin + Event.Types.EV_USR_DELETED_BY_ADMIN, # User deactivated by admin + Event.Types.EV_DID_CREATED_BY_USER, # DID created by user + Event.Types.EV_CREDENTIAL_DELETED_BY_USER, # Credential deleted by user + Event.Types.EV_CREDENTIAL_ISSUED_FOR_USER, # Credential issued for user + Event.Types.EV_CREDENTIAL_PRESENTED_BY_USER, # Credential presented by user + Event.Types.EV_CREDENTIAL_ENABLED, # Credential enabled + Event.Types.EV_CREDENTIAL_REVOKED_BY_ADMIN, # Credential revoked by admin + Event.Types.EV_ROLE_CREATED_BY_ADMIN, # Role created by admin + Event.Types.EV_ROLE_MODIFIED_BY_ADMIN, # Role modified by admin + Event.Types.EV_ROLE_DELETED_BY_ADMIN, # Role deleted by admin + Event.Types.EV_SERVICE_CREATED_BY_ADMIN, # Service created by admin + Event.Types.EV_SERVICE_MODIFIED_BY_ADMIN, # Service modified by admin + Event.Types.EV_SERVICE_DELETED_BY_ADMIN, # Service deleted by admin + Event.Types.EV_ORG_DID_CREATED_BY_ADMIN, # Organisational DID created by admin + Event.Types.EV_ORG_DID_DELETED_BY_ADMIN, # Organisational DID deleted by admin + Event.Types.EV_USR_DEACTIVATED_BY_ADMIN, # User deactivated + Event.Types.EV_DATA_UPDATE_REQUESTED, # Data update requested. Pending approval by administrator + ] + class People(AdminView): title = _("User management") diff --git a/idhub/user/tables.py b/idhub/user/tables.py index eacdcb8..b6cb9b8 100644 --- a/idhub/user/tables.py +++ b/idhub/user/tables.py @@ -27,6 +27,7 @@ class DashboardTable(tables.Table): model = Event template_name = "idhub/custom_table.html" fields = ("type", "message", "created") + empty_text="No events available" class PersonalInfoTable(tables.Table): diff --git a/idhub/user/views.py b/idhub/user/views.py index 27c8f77..3e70336 100644 --- a/idhub/user/views.py +++ b/idhub/user/views.py @@ -67,11 +67,26 @@ class DashboardView(UserView, SingleTableView): section = "Home" def get_queryset(self, **kwargs): + events_for_users = self.get_user_events() queryset = Event.objects.select_related('user').filter( - user=self.request.user) + user=self.request.user).filter(type__in=events_for_users) return queryset + def get_user_events(self): + events_for_users = [ + Event.Types.EV_USR_WELCOME, # User welcomed + Event.Types.EV_USR_UPDATED, # Your data updated by admin + Event.Types.EV_DID_CREATED, # DID created + Event.Types.EV_DID_DELETED, # DID deleted + Event.Types.EV_CREDENTIAL_DELETED, # Credential deleted + Event.Types.EV_CREDENTIAL_ISSUED, # Credential issued + Event.Types.EV_CREDENTIAL_PRESENTED, # Credential presented + Event.Types.EV_CREDENTIAL_CAN_BE_REQUESTED, # Credential available + Event.Types.EV_CREDENTIAL_REVOKED, # Credential revoked + ] + return events_for_users + class ProfileView(MyProfile, UpdateView, SingleTableView): template_name = "idhub/user/profile.html" From 46531e5d1c704a923eabba6470ffa8b8c82bfda8 Mon Sep 17 00:00:00 2001 From: Elijah Date: Sun, 18 Feb 2024 21:51:35 +0100 Subject: [PATCH 2/4] Started tests draft --- idhub/tests/test_views.py | 95 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) diff --git a/idhub/tests/test_views.py b/idhub/tests/test_views.py index b23f9de..dccd648 100644 --- a/idhub/tests/test_views.py +++ b/idhub/tests/test_views.py @@ -1,7 +1,8 @@ -from django.urls import reverse from django.test import TestCase, RequestFactory +from django.urls import reverse from idhub_auth.models import User +from idhub.models import Event from idhub.admin.views import PeopleListView @@ -59,6 +60,36 @@ class AdminDashboardViewTest(TestCase): self.assertTemplateUsed(response, 'idhub/admin/dashboard.html') + def test_admin_event_filtering(self): + # Create a test admin user + admin_user = User.objects.create_superuser(email='admin@example.org', password='test') + self.client.login(email='admin@example.org', password='test') + + # Create test events, including some that should not be visible to admins + Event.objects.create(type=Event.Types.EV_USR_REGISTERED, message="User registered") + Event.objects.create(type=Event.Types.EV_USR_WELCOME, message="User welcomed") # Should not appear + + # Fetch the dashboard view + response = self.client.get('/admin/dashboard/') + events = response.context['events'] + + # Check that only admin-visible events are included + self.assertIn(Event.Types.EV_USR_REGISTERED, [event.type for event in events]) + self.assertNotIn(Event.Types.EV_USR_WELCOME, [event.type for event in events]) + + def test_access_control(self): + # Attempt to access the dashboard as a non-admin user + regular_user = User.objects.create_user(email='user', password='test') + self.client.login(email='user@example.org', password='test') + response = self.client.get('/admin/dashboard/') + self.assertEqual(response.status_code, 302) # Or 403 if not redirected + + # Access as an admin + admin_user = User.objects.create_superuser(email='admin@example.org', password='test') + self.client.login(email='admin@example.org', password='test') + response = self.client.get('/admin/dashboard/') + self.assertEqual(response.status_code, 200) + class PeopleListViewTest(TestCase): @@ -104,3 +135,65 @@ class PeopleListViewTest(TestCase): # Assuming 2 users in the database self.assertEqual(queryset.count(), 2) + + +class UserDashboardViewTests(TestCase): + def setUp(self): + # Create test users + self.admin_user = User.objects.create_superuser('admin@example.org', 'password') + self.admin_user.accept_gdpr=True + self.admin_user.save() + self.regular_user = User.objects.create_user('regular@example.org', 'password') + self.regular_user.accept_gdpr=True + self.regular_user.save() + + # Create events visible to users + self.visible_events_types = [ + Event.Types.EV_USR_WELCOME, + Event.Types.EV_USR_UPDATED, + Event.Types.EV_DID_CREATED, + Event.Types.EV_DID_DELETED, + Event.Types.EV_CREDENTIAL_DELETED, + Event.Types.EV_CREDENTIAL_ISSUED, + Event.Types.EV_CREDENTIAL_PRESENTED, + Event.Types.EV_CREDENTIAL_CAN_BE_REQUESTED, + Event.Types.EV_CREDENTIAL_REVOKED, + ] + + # Create events for both users + for event_type in self.visible_events_types: + Event.objects.create(type=event_type, message=f"Test event for {event_type.label}", user=self.regular_user) + + # Create an event that should not be visible to a regular user + Event.objects.create(type=Event.Types.EV_USR_REGISTERED, message="Admin only event", user=self.regular_user) + + def test_events_visibility_for_regular_user(self): + self.client.login(email='regularuser@example.org', password='password') + response = self.client.get(reverse('idhub:user_dashboard')) + # Ensure the response contains only the events that should be visible + for event in Event.objects.filter(user=self.regular_user, type__in=self.visible_events_types): + self.assertContains(response, event.message) + # Ensure the response does not contain the admin only event + self.assertNotContains(response, "Admin only event") + + def test_no_events_for_regular_user(self): + # Delete all events for the setup user + Event.objects.filter(user=self.regular_user).delete() + self.client.login(email='regularuser@example.org', password='password') + response = self.client.get(reverse('idhub:user_dashboard')) + # Verify that the response indicates no events are available + self.assertContains(response, "No events available") # Adjust based on your actual no-events message + + def test_events_visibility_for_new_user(self): + # Create a new user who has no events + new_user = User.objects.create_user('new@example.org', 'password') + self.client.login(email='newuser@example.org', password='password') + response = self.client.get(reverse('idhub:user_dashboard')) + # Verify that the response correctly indicates no events for the new user + self.assertContains(response, "No events available") # Adjust based on your actual no-events message + + def test_unauthorized_access(self): + # Attempt to access the dashboard without logging in + response = self.client.get(reverse('idhub:user_dashboard'), follow=True) + # Ensure the response redirects to the login page + self.assertTemplateUsed(response, 'auth/login.html') From 166bd466546c4dd2ea3579d5694393703f0195a4 Mon Sep 17 00:00:00 2001 From: Elahi-cs Date: Thu, 22 Feb 2024 17:55:18 +0100 Subject: [PATCH 3/4] Fixed some tests --- idhub/tests/test_views.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/idhub/tests/test_views.py b/idhub/tests/test_views.py index dccd648..67d68c9 100644 --- a/idhub/tests/test_views.py +++ b/idhub/tests/test_views.py @@ -63,6 +63,8 @@ class AdminDashboardViewTest(TestCase): def test_admin_event_filtering(self): # Create a test admin user admin_user = User.objects.create_superuser(email='admin@example.org', password='test') + admin_user.accept_gdpr = True + admin_user.save() self.client.login(email='admin@example.org', password='test') # Create test events, including some that should not be visible to admins @@ -71,21 +73,25 @@ class AdminDashboardViewTest(TestCase): # Fetch the dashboard view response = self.client.get('/admin/dashboard/') + #import pdb; pdb.set_trace() events = response.context['events'] # Check that only admin-visible events are included self.assertIn(Event.Types.EV_USR_REGISTERED, [event.type for event in events]) self.assertNotIn(Event.Types.EV_USR_WELCOME, [event.type for event in events]) - def test_access_control(self): + def test_access_control_redirects_when_normal_user(self): # Attempt to access the dashboard as a non-admin user regular_user = User.objects.create_user(email='user', password='test') self.client.login(email='user@example.org', password='test') response = self.client.get('/admin/dashboard/') self.assertEqual(response.status_code, 302) # Or 403 if not redirected + def test_access_control_accepted_when_admin(self): # Access as an admin admin_user = User.objects.create_superuser(email='admin@example.org', password='test') + admin_user.accept_gdpr=True + admin_user.save() self.client.login(email='admin@example.org', password='test') response = self.client.get('/admin/dashboard/') self.assertEqual(response.status_code, 200) @@ -168,7 +174,7 @@ class UserDashboardViewTests(TestCase): Event.objects.create(type=Event.Types.EV_USR_REGISTERED, message="Admin only event", user=self.regular_user) def test_events_visibility_for_regular_user(self): - self.client.login(email='regularuser@example.org', password='password') + self.client.login(email='regular@example.org', password='password') response = self.client.get(reverse('idhub:user_dashboard')) # Ensure the response contains only the events that should be visible for event in Event.objects.filter(user=self.regular_user, type__in=self.visible_events_types): @@ -179,7 +185,7 @@ class UserDashboardViewTests(TestCase): def test_no_events_for_regular_user(self): # Delete all events for the setup user Event.objects.filter(user=self.regular_user).delete() - self.client.login(email='regularuser@example.org', password='password') + self.client.login(email='regular@example.org', password='password') response = self.client.get(reverse('idhub:user_dashboard')) # Verify that the response indicates no events are available self.assertContains(response, "No events available") # Adjust based on your actual no-events message @@ -187,7 +193,9 @@ class UserDashboardViewTests(TestCase): def test_events_visibility_for_new_user(self): # Create a new user who has no events new_user = User.objects.create_user('new@example.org', 'password') - self.client.login(email='newuser@example.org', password='password') + new_user.accept_gdpr = True + new_user.save() + self.client.login(email='new@example.org', password='password') response = self.client.get(reverse('idhub:user_dashboard')) # Verify that the response correctly indicates no events for the new user self.assertContains(response, "No events available") # Adjust based on your actual no-events message From 488f60e280d6b683a63fed371557fc2770b65934 Mon Sep 17 00:00:00 2001 From: Elijah Date: Thu, 22 Feb 2024 18:10:49 +0100 Subject: [PATCH 4/4] Added tests for the dashboard events filter --- idhub/tests/test_views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/idhub/tests/test_views.py b/idhub/tests/test_views.py index 67d68c9..a6c66f7 100644 --- a/idhub/tests/test_views.py +++ b/idhub/tests/test_views.py @@ -73,8 +73,7 @@ class AdminDashboardViewTest(TestCase): # Fetch the dashboard view response = self.client.get('/admin/dashboard/') - #import pdb; pdb.set_trace() - events = response.context['events'] + events = response.context['event_list'] # Check that only admin-visible events are included self.assertIn(Event.Types.EV_USR_REGISTERED, [event.type for event in events])