diff --git a/idhub/admin/tables.py b/idhub/admin/tables.py new file mode 100644 index 0000000..7ce7d43 --- /dev/null +++ b/idhub/admin/tables.py @@ -0,0 +1,28 @@ +import django_tables2 as tables +from idhub.models import Rol, Event +from idhub_auth.models import User + + +class UserTable(tables.Table): + class Meta: + model = User + template_name = "idhub/custom_table.html" + fields = ("first_name", "last_name", "email", "is_active", "is_admin") + + +class RolesTable(tables.Table): + class Meta: + model = Rol + template_name = "idhub/custom_table.html" + fields = ("name", "description") + + +class DashboardTable(tables.Table): + type = tables.Column(verbose_name="Event") + message = tables.Column(verbose_name="Description") + created = tables.Column(verbose_name="Date") + + class Meta: + model = Event + template_name = "idhub/custom_table.html" + fields = ("type", "message", "created") diff --git a/idhub/admin/views.py b/idhub/admin/views.py index 1b380d2..f8fd6d0 100644 --- a/idhub/admin/views.py +++ b/idhub/admin/views.py @@ -5,6 +5,7 @@ import pandas as pd from pathlib import Path from jsonschema import validate from smtplib import SMTPException +from django_tables2 import SingleTableView from django.conf import settings from django.utils.translation import gettext_lazy as _ @@ -30,6 +31,9 @@ from idhub.admin.forms import ( SchemaForm, UserRolForm, ) +from idhub.admin.tables import ( + DashboardTable +) from idhub.models import ( DID, Event, @@ -43,19 +47,15 @@ from idhub.models import ( ) -class DashboardView(AdminView, TemplateView): +class DashboardView(AdminView, SingleTableView): template_name = "idhub/admin/dashboard.html" + table_class = DashboardTable title = _('Dashboard') subtitle = _('Events') icon = 'bi bi-bell' section = "Home" + model = Event - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context.update({ - 'events': Event.objects.filter(user=None), - }) - return context class People(AdminView): title = _("User management") diff --git a/idhub/templates/idhub/admin/dashboard.html b/idhub/templates/idhub/admin/dashboard.html index d1317e7..4862f82 100644 --- a/idhub/templates/idhub/admin/dashboard.html +++ b/idhub/templates/idhub/admin/dashboard.html @@ -1,29 +1,11 @@ {% extends "idhub/base_admin.html" %} {% load i18n %} +{% load render_table from django_tables2 %} {% block content %}

{{ subtitle }}

-
- - - - - - - - - - {% for ev in events %} - - - - - - {% endfor %} - -
{{ ev.get_type_name }}{{ ev.message }}{{ ev.created }}
-
+{% render_table table %} {% endblock %} diff --git a/idhub/templates/idhub/custom_table.html b/idhub/templates/idhub/custom_table.html new file mode 100644 index 0000000..808de83 --- /dev/null +++ b/idhub/templates/idhub/custom_table.html @@ -0,0 +1,98 @@ +{% load django_tables2 %} +{% load i18n %} +{% block table-wrapper %} +
+ {% block table %} + + {% block table.thead %} + {% if table.show_header %} + + + {% for column in table.columns %} + + {% endfor %} + + + {% endif %} + {% endblock table.thead %} + {% block table.tbody %} + + {% for row in table.paginated_rows %} + {% block table.tbody.row %} + + {% for column, cell in row.items %} + + {% endfor %} + + {% endblock table.tbody.row %} + {% empty %} + {% if table.empty_text %} + {% block table.tbody.empty_text %} + + {% endblock table.tbody.empty_text %} + {% endif %} + {% endfor %} + + {% endblock table.tbody %} + {% block table.tfoot %} + {% if table.has_footer %} + + + {% for column in table.columns %} + + {% endfor %} + + + {% endif %} + {% endblock table.tfoot %} +
+ {% if column.orderable %} + {{ column.header }} + {% else %} + {{ column.header }} + {% endif %} +
{% if column.localize == None %}{{ cell }}{% else %}{% if column.localize %}{{ cell|localize }}{% else %}{{ cell|unlocalize }}{% endif %}{% endif %}
{{ table.empty_text }}
{{ column.footer }}
+ {% endblock table %} + + {% block pagination %} + {% if table.page and table.paginator.num_pages > 1 %} + + {% endif %} + {% endblock pagination %} +
+{% endblock table-wrapper %} diff --git a/idhub/tests.py b/idhub/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/idhub/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/idhub/tests/__init__.py b/idhub/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/idhub/tests/test_models.py b/idhub/tests/test_models.py new file mode 100644 index 0000000..62bcdb3 --- /dev/null +++ b/idhub/tests/test_models.py @@ -0,0 +1,17 @@ +from django.test import TestCase +from idhub.models import Event +from idhub_auth.models import User + + +class EventModelTest(TestCase): + @classmethod + def setUpTestData(cls): + user = User.objects.create(email='testuser@example.org') + Event.objects.create(message='Test Event', type=1, user=user) + + def test_event_creation(self): + event = Event.objects.get(id=1) + self.assertEqual(event.message, 'Test Event') + self.assertEqual(event.get_type_name(), 'User registered') + + # Add more tests for other model methods and properties diff --git a/idhub/tests/test_tables.py b/idhub/tests/test_tables.py new file mode 100644 index 0000000..a78fde9 --- /dev/null +++ b/idhub/tests/test_tables.py @@ -0,0 +1,65 @@ +from datetime import datetime + +from django.test import TestCase +from django.urls import reverse + +from idhub_auth.models import User +from idhub.admin.tables import DashboardTable +from idhub.models import Event + + +class AdminDashboardTableTest(TestCase): + def setUp(self): + self.admin_user = User.objects.create_superuser( + email='adminuser@example.org', + password='adminpass12') + + @classmethod + def setUpTestData(cls): + # Creating test events with different dates + Event.objects.create(message='Event 1', type=1, + created=datetime(2023, 1, 3)) + Event.objects.create(message='Event 2', type=2, + created=datetime(2023, 1, 2)) + Event.objects.create(message='Event 3', type=3, + created=datetime(2023, 1, 25)) + + def test_sorting_by_date(self): + # Create the table + table = DashboardTable(Event.objects.all()) + + # Apply sorting + table.order_by = 'created' + + # Fetch the sorted records + sorted_records = list(table.rows) + + # Verify the order is as expected + self.assertTrue(sorted_records[0].record.created + < sorted_records[1].record.created) + self.assertTrue(sorted_records[1].record.created + < sorted_records[2].record.created) + + def test_table_in_template(self): + self.client.login(email='adminuser@example.org', password='adminpass12') + response = self.client.get(reverse('idhub:admin_dashboard')) + + self.assertTemplateUsed(response, 'idhub/custom_table.html') + + def test_table_data(self): + Event.objects.create(message="test_event", type=2) + Event.objects.create(message="test_event", type=9) + + table = DashboardTable(Event.objects.all()) + self.assertTrue(isinstance(table, DashboardTable)) + self.assertEqual(len(table.rows), Event.objects.count()) + + def test_table_columns(self): + table = DashboardTable(Event.objects.all()) + expected_columns = ['type', 'message', 'created'] + for column in expected_columns: + self.assertIn(column, table.columns) + + def test_pagination(self): + # TODO + pass diff --git a/idhub/tests/test_templates.py b/idhub/tests/test_templates.py new file mode 100644 index 0000000..c1b8f3c --- /dev/null +++ b/idhub/tests/test_templates.py @@ -0,0 +1,18 @@ +from django.urls import reverse +from django.test import Client, TestCase + +from idhub_auth.models import User + + +class TemplateTest(TestCase): + def setUp(self): + self.client = Client() + self.admin_user = User.objects.create_superuser( + email='adminuser@example.org', + password='adminpass12') + + def test_dashboard_template(self): + self.client.login(email='adminuser@example.org', password='adminpass12') + response = self.client.get(reverse('idhub:admin_dashboard')) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'idhub/base_admin.html') diff --git a/idhub/tests/test_views.py b/idhub/tests/test_views.py new file mode 100644 index 0000000..cb9bbd5 --- /dev/null +++ b/idhub/tests/test_views.py @@ -0,0 +1,50 @@ +from django.urls import reverse +from django.test import TestCase + +from idhub_auth.models import User + + +class AdminDashboardViewTest(TestCase): + + def setUp(self): + self.user = User.objects.create_user(email='normaluser@example.org', + password='testpass12') + self.admin_user = User.objects.create_superuser( + email='adminuser@example.org', + password='adminpass12') + + def test_view_url_exists_at_desired_location(self): + response = self.client.get('/admin/dashboard/', follow=True) + + self.assertEqual(response.status_code, 200) + + def test_view_redirects_to_login_when_not_authenticated(self): + response = self.client.get(reverse("idhub:admin_dashboard"), + follow=True) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'auth/login.html') + + def test_view_redirects_on_incorrect_login_attempt(self): + self.client.login(email='adminuser@example.org', password='wrongpass') + response = self.client.get(reverse('idhub:admin_dashboard')) + + self.assertEqual(response.status_code, 302) + + def test_view_redirects_to_login_on_incorrect_login_attempt(self): + self.client.login(email='adminuser@example.org', password='wrongpass') + response = self.client.get(reverse('idhub:admin_dashboard'), + follow=True) + + self.assertTemplateUsed(response, 'auth/login.html') + + def test_login_admin_user(self): + self.client.login(email='adminuser@example.org', password='adminpass12') + response = self.client.get(reverse('idhub:admin_dashboard')) + + self.assertEqual(response.status_code, 200) + + def test_view_uses_correct_template(self): + self.client.login(email='adminuser@example.org', password='adminpass12') + response = self.client.get(reverse('idhub:admin_dashboard')) + + self.assertTemplateUsed(response, 'idhub/admin/dashboard.html') diff --git a/requirements.txt b/requirements.txt index 83aea96..f009565 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,7 @@ django==4.2.5 django-bootstrap5==23.3 django-extensions==3.2.3 +django-tables2==2.6.0 black==23.9.1 python-decouple==3.8 jsonschema==4.19.1 diff --git a/trustchain_idhub/settings.py b/trustchain_idhub/settings.py index df36198..4d90de7 100644 --- a/trustchain_idhub/settings.py +++ b/trustchain_idhub/settings.py @@ -70,6 +70,7 @@ INSTALLED_APPS = [ 'django.contrib.staticfiles', 'django_extensions', 'django_bootstrap5', + 'django_tables2', 'idhub_auth', 'oidc4vp', 'idhub'