Skip to content

Commit

Permalink
feat: add open_managed team type (openedx#33672)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ian2012 authored Feb 14, 2024
1 parent f76b6b4 commit 5a36fa9
Show file tree
Hide file tree
Showing 8 changed files with 33 additions and 5 deletions.
2 changes: 1 addition & 1 deletion cms/djangoapps/models/settings/course_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ def validate_single_topic(cls, topic_settings):
"""
error_list = []
valid_teamset_types = [TeamsetType.open.value, TeamsetType.public_managed.value,
TeamsetType.private_managed.value]
TeamsetType.private_managed.value, TeamsetType.open_managed.value]
valid_keys = {'id', 'name', 'description', 'max_team_size', 'type'}
teamset_type = topic_settings.get('type', {})
if teamset_type:
Expand Down
6 changes: 6 additions & 0 deletions cms/djangoapps/models/settings/tests/test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@
"type": "private_managed",
"description": "Private Topic 2 desc",
"name": "Private Topic 2 Name"
},
{
"id": "open_managed_topic_1_id",
"type": "open_managed",
"description": "Open Managed Topic 1 desc",
"name": "Open Managed Topic 1 Name"
}
]
}
Expand Down
3 changes: 2 additions & 1 deletion lms/djangoapps/teams/static/teams/js/views/team_profile.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,14 @@
isMember = TeamUtils.isUserMemberOfTeam(memberships, this.context.userInfo.username),
isAdminOrStaff = this.context.userInfo.privileged || this.context.userInfo.staff,
isInstructorManagedTopic = TeamUtils.isInstructorManagedTopic(this.topic.attributes.type),
canJoinTeam = TeamUtils.canJoinTeam(this.context.userInfo, this.topic.attributes.type),
maxTeamSize = this.topic.getMaxTeamSize(this.context.courseMaxTeamSize);

// Assignments URL isn't provided if team assignments shouldn't be shown
// so we can treat it like a toggle
var showAssignments = !!this.context.teamsAssignmentsUrl;

var showLeaveLink = isMember && (isAdminOrStaff || !isInstructorManagedTopic);
var showLeaveLink = isMember && (isAdminOrStaff || !isInstructorManagedTopic || canJoinTeam);

HtmlUtils.setHtml(
this.$el,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
} else if (!teamHasSpace) {
showJoinButton = false;
message = view.teamFullMessage;
} else if (info.canJoinTeam) {
showJoinButton = true;
} else if (!info.isAdminOrStaff && info.isInstructorManagedTopic) {
showJoinButton = false;
message = view.notJoinInstructorManagedTeam;
Expand Down Expand Up @@ -100,12 +102,14 @@
// this.topic.getMaxTeamSize() will return null for a managed team,
// but the size is considered to be arbitarily large.
var isInstructorManagedTopic = TeamUtils.isInstructorManagedTopic(this.topic.attributes.type);
var canJoinTeam = TeamUtils.canJoinTeam(this.context.userInfo, this.topic.attributes.type)
var teamHasSpace = isInstructorManagedTopic
|| (this.model.get('membership').length < this.topic.getMaxTeamSize(courseMaxTeamSize));

info.memberOfCurrentTeam = TeamUtils.isUserMemberOfTeam(this.model.get('membership'), username);
info.isAdminOrStaff = this.context.userInfo.privileged || this.context.userInfo.staff;
info.isInstructorManagedTopic = isInstructorManagedTopic;
info.canJoinTeam = canJoinTeam;

if (info.memberOfCurrentTeam) {
info.alreadyInTeamset = true;
Expand Down
4 changes: 4 additions & 0 deletions lms/djangoapps/teams/static/teams/js/views/team_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@
return topicType.toLowerCase() !== 'open';
},

canJoinTeam: function(userInfo, topicType = '') {
return userInfo.privileged || userInfo.staff || topicType.includes("open");
},

/** Shows info/error banner for team membership CSV upload
* @param: content - string or array for display
* @param: isError - true sets error styling, false/none uses info styling
Expand Down
13 changes: 11 additions & 2 deletions lms/djangoapps/teams/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
TOPIC1 = 'topic-1'
TOPIC2 = 'topic-2'
TOPIC3 = 'topic-3'
TOPIC4 = 'topic-4'

DISCUSSION_TOPIC_ID = uuid4().hex

Expand All @@ -44,7 +45,8 @@ def setUpClass(cls):
topic_data = [
(TOPIC1, TeamsetType.private_managed.value),
(TOPIC2, TeamsetType.open.value),
(TOPIC3, TeamsetType.public_managed.value)
(TOPIC3, TeamsetType.public_managed.value),
(TOPIC4, TeamsetType.open_managed.value),
]
topics = [
{
Expand All @@ -55,7 +57,7 @@ def setUpClass(cls):
} for topic_id, teamset_type in topic_data
]
teams_config_1 = TeamsConfig({'topics': [topics[0]]})
teams_config_2 = TeamsConfig({'topics': [topics[1], topics[2]]})
teams_config_2 = TeamsConfig({'topics': [topics[1], topics[2], topics[3]]})
cls.course1 = CourseFactory(
org=COURSE_KEY1.org,
course=COURSE_KEY1.course,
Expand Down Expand Up @@ -93,10 +95,12 @@ def setUpClass(cls):
topic_id=TOPIC2
)
cls.team3 = CourseTeamFactory(course_id=COURSE_KEY2, team_id='team3', topic_id=TOPIC3)
cls.team4 = CourseTeamFactory(course_id=COURSE_KEY2, team_id='team4', topic_id=TOPIC4)

cls.team1.add_user(cls.user1)
cls.team1.add_user(cls.user2)
cls.team2.add_user(cls.user3)
cls.team4.add_user(cls.user3)

cls.team1a.add_user(cls.user4)
cls.team2a.add_user(cls.user4)
Expand All @@ -122,21 +126,25 @@ def test_is_team_discussion_private_is_public(self):
assert not teams_api.is_team_discussion_private(None)
assert not teams_api.is_team_discussion_private(self.team2)
assert not teams_api.is_team_discussion_private(self.team3)
assert not teams_api.is_team_discussion_private(self.team4)

def test_is_instructor_managed_team(self):
assert teams_api.is_instructor_managed_team(self.team1)
assert not teams_api.is_instructor_managed_team(self.team2)
assert teams_api.is_instructor_managed_team(self.team3)
assert not teams_api.is_instructor_managed_team(self.team4)

def test_is_instructor_managed_topic(self):
assert teams_api.is_instructor_managed_topic(COURSE_KEY1, TOPIC1)
assert not teams_api.is_instructor_managed_topic(COURSE_KEY2, TOPIC2)
assert teams_api.is_instructor_managed_topic(COURSE_KEY2, TOPIC3)
assert not teams_api.is_instructor_managed_topic(COURSE_KEY2, TOPIC4)

def test_user_is_a_team_member(self):
assert teams_api.user_is_a_team_member(self.user1, self.team1)
assert not teams_api.user_is_a_team_member(self.user1, None)
assert not teams_api.user_is_a_team_member(self.user1, self.team2)
assert not teams_api.user_is_a_team_member(self.user1, self.team4)

def test_private_discussion_visible_by_user(self):
assert teams_api.discussion_visible_by_user(DISCUSSION_TOPIC_ID, self.user1)
Expand All @@ -147,6 +155,7 @@ def test_public_discussion_visible_by_user(self):
assert teams_api.discussion_visible_by_user(self.team2.discussion_topic_id, self.user1)
assert teams_api.discussion_visible_by_user(self.team2.discussion_topic_id, self.user2)
assert teams_api.discussion_visible_by_user('DO_NOT_EXISTS', self.user3)
assert teams_api.discussion_visible_by_user(self.team4.discussion_topic_id, self.user3)

@ddt.unpack
@ddt.data(
Expand Down
5 changes: 4 additions & 1 deletion lms/djangoapps/teams/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,10 @@ def get(self, request, course_id):
"teams": user_teams_data
},
"has_open_teamset": bool(teamset_counts_by_type[TeamsetType.open.value]),
"has_public_managed_teamset": bool(teamset_counts_by_type[TeamsetType.public_managed.value]),
"has_public_managed_teamset": bool(
teamset_counts_by_type[TeamsetType.public_managed.value] +
teamset_counts_by_type[TeamsetType.open_managed.value]
),
"has_managed_teamset": bool(
teamset_counts_by_type[TeamsetType.public_managed.value] +
teamset_counts_by_type[TeamsetType.private_managed.value]
Expand Down
1 change: 1 addition & 0 deletions openedx/core/lib/teams_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ class TeamsetType(Enum):
open = "open"
public_managed = "public_managed"
private_managed = "private_managed"
open_managed = "open_managed"

@classmethod
def get_default(cls):
Expand Down

0 comments on commit 5a36fa9

Please sign in to comment.