diff --git a/idhub/models.py b/idhub/models.py index 83dd90a..b5c91e6 100644 --- a/idhub/models.py +++ b/idhub/models.py @@ -489,6 +489,7 @@ class VerificableCredential(models.Model): issued_on = models.DateTimeField(null=True) data = models.TextField() csv_data = models.TextField() + description = models.TextField(null=True) status = models.PositiveSmallIntegerField( choices=Status.choices, default=Status.ENABLED @@ -518,7 +519,8 @@ class VerificableCredential(models.Model): def type(self): return self.schema.type - def description(self): + @property + def get_description(self): for des in json.loads(self.render()).get('description', []): if settings.LANGUAGE_CODE == des.get('lang'): return des.get('value', '') diff --git a/idhub/templates/idhub/user/credentials.html b/idhub/templates/idhub/user/credentials.html index 6f68e56..fcb0378 100644 --- a/idhub/templates/idhub/user/credentials.html +++ b/idhub/templates/idhub/user/credentials.html @@ -1,39 +1,11 @@ {% extends "idhub/base.html" %} {% load i18n %} +{% load render_table from django_tables2 %} {% block content %}

{{ subtitle }}

-
-
-
- - - - - - - - - - - - {% for f in credentials.all %} - - - - - - - - {% endfor %} - -
{{ f.type }}{{ f.description }}{{ f.get_issued_on }}{{ f.get_status }} - -
-
-
-
+{% render_table table %} {% endblock %} diff --git a/idhub/templates/idhub/user/dids.html b/idhub/templates/idhub/user/dids.html index 28177e2..dc3bfc4 100644 --- a/idhub/templates/idhub/user/dids.html +++ b/idhub/templates/idhub/user/dids.html @@ -1,41 +1,15 @@ {% extends "idhub/base.html" %} {% load i18n %} +{% load render_table from django_tables2 %} {% block content %}

{{ subtitle }}

-
-
-
- - - - - - - - - - - - {% for d in dids.all %} - - - - - - - - {% endfor %} - -
{{ d.created_at }}{{ d.label }}{{ d.did }}
- -
-
+{% render_table table %} +
+ {% translate "Add Identity" %}
{% for d in dids.all %} diff --git a/idhub/templates/idhub/user/profile.html b/idhub/templates/idhub/user/profile.html index 3a5d5f3..6efdc48 100644 --- a/idhub/templates/idhub/user/profile.html +++ b/idhub/templates/idhub/user/profile.html @@ -1,5 +1,6 @@ {% extends "idhub/base.html" %} {% load i18n %} +{% load render_table from django_tables2 %} {% block content %}
@@ -33,33 +34,6 @@ {% bootstrap_form form %}
+{% render_table table %} -
-
-
- - - - - - - - - - - {% for membership in object.memberships.all %} - - - - - - - {% endfor %} - -
{{ membership.get_type }}{{ membership.start_date|default:'' }}{{ membership.end_date|default:'' }} - -
-
-
-
{% endblock %} diff --git a/idhub/templates/idhub/user/roles.html b/idhub/templates/idhub/user/roles.html index 2c32e97..22777ee 100644 --- a/idhub/templates/idhub/user/roles.html +++ b/idhub/templates/idhub/user/roles.html @@ -1,35 +1,12 @@ {% extends "idhub/base.html" %} {% load i18n %} +{% load render_table from django_tables2 %} {% block content %}

{{ subtitle }}

-
-
-
- - - - - - - - - - {% for rol in user.roles.all %} - - - - - - {% endfor %} - -
{{ rol.service.get_roles }}{{ rol.service.description }}{{ rol.service.domain }}
-
-
-
-
+{% render_table table %} {% endblock %} diff --git a/idhub/user/forms.py b/idhub/user/forms.py index 5ac04ad..f39b102 100644 --- a/idhub/user/forms.py +++ b/idhub/user/forms.py @@ -2,20 +2,12 @@ import requests from django import forms from django.conf import settings from django.utils.translation import gettext_lazy as _ +from idhub.models import DID, VerificableCredential, Organization from idhub_auth.models import User from idhub.models import DID, VerificableCredential from oidc4vp.models import Organization - -class ProfileForm(forms.ModelForm): - MANDATORY_FIELDS = ['first_name', 'last_name', 'email'] - - class Meta: - model = User - fields = ('first_name', 'last_name', 'email') - - class RequestCredentialForm(forms.Form): did = forms.ChoiceField(label=_("Did"), choices=[]) credential = forms.ChoiceField(label=_("Credential"), choices=[]) diff --git a/idhub/user/tables.py b/idhub/user/tables.py index 0331bd6..cf90d33 100644 --- a/idhub/user/tables.py +++ b/idhub/user/tables.py @@ -1,5 +1,21 @@ +from django.utils.html import format_html import django_tables2 as tables -from idhub.models import Event +from idhub.models import Event, Membership, UserRol, DID, VerificableCredential + + +class ButtonColumn(tables.Column): + attrs = { + "a": { + "type": "button", + "class": "text-primary", + } + } + # it makes no sense to order a column of buttons + orderable = False + # django_tables will only call the render function if it doesn't find + # any empty values in the data, so we stop it from matching the data + # to any value considered empty + empty_values = () class DashboardTable(tables.Table): @@ -11,3 +27,97 @@ class DashboardTable(tables.Table): model = Event template_name = "idhub/custom_table.html" fields = ("type", "message", "created") + + +class PersonalInfoTable(tables.Table): + type = tables.Column(verbose_name="Membership") + credential = ButtonColumn( + # TODO: See where this should actually link + linkify="idhub:user_credentials", + orderable=False + ) + + def render_credential(self): + return format_html('') + + class Meta: + model = Membership + template_name = "idhub/custom_table.html" + fields = ("type", "start_date", "end_date", "credential") + + +class RolesTable(tables.Table): + name = tables.Column(verbose_name="Role", empty_values=()) + description = tables.Column(empty_values=()) + service = tables.Column() + + def render_name(self, record): + return record.service.get_roles() + + def render_description(self, record): + return record.service.description + + def render_service(self, record): + return record.service.domain + + def order_name(self, queryset, is_descending): + queryset = queryset.order_by( + ("-" if is_descending else "") + "service__rol__name" + ) + + return (queryset, True) + + def order_description(self, queryset, is_descending): + queryset = queryset.order_by( + ("-" if is_descending else "") + "service__rol__description" + ) + + return (queryset, True) + + class Meta: + model = UserRol + template_name = "idhub/custom_table.html" + fields = ("name", "description", "service") + + +class DIDTable(tables.Table): + created_at = tables.Column(verbose_name="Date") + did = tables.Column(verbose_name="ID") + edit = ButtonColumn( + linkify={ + "viewname": "idhub:user_dids_edit", + "args": [tables.A("pk")] + }, + orderable=False + ) + delete_template_code = """""" + delete = tables.TemplateColumn(template_code=delete_template_code, + orderable=False) + + def render_edit(self): + return format_html('') + + class Meta: + model = DID + template_name = "idhub/custom_table.html" + fields = ("created_at", "label", "did", "edit", "delete") + + +class CredentialsTable(tables.Table): + description = tables.Column(verbose_name="Details") + + def render_description(self, record): + return record.get_description() + + def render_status(self, record): + return record.get_status() + + class Meta: + model = VerificableCredential + template_name = "idhub/custom_table.html" + fields = ("type", "description", "issued_on", "status") diff --git a/idhub/user/views.py b/idhub/user/views.py index 042bc10..c5c2752 100644 --- a/idhub/user/views.py +++ b/idhub/user/views.py @@ -15,14 +15,18 @@ from django.contrib import messages from django_tables2 import SingleTableView from idhub.user.tables import ( DashboardTable, + PersonalInfoTable, + RolesTable, + DIDTable, + CredentialsTable ) from idhub.user.forms import ( - ProfileForm, RequestCredentialForm, CredentialPresentationForm ) from idhub.mixins import UserView -from idhub.models import DID, VerificableCredential, Event +from idhub.models import DID, VerificableCredential, Event, Membership +from idhub_auth.models import User class MyProfile(UserView): @@ -50,13 +54,20 @@ class DashboardView(UserView, SingleTableView): return queryset -class ProfileView(MyProfile, UpdateView): +class ProfileView(MyProfile, UpdateView, SingleTableView): template_name = "idhub/user/profile.html" + table_class = PersonalInfoTable subtitle = _('My personal data') icon = 'bi bi-person-gear' - from_class = ProfileForm fields = ('first_name', 'last_name', 'email') success_url = reverse_lazy('idhub:user_profile') + model = User + + def get_queryset(self, **kwargs): + queryset = Membership.objects.select_related('user').filter( + user=self.request.user) + + return queryset def get_object(self): return self.request.user @@ -72,11 +83,17 @@ class ProfileView(MyProfile, UpdateView): return super().form_valid(form) -class RolesView(MyProfile, TemplateView): +class RolesView(MyProfile, SingleTableView): template_name = "idhub/user/roles.html" + table_class = RolesTable subtitle = _('My roles') icon = 'fa-brands fa-critical-role' + def get_queryset(self, **kwargs): + queryset = self.request.user.roles.all() + + return queryset + class GDPRView(MyProfile, TemplateView): template_name = "idhub/user/gdpr.html" @@ -84,8 +101,9 @@ class GDPRView(MyProfile, TemplateView): icon = 'bi bi-file-earmark-medical' -class CredentialsView(MyWallet, TemplateView): +class CredentialsView(MyWallet, SingleTableView): template_name = "idhub/user/credentials.html" + table_class = CredentialsTable subtitle = _('Credential management') icon = 'bi bi-patch-check-fill' @@ -99,6 +117,12 @@ class CredentialsView(MyWallet, TemplateView): }) return context + def get_queryset(self): + queryset = VerificableCredential.objects.filter( + user=self.request.user) + + return queryset + class CredentialView(MyWallet, TemplateView): template_name = "idhub/user/credential.html" @@ -191,8 +215,9 @@ class DemandAuthorizationView(MyWallet, FormView): return super().form_valid(form) -class DidsView(MyWallet, TemplateView): +class DidsView(MyWallet, SingleTableView): template_name = "idhub/user/dids.html" + table_class = DIDTable subtitle = _('Identities (DIDs)') icon = 'bi bi-patch-check-fill' @@ -203,6 +228,11 @@ class DidsView(MyWallet, TemplateView): }) return context + def get_queryset(self, **kwargs): + queryset = DID.objects.filter(user=self.request.user) + + return queryset + class DidRegisterView(MyWallet, CreateView): template_name = "idhub/user/did_register.html"