feat: Send confirmation email to trust giver

This commit is contained in:
aldrin 2021-10-22 10:36:11 +02:00
parent 2ebb0b7ee4
commit 0d3e1e3891
5 changed files with 65 additions and 16 deletions

View file

@ -1,8 +1,8 @@
from djeveric.emails import ConfirmationEmail from djeveric.emails import ConfirmationEmail
class ConfidantConfirmationEmail(ConfirmationEmail): class TrustBridgeConfirmationEmail(ConfirmationEmail):
subject = "TODO" subject = "TODO"
def get_message(self, context): def get_body(self, context: dict[str]) -> str:
return '"token": "{token}", "uid": "{uid}", "rtid": "{rtid}", "rid": "{rid}"'.format(**context) return "{token}".format(**context)

View file

@ -1,3 +1,4 @@
from django.conf import settings
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
from django.contrib.auth.models import PermissionsMixin from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.validators import UnicodeUsernameValidator from django.contrib.auth.validators import UnicodeUsernameValidator
@ -5,8 +6,11 @@ from django.core.mail import send_mail
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from djeveric.fields import ConfirmationField
from djeveric.models import ConfirmableModelMixin
from userausfall import ldap from userausfall import ldap
from userausfall.emails import TrustBridgeConfirmationEmail
class MissingUserAttribute(Exception): class MissingUserAttribute(Exception):
@ -98,13 +102,24 @@ class User(PermissionsMixin, AbstractBaseUser):
return ldap.create_account(self.username, raw_password) return ldap.create_account(self.username, raw_password)
def get_or_create_trust_bridge(self): def get_or_create_trust_bridge(self):
"""Returns a trust bridge instance. If it doesn't exist it is created."""
try: try:
return self.trust_bridge return self.trust_bridge
except TrustBridge.DoesNotExist: except TrustBridge.DoesNotExist:
return TrustBridge.objects.create(trust_taker=self) return TrustBridge.objects.create(trust_taker=self)
def get_primary_email(self):
"""Returns the primary email address for this user."""
return f"{self.username}@{settings.USERAUSFALL['PRIMARY_EMAIL_DOMAIN']}"
class TrustBridge(models.Model):
is_trusted = models.BooleanField(default=False) class TrustBridge(ConfirmableModelMixin, models.Model):
is_trusted = ConfirmationField(email_class=TrustBridgeConfirmationEmail)
trust_giver = models.ForeignKey("User", on_delete=models.SET_NULL, null=True) trust_giver = models.ForeignKey("User", on_delete=models.SET_NULL, null=True)
trust_taker = models.OneToOneField("User", on_delete=models.CASCADE, related_name="trust_bridge") trust_taker = models.OneToOneField("User", on_delete=models.CASCADE, related_name="trust_bridge")
def get_confirmation_email_recipient(self) -> str:
return self.trust_giver.get_primary_email()
def _has_confirmation_recipient(self):
return self.trust_giver is not None

View file

@ -1,10 +1,25 @@
from rest_framework import serializers from rest_framework import serializers
from userausfall.models import TrustBridge from userausfall.models import TrustBridge, User
class TrustBridgeSerializer(serializers.ModelSerializer): class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ["username"]
# the UniqueValidator for username prevents successful validation for existing users
extra_kwargs = {"username": {"validators": []}}
class TrustBridgeSerializer(serializers.HyperlinkedModelSerializer):
trust_giver = UserSerializer()
class Meta: class Meta:
model = TrustBridge model = TrustBridge
fields = ["is_trusted", "trust_giver"] fields = ["is_trusted", "trust_giver"]
read_only_fields = ["is_trusted"] read_only_fields = ["is_trusted"]
def update(self, instance: TrustBridge, validated_data):
instance.trust_giver, _ = User.objects.get_or_create(username=validated_data["trust_giver"]["username"])
instance.save()
return instance

View file

@ -1,3 +1,4 @@
from django.core import mail
from rest_framework import status from rest_framework import status
from userausfall.rest_api.tests import UserausfallAPITestCase from userausfall.rest_api.tests import UserausfallAPITestCase
@ -6,9 +7,7 @@ from userausfall.tests import UserMixin
class TrustBridgeTestCase(UserMixin, UserausfallAPITestCase): class TrustBridgeTestCase(UserMixin, UserausfallAPITestCase):
def test_retrieve_trust_bridge(self): def test_retrieve_trust_bridge(self):
""" """Retrieve the trust bridge information of a user without an ldap account."""
Retrieve the trust bridge information of a user without an ldap account.
"""
url = "/trust-bridge/" url = "/trust-bridge/"
self.authenticate_user() self.authenticate_user()
response = self.client.get(self.get_api_url(url)) response = self.client.get(self.get_api_url(url))
@ -22,13 +21,29 @@ class TrustBridgeTestCase(UserMixin, UserausfallAPITestCase):
) )
def test_update_trust_bridge(self): def test_update_trust_bridge(self):
""" """Update the trust giver of the user's trust bridge."""
Update the trust giver of the user's trust bridge.
"""
url = "/trust-bridge/" url = "/trust-bridge/"
other_user = self.create_user() trust_giver = self.create_user()
self.create_user() self.create_user()
self.authenticate_user() self.authenticate_user()
response = self.client.put(self.get_api_url(url), {"trust_giver": other_user.pk}) response = self.client.put(
self.get_api_url(url),
{
"trust_giver": {
"username": trust_giver.username,
},
},
)
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(self.user.trust_bridge.trust_giver, other_user) self.assertEqual(self.user.trust_bridge.trust_giver, trust_giver)
def test_set_trust_giver(self):
"""When setting a trust giver a confirmation email is sent."""
self.trust_giver = self.create_user()
self.create_user()
trust_bridge = self.user.get_or_create_trust_bridge()
trust_bridge.trust_giver = self.trust_giver
trust_bridge.save()
self.assertEqual(len(mail.outbox), 1)
self.assertIn(self.user.trust_bridge.get_confirmation_token(), mail.outbox[0].body)

View file

@ -200,3 +200,7 @@ USERAUSFALL_LDAP = {
"ADMIN_USER_DN": "cn=admin,dc=local", "ADMIN_USER_DN": "cn=admin,dc=local",
"ADMIN_USER_PASSWORD": os.environ.get("USERAUSFALL_LDAP_PASSWORD"), "ADMIN_USER_PASSWORD": os.environ.get("USERAUSFALL_LDAP_PASSWORD"),
} }
USERAUSFALL = {
"PRIMARY_EMAIL_DOMAIN": "systemausfall.org",
}