From 8d3ce446828dbda89215e44df9597629bd2d262e Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Thu, 11 Sep 2014 15:45:41 -0400 Subject: [PATCH] Address comments on code review --- data/database.py | 4 +- endpoints/api/team.py | 31 ++++++++---- endpoints/api/user.py | 17 ++++++- static/directives/signup-form.html | 2 +- static/directives/team-view-add.html | 2 +- static/directives/user-setup.html | 2 +- static/js/app.js | 50 ++++++++++++++++++- static/js/controllers.js | 5 +- ...m-team-invite.html => confirm-invite.html} | 6 ++- static/partials/team-view.html | 7 +-- test/test_api_usage.py | 36 ++++++++++--- util/names.py | 21 ++++++++ 12 files changed, 150 insertions(+), 33 deletions(-) rename static/partials/{confirm-team-invite.html => confirm-invite.html} (79%) diff --git a/data/database.py b/data/database.py index 5736ff611..72c2c3e30 100644 --- a/data/database.py +++ b/data/database.py @@ -8,7 +8,7 @@ from peewee import * from data.read_slave import ReadSlaveModel from sqlalchemy.engine.url import make_url from urlparse import urlparse - +from util.names import urn_generator logger = logging.getLogger(__name__) @@ -116,7 +116,7 @@ class TeamMemberInvite(BaseModel): email = CharField(null=True) team = ForeignKeyField(Team, index=True) inviter = ForeignKeyField(User, related_name='inviter') - invite_token = CharField(default=uuid_generator) + invite_token = CharField(default=urn_generator(['teaminvite'])) class LoginService(BaseModel): diff --git a/endpoints/api/team.py b/endpoints/api/team.py index 3a99b591b..24243f911 100644 --- a/endpoints/api/team.py +++ b/endpoints/api/team.py @@ -10,6 +10,24 @@ from data import model from util.useremails import send_org_invite_email from util.gravatar import compute_hash +def try_accept_invite(code, user): + try: + (team, inviter) = model.confirm_team_invite(code, user) + except model.DataModelException: + return None + + model.delete_matching_notifications(user, 'org_team_invite', code=code) + + orgname = team.organization.username + log_action('org_team_member_invite_accepted', orgname, { + 'member': user.username, + 'team': team.name, + 'inviter': inviter.username + }) + + return team + + def handle_addinvite_team(inviter, team, user=None, email=None): invite = model.add_or_invite_to_team(inviter, team, user, email) if not invite: @@ -323,20 +341,11 @@ class TeamMemberInvite(ApiResource): def put(self, code): """ Accepts an invite to join a team in an organization. """ # Accept the invite for the current user. - try: - (team, inviter) = model.confirm_team_invite(code, get_authenticated_user()) - except model.DataModelException: + team = try_accept_invite(code, get_authenticated_user()) + if not team: raise NotFound() - model.delete_matching_notifications(get_authenticated_user(), 'org_team_invite', code=code) - orgname = team.organization.username - log_action('org_team_member_invite_accepted', orgname, { - 'member': get_authenticated_user().username, - 'team': team.name, - 'inviter': inviter.username - }) - return { 'org': orgname, 'team': team.name diff --git a/endpoints/api/user.py b/endpoints/api/user.py index e2e6a0ff4..cf8f05eae 100644 --- a/endpoints/api/user.py +++ b/endpoints/api/user.py @@ -12,6 +12,8 @@ from endpoints.api import (ApiResource, nickname, resource, validate_json_reques license_error) from endpoints.api.subscribe import subscribe from endpoints.common import common_login +from endpoints.api.team import try_accept_invite + from data import model from data.billing import get_plan from auth.permissions import (AdministerOrganizationPermission, CreateRepositoryPermission, @@ -20,6 +22,7 @@ from auth.auth_context import get_authenticated_user from auth import scopes from util.gravatar import compute_hash from util.useremails import (send_confirmation_email, send_recovery_email, send_change_email) +from util.names import parse_single_urn import features @@ -179,11 +182,15 @@ class User(ApiResource): return user_view(user) @nickname('createNewUser') + @parse_args + @query_param('inviteCode', 'Invitation code given for creating the user.', type=str, + default='') @internal_only @validate_json_request('NewUser') - def post(self): + def post(self, args): """ Create a new user. """ user_data = request.get_json() + invite_code = args['inviteCode'] existing_user = model.get_user(user_data['username']) if existing_user: @@ -194,6 +201,14 @@ class User(ApiResource): user_data['email']) code = model.create_confirm_email_code(new_user) send_confirmation_email(new_user.username, new_user.email, code.code) + + # 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_accept_invite(invite_code, new_user) + return 'Created', 201 except model.TooManyUsersException as ex: raise license_error(exception=ex) diff --git a/static/directives/signup-form.html b/static/directives/signup-form.html index e6bd400b4..4947a966e 100644 --- a/static/directives/signup-form.html +++ b/static/directives/signup-form.html @@ -1,5 +1,5 @@
-