Support invite codes for verification of email
Also changes the system so we don't apply the invite until it is called explicitly from the frontend Fixes #241
This commit is contained in:
parent
5d86fa80e7
commit
687bab1c05
7 changed files with 3185 additions and 35 deletions
|
@ -19,7 +19,7 @@ from endpoints.api import (ApiResource, nickname, resource, validate_json_reques
|
|||
from endpoints.api.subscribe import subscribe
|
||||
from endpoints.common import common_login
|
||||
from endpoints.decorators import anon_allowed
|
||||
from endpoints.api.team import try_accept_invite
|
||||
|
||||
from data import model
|
||||
from data.billing import get_plan
|
||||
from auth.permissions import (AdministerOrganizationPermission, CreateRepositoryPermission,
|
||||
|
@ -33,6 +33,33 @@ from util.names import parse_single_urn
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def handle_invite_code(invite_code, user):
|
||||
""" Checks that the given invite code matches the specified user's e-mail address. If so, the
|
||||
user is marked as having a verified e-mail address and this method returns True.
|
||||
"""
|
||||
parsed_invite = parse_single_urn(invite_code)
|
||||
if parsed_invite is None:
|
||||
return False
|
||||
|
||||
if parsed_invite[0] != 'teaminvite':
|
||||
return False
|
||||
|
||||
# Check to see if the team invite is valid. If so, then we know the user has
|
||||
# a possible matching email address.
|
||||
try:
|
||||
found = model.team.find_matching_team_invite(invite_code, user)
|
||||
except model.DataModelException:
|
||||
return False
|
||||
|
||||
# Since we sent the invite code via email, mark the user as having a verified
|
||||
# email address.
|
||||
if found.email != user.email:
|
||||
return False
|
||||
|
||||
user.verified = True
|
||||
user.save()
|
||||
return True
|
||||
|
||||
|
||||
def user_view(user):
|
||||
def org_view(o):
|
||||
|
@ -105,7 +132,6 @@ class User(ApiResource):
|
|||
""" Operations related to users. """
|
||||
schemas = {
|
||||
'NewUser': {
|
||||
|
||||
'id': 'NewUser',
|
||||
'type': 'object',
|
||||
'description': 'Fields which must be specified for a new user.',
|
||||
|
@ -299,18 +325,8 @@ class User(ApiResource):
|
|||
new_user = model.user.create_user(user_data['username'], user_data['password'],
|
||||
user_data['email'], auto_verify=not features.MAILING)
|
||||
|
||||
# Handle any invite codes.
|
||||
parsed_invite = parse_single_urn(invite_code)
|
||||
if parsed_invite is not None:
|
||||
if parsed_invite[0] == 'teaminvite':
|
||||
# Add the user to the team.
|
||||
try:
|
||||
try_accept_invite(invite_code, new_user)
|
||||
except model.user.DataModelException:
|
||||
pass
|
||||
|
||||
|
||||
if features.MAILING:
|
||||
email_address_confirmed = handle_invite_code(invite_code, new_user)
|
||||
if features.MAILING and not email_address_confirmed:
|
||||
code = model.user.create_confirm_email_code(new_user)
|
||||
send_confirmation_email(new_user.username, new_user.email, code.code)
|
||||
return {
|
||||
|
@ -389,18 +405,23 @@ class ClientKey(ApiResource):
|
|||
}
|
||||
|
||||
|
||||
def conduct_signin(username_or_email, password):
|
||||
def conduct_signin(username_or_email, password, invite_code=None):
|
||||
needs_email_verification = False
|
||||
invalid_credentials = False
|
||||
found_user = None
|
||||
|
||||
verified = None
|
||||
try:
|
||||
(verified, error_message) = authentication.verify_and_link_user(username_or_email, password)
|
||||
(found_user, error_message) = authentication.verify_and_link_user(username_or_email, password)
|
||||
except model.user.TooManyUsersException as ex:
|
||||
raise license_error(exception=ex)
|
||||
|
||||
if verified:
|
||||
if common_login(verified):
|
||||
# If there is an attached invitation code, handle it here. This will mark the
|
||||
# user as verified if the code is valid.
|
||||
if invite_code:
|
||||
handle_invite_code(invite_code, found_user)
|
||||
|
||||
if found_user:
|
||||
if common_login(found_user):
|
||||
return {'success': True}
|
||||
else:
|
||||
needs_email_verification = True
|
||||
|
@ -501,6 +522,10 @@ class Signin(ApiResource):
|
|||
'type': 'string',
|
||||
'description': 'The user\'s password',
|
||||
},
|
||||
'invite_code': {
|
||||
'type': 'string',
|
||||
'description': 'The optional invite code'
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -516,8 +541,9 @@ class Signin(ApiResource):
|
|||
|
||||
username = signin_data['username']
|
||||
password = signin_data['password']
|
||||
invite_code = signin_data.get('invite_code', '')
|
||||
|
||||
return conduct_signin(username, password)
|
||||
return conduct_signin(username, password, invite_code=invite_code)
|
||||
|
||||
|
||||
@resource('/v1/signin/verify')
|
||||
|
|
Reference in a new issue