From f1d2ddc97a56a9017ce62d68bd170a4d5d215afd Mon Sep 17 00:00:00 2001 From: Alex Wang Date: Fri, 6 Dec 2019 13:41:56 -0500 Subject: [PATCH] no student create team in instructor managed topic (#22432) Students can't create team in an instructor-managed topic --- lms/djangoapps/teams/api.py | 21 +++++++++++++++++++ .../teams/js/spec/views/topic_teams_spec.js | 10 +++++++-- .../static/teams/js/views/topic_teams.js | 10 ++++++--- lms/djangoapps/teams/tests/test_views.py | 17 +++++++++++++++ lms/djangoapps/teams/views.py | 8 +++++++ 5 files changed, 61 insertions(+), 5 deletions(-) diff --git a/lms/djangoapps/teams/api.py b/lms/djangoapps/teams/api.py index 0d31aac925..39ab79e957 100644 --- a/lms/djangoapps/teams/api.py +++ b/lms/djangoapps/teams/api.py @@ -79,6 +79,15 @@ def is_instructor_managed_team(team): # pylint: disable=unused-argument return False +def is_instructor_managed_topic(topic): # pylint: disable=unused-argument + """ + Return true if the topic is managed by instructors. + For now always return false, will complete the logic later. + TODO MST-25 + """ + return False + + def user_is_a_team_member(user, team): """ Return if the user is a member of the team @@ -220,3 +229,15 @@ def can_user_modify_team(user, team): (not is_instructor_managed_team(team)) or has_course_staff_privileges(user, team.course_id) ) + + +def can_user_create_team_in_topic(user, course_id, topic_id): + """ + Returns whether a User has permission to create a team in the given topic. + + Assumes that user is enrolled in course run. + """ + return ( + (not is_instructor_managed_topic(topic_id)) or + has_course_staff_privileges(user, course_id) + ) diff --git a/lms/djangoapps/teams/static/teams/js/spec/views/topic_teams_spec.js b/lms/djangoapps/teams/static/teams/js/spec/views/topic_teams_spec.js index d775ca4f62..80e59e0264 100644 --- a/lms/djangoapps/teams/static/teams/js/spec/views/topic_teams_spec.js +++ b/lms/djangoapps/teams/static/teams/js/spec/views/topic_teams_spec.js @@ -7,13 +7,14 @@ define([ ], function(Backbone, _, TopicTeamsView, TeamSpecHelpers, PageHelpers) { 'use strict'; describe('Topic Teams View', function() { - var createTopicTeamsView = function(options) { + var createTopicTeamsView = function(options, isInstructorManagedTopic) { var myTeamsCollection; options = options || {}; // eslint-disable-line no-param-reassign myTeamsCollection = options.myTeamsCollection || TeamSpecHelpers.createMockTeams({results: []}); return new TopicTeamsView({ el: '.teams-container', - model: TeamSpecHelpers.createMockTopic(), + model: isInstructorManagedTopic ? + TeamSpecHelpers.createMockInstructorManagedTopic() : TeamSpecHelpers.createMockTopic(), collection: options.teams || TeamSpecHelpers.createMockTeams(), myTeamsCollection: myTeamsCollection, showActions: true, @@ -89,6 +90,11 @@ define([ verifyActions(teamsView, {showActions: false}); }); + it('does not show actions for a student in an instructor managed topic', function() { + var teamsView = createTopicTeamsView({privileged: false}, true); + verifyActions(teamsView, {showActions: false}); + }); + it('shows actions for a privileged user already in a team', function() { var teamsView = createTopicTeamsView({privileged: true}); verifyActions(teamsView); diff --git a/lms/djangoapps/teams/static/teams/js/views/topic_teams.js b/lms/djangoapps/teams/static/teams/js/views/topic_teams.js index 38a3e9e5a9..19269379b4 100644 --- a/lms/djangoapps/teams/static/teams/js/views/topic_teams.js +++ b/lms/djangoapps/teams/static/teams/js/views/topic_teams.js @@ -7,8 +7,9 @@ 'edx-ui-toolkit/js/utils/html-utils', 'teams/js/views/teams', 'common/js/components/views/paging_header', - 'text!teams/templates/team-actions.underscore' - ], function(_, Backbone, gettext, HtmlUtils, TeamsView, PagingHeader, teamActionsTemplate) { + 'text!teams/templates/team-actions.underscore', + 'teams/js/views/team_utils' + ], function(_, Backbone, gettext, HtmlUtils, TeamsView, PagingHeader, teamActionsTemplate, TeamUtils) { var TopicTeamsView = TeamsView.extend({ events: { 'click a.browse-teams': 'browseTeams', @@ -29,7 +30,10 @@ // that they create. This means that if multiple team membership is // disabled that they cannot create a new team when they already // belong to one. - return this.context.staff || this.context.privileged || this.myTeamsCollection.length === 0; + return this.context.staff + || this.context.privileged + || (!TeamUtils.isInstructorManagedTopic(this.model.attributes.type) + && this.myTeamsCollection.length === 0); }, render: function() { diff --git a/lms/djangoapps/teams/tests/test_views.py b/lms/djangoapps/teams/tests/test_views.py index c49a9cba01..a7d288075c 100644 --- a/lms/djangoapps/teams/tests/test_views.py +++ b/lms/djangoapps/teams/tests/test_views.py @@ -834,6 +834,23 @@ class TestCreateTeamAPI(EventTestMixin, TeamAPITestCase): json.loads(response.content.decode('utf-8'))["user_message"] ) + @patch('lms.djangoapps.teams.views.can_user_create_team_in_topic', return_value=False) + def test_student_create_team_instructor_managed_topic(self, *args): # pylint: disable=unused-argument + response = self.post_create_team( + 403, + data=self.build_team_data( + name="student create team in instructor managed topic", + course=self.test_course_1, + description="student cannot create team in instructor-managed topic", + topic_id='great-topic' + ), + user='student_enrolled_not_on_team' + ) + self.assertEqual( + "You can't create a team in an instructor managed topic.", + json.loads(response.content.decode('utf-8'))["user_message"] + ) + @ddt.data('staff', 'course_staff', 'community_ta') def test_privileged_create_multiple_teams(self, user): """ Privileged users can create multiple teams, even if they are already in one. """ diff --git a/lms/djangoapps/teams/views.py b/lms/djangoapps/teams/views.py index 3dd2b2e086..a0aa038f8e 100644 --- a/lms/djangoapps/teams/views.py +++ b/lms/djangoapps/teams/views.py @@ -49,6 +49,7 @@ from .api import ( OrganizationProtectionStatus, add_team_count, can_user_modify_team, + can_user_create_team_in_topic, has_course_staff_privileges, has_specific_team_access, has_team_api_access, @@ -525,6 +526,13 @@ class TeamsListView(ExpandableFieldViewMixin, GenericAPIView): if course_key and not has_team_api_access(request.user, course_key): return Response(status=status.HTTP_403_FORBIDDEN) + topic_id = request.data.get('topic_id') + if not can_user_create_team_in_topic(request.user, course_id, topic_id): + return Response( + build_api_error(ugettext_noop("You can't create a team in an instructor managed topic.")), + status=status.HTTP_403_FORBIDDEN + ) + data = request.data.copy() data['course_id'] = six.text_type(course_key)