api: manage verified attributes (fixes #28962)

This commit is contained in:
Benjamin Dauvergne 2018-12-14 00:07:23 +01:00
parent 7d2840d4a4
commit 5cb0cb54c3
3 changed files with 98 additions and 5 deletions

View File

@ -363,6 +363,8 @@ class BaseUserSerializer(serializers.ModelSerializer):
kwargs):
kwargs['allow_blank'] = True
self.fields[at.name] = field_class(**kwargs)
self.fields[at.name + '_verified'] = serializers.BooleanField(
source='is_verified.%s' % at.name, required=False)
for key in self.fields:
if key in app_settings.A2_REQUIRED_FIELDS:
self.fields[key].required = True
@ -383,10 +385,18 @@ class BaseUserSerializer(serializers.ModelSerializer):
force_password_reset = validated_data.pop('force_password_reset', False)
attributes = validated_data.pop('attributes', {})
is_verified = validated_data.pop('is_verified', {})
self.check_perm('custom_user.add_user', validated_data.get('ou'))
instance = super(BaseUserSerializer, self).create(validated_data)
for key, value in attributes.iteritems():
setattr(instance.attributes, key, value)
if is_verified.get(key):
setattr(instance.verified_attributes, key, value)
else:
setattr(instance.attributes, key, value)
if is_verified.get('first_name'):
instance.verified_attributes.first_name = instance.first_name
if is_verified.get('last_name'):
instance.verified_attributes.last_name = instance.last_name
if 'password' in validated_data:
instance.set_password(validated_data['password'])
instance.save()
@ -414,13 +424,27 @@ class BaseUserSerializer(serializers.ModelSerializer):
validated_data.pop('send_registration_email', False)
validated_data.pop('send_registration_email_next_url', None)
attributes = validated_data.pop('attributes', {})
is_verified = validated_data.pop('is_verified', {})
# Double check: to move an user from one ou into another you must be administrator of both
self.check_perm('custom_user.change_user', instance.ou)
if 'ou' in validated_data:
self.check_perm('custom_user.change_user', validated_data.get('ou'))
super(BaseUserSerializer, self).update(instance, validated_data)
for key, value in attributes.iteritems():
setattr(instance.attributes, key, value)
if is_verified.get(key):
setattr(instance.verified_attributes, key, value)
else:
setattr(instance.attributes, key, value)
for key in is_verified:
if key not in attributes:
if is_verified.get(key):
setattr(instance.verified_attributes, key, getattr(instance.attributes, key))
else:
setattr(instance.attributes, key, getattr(instance.attributes, key))
if is_verified.get('first_name'):
instance.verified_attributes.first_name = instance.first_name
if is_verified.get('last_name'):
instance.verified_attributes.last_name = instance.last_name
if 'password' in validated_data:
instance.set_password(validated_data['password'])
instance.save()

View File

