Add support for temp usernames and an interstitial to confirm username
When a user now logs in for the first time for any external auth (LDAP, JWT, Keystone, Github, Google, Dex), they will be presented with a confirmation screen that affords them the opportunity to change their Quay-assigned username. Addresses most of the user issues around #74
This commit is contained in:
parent
840ea4e768
commit
1e3b354201
18 changed files with 388 additions and 24 deletions
|
@ -66,7 +66,7 @@ def handle_invite_code(invite_code, user):
|
|||
return True
|
||||
|
||||
|
||||
def user_view(user):
|
||||
def user_view(user, previous_username=None):
|
||||
def org_view(o, user_admin=True):
|
||||
admin_org = AdministerOrganizationPermission(o.username)
|
||||
org_response = {
|
||||
|
@ -105,7 +105,7 @@ def user_view(user):
|
|||
'avatar': avatar.get_data_for_user(user),
|
||||
}
|
||||
|
||||
user_admin = UserAdminPermission(user.username)
|
||||
user_admin = UserAdminPermission(previous_username if previous_username else user.username)
|
||||
if user_admin.can():
|
||||
user_response.update({
|
||||
'can_create_repo': True,
|
||||
|
@ -117,6 +117,7 @@ def user_view(user):
|
|||
'invoice_email_address': user.invoice_email_address,
|
||||
'preferred_namespace': not (user.stripe_id is None),
|
||||
'tag_expiration': user.removed_tag_expiration_s,
|
||||
'prompts': model.user.get_user_prompts(user),
|
||||
})
|
||||
|
||||
analytics_metadata = user_analytics.get_user_analytics_metadata(user)
|
||||
|
@ -217,7 +218,7 @@ class User(ApiResource):
|
|||
'UserView': {
|
||||
'type': 'object',
|
||||
'description': 'Describes a user',
|
||||
'required': ['verified', 'anonymous', 'avatar'],
|
||||
'required': ['anonymous', 'avatar'],
|
||||
'properties': {
|
||||
'verified': {
|
||||
'type': 'boolean',
|
||||
|
@ -283,6 +284,7 @@ class User(ApiResource):
|
|||
""" Update a users details such as password or email. """
|
||||
user = get_authenticated_user()
|
||||
user_data = request.get_json()
|
||||
previous_username = None
|
||||
|
||||
try:
|
||||
if 'password' in user_data:
|
||||
|
@ -324,19 +326,29 @@ class User(ApiResource):
|
|||
else:
|
||||
model.user.update_email(user, new_email, auto_verify=not features.MAILING)
|
||||
|
||||
if ('username' in user_data and user_data['username'] != user.username and
|
||||
features.USER_RENAME):
|
||||
new_username = user_data['username']
|
||||
if model.user.get_user_or_org(new_username) is not None:
|
||||
# Username already used
|
||||
raise request_error(message='Username is already in use')
|
||||
# Check for username rename. A username can be renamed if the feature is enabled OR the user
|
||||
# currently has a confirm_username prompt.
|
||||
if 'username' in user_data:
|
||||
confirm_username = model.user.has_user_prompt(user, 'confirm_username')
|
||||
new_username = user_data.get('username')
|
||||
previous_username = user.username
|
||||
|
||||
model.user.change_username(user.id, new_username)
|
||||
rename_allowed = features.USER_RENAME or confirm_username
|
||||
username_changing = new_username and new_username != previous_username
|
||||
|
||||
if rename_allowed and username_changing:
|
||||
if model.user.get_user_or_org(new_username) is not None:
|
||||
# Username already used.
|
||||
raise request_error(message='Username is already in use')
|
||||
|
||||
user = model.user.change_username(user.id, new_username)
|
||||
elif confirm_username:
|
||||
model.user.remove_user_prompt(user, 'confirm_username')
|
||||
|
||||
except model.user.InvalidPasswordException, ex:
|
||||
raise request_error(exception=ex)
|
||||
|
||||
return user_view(user)
|
||||
return user_view(user, previous_username=previous_username)
|
||||
|
||||
@show_if(features.USER_CREATION)
|
||||
@show_if(features.DIRECT_LOGIN)
|
||||
|
|
|
@ -37,11 +37,11 @@ def get_user(service, token):
|
|||
'access_token': token,
|
||||
'alt': 'json',
|
||||
}
|
||||
get_user = client.get(service.user_endpoint(), params=token_param)
|
||||
if get_user.status_code != requests.codes.ok:
|
||||
got_user = client.get(service.user_endpoint(), params=token_param)
|
||||
if got_user.status_code != requests.codes.ok:
|
||||
return {}
|
||||
|
||||
return get_user.json()
|
||||
return got_user.json()
|
||||
|
||||
|
||||
def conduct_oauth_login(service, user_id, username, email, metadata={}):
|
||||
|
@ -65,7 +65,7 @@ def conduct_oauth_login(service, user_id, username, email, metadata={}):
|
|||
|
||||
to_login = model.user.create_federated_user(new_username, email, service_name.lower(),
|
||||
user_id, set_password_notification=True,
|
||||
metadata=metadata)
|
||||
metadata=metadata, confirm_username=True)
|
||||
|
||||
# Success, tell analytics
|
||||
analytics.track(to_login.username, 'register', {'service': service_name.lower()})
|
||||
|
@ -75,7 +75,7 @@ def conduct_oauth_login(service, user_id, username, email, metadata={}):
|
|||
logger.debug('Aliasing with state: %s', state)
|
||||
analytics.alias(to_login.username, state)
|
||||
|
||||
except model.InvalidEmailAddressException as ieex:
|
||||
except model.InvalidEmailAddressException:
|
||||
message = "The e-mail address %s is already associated " % (email, )
|
||||
message = message + "with an existing %s account." % (app.config['REGISTRY_TITLE_SHORT'], )
|
||||
message = message + "\nPlease log in with your username and password and "
|
||||
|
@ -87,7 +87,10 @@ def conduct_oauth_login(service, user_id, username, email, metadata={}):
|
|||
return render_ologin_error(service_name, ex.message)
|
||||
|
||||
if common_login(to_login):
|
||||
return redirect(url_for('web.index'))
|
||||
if model.user.has_user_prompts(to_login):
|
||||
return redirect(url_for('web.updateuser'))
|
||||
else:
|
||||
return redirect(url_for('web.index'))
|
||||
|
||||
return render_ologin_error(service_name)
|
||||
|
||||
|
|
|
@ -170,6 +170,12 @@ def new():
|
|||
return index('')
|
||||
|
||||
|
||||
@web.route('/updateuser')
|
||||
@no_cache
|
||||
def updateuser():
|
||||
return index('')
|
||||
|
||||
|
||||
@web.route('/confirminvite')
|
||||
@no_cache
|
||||
def confirm_invite():
|
||||
|
|
Reference in a new issue