feat: Add api endpoints for activation/ user attrs
This commit is contained in:
parent
d75ae86409
commit
2bc9b5ba85
4 changed files with 106 additions and 47 deletions
37
userausfall/migrations/0006_auto_20210521_0805.py
Normal file
37
userausfall/migrations/0006_auto_20210521_0805.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
# Generated by Django 2.2.20 on 2021-05-21 08:05
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('userausfall', '0005_delete_accountrequest'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='user',
|
||||
name='first_name',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='user',
|
||||
name='is_active',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='user',
|
||||
name='last_name',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='confidant_unconfirmed',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='unconfirmed_confidants', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='confidant',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='confidants', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
|
@ -11,11 +11,13 @@ from userausfall import ldap
|
|||
|
||||
class MissingUserAttribute(Exception):
|
||||
"""The user object is missing a required attribute."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class PasswordMismatch(Exception):
|
||||
"""The given password does not match the user's password."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -34,18 +36,18 @@ class UserManager(BaseUserManager):
|
|||
return user
|
||||
|
||||
def create_user(self, email, password=None, **extra_fields):
|
||||
extra_fields.setdefault('is_staff', False)
|
||||
extra_fields.setdefault('is_superuser', False)
|
||||
extra_fields.setdefault("is_staff", False)
|
||||
extra_fields.setdefault("is_superuser", False)
|
||||
return self._create_user(email, password, **extra_fields)
|
||||
|
||||
def create_superuser(self, email, password, **extra_fields):
|
||||
extra_fields.setdefault('is_staff', True)
|
||||
extra_fields.setdefault('is_superuser', True)
|
||||
extra_fields.setdefault("is_staff", True)
|
||||
extra_fields.setdefault("is_superuser", True)
|
||||
|
||||
if extra_fields.get('is_staff') is not True:
|
||||
raise ValueError('Superuser must have is_staff=True.')
|
||||
if extra_fields.get('is_superuser') is not True:
|
||||
raise ValueError('Superuser must have is_superuser=True.')
|
||||
if extra_fields.get("is_staff") is not True:
|
||||
raise ValueError("Superuser must have is_staff=True.")
|
||||
if extra_fields.get("is_superuser") is not True:
|
||||
raise ValueError("Superuser must have is_superuser=True.")
|
||||
|
||||
return self._create_user(email, password, **extra_fields)
|
||||
|
||||
|
@ -54,41 +56,53 @@ class User(AbstractBaseUser, PermissionsMixin):
|
|||
username_validator = UnicodeUsernameValidator()
|
||||
|
||||
username = models.CharField(
|
||||
_('username'),
|
||||
_("username"),
|
||||
max_length=150,
|
||||
help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
|
||||
help_text=_(
|
||||
"Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only."
|
||||
),
|
||||
validators=[username_validator],
|
||||
error_messages={
|
||||
'unique': _("A user with that username already exists."),
|
||||
},
|
||||
error_messages={"unique": _("A user with that username already exists.")},
|
||||
blank=True,
|
||||
)
|
||||
email = models.EmailField(_('email address'), unique=True, blank=True)
|
||||
email = models.EmailField(_("email address"), unique=True, blank=True)
|
||||
is_staff = models.BooleanField(
|
||||
_('staff status'),
|
||||
_("staff status"),
|
||||
default=False,
|
||||
help_text=_('Designates whether the user can log into this admin site.'),
|
||||
help_text=_("Designates whether the user can log into this admin site."),
|
||||
)
|
||||
date_joined = models.DateTimeField(_("date joined"), default=timezone.now)
|
||||
confidant = models.ForeignKey(
|
||||
"User", on_delete=models.SET_NULL, null=True, related_name="confidants"
|
||||
)
|
||||
confidant_unconfirmed = models.ForeignKey(
|
||||
"User",
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
related_name="unconfirmed_confidants",
|
||||
)
|
||||
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
|
||||
confidant = models.ForeignKey("User", on_delete=models.SET_NULL, null=True)
|
||||
|
||||
objects = UserManager()
|
||||
|
||||
EMAIL_FIELD = 'email'
|
||||
USERNAME_FIELD = 'email'
|
||||
EMAIL_FIELD = "email"
|
||||
USERNAME_FIELD = "email"
|
||||
REQUIRED_FIELDS = []
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('user')
|
||||
verbose_name_plural = _('users')
|
||||
verbose_name = _("user")
|
||||
verbose_name_plural = _("users")
|
||||
|
||||
@property
|
||||
def confidant_email(self):
|
||||
if self.confidant is not None:
|
||||
return self.confidant.email
|
||||
else:
|
||||
return None
|
||||
|
||||
def clean(self):
|
||||
super().clean()
|
||||
self.email = self.__class__.objects.normalize_email(self.email)
|
||||
|
||||
def get_confidant_email(self):
|
||||
return ""
|
||||
|
||||
def email_user(self, subject, message, from_email=None, **kwargs):
|
||||
"""Send an email to this user."""
|
||||
send_mail(subject, message, from_email, [self.email], **kwargs)
|
||||
|
@ -100,5 +114,7 @@ class User(AbstractBaseUser, PermissionsMixin):
|
|||
if not self.confidant:
|
||||
raise MissingUserAttribute("User is missing a confirmed confidant.")
|
||||
if not self.check_password(raw_password):
|
||||
raise PasswordMismatch("The given password does not match the user's password.")
|
||||
raise PasswordMismatch(
|
||||
"The given password does not match the user's password."
|
||||
)
|
||||
return ldap.create_account(self.username, raw_password)
|
||||
|
|
|
@ -3,17 +3,17 @@ from rest_framework import serializers
|
|||
from userausfall.models import User
|
||||
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
confidant_email = serializers.EmailField(source="get_confidant_email")
|
||||
class UserActivationSerializer(serializers.Serializer):
|
||||
password = serializers.CharField()
|
||||
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ("email", "username", "confidant_email")
|
||||
fields = ("pk", "email", "username", "confidant_email")
|
||||
|
||||
def get_confidant_email(self):
|
||||
return ""
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
print(validated_data)
|
||||
confidant = validated_data.pop("get_confidant_email")
|
||||
def update(self, instance: User, validated_data):
|
||||
confidant_email = validated_data.pop("confidant_email")
|
||||
confidant, _ = User.objects.get_or_create(email=confidant_email)
|
||||
instance.confidant_unconfirmed = confidant
|
||||
return super().update(instance, validated_data)
|
||||
|
|
|
@ -1,19 +1,25 @@
|
|||
from rest_framework import viewsets
|
||||
from rest_framework import viewsets, status
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
|
||||
from userausfall.models import User
|
||||
from userausfall.rest_api.serializers import UserSerializer
|
||||
from userausfall.models import User, MissingUserAttribute, PasswordMismatch
|
||||
from userausfall.rest_api.serializers import UserSerializer, UserActivationSerializer
|
||||
|
||||
|
||||
class UserViewSet(viewsets.ModelViewSet):
|
||||
class Meta:
|
||||
queryset = User.objects.all()
|
||||
queryset = User.objects.all()
|
||||
serializer_class = UserSerializer
|
||||
|
||||
@action(detail=False, methods=["PATCH"])
|
||||
def me(self, request):
|
||||
return Response(
|
||||
UserSerializer(
|
||||
instance=request.user, context={"request": request}
|
||||
).data
|
||||
)
|
||||
@action(detail=True, methods=["post"])
|
||||
def activate(self, request, pk=None):
|
||||
"""Create the corresponding LDAP account."""
|
||||
user: User = self.get_object()
|
||||
serializer = UserActivationSerializer(data=request.data)
|
||||
if serializer.is_valid():
|
||||
try:
|
||||
user.create_ldap_account(serializer.validated_data["password"])
|
||||
except (MissingUserAttribute, PasswordMismatch) as e:
|
||||
return Response({"message": str(e)}, status=status.HTTP_400_BAD_REQUEST)
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
else:
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
|
Reference in a new issue