EDUCATOR-4918: Hide teams listing for team-sets with privacy enabled (#23293)
* pass teamset type existence flags to the teams tab view
This commit is contained in:
@@ -4,8 +4,11 @@ define(['jquery', 'backbone', 'teams/js/teams_tab_factory', 'teams/js/views/team
|
||||
'use strict';
|
||||
|
||||
describe('Teams Tab Factory', function() {
|
||||
var initializeTeamsTabFactory = function() {
|
||||
TeamsTabFactory(TeamSpecHelpers.createMockContext());
|
||||
var initializeTeamsTabFactory = function(hasOpenTopic, hasPublicManagedTopic) {
|
||||
var context = TeamSpecHelpers.createMockContext();
|
||||
context.hasOpenTopic = hasOpenTopic;
|
||||
context.hasPublicManagedTopic = hasPublicManagedTopic;
|
||||
TeamsTabFactory(context);
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
@@ -18,9 +21,31 @@ define(['jquery', 'backbone', 'teams/js/teams_tab_factory', 'teams/js/views/team
|
||||
$(document).off('ajaxError', TeamsTabView.prototype.errorHandler);
|
||||
});
|
||||
|
||||
it('can render the "Teams" tab', function() {
|
||||
initializeTeamsTabFactory();
|
||||
expect($('.teams-content').text()).toContain('See all teams in your course, organized by topic');
|
||||
describe('can render the "Teams" tab', function() {
|
||||
it('when there are no private or open teamsets', function() {
|
||||
initializeTeamsTabFactory(false, false);
|
||||
expect($('.teams-content').text()).toContain('See all teams you belong to');
|
||||
expect($('.teams-content').text()).not.toContain('and all public teams in your course');
|
||||
expect($('.teams-content').text()).not.toContain('Join an open public team');
|
||||
});
|
||||
it('when there are no open teamsets but there are public teamsets', function() {
|
||||
initializeTeamsTabFactory(false, true);
|
||||
expect($('.teams-content').text()).toContain('See all teams you belong to');
|
||||
expect($('.teams-content').text()).toContain('and all public teams in your course');
|
||||
expect($('.teams-content').text()).not.toContain('Join an open public team');
|
||||
});
|
||||
it('when there are open teamsets but no public teamsets', function() {
|
||||
initializeTeamsTabFactory(true, false);
|
||||
expect($('.teams-content').text()).toContain('See all teams you belong to');
|
||||
expect($('.teams-content').text()).toContain('and all public teams in your course');
|
||||
expect($('.teams-content').text()).toContain('Join an open public team');
|
||||
});
|
||||
it('when there are both open and public teamsets', function() {
|
||||
initializeTeamsTabFactory(true, true);
|
||||
expect($('.teams-content').text()).toContain('See all teams you belong to');
|
||||
expect($('.teams-content').text()).toContain('and all public teams in your course');
|
||||
expect($('.teams-content').text()).toContain('Join an open public team');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -232,30 +232,10 @@ define([
|
||||
|
||||
describe('Manage Tab', function() {
|
||||
var manageTabSelector = '.page-content-nav>.nav-item[data-url=manage]';
|
||||
var noManagedData = TeamSpecHelpers.createMockTopicData(1, 2);
|
||||
var withManagedData = TeamSpecHelpers.createMockTopicData(1, 2);
|
||||
var topicsNoManaged, topicsWithManaged;
|
||||
|
||||
topicsNoManaged = {
|
||||
count: 2,
|
||||
num_pages: 1,
|
||||
current_page: 1,
|
||||
start: 0,
|
||||
results: noManagedData
|
||||
};
|
||||
withManagedData[1].type = 'public_managed';
|
||||
topicsWithManaged = {
|
||||
count: 2,
|
||||
num_pages: 1,
|
||||
current_page: 1,
|
||||
start: 0,
|
||||
results: withManagedData
|
||||
};
|
||||
|
||||
it('is not visible to unprivileged users', function() {
|
||||
var teamsTabView = createTeamsTabView(this, {
|
||||
userInfo: TeamSpecHelpers.createMockUserInfo({privileged: false}),
|
||||
topics: topicsNoManaged
|
||||
hasManagedTopic: true
|
||||
});
|
||||
expect(teamsTabView.$(manageTabSelector).length).toBe(0);
|
||||
});
|
||||
@@ -263,7 +243,7 @@ define([
|
||||
it('is not visible when there are no managed topics', function() {
|
||||
var teamsTabView = createTeamsTabView(this, {
|
||||
userInfo: TeamSpecHelpers.createMockUserInfo({privileged: true}),
|
||||
topics: topicsNoManaged
|
||||
hasManagedTopic: false
|
||||
});
|
||||
expect(teamsTabView.$(manageTabSelector).length).toBe(0);
|
||||
});
|
||||
@@ -271,12 +251,47 @@ define([
|
||||
it('is visible to privileged users when there is a managed topic', function() {
|
||||
var teamsTabView = createTeamsTabView(this, {
|
||||
userInfo: TeamSpecHelpers.createMockUserInfo({privileged: true}),
|
||||
topics: topicsWithManaged
|
||||
hasManagedTopic: true
|
||||
});
|
||||
expect(teamsTabView.$(manageTabSelector).length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Browse Tab', function() {
|
||||
var browseTabSelector = '.page-content-nav>.nav-item[data-url=browse]';
|
||||
it('is not visible if there are no open and no public teamsets', function() {
|
||||
var teamsTabView = createTeamsTabView(this, {
|
||||
hasOpenTopic: false,
|
||||
hasPublicManagedTopic: false
|
||||
});
|
||||
expect(teamsTabView.$(browseTabSelector).length).toBe(0);
|
||||
});
|
||||
|
||||
it('is visible if there are open teamsets', function() {
|
||||
var teamsTabView = createTeamsTabView(this, {
|
||||
hasOpenTopic: true,
|
||||
hasPublicManagedTopic: false
|
||||
});
|
||||
expect(teamsTabView.$(browseTabSelector).length).toBe(1);
|
||||
});
|
||||
|
||||
it('is visible if there are public teamsets', function() {
|
||||
var teamsTabView = createTeamsTabView(this, {
|
||||
hasOpenTopic: false,
|
||||
hasPublicManagedTopic: true
|
||||
});
|
||||
expect(teamsTabView.$(browseTabSelector).length).toBe(1);
|
||||
});
|
||||
|
||||
it('is visible if there are both public and open teamsets', function() {
|
||||
var teamsTabView = createTeamsTabView(this, {
|
||||
hasOpenTopic: true,
|
||||
hasPublicManagedTopic: true
|
||||
});
|
||||
expect(teamsTabView.$(browseTabSelector).length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Search', function() {
|
||||
var performSearch = function(reqs, teamsTabView) {
|
||||
teamsTabView.$('.search-field').val('foo');
|
||||
|
||||
@@ -274,6 +274,9 @@ define([
|
||||
start: 0,
|
||||
results: createMockTopicData(1, 5)
|
||||
},
|
||||
hasOpenTopic: true,
|
||||
hasPublicManagedTopic: false,
|
||||
hasManagedTopic: false,
|
||||
maxTeamSize: 6,
|
||||
languages: testLanguages,
|
||||
countries: testCountries,
|
||||
|
||||
@@ -143,14 +143,17 @@
|
||||
});
|
||||
|
||||
tabsList = [{
|
||||
title: gettext('My Team'),
|
||||
title: gettext('My Teams'),
|
||||
url: 'my-teams',
|
||||
view: this.myTeamsView
|
||||
}, {
|
||||
title: gettext('Browse'),
|
||||
url: 'browse',
|
||||
view: this.topicsView
|
||||
}];
|
||||
if (this.shouldSeeBrowseTab()) {
|
||||
tabsList.push({
|
||||
title: gettext('Browse'),
|
||||
url: 'browse',
|
||||
view: this.topicsView
|
||||
});
|
||||
}
|
||||
if (this.canViewManageTab()) {
|
||||
tabsList.push({
|
||||
title: gettext('Manage'),
|
||||
@@ -161,11 +164,7 @@
|
||||
|
||||
this.mainView = this.tabbedView = this.createViewWithHeader({
|
||||
title: gettext('Teams'),
|
||||
description: gettext(
|
||||
'See all teams in your course, organized by topic. ' +
|
||||
'Join a team to collaborate with other learners who are ' +
|
||||
'interested in the same topic as you are.'
|
||||
),
|
||||
description: this.getTeamsTabViewDescription(),
|
||||
mainView: new TeamsTabbedView({
|
||||
tabs: tabsList,
|
||||
router: this.router
|
||||
@@ -183,9 +182,10 @@
|
||||
|
||||
// Navigate to the default page if there is no history:
|
||||
// 1. If the user belongs to at least one team, jump to the "My Teams" page
|
||||
// 2. If not, then jump to the "Browse" page
|
||||
// 2. If the user will not see a "Browse" page, jump to the "My Teams" page
|
||||
// 3. Otherwise, jump to the "Browse" page
|
||||
if (Backbone.history.getFragment() === '') {
|
||||
if (this.myTeamsCollection.length > 0) {
|
||||
if (this.myTeamsCollection.length > 0 || !this.shouldSeeBrowseTab()) {
|
||||
this.router.navigate('my-teams', {trigger: true});
|
||||
} else {
|
||||
this.router.navigate('browse', {trigger: true});
|
||||
@@ -490,7 +490,7 @@
|
||||
* Returns whether the "Manage" tab should be shown to the user.
|
||||
*/
|
||||
canViewManageTab: function() {
|
||||
return this.canManageTeams() && this.anyInstructorManagedTopics();
|
||||
return this.canManageTeams() && this.context.hasManagedTopic;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -501,13 +501,26 @@
|
||||
return this.canEditTeam();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns whether _any_ of the topics are instructor-managed.
|
||||
*/
|
||||
anyInstructorManagedTopics: function() {
|
||||
return this.topicsCollection.some(
|
||||
function(topic) { return topic.isInstructorManaged(); }
|
||||
);
|
||||
shouldSeeBrowseTab: function() {
|
||||
return this.context.hasOpenTopic || this.context.hasPublicManagedTopic;
|
||||
},
|
||||
|
||||
getTeamsTabViewDescription: function() {
|
||||
if (this.context.hasOpenTopic) {
|
||||
return gettext(
|
||||
'See all teams you belong to and all public ' +
|
||||
'teams in your course, organized by topic. ' +
|
||||
'Join an open public team to collaborate with other learners ' +
|
||||
'who are interested in the same topic as you are.'
|
||||
);
|
||||
} else if (this.context.hasPublicManagedTopic) {
|
||||
return gettext(
|
||||
'See all teams you belong to and all public ' +
|
||||
'teams in your course, organized by topic.'
|
||||
);
|
||||
} else {
|
||||
return gettext('See all teams you belong to.');
|
||||
}
|
||||
},
|
||||
|
||||
createBreadcrumbs: function(topic, team) {
|
||||
|
||||
@@ -43,6 +43,9 @@ from openedx.core.djangolib.js_utils import (
|
||||
TeamsTabFactory({
|
||||
courseID: '${six.text_type(course.id) | n, js_escaped_string}',
|
||||
topics: ${topics | n, dump_js_escaped_json},
|
||||
hasManagedTopic: ${has_managed_teamset | n, dump_js_escaped_json},
|
||||
hasPublicManagedTopic: ${has_public_managed_teamset | n, dump_js_escaped_json},
|
||||
hasOpenTopic: ${has_open_teamset | n, dump_js_escaped_json},
|
||||
userInfo: ${user_info | n, dump_js_escaped_json},
|
||||
topicUrl: '${topic_url | n, js_escaped_string}',
|
||||
topicsUrl: '${topics_url | n, js_escaped_string}',
|
||||
|
||||
@@ -39,6 +39,7 @@ from ..search_indexes import CourseTeam, CourseTeamIndexer, course_team_post_sav
|
||||
from .factories import LAST_ACTIVITY_AT, CourseTeamFactory
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestDashboard(SharedModuleStoreTestCase):
|
||||
"""Tests for the Teams dashboard."""
|
||||
test_password = "test"
|
||||
@@ -197,6 +198,54 @@ class TestDashboard(SharedModuleStoreTestCase):
|
||||
response = self.client.get(course_two_teams_url)
|
||||
self.assertContains(response, '"teams": {"count": 0')
|
||||
|
||||
@ddt.unpack
|
||||
@ddt.data(
|
||||
(True, False, False),
|
||||
(False, True, False),
|
||||
(False, False, True),
|
||||
(True, True, True),
|
||||
(False, True, True),
|
||||
)
|
||||
def test_teamset_counts(self, has_open, has_private, has_public):
|
||||
topics = []
|
||||
if has_open:
|
||||
topics.append({
|
||||
"name": "test topic 1",
|
||||
"id": 1,
|
||||
"description": "Desc1",
|
||||
"type": "open"
|
||||
})
|
||||
if has_private:
|
||||
topics.append({
|
||||
"name": "test topic 2",
|
||||
"id": 2,
|
||||
"description": "Desc2",
|
||||
"type": "private_managed"
|
||||
})
|
||||
if has_public:
|
||||
topics.append({
|
||||
"name": "test topic 3",
|
||||
"id": 3,
|
||||
"description": "Desc3",
|
||||
"type": "public_managed"
|
||||
})
|
||||
|
||||
course = CourseFactory.create(
|
||||
teams_configuration=TeamsConfig({"topics": topics})
|
||||
)
|
||||
teams_url = reverse('teams_dashboard', args=[course.id])
|
||||
CourseEnrollmentFactory.create(user=self.user, course_id=course.id)
|
||||
self.client.login(username=self.user.username, password=self.test_password)
|
||||
response = self.client.get(teams_url)
|
||||
|
||||
expected_has_open = "hasOpenTopic: " + "true" if has_open else "false"
|
||||
expected_has_public = "hasPublicManagedTopic: " + "true" if has_public else "false"
|
||||
expected_has_managed = "hasManagedTopic: " + "true" if has_public or has_private else "false"
|
||||
|
||||
self.assertContains(response, expected_has_open)
|
||||
self.assertContains(response, expected_has_public)
|
||||
self.assertContains(response, expected_has_managed)
|
||||
|
||||
|
||||
class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase):
|
||||
"""Base class for Team API test cases."""
|
||||
|
||||
@@ -4,6 +4,7 @@ HTTP endpoints for the Teams API.
|
||||
|
||||
|
||||
import logging
|
||||
from collections import Counter
|
||||
|
||||
import six
|
||||
from django.conf import settings
|
||||
@@ -31,6 +32,7 @@ from openedx.core.lib.api.authentication import BearerAuthentication
|
||||
from lms.djangoapps.courseware.courses import get_course_with_access, has_access
|
||||
from lms.djangoapps.discussion.django_comment_client.utils import has_discussion_privileges
|
||||
from lms.djangoapps.teams.models import CourseTeam, CourseTeamMembership
|
||||
from openedx.core.lib.teams_config import TeamsetType
|
||||
from openedx.core.lib.api.parsers import MergePatchParser
|
||||
from openedx.core.lib.api.permissions import IsStaffOrReadOnly
|
||||
from openedx.core.lib.api.view_utils import (
|
||||
@@ -136,6 +138,10 @@ class TeamsDashboardView(GenericAPIView):
|
||||
topics = get_alphabetical_topics(course)
|
||||
organization_protection_status = user_organization_protection_status(request.user, course_key)
|
||||
|
||||
# We have some frontend logic that needs to know if we have any open, public, or managed teamsets,
|
||||
# and it's easier to just figure that out here when we have them all already
|
||||
teamset_counts_by_type = Counter([topic['type'] for topic in topics])
|
||||
|
||||
# Paginate and serialize topic data
|
||||
# BulkTeamCountPaginatedTopicSerializer will add team counts to the topics in a single
|
||||
# bulk operation per page.
|
||||
@@ -180,6 +186,12 @@ class TeamsDashboardView(GenericAPIView):
|
||||
"staff": bool(has_access(user, 'staff', course_key)),
|
||||
"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_managed_teamset": bool(
|
||||
teamset_counts_by_type[TeamsetType.public_managed.value] +
|
||||
teamset_counts_by_type[TeamsetType.private_managed.value]
|
||||
),
|
||||
"topic_url": reverse(
|
||||
'topics_detail', kwargs={'topic_id': 'topic_id', 'course_id': str(course_id)}, request=request
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user