ctl: always retry provisionning when detecting duplicates (#75777)
This commit is contained in:
parent
2bb316e2ed
commit
e01c6b65cc
|
@ -16,7 +16,9 @@
|
|||
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
import time
|
||||
|
||||
from quixote import get_publisher
|
||||
|
||||
|
@ -142,7 +144,6 @@ class CmdHoboNotify(Command):
|
|||
|
||||
@classmethod
|
||||
def provision_user(cls, publisher, issuer, action, data, full=False):
|
||||
formdef = UserFieldsFormDef(publisher=publisher)
|
||||
User = publisher.user_class
|
||||
|
||||
if full:
|
||||
|
@ -152,45 +153,7 @@ class CmdHoboNotify(Command):
|
|||
try:
|
||||
o = json_encode_helper(o, publisher.site_charset)
|
||||
if action == 'provision':
|
||||
if not cls.check_valid_user(o):
|
||||
raise ValueError('invalid user')
|
||||
uuid = o['uuid']
|
||||
users = User.get_users_with_name_identifier(uuid)
|
||||
if len(users) > 1:
|
||||
raise Exception('duplicate users')
|
||||
if users:
|
||||
user = users[0]
|
||||
else:
|
||||
user = User(uuid)
|
||||
user.form_data = user.form_data or {}
|
||||
for field in formdef.fields:
|
||||
if not field.id.startswith('_'):
|
||||
continue
|
||||
field_value = o.get(field.id[1:])
|
||||
if field.convert_value_from_anything:
|
||||
try:
|
||||
field_value = field.convert_value_from_anything(field_value)
|
||||
except ValueError as e:
|
||||
publisher.record_error(exception=e, context='[PROVISIONNING]', notify=True)
|
||||
continue
|
||||
user.form_data[field.id] = field_value
|
||||
user.name_identifiers = [uuid]
|
||||
# reset roles
|
||||
user.is_active = o.get('is_active', True)
|
||||
user.is_admin = o.get('is_superuser', False)
|
||||
user.roles = []
|
||||
for role_ref in o.get('roles', []):
|
||||
role = get_publisher().role_class.resolve(role_ref['uuid'])
|
||||
if role and role.id not in user.roles:
|
||||
user.add_roles([role.id])
|
||||
user.set_attributes_from_formdata(user.form_data)
|
||||
user.store()
|
||||
# verify we did not produce a doublon
|
||||
users = User.get_users_with_name_identifier(uuid)
|
||||
for doublon in users:
|
||||
if int(doublon.id) < int(user.id): # we are not the first so backoff
|
||||
user.remove_self()
|
||||
break
|
||||
cls.create_or_update_user(publisher, o)
|
||||
elif action == 'deprovision':
|
||||
if 'uuid' not in o:
|
||||
raise KeyError('user without uuid')
|
||||
|
@ -200,5 +163,54 @@ class CmdHoboNotify(Command):
|
|||
except Exception as e:
|
||||
publisher.record_error(exception=e, context='[PROVISIONNING]', notify=True)
|
||||
|
||||
@classmethod
|
||||
def create_or_update_user(cls, publisher, o, retry=0):
|
||||
User = publisher.user_class
|
||||
formdef = UserFieldsFormDef(publisher=publisher)
|
||||
|
||||
if retry > 3:
|
||||
raise Exception('user provisionning failed after %s tries.' % retry)
|
||||
if retry > 0:
|
||||
time.sleep(random.random() * 2 * retry)
|
||||
|
||||
if not cls.check_valid_user(o):
|
||||
raise ValueError('invalid user')
|
||||
uuid = o['uuid']
|
||||
users = User.get_users_with_name_identifier(uuid)
|
||||
if len(users) > 1:
|
||||
raise Exception('duplicate users')
|
||||
if users:
|
||||
user = users[0]
|
||||
else:
|
||||
user = User(uuid)
|
||||
user.form_data = user.form_data or {}
|
||||
for field in formdef.fields:
|
||||
if not field.id.startswith('_'):
|
||||
continue
|
||||
field_value = o.get(field.id[1:])
|
||||
if field.convert_value_from_anything:
|
||||
try:
|
||||
field_value = field.convert_value_from_anything(field_value)
|
||||
except ValueError as e:
|
||||
publisher.record_error(exception=e, context='[PROVISIONNING]', notify=True)
|
||||
continue
|
||||
user.form_data[field.id] = field_value
|
||||
user.name_identifiers = [uuid]
|
||||
# reset roles
|
||||
user.is_active = o.get('is_active', True)
|
||||
user.is_admin = o.get('is_superuser', False)
|
||||
user.roles = []
|
||||
for role_ref in o.get('roles', []):
|
||||
role = get_publisher().role_class.resolve(role_ref['uuid'])
|
||||
if role and role.id not in user.roles:
|
||||
user.add_roles([role.id])
|
||||
user.set_attributes_from_formdata(user.form_data)
|
||||
user.store()
|
||||
# verify we did not produce a doublon
|
||||
users = User.get_users_with_name_identifier(uuid)
|
||||
if len(users) > 1:
|
||||
user.remove_self()
|
||||
cls.create_or_update_user(publisher, o, retry=retry + 1)
|
||||
|
||||
|
||||
CmdHoboNotify.register()
|
||||
|
|
Loading…
Reference in New Issue