diff --git a/lms/djangoapps/teams/models.py b/lms/djangoapps/teams/models.py index 694afe3b5f..6e2a4f012e 100644 --- a/lms/djangoapps/teams/models.py +++ b/lms/djangoapps/teams/models.py @@ -70,7 +70,7 @@ class CourseTeam(models.Model): """Adds the given user to the CourseTeam.""" if not CourseEnrollment.is_enrolled(user, self.course_id): raise NotEnrolledInCourseForTeam - if CourseTeamMembership.objects.filter(user=user, team__course_id=self.course_id).exists(): + if CourseTeamMembership.user_in_team_for_course(user, self.course_id): raise AlreadyOnTeamInCourse return CourseTeamMembership.objects.create( user=user, @@ -108,3 +108,18 @@ class CourseTeamMembership(models.Model): queryset = queryset.filter(team__team_id=team_id) return queryset + + @classmethod + def user_in_team_for_course(cls, user, course_id): + """ + Checks whether or not a user is already in a team in the given course. + + Args: + user: the user that we want to query on + course_id: the course_id of the course we're interested in + + Returns: + True if the user is on a team in the course already + False if not + """ + return cls.objects.filter(user=user, team__course_id=course_id).exists() diff --git a/lms/djangoapps/teams/static/teams/js/spec/views/edit_team_spec.js b/lms/djangoapps/teams/static/teams/js/spec/views/edit_team_spec.js index 253bcebf41..ec4d37b28f 100644 --- a/lms/djangoapps/teams/static/teams/js/spec/views/edit_team_spec.js +++ b/lms/djangoapps/teams/static/teams/js/spec/views/edit_team_spec.js @@ -162,6 +162,25 @@ define([ expect(teamEditView.$('.wrapper-msg .copy').text().trim()).toBe("An error occurred. Please try again."); }); + it("shows correct error message when server returns an error", function () { + var requests = AjaxHelpers.requests(this); + + teamEditView.$('.u-field-name input').val(teamsData.name); + teamEditView.$('.u-field-textarea textarea').val(teamsData.description); + + teamEditView.$('.create-team.form-actions .action-primary').click(); + teamsData.country = ''; + teamsData.language = ''; + AjaxHelpers.expectJsonRequest(requests, 'POST', teamsUrl, teamsData); + AjaxHelpers.respondWithError( + requests, + 400, + {'error_message': {'user_message': 'User message', 'developer_message': 'Developer message' }} + ); + + expect(teamEditView.$('.wrapper-msg .copy').text().trim()).toBe("User message"); + }); + it("changes route on cancel click", function () { teamEditView.$('.create-team.form-actions .action-cancel').click(); expect(Backbone.history.navigate.calls[0].args).toContain('topics/awesomeness'); diff --git a/lms/djangoapps/teams/static/teams/js/views/edit_team.js b/lms/djangoapps/teams/static/teams/js/views/edit_team.js index 556cecbf38..3df0d81080 100644 --- a/lms/djangoapps/teams/static/teams/js/views/edit_team.js +++ b/lms/djangoapps/teams/static/teams/js/views/edit_team.js @@ -118,8 +118,12 @@ {trigger: true} ); }) - .fail(function() { - var message = gettext('An error occurred. Please try again.'); + .fail(function(data) { + var response = JSON.parse(data.responseText); + var message = gettext("An error occurred. Please try again.") + if ('error_message' in response && 'user_message' in response['error_message']){ + message = response['error_message']['user_message']; + } view.showMessage(message, message); }); }, diff --git a/lms/djangoapps/teams/tests/test_models.py b/lms/djangoapps/teams/tests/test_models.py index 885088ae4b..ee6f523517 100644 --- a/lms/djangoapps/teams/tests/test_models.py +++ b/lms/djangoapps/teams/tests/test_models.py @@ -46,3 +46,16 @@ class TeamMembershipTest(SharedModuleStoreTestCase): CourseTeamMembership.get_memberships(username=username, course_ids=course_ids, team_id=team_id).count(), expected_count ) + + @ddt.data( + ('user1', COURSE_KEY1, True), + ('user2', COURSE_KEY1, True), + ('user2', COURSE_KEY2, False), + ) + @ddt.unpack + def test_user_in_team_for_course(self, username, course_id, expected_value): + user = getattr(self, username) + self.assertEqual( + CourseTeamMembership.user_in_team_for_course(user, course_id), + expected_value + ) diff --git a/lms/djangoapps/teams/tests/test_views.py b/lms/djangoapps/teams/tests/test_views.py index bd1daded4c..b97252fadd 100644 --- a/lms/djangoapps/teams/tests/test_views.py +++ b/lms/djangoapps/teams/tests/test_views.py @@ -501,16 +501,26 @@ class TestCreateTeamAPI(TeamAPITestCase): def test_bad_course_data(self, status, data): self.post_create_team(status, data) + def test_student_in_team(self): + self.post_create_team( + 400, + { + 'course_id': str(self.test_course_1.id), + 'description': "You are already on a team in this course." + }, + user='student_enrolled' + ) + + @ddt.data({'description': ''}, {'name': 'x' * 1000}, {'name': ''}) + def test_bad_fields(self, kwargs): + self.post_create_team(400, self.build_team_data(**kwargs)) + def test_missing_name(self): self.post_create_team(400, { 'course_id': str(self.test_course_1.id), 'description': "foobar" }) - @ddt.data({'description': ''}, {'name': 'x' * 1000}, {'name': ''}) - def test_bad_fields(self, kwargs): - self.post_create_team(400, self.build_team_data(**kwargs)) - def test_full_student_creator(self): creator = self.create_and_enroll_student() team = self.post_create_team(data=self.build_team_data( diff --git a/lms/djangoapps/teams/views.py b/lms/djangoapps/teams/views.py index 5df771309c..91038b3145 100644 --- a/lms/djangoapps/teams/views.py +++ b/lms/djangoapps/teams/views.py @@ -363,6 +363,18 @@ class TeamsListView(ExpandableFieldViewMixin, GenericAPIView): ugettext_noop('The supplied course_id {course_id} is not valid.'), course_id=course_id ) + return Response({ + 'field_errors': field_errors, + }, status=status.HTTP_400_BAD_REQUEST) + + if CourseTeamMembership.user_in_team_for_course(request.user, course_key): + error_message = build_api_error( + ugettext_noop('You are already in a team in this course.'), + course_id=course_id + ) + return Response({ + 'error_message': error_message, + }, status=status.HTTP_400_BAD_REQUEST) if course_key and not has_team_api_access(request.user, course_key): return Response(status=status.HTTP_403_FORBIDDEN)