Only allow users matching the team invite to accept, if the invite was specified for a user (rather than an email)
This commit is contained in:
parent
c5ca46a14b
commit
10faa7de84
7 changed files with 24 additions and 21 deletions
|
@ -1988,6 +1988,12 @@ def delete_team_invite(code, user=None):
|
||||||
def confirm_team_invite(code, user):
|
def confirm_team_invite(code, user):
|
||||||
found = lookup_team_invite(code)
|
found = lookup_team_invite(code)
|
||||||
|
|
||||||
|
# If the invite is for a specific user, we have to confirm that here.
|
||||||
|
if found.user is not None and found.user != user:
|
||||||
|
message = """This invite is intended for user "%s".
|
||||||
|
Please login to that account and try again.""" % found.user.username
|
||||||
|
raise DataModelException(message)
|
||||||
|
|
||||||
# Add the user to the team.
|
# Add the user to the team.
|
||||||
try:
|
try:
|
||||||
add_user_to_team(user, found.team)
|
add_user_to_team(user, found.team)
|
||||||
|
|
|
@ -11,10 +11,7 @@ from util.useremails import send_org_invite_email
|
||||||
from util.gravatar import compute_hash
|
from util.gravatar import compute_hash
|
||||||
|
|
||||||
def try_accept_invite(code, user):
|
def try_accept_invite(code, user):
|
||||||
try:
|
(team, inviter) = model.confirm_team_invite(code, user)
|
||||||
(team, inviter) = model.confirm_team_invite(code, user)
|
|
||||||
except model.DataModelException:
|
|
||||||
return None
|
|
||||||
|
|
||||||
model.delete_matching_notifications(user, 'org_team_invite', code=code)
|
model.delete_matching_notifications(user, 'org_team_invite', code=code)
|
||||||
|
|
||||||
|
@ -355,10 +352,7 @@ class TeamMemberInvite(ApiResource):
|
||||||
@require_user_admin
|
@require_user_admin
|
||||||
def delete(self, code):
|
def delete(self, code):
|
||||||
""" Delete an existing member of a team. """
|
""" Delete an existing member of a team. """
|
||||||
try:
|
(team, inviter) = model.delete_team_invite(code, get_authenticated_user())
|
||||||
(team, inviter) = model.delete_team_invite(code, get_authenticated_user())
|
|
||||||
except model.DataModelException:
|
|
||||||
raise NotFound()
|
|
||||||
|
|
||||||
model.delete_matching_notifications(get_authenticated_user(), 'org_team_invite', code=code)
|
model.delete_matching_notifications(get_authenticated_user(), 'org_team_invite', code=code)
|
||||||
|
|
||||||
|
|
|
@ -215,7 +215,10 @@ class User(ApiResource):
|
||||||
if parsed_invite is not None:
|
if parsed_invite is not None:
|
||||||
if parsed_invite[0] == 'teaminvite':
|
if parsed_invite[0] == 'teaminvite':
|
||||||
# Add the user to the team.
|
# Add the user to the team.
|
||||||
try_accept_invite(invite_code, new_user)
|
try:
|
||||||
|
try_accept_invite(invite_code, new_user)
|
||||||
|
except model.DataModelException:
|
||||||
|
pass
|
||||||
|
|
||||||
return 'Created', 201
|
return 'Created', 201
|
||||||
except model.TooManyUsersException as ex:
|
except model.TooManyUsersException as ex:
|
||||||
|
|
|
@ -2785,9 +2785,9 @@ function ConfirmInviteCtrl($scope, $location, UserService, ApiService, Notificat
|
||||||
ApiService.acceptOrganizationTeamInvite(null, params).then(function(resp) {
|
ApiService.acceptOrganizationTeamInvite(null, params).then(function(resp) {
|
||||||
NotificationService.update();
|
NotificationService.update();
|
||||||
$location.path('/organization/' + resp.org + '/teams/' + resp.team);
|
$location.path('/organization/' + resp.org + '/teams/' + resp.team);
|
||||||
}, function() {
|
}, function(resp) {
|
||||||
$scope.loading = false;
|
$scope.loading = false;
|
||||||
$scope.invalid = true;
|
$scope.invalid = ApiService.getErrorMessage(resp, 'Invalid confirmation code');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="quay-spinner" ng-show="!user.anonymous && loading"></div>
|
<div class="quay-spinner" ng-show="!user.anonymous && loading"></div>
|
||||||
<div class="alert alert-danger" ng-show="!user.anonymous && invalid">
|
<div class="alert alert-danger" ng-show="!user.anonymous && invalid">
|
||||||
Invalid confirmation code
|
{{ invalid }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3518,25 +3518,25 @@ class TestTeamMemberInvite(ApiTestCase):
|
||||||
self._run_test('PUT', 401, None, None)
|
self._run_test('PUT', 401, None, None)
|
||||||
|
|
||||||
def test_put_freshuser(self):
|
def test_put_freshuser(self):
|
||||||
self._run_test('PUT', 404, 'freshuser', None)
|
self._run_test('PUT', 400, 'freshuser', None)
|
||||||
|
|
||||||
def test_put_reader(self):
|
def test_put_reader(self):
|
||||||
self._run_test('PUT', 404, 'reader', None)
|
self._run_test('PUT', 400, 'reader', None)
|
||||||
|
|
||||||
def test_put_devtable(self):
|
def test_put_devtable(self):
|
||||||
self._run_test('PUT', 404, 'devtable', None)
|
self._run_test('PUT', 400, 'devtable', None)
|
||||||
|
|
||||||
def test_delete_anonymous(self):
|
def test_delete_anonymous(self):
|
||||||
self._run_test('DELETE', 401, None, None)
|
self._run_test('DELETE', 401, None, None)
|
||||||
|
|
||||||
def test_delete_freshuser(self):
|
def test_delete_freshuser(self):
|
||||||
self._run_test('DELETE', 404, 'freshuser', None)
|
self._run_test('DELETE', 400, 'freshuser', None)
|
||||||
|
|
||||||
def test_delete_reader(self):
|
def test_delete_reader(self):
|
||||||
self._run_test('DELETE', 404, 'reader', None)
|
self._run_test('DELETE', 400, 'reader', None)
|
||||||
|
|
||||||
def test_delete_devtable(self):
|
def test_delete_devtable(self):
|
||||||
self._run_test('DELETE', 404, 'devtable', None)
|
self._run_test('DELETE', 400, 'devtable', None)
|
||||||
|
|
||||||
|
|
||||||
class TestSuperUserList(ApiTestCase):
|
class TestSuperUserList(ApiTestCase):
|
||||||
|
|
|
@ -891,7 +891,7 @@ class TestAcceptTeamMemberInvite(ApiTestCase):
|
||||||
# Verify the accept now fails.
|
# Verify the accept now fails.
|
||||||
self.putResponse(TeamMemberInvite,
|
self.putResponse(TeamMemberInvite,
|
||||||
params=dict(code=invites[0].invite_token),
|
params=dict(code=invites[0].invite_token),
|
||||||
expected_code=404)
|
expected_code=400)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -914,7 +914,7 @@ class TestDeclineTeamMemberInvite(ApiTestCase):
|
||||||
|
|
||||||
self.deleteResponse(TeamMemberInvite,
|
self.deleteResponse(TeamMemberInvite,
|
||||||
params=dict(code=invites[0].invite_token),
|
params=dict(code=invites[0].invite_token),
|
||||||
expected_code=404)
|
expected_code=400)
|
||||||
|
|
||||||
|
|
||||||
def test_decline(self):
|
def test_decline(self):
|
||||||
|
@ -942,7 +942,7 @@ class TestDeclineTeamMemberInvite(ApiTestCase):
|
||||||
# Make sure the invite was deleted.
|
# Make sure the invite was deleted.
|
||||||
self.deleteResponse(TeamMemberInvite,
|
self.deleteResponse(TeamMemberInvite,
|
||||||
params=dict(code=invites[0].invite_token),
|
params=dict(code=invites[0].invite_token),
|
||||||
expected_code=404)
|
expected_code=400)
|
||||||
|
|
||||||
|
|
||||||
class TestDeleteOrganizationTeamMember(ApiTestCase):
|
class TestDeleteOrganizationTeamMember(ApiTestCase):
|
||||||
|
|
Reference in a new issue