api: manage verified attributes (fixes #28962)
This commit is contained in:
parent
7d2840d4a4
commit
5cb0cb54c3
|
@ -363,6 +363,8 @@ class BaseUserSerializer(serializers.ModelSerializer):
|
||||||
kwargs):
|
kwargs):
|
||||||
kwargs['allow_blank'] = True
|
kwargs['allow_blank'] = True
|
||||||
self.fields[at.name] = field_class(**kwargs)
|
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:
|
for key in self.fields:
|
||||||
if key in app_settings.A2_REQUIRED_FIELDS:
|
if key in app_settings.A2_REQUIRED_FIELDS:
|
||||||
self.fields[key].required = True
|
self.fields[key].required = True
|
||||||
|
@ -383,10 +385,18 @@ class BaseUserSerializer(serializers.ModelSerializer):
|
||||||
force_password_reset = validated_data.pop('force_password_reset', False)
|
force_password_reset = validated_data.pop('force_password_reset', False)
|
||||||
|
|
||||||
attributes = validated_data.pop('attributes', {})
|
attributes = validated_data.pop('attributes', {})
|
||||||
|
is_verified = validated_data.pop('is_verified', {})
|
||||||
self.check_perm('custom_user.add_user', validated_data.get('ou'))
|
self.check_perm('custom_user.add_user', validated_data.get('ou'))
|
||||||
instance = super(BaseUserSerializer, self).create(validated_data)
|
instance = super(BaseUserSerializer, self).create(validated_data)
|
||||||
for key, value in attributes.iteritems():
|
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:
|
if 'password' in validated_data:
|
||||||
instance.set_password(validated_data['password'])
|
instance.set_password(validated_data['password'])
|
||||||
instance.save()
|
instance.save()
|
||||||
|
@ -414,13 +424,27 @@ class BaseUserSerializer(serializers.ModelSerializer):
|
||||||
validated_data.pop('send_registration_email', False)
|
validated_data.pop('send_registration_email', False)
|
||||||
validated_data.pop('send_registration_email_next_url', None)
|
validated_data.pop('send_registration_email_next_url', None)
|
||||||
attributes = validated_data.pop('attributes', {})
|
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
|
# 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)
|
self.check_perm('custom_user.change_user', instance.ou)
|
||||||
if 'ou' in validated_data:
|
if 'ou' in validated_data:
|
||||||
self.check_perm('custom_user.change_user', validated_data.get('ou'))
|
self.check_perm('custom_user.change_user', validated_data.get('ou'))
|
||||||
super(BaseUserSerializer, self).update(instance, validated_data)
|
super(BaseUserSerializer, self).update(instance, validated_data)
|
||||||
for key, value in attributes.iteritems():
|
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:
|
if 'password' in validated_data:
|
||||||
instance.set_password(validated_data['password'])
|
instance.set_password(validated_data['password'])
|
||||||
instance.save()
|
instance.save()
|
||||||
|
|
|
@ -36,6 +36,8 @@ class Attributes(object):
|
||||||
values = {}
|
values = {}
|
||||||
super(Attributes, self).__setattr__('values', values)
|
super(Attributes, self).__setattr__('values', values)
|
||||||
for atv in self.owner.attribute_values.all():
|
for atv in self.owner.attribute_values.all():
|
||||||
|
if verified and not atv.verified:
|
||||||
|
continue
|
||||||
try:
|
try:
|
||||||
attribute = at_map[atv.attribute_id]
|
attribute = at_map[atv.attribute_id]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -73,6 +75,23 @@ class AttributesDescriptor(object):
|
||||||
return getattr(obj, cache_name)
|
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):
|
class User(AbstractBaseUser, PermissionMixin):
|
||||||
"""
|
"""
|
||||||
An abstract base class implementing a fully featured User model with
|
An abstract base class implementing a fully featured User model with
|
||||||
|
@ -111,6 +130,7 @@ class User(AbstractBaseUser, PermissionMixin):
|
||||||
objects = UserManager.from_queryset(UserQuerySet)()
|
objects = UserManager.from_queryset(UserQuerySet)()
|
||||||
attributes = AttributesDescriptor()
|
attributes = AttributesDescriptor()
|
||||||
verified_attributes = AttributesDescriptor(verified=True)
|
verified_attributes = AttributesDescriptor(verified=True)
|
||||||
|
is_verified = IsVerifiedDescriptor()
|
||||||
|
|
||||||
attribute_values = GenericRelation('authentic2.AttributeValue')
|
attribute_values = GenericRelation('authentic2.AttributeValue')
|
||||||
|
|
||||||
|
|
|
@ -249,9 +249,11 @@ def test_api_users_create(settings, app, api_user):
|
||||||
|
|
||||||
resp = app.post_json('/api/users/', params=payload, status=status)
|
resp = app.post_json('/api/users/', params=payload, status=status)
|
||||||
if api_user.is_superuser or api_user.roles.exists():
|
if api_user.is_superuser or api_user.roles.exists():
|
||||||
assert set(['ou', 'id', 'uuid', 'is_staff', 'is_superuser', 'first_name', 'last_name',
|
assert set(['ou', 'id', 'uuid', 'is_staff', 'is_superuser',
|
||||||
'date_joined', 'last_login', 'username', 'password', 'email', 'is_active',
|
'first_name', 'first_name_verified', 'last_name',
|
||||||
'title', 'modified', 'email_verified']) == set(resp.json.keys())
|
'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['first_name'] == payload['first_name']
|
||||||
assert resp.json['last_name'] == payload['last_name']
|
assert resp.json['last_name'] == payload['last_name']
|
||||||
assert resp.json['email'] == payload['email']
|
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['uuid']
|
||||||
assert resp.json['id']
|
assert resp.json['id']
|
||||||
assert resp.json['date_joined']
|
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:
|
if api_user.is_superuser:
|
||||||
assert resp.json['ou'] == 'default'
|
assert resp.json['ou'] == 'default'
|
||||||
elif api_user.roles.exists():
|
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.first_name == resp.json['first_name']
|
||||||
assert new_user.last_name == resp.json['last_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).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).filter(attribute=at).exists()
|
||||||
assert (AttributeValue.objects.with_owner(new_user).get(attribute=at).content ==
|
assert (AttributeValue.objects.with_owner(new_user).get(attribute=at).content ==
|
||||||
payload['title'])
|
payload['title'])
|
||||||
|
@ -286,6 +292,49 @@ def test_api_users_create(settings, app, api_user):
|
||||||
resp = app.get('/api/users/1234567890/')
|
resp = app.get('/api/users/1234567890/')
|
||||||
assert 'title' not in resp.json
|
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):
|
def test_api_users_create_email_is_unique(settings, app, superuser):
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
|
Loading…
Reference in New Issue