Merge pull request #2066 from coreos-inc/select-username

Add support for temp usernames and an interstitial to confirm username
This commit is contained in:
josephschorr 2016-11-03 16:22:16 -04:00 committed by GitHub
commit 233b2be5c2
18 changed files with 388 additions and 24 deletions

View file

@ -372,6 +372,22 @@ class User(BaseModel):
Namespace = User.alias()
class UserPromptKind(BaseModel):
name = CharField(index=True)
class UserPrompt(BaseModel):
user = QuayUserField(allows_robots=False, index=True)
kind = ForeignKeyField(UserPromptKind)
class Meta:
database = db
read_slaves = (read_slave,)
indexes = (
(('user', 'kind'), True),
)
class TeamRole(BaseModel):
name = CharField(index=True)

View file

@ -0,0 +1,47 @@
"""Add user prompt support
Revision ID: 6c7014e84a5e
Revises: c156deb8845d
Create Date: 2016-10-31 16:26:31.447705
"""
# revision identifiers, used by Alembic.
revision = '6c7014e84a5e'
down_revision = 'c156deb8845d'
from alembic import op
import sqlalchemy as sa
def upgrade(tables):
### commands auto generated by Alembic - please adjust! ###
op.create_table('userpromptkind',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=255), nullable=False),
sa.PrimaryKeyConstraint('id', name=op.f('pk_userpromptkind'))
)
op.create_index('userpromptkind_name', 'userpromptkind', ['name'], unique=False)
op.create_table('userprompt',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column('kind_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['kind_id'], ['userpromptkind.id'], name=op.f('fk_userprompt_kind_id_userpromptkind')),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], name=op.f('fk_userprompt_user_id_user')),
sa.PrimaryKeyConstraint('id', name=op.f('pk_userprompt'))
)
op.create_index('userprompt_kind_id', 'userprompt', ['kind_id'], unique=False)
op.create_index('userprompt_user_id', 'userprompt', ['user_id'], unique=False)
op.create_index('userprompt_user_id_kind_id', 'userprompt', ['user_id', 'kind_id'], unique=True)
### end Alembic commands ###
op.bulk_insert(tables.userpromptkind,
[
{'name':'confirm_username'},
])
def downgrade(tables):
### commands auto generated by Alembic - please adjust! ###
op.drop_table('userprompt')
op.drop_table('userpromptkind')
### end Alembic commands ###

View file

@ -11,7 +11,8 @@ from data.database import (User, LoginService, FederatedLogin, RepositoryPermiss
Team, Repository, TupleSelector, TeamRole, Namespace, Visibility,
EmailConfirmation, Role, db_for_update, random_string_generator,
UserRegion, ImageStorageLocation, QueueItem, TeamMemberInvite,
ServiceKeyApproval, OAuthApplication, RepositoryBuildTrigger)
ServiceKeyApproval, OAuthApplication, RepositoryBuildTrigger,
UserPromptKind, UserPrompt)
from data.model import (DataModelException, InvalidPasswordException, InvalidRobotException,
InvalidUsernameException, InvalidEmailAddressException,
TooManyLoginAttemptsException, db_transaction,
@ -102,6 +103,38 @@ def change_password(user, new_password):
notification.delete_notifications_by_kind(user, 'password_required')
def has_user_prompts(user):
try:
UserPrompt.select().where(UserPrompt.user == user).get()
return True
except UserPrompt.DoesNotExist:
return False
def has_user_prompt(user, prompt_name):
prompt_kind = UserPromptKind.get(name=prompt_name)
try:
UserPrompt.get(user=user, kind=prompt_kind)
return True
except UserPrompt.DoesNotExist:
return False
def create_user_prompt(user, prompt_name):
prompt_kind = UserPromptKind.get(name=prompt_name)
return UserPrompt.create(user=user, kind=prompt_kind)
def remove_user_prompt(user, prompt_name):
prompt_kind = UserPromptKind.get(name=prompt_name)
UserPrompt.delete().where(UserPrompt.user == user, UserPrompt.kind == prompt_kind).execute()
def get_user_prompts(user):
query = UserPrompt.select().where(UserPrompt.user == user).join(UserPromptKind)
return [prompt.kind.name for prompt in query]
def change_username(user_id, new_username):
(username_valid, username_issue) = validate_username(new_username)
if not username_valid:
@ -121,6 +154,10 @@ def change_username(user_id, new_username):
# Rename the user
user.username = new_username
user.save()
# Remove any prompts for username.
remove_user_prompt(user, 'confirm_username')
return user
@ -305,11 +342,15 @@ def list_entity_robot_permission_teams(entity_name, include_permissions=False):
def create_federated_user(username, email, service_name, service_ident,
set_password_notification, metadata={}, email_required=True):
set_password_notification, metadata={},
email_required=True, confirm_username=False):
new_user = create_user_noverify(username, email, email_required=email_required)
new_user.verified = True
new_user.save()
if confirm_username:
create_user_prompt(new_user, 'confirm_username')
service = LoginService.get(LoginService.name == service_name)
FederatedLogin.create(user=new_user, service=service,
service_ident=service_ident,

View file

@ -52,7 +52,8 @@ class FederatedUsers(object):
db_user = model.user.create_federated_user(valid_username, email, self._federated_service,
username,
set_password_notification=False,
email_required=self._requires_email)
email_required=self._requires_email,
confirm_username=True)
else:
# Update the db attributes from the federated service.
if email: