From 7581bf59dfc08d7c9cad45686d8ae8f0475d5ce6 Mon Sep 17 00:00:00 2001 From: Tom Hubrecht Date: Fri, 13 Sep 2024 16:55:44 +0200 Subject: [PATCH] feat(models): Add a Profile model This simplifies the management of the views data --- src/dgsi/migrations/0001_initial.py | 37 +++++++++++++++++++++++ src/dgsi/models.py | 30 ++++++++++++++++++ src/dgsi/views.py | 37 ++++++----------------- src/shared/templates/account/profile.html | 10 +++--- 4 files changed, 82 insertions(+), 32 deletions(-) create mode 100644 src/dgsi/migrations/0001_initial.py diff --git a/src/dgsi/migrations/0001_initial.py b/src/dgsi/migrations/0001_initial.py new file mode 100644 index 0000000..1a56d02 --- /dev/null +++ b/src/dgsi/migrations/0001_initial.py @@ -0,0 +1,37 @@ +# Generated by Django 4.2.12 on 2024-09-13 14:30 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="Profile", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "user", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + ), + ] diff --git a/src/dgsi/models.py b/src/dgsi/models.py index 6b20219..6d3491f 100644 --- a/src/dgsi/models.py +++ b/src/dgsi/models.py @@ -1 +1,31 @@ # Create your models here. + +from dataclasses import dataclass +from functools import cached_property +from typing import Optional + +from asgiref.sync import async_to_sync +from django.contrib.auth.models import User +from django.db import models +from kanidm.models.person import Person + +from shared.kanidm import client + + +@dataclass +class KanidmProfile: + person: Person + secret: Optional[str] + + +class Profile(models.Model): + user = models.OneToOneField(User, on_delete=models.CASCADE) + + @cached_property + def kanidm_profile(self): + person = async_to_sync(client.person_account_get)(self.user.username) + data = async_to_sync(client.get_radius_token)(self.user.username).data + + secret = data.get("secret") if data is not None else None + + return KanidmProfile(person, secret) diff --git a/src/dgsi/views.py b/src/dgsi/views.py index 2277922..786a36b 100644 --- a/src/dgsi/views.py +++ b/src/dgsi/views.py @@ -1,35 +1,18 @@ -# Create your views here. -import json -from typing import Optional - -from asgiref.sync import async_to_sync -from django.contrib.auth import get_user_model from django.contrib.auth.mixins import LoginRequiredMixin -from django.db.models import QuerySet -from django.views.generic import DetailView - -from shared.kanidm import client - -User = get_user_model() +from django.contrib.auth.models import User +from django.views.generic import TemplateView -class ProfileView(LoginRequiredMixin, DetailView): +class ProfileView(LoginRequiredMixin, TemplateView): model = User template_name = "account/profile.html" - def get_object(self, queryset: Optional[QuerySet] = None): + def get_context_data(self, **kwargs): assert isinstance(self.request.user, User) - return self.request.user - - def get_context_data(self, **kwargs): - ctx = super().get_context_data(**kwargs) - - username = self.request.user.get_username() - - ctx["person"] = async_to_sync(client.person_account_get)(username) - - content: str = async_to_sync(client.get_radius_token)(username).content - - ctx["radius_secret"] = json.loads(content).get("secret") - return ctx + return super().get_context_data( + # Pyright throws a fit as it doesn't detect the reverse relation + # giving a user its profile + profile=self.request.user.profile.kanidm_profile, # pyright: ignore + **kwargs + ) diff --git a/src/shared/templates/account/profile.html b/src/shared/templates/account/profile.html index fdbd01c..cb3bf13 100644 --- a/src/shared/templates/account/profile.html +++ b/src/shared/templates/account/profile.html @@ -2,24 +2,24 @@ {% block content %}

- Profil de {{ person.displayname }} - {{ person.name }} + Profil de {{ profile.person.displayname }} + {{ profile.person.name }}


Identifiant unique :

- {{ person.uuid }} + {{ profile.person.uuid }}

Token RADIUS :

- {{ radius_secret }} + {{ profile.secret }}

Membre des groupes suivants :

- {% for group in person.memberof %} + {% for group in profile.person.memberof %} {{ group }}
{% endfor %} {% endblock content %}