@ -36,6 +36,8 @@ class Attributes(object):
values = {}
super(Attributes, self).__setattr__('values', values)
for atv in self.owner.attribute_values.all():
if verified and not atv.verified:
continue
try:
attribute = at_map[atv.attribute_id]
except KeyError:
@ -73,6 +75,23 @@ class AttributesDescriptor(object):
return getattr(obj, cache_name)
class IsVerified(object):
def __init__(self, user):
self.user = user
def __getattr__(self, name):
v = getattr(self.user.attributes, name, None)
return (
v is not None and
v == getattr(self.user.verified_attributes, name, None)
)
class IsVerifiedDescriptor(object):
def __get__(self, obj, objtype):
return IsVerified(obj)
class User(AbstractBaseUser, PermissionMixin):
"""
An abstract base class implementing a fully featured User model with
@ -111,6 +130,7 @@ class User(AbstractBaseUser, PermissionMixin):
objects = UserManager.from_queryset(UserQuerySet)()
attributes = AttributesDescriptor()
verified_attributes = AttributesDescriptor(verified=True)
is_verified = IsVerifiedDescriptor()
attribute_values = GenericRelation('authentic2.AttributeValue')

View File

@ -249,9 +249,11 @@ def test_api_users_create(settings, app, api_user):
resp = app.post_json('/api/users/', params=payload, status=status)
if api_user.is_superuser or api_user.roles.exists():
assert set(['ou', 'id', 'uuid', 'is_staff', 'is_superuser', 'first_name', 'last_name',
'date_joined', 'last_login', 'username', 'password', 'email', 'is_active',
'title', 'modified', 'email_verified']) == set(resp.json.keys())
assert set(['ou', 'id', 'uuid', 'is_staff', 'is_superuser',
'first_name', 'first_name_verified', 'last_name',
'last_name_verified', 'date_joined', 'last_login',
'username', 'password', 'email', 'is_active', 'title',
'title_verified', 'modified', 'email_verified']) == set(resp.json.keys())
assert resp.json['first_name'] == payload['first_name']
assert resp.json['last_name'] == payload['last_name']
assert resp.json['email'] == payload['email']
@ -260,6 +262,9 @@ def test_api_users_create(settings, app, api_user):
assert resp.json['uuid']
assert resp.json['id']
assert resp.json['date_joined']
assert not resp.json['first_name_verified']
assert not resp.json['last_name_verified']
assert not resp.json['title_verified']
if api_user.is_superuser:
assert resp.json['ou'] == 'default'
elif api_user.roles.exists():
@ -271,6 +276,7 @@ def test_api_users_create(settings, app, api_user):
assert new_user.first_name == resp.json['first_name']
assert new_user.last_name == resp.json['last_name']
assert AttributeValue.objects.with_owner(new_user).count() == 3
assert AttributeValue.objects.with_owner(new_user).filter(verified=True).count() == 0
assert AttributeValue.objects.with_owner(new_user).filter(attribute=at).exists()
assert (AttributeValue.objects.with_owner(new_user).get(attribute=at).content ==
payload['title'])
@ -286,6 +292,49 @@ def test_api_users_create(settings, app, api_user):
resp = app.get('/api/users/1234567890/')
assert 'title' not in resp.json
at.disabled = False
at.save()
payload = {
'username': 'john.doe2',
'first_name': 'John',
'first_name_verified': True,
'last_name': 'Doe',
'last_name_verified': True,
'email': 'john.doe@example.net',
'password': 'password',
'title': 'Mr',
'title_verified': True,
}
if api_user.is_superuser:
status = 201
elif api_user.roles.exists():
status = 201
payload['ou'] = api_user.ou.slug
else:
status = 403
resp = app.post_json('/api/users/', params=payload, status=status)
if api_user.is_superuser or api_user.roles.exists():
assert set(['ou', 'id', 'uuid', 'is_staff', 'is_superuser',
'first_name', 'first_name_verified', 'last_name',
'last_name_verified', 'date_joined', 'last_login',
'username', 'password', 'email', 'is_active', 'title',
'title_verified', 'modified', 'email_verified']) == set(resp.json.keys())
user = get_user_model().objects.get(pk=resp.json['id'])
assert AttributeValue.objects.with_owner(user).filter(verified=True).count() == 3
assert AttributeValue.objects.with_owner(user).filter(verified=False).count() == 0
assert user.verified_attributes.first_name == 'John'
assert user.verified_attributes.last_name == 'Doe'
assert user.verified_attributes.title == 'Mr'
assert resp.json['first_name_verified']
assert resp.json['last_name_verified']
assert resp.json['title_verified']
resp2 = app.patch_json('/api/users/%s/' % resp.json['uuid'],
params={'title_verified': False})
assert resp.json['first_name_verified']
assert resp.json['last_name_verified']
assert not resp2.json['title_verified']
def test_api_users_create_email_is_unique(settings, app, superuser):
from django.contrib.auth import get_user_model