Commit 8bd1f698 by Andy Armstrong

Govern team creation for non-privileged users

TNL-2960

Non-privileged users can only be in one team, so don't
allow them to create new teams if they are already
members of another.
parent 716c1f74
...@@ -8,15 +8,25 @@ ...@@ -8,15 +8,25 @@
this.course_id = options.course_id; this.course_id = options.course_id;
this.username = options.username; this.username = options.username;
this.privileged = options.privileged;
this.perPage = options.per_page || 10; this.perPage = options.per_page || 10;
this.server_api['expand'] = 'team'; this.server_api['expand'] = 'team';
this.server_api['course_id'] = function () { return encodeURIComponent(this.course_id); }; this.server_api['course_id'] = function () { return encodeURIComponent(options.course_id); };
this.server_api['username'] = this.username; this.server_api['username'] = this.username;
delete this.server_api['sort_order']; // Sort order is not specified for the TeamMembership API delete this.server_api['sort_order']; // Sort order is not specified for the TeamMembership API
delete this.server_api['order_by']; // Order by is not specified for the TeamMembership API delete this.server_api['order_by']; // Order by is not specified for the TeamMembership API
}, },
model: TeamMembershipModel model: TeamMembershipModel,
canUserCreateTeam: function() {
// Note: users can only belong to one team at a time, and
// non-privileged users are automatically added to any team
// that they create. This means that non-privileged users
// are not allowed to create a new team when they already
// belong to a different one.
return this.privileged || this.length === 0;
}
}); });
return TeamMembershipCollection; return TeamMembershipCollection;
}); });
......
define([
'jquery',
'backbone',
'teams/js/views/team_actions'
], function ($, Backbone, TeamActionsView) {
'use strict';
describe('TeamActions', function () {
var teamActionsView;
beforeEach(function () {
setFixtures('<div class="teams-content"></div>');
spyOn(Backbone.history, 'navigate');
teamActionsView = new TeamActionsView({
el: $('.teams-content'),
teamParams: {topicId: 'awesomeness'}
}).render();
});
it('can render itself correctly', function () {
expect(teamActionsView.$('.title').text()).toBe('Are you having trouble finding a team to join?');
expect(teamActionsView.$('.copy').text()).toBe(
"Try browsing all teams or searching team descriptions. If you " +
"still can't find a team to join, create a new team in this topic."
);
});
it('can navigate to correct routes', function () {
teamActionsView.$('a.browse-teams').click();
expect(Backbone.history.navigate.calls[0].args).toContain('browse');
teamActionsView.$('a.search-team-descriptions').click();
// TODO! Should be updated once team description search feature is available
expect(Backbone.history.navigate.calls[1].args).toContain('browse');
teamActionsView.$('a.create-team').click();
expect(Backbone.history.navigate.calls[2].args).toContain('topics/awesomeness/create-team');
});
});
});
...@@ -5,15 +5,23 @@ define(["jquery", "backbone", "teams/js/teams_tab_factory"], ...@@ -5,15 +5,23 @@ define(["jquery", "backbone", "teams/js/teams_tab_factory"],
describe("Teams Tab Factory", function() { describe("Teams Tab Factory", function() {
var teamsTab; var teamsTab;
beforeEach(function() { var initializeTeamsTabFactory = function() {
setFixtures('<section class="teams-content"></section>'); TeamsTabFactory({
teamsTab = new TeamsTabFactory({
topics: {results: []}, topics: {results: []},
topicsUrl: '', topicsUrl: '',
teamsUrl: '', teamsUrl: '',
maxTeamSize: 9999, maxTeamSize: 9999,
courseID: 'edX/DemoX/Demo_Course' courseID: 'edX/DemoX/Demo_Course',
userInfo: {
username: 'test-user',
privileged: false,
teamMembershipData: null
}
}); });
};
beforeEach(function() {
setFixtures('<section class="teams-content"></section>');
}); });
afterEach(function() { afterEach(function() {
...@@ -21,12 +29,14 @@ define(["jquery", "backbone", "teams/js/teams_tab_factory"], ...@@ -21,12 +29,14 @@ define(["jquery", "backbone", "teams/js/teams_tab_factory"],
}); });
it("can load templates", function() { it("can load templates", function() {
expect($("body").text()).toContain("My Teams"); initializeTeamsTabFactory();
expect($("body").text()).toContain("Showing 0 out of 0 total"); expect($('.teams-content').text()).toContain("My Teams");
expect($('.teams-content').text()).toContain("Showing 0 out of 0 total");
}); });
it("displays a header", function() { it("displays a header", function() {
expect($("body").html()).toContain("See all teams in your course, organized by topic"); initializeTeamsTabFactory();
expect($('.teams-content').html()).toContain("See all teams in your course, organized by topic");
}); });
}); });
} }
......
...@@ -2,31 +2,62 @@ define([ ...@@ -2,31 +2,62 @@ define([
'jquery', 'jquery',
'backbone', 'backbone',
'common/js/spec_helpers/ajax_helpers', 'common/js/spec_helpers/ajax_helpers',
'teams/js/views/teams_tab', 'teams/js/views/teams_tab'
'URI' ], function ($, Backbone, AjaxHelpers, TeamsTabView) {
], function ($, Backbone, AjaxHelpers, TeamsTabView, URI) {
'use strict'; 'use strict';
describe('TeamsTab', function () { describe('TeamsTab', function () {
var teamsTabView, var expectContent = function (teamsTabView, text) {
expectContent = function (text) { expect(teamsTabView.$('.page-content-main').text()).toContain(text);
expect(teamsTabView.$('.page-content-main').text()).toContain(text); };
},
expectHeader = function (text) { var expectHeader = function (teamsTabView, text) {
expect(teamsTabView.$('.teams-header').text()).toContain(text); expect(teamsTabView.$('.teams-header').text()).toContain(text);
}, };
expectError = function (text) {
expect(teamsTabView.$('.warning').text()).toContain(text); var expectError = function (teamsTabView, text) {
}, expect(teamsTabView.$('.warning').text()).toContain(text);
expectFocus = function (element) { };
expect(element.focus).toHaveBeenCalled();
var expectFocus = function (element) {
expect(element.focus).toHaveBeenCalled();
};
var createUserInfo = function(options) {
var defaultTeamMembershipData = {
count: 1,
currentPage: 1,
numPages: 1,
next: null,
previous: null,
results: [
{
user: {
username: 'andya',
url: 'https://openedx.example.com/api/user/v1/accounts/andya'
},
team: {
description: '',
name: 'Discrete Maths',
id: 'dm',
topic_id: 'algorithms'
},
date_joined: '2015-04-09T17:31:56Z'
}
]
}; };
return _.extend(
{
username: 'andya',
privileged: false,
teamMembershipData: defaultTeamMembershipData
},
options
);
};
beforeEach(function () { var createTeamsTabView = function(options) {
setFixtures('<div class="teams-content"></div>'); var defaultTopics = {
teamsTabView = new TeamsTabView({
el: $('.teams-content'),
topics: {
count: 1, count: 1,
num_pages: 1, num_pages: 1,
current_page: 1, current_page: 1,
...@@ -38,33 +69,25 @@ define([ ...@@ -38,33 +69,25 @@ define([
team_count: 0 team_count: 0
}] }]
}, },
teamMemberships: { teamsTabView = new TeamsTabView(
count: 1, _.extend(
currentPage: 1, {
numPages: 1, el: $('.teams-content'),
next: null, topics: defaultTopics,
previous: null, userInfo: createUserInfo(),
results: [ topicsUrl: 'api/topics/',
{ topicUrl: 'api/topics/topic_id,test/course/id',
user: { teamsUrl: 'api/teams/',
username: 'andya', courseID: 'test/course/id'
url: 'https://openedx.example.com/api/user/v1/accounts/andya'
}, },
team: { options || {}
description: '', )
name: 'Discrete Maths', ).render();
id: 'dm', return teamsTabView;
topic_id: 'algorithms' };
},
date_joined: '2015-04-09T17:31:56Z' beforeEach(function () {
}, setFixtures('<div class="teams-content"></div>');
]
},
topicsUrl: 'api/topics/',
topicUrl: 'api/topics/topic_id,test/course/id',
teamsUrl: 'api/teams/',
courseID: 'test/course/id'
}).render();
Backbone.history.start(); Backbone.history.start();
spyOn($.fn, 'focus'); spyOn($.fn, 'focus');
}); });
...@@ -74,48 +97,55 @@ define([ ...@@ -74,48 +97,55 @@ define([
}); });
it('shows the my teams tab initially', function () { it('shows the my teams tab initially', function () {
expectHeader('See all teams in your course, organized by topic'); var teamsTabView = createTeamsTabView();
expectContent('Showing 1 out of 1 total'); expectHeader(teamsTabView, 'See all teams in your course, organized by topic');
expectContent('Discrete Maths'); expectContent(teamsTabView, 'Showing 1 out of 1 total');
expectContent(teamsTabView, 'Discrete Maths');
}); });
describe('Navigation', function () { describe('Navigation', function () {
it('can switch tabs', function () { it('can switch tabs', function () {
var teamsTabView = createTeamsTabView();
teamsTabView.$('a.nav-item[data-url="browse"]').click(); teamsTabView.$('a.nav-item[data-url="browse"]').click();
expectContent('test description'); expectContent(teamsTabView, 'test description');
teamsTabView.$('a.nav-item[data-url="my-teams"]').click(); teamsTabView.$('a.nav-item[data-url="my-teams"]').click();
expectContent('Showing 1 out of 1 total'); expectContent(teamsTabView, 'Showing 1 out of 1 total');
expectContent('Discrete Maths'); expectContent(teamsTabView, 'Discrete Maths');
}); });
it('displays and focuses an error message when trying to navigate to a nonexistent page', function () { it('displays and focuses an error message when trying to navigate to a nonexistent page', function () {
var teamsTabView = createTeamsTabView();
teamsTabView.router.navigate('no_such_page', {trigger: true}); teamsTabView.router.navigate('no_such_page', {trigger: true});
expectError('The page "no_such_page" could not be found.'); expectError(teamsTabView, 'The page "no_such_page" could not be found.');
expectFocus(teamsTabView.$('.warning')); expectFocus(teamsTabView.$('.warning'));
}); });
it('displays and focuses an error message when trying to navigate to a nonexistent topic', function () { it('displays and focuses an error message when trying to navigate to a nonexistent topic', function () {
var requests = AjaxHelpers.requests(this); var requests = AjaxHelpers.requests(this),
teamsTabView = createTeamsTabView();
teamsTabView.router.navigate('topics/no_such_topic', {trigger: true}); teamsTabView.router.navigate('topics/no_such_topic', {trigger: true});
AjaxHelpers.expectRequest(requests, 'GET', 'api/topics/no_such_topic,test/course/id', null); AjaxHelpers.expectRequest(requests, 'GET', 'api/topics/no_such_topic,test/course/id', null);
AjaxHelpers.respondWithError(requests, 404); AjaxHelpers.respondWithError(requests, 404);
expectError('The topic "no_such_topic" could not be found.'); expectError(teamsTabView, 'The topic "no_such_topic" could not be found.');
expectFocus(teamsTabView.$('.warning')); expectFocus(teamsTabView.$('.warning'));
}); });
it('displays and focuses an error message when trying to navigate to a nonexistent team', function () { it('displays and focuses an error message when trying to navigate to a nonexistent team', function () {
var requests = AjaxHelpers.requests(this); var requests = AjaxHelpers.requests(this),
teamsTabView = createTeamsTabView();
teamsTabView.router.navigate('teams/test_topic/no_such_team', {trigger: true}); teamsTabView.router.navigate('teams/test_topic/no_such_team', {trigger: true});
AjaxHelpers.expectRequest(requests, 'GET', 'api/teams/no_such_team', null); AjaxHelpers.expectRequest(requests, 'GET', 'api/teams/no_such_team', null);
AjaxHelpers.respondWithError(requests, 404); AjaxHelpers.respondWithError(requests, 404);
expectError('The team "no_such_team" could not be found.'); expectError(teamsTabView, 'The team "no_such_team" could not be found.');
expectFocus(teamsTabView.$('.warning')); expectFocus(teamsTabView.$('.warning'));
}); });
}); });
describe('Discussion privileges', function () { describe('Discussion privileges', function () {
it('allows privileged access to any team', function () { it('allows privileged access to any team', function () {
teamsTabView.$el.data('privileged', true); var teamsTabView = createTeamsTabView({
userInfo: createUserInfo({ privileged: true })
});
// Note: using `undefined` here to ensure that we // Note: using `undefined` here to ensure that we
// don't even look at the team when the user is // don't even look at the team when the user is
// privileged // privileged
...@@ -123,7 +153,12 @@ define([ ...@@ -123,7 +153,12 @@ define([
}); });
it('allows access to a team which an unprivileged user is a member of', function () { it('allows access to a team which an unprivileged user is a member of', function () {
teamsTabView.$el.data('privileged', false).data('username', 'test-user'); var teamsTabView = createTeamsTabView({
userInfo: createUserInfo({
username: 'test-user',
privileged: false
})
});
expect(teamsTabView.readOnlyDiscussion({ expect(teamsTabView.readOnlyDiscussion({
attributes: { attributes: {
membership: [{ membership: [{
...@@ -136,7 +171,9 @@ define([ ...@@ -136,7 +171,9 @@ define([
}); });
it('does not allow access if the user is neither privileged nor a team member', function () { it('does not allow access if the user is neither privileged nor a team member', function () {
teamsTabView.$el.data('privileged', false).data('username', 'test-user'); var teamsTabView = createTeamsTabView({
userInfo: createUserInfo({ privileged: false })
});
expect(teamsTabView.readOnlyDiscussion({ expect(teamsTabView.readOnlyDiscussion({
attributes: { membership: [] } attributes: { membership: [] }
})).toBe(true); })).toBe(true);
......
define([ define(['underscore'], function (_) {
'underscore', 'common/js/spec_helpers/ajax_helpers'
], function (_, AjaxHelpers) {
'use strict'; 'use strict';
var createMockPostResponse, createMockDiscussionResponse, createAnnotatedContentInfo, createMockThreadResponse, var createMockPostResponse, createMockDiscussionResponse, createAnnotatedContentInfo, createMockThreadResponse,
testCourseID = 'course/1', testCourseID = 'course/1',
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
'js/views/fields', 'js/views/fields',
'teams/js/models/team', 'teams/js/models/team',
'text!teams/templates/edit-team.underscore'], 'text!teams/templates/edit-team.underscore'],
function (Backbone, _, gettext, FieldViews, TeamModel, edit_team_template) { function (Backbone, _, gettext, FieldViews, TeamModel, editTeamTemplate) {
return Backbone.View.extend({ return Backbone.View.extend({
maxTeamNameLength: 255, maxTeamNameLength: 255,
...@@ -79,7 +79,7 @@ ...@@ -79,7 +79,7 @@
}, },
render: function() { render: function() {
this.$el.html(_.template(edit_team_template)({primaryButtonTitle: this.primaryButtonTitle})); this.$el.html(_.template(editTeamTemplate)({primaryButtonTitle: this.primaryButtonTitle}));
this.set(this.teamNameField, '.team-required-fields'); this.set(this.teamNameField, '.team-required-fields');
this.set(this.teamDescriptionField, '.team-required-fields'); this.set(this.teamDescriptionField, '.team-required-fields');
this.set(this.optionalDescriptionField, '.team-optional-fields'); this.set(this.optionalDescriptionField, '.team-optional-fields');
......
;(function (define) {
'use strict';
define([
'gettext',
'underscore',
'backbone',
'text!teams/templates/team-actions.underscore'
], function (gettext, _, Backbone, team_actions_template) {
return Backbone.View.extend({
events: {
'click a.browse-teams': 'browseTeams',
'click a.search-team-descriptions': 'searchTeamDescriptions',
'click a.create-team': 'showCreateTeamForm'
},
initialize: function (options) {
this.template = _.template(team_actions_template);
this.teamParams = options.teamParams;
},
render: function () {
var message = interpolate_text(
_.escape(gettext("Try {browse_span_start}browsing all teams{span_end} or {search_span_start}searching team descriptions{span_end}. If you still can't find a team to join, {create_span_start}create a new team in this topic{span_end}.")),
{
'browse_span_start': '<a class="browse-teams" href="">',
'search_span_start': '<a class="search-team-descriptions" href="">',
'create_span_start': '<a class="create-team" href="">',
'span_end': '</a>'
}
);
this.$el.html(this.template({message: message}));
return this;
},
browseTeams: function (event) {
event.preventDefault();
Backbone.history.navigate('browse', {trigger: true});
},
searchTeamDescriptions: function (event) {
event.preventDefault();
// TODO! Will navigate to correct place once required functionality is available
Backbone.history.navigate('browse', {trigger: true});
},
showCreateTeamForm: function (event) {
event.preventDefault();
Backbone.history.navigate('topics/' + this.teamParams.topicId + '/create-team', {trigger: true});
}
});
});
}).call(this, define || RequireJS.define);
...@@ -4,34 +4,45 @@ ...@@ -4,34 +4,45 @@
'backbone', 'backbone',
'teams/js/views/team_card', 'teams/js/views/team_card',
'common/js/components/views/paginated_view', 'common/js/components/views/paginated_view',
'teams/js/views/team_actions' 'text!teams/templates/team-actions.underscore'
], function (Backbone, TeamCardView, PaginatedView, TeamActionsView) { ], function (Backbone, TeamCardView, PaginatedView, teamActionsTemplate) {
var TeamsView = PaginatedView.extend({ var TeamsView = PaginatedView.extend({
type: 'teams', type: 'teams',
events: {
'click a.browse-teams': 'browseTeams',
'click a.search-teams': 'searchTeams',
'click a.create-team': 'showCreateTeamForm'
},
initialize: function (options) { initialize: function (options) {
this.topic = options.topic; this.topic = options.topic;
this.teamMemberships = options.teamMemberships;
this.teamParams = options.teamParams;
this.itemViewClass = TeamCardView.extend({ this.itemViewClass = TeamCardView.extend({
router: options.router, router: options.router,
topic: options.topic, topic: options.topic,
maxTeamSize: options.maxTeamSize, maxTeamSize: options.maxTeamSize,
countries: this.selectorOptionsArrayToHashWithBlank(options.teamParams.countries), countries: this.selectorOptionsArrayToHashWithBlank(options.teamParams.countries),
languages: this.selectorOptionsArrayToHashWithBlank(options.teamParams.languages), languages: this.selectorOptionsArrayToHashWithBlank(options.teamParams.languages)
}); });
PaginatedView.prototype.initialize.call(this); PaginatedView.prototype.initialize.call(this);
this.teamParams = options.teamParams;
this.showActions = options.showActions;
}, },
render: function () { render: function () {
PaginatedView.prototype.render.call(this); PaginatedView.prototype.render.call(this);
if (this.showActions === true) { if (this.teamMemberships.canUserCreateTeam()) {
var teamActionsView = new TeamActionsView({ var message = interpolate_text(
teamParams: this.teamParams _.escape(gettext("Try {browse_span_start}browsing all teams{span_end} or {search_span_start}searching team descriptions{span_end}. If you still can't find a team to join, {create_span_start}create a new team in this topic{span_end}.")),
}); {
this.$el.append(teamActionsView.$el); 'browse_span_start': '<a class="browse-teams" href="">',
teamActionsView.render(); 'search_span_start': '<a class="search-teams" href="">',
'create_span_start': '<a class="create-team" href="">',
'span_end': '</a>'
}
);
this.$el.append(_.template(teamActionsTemplate, {message: message}));
} }
return this; return this;
...@@ -49,6 +60,22 @@ ...@@ -49,6 +60,22 @@
var map = _.object(options); var map = _.object(options);
map[""] = ""; map[""] = "";
return map; return map;
},
browseTeams: function (event) {
event.preventDefault();
Backbone.history.navigate('browse', {trigger: true});
},
searchTeamDescriptions: function (event) {
event.preventDefault();
// TODO! Will navigate to correct place once required functionality is available
Backbone.history.navigate('browse', {trigger: true});
},
showCreateTeamForm: function (event) {
event.preventDefault();
Backbone.history.navigate('topics/' + this.teamParams.topicID + '/create-team', {trigger: true});
} }
}); });
return TeamsView; return TeamsView;
......
...@@ -41,18 +41,18 @@ ...@@ -41,18 +41,18 @@
var router; var router;
this.courseID = options.courseID; this.courseID = options.courseID;
this.topics = options.topics; this.topics = options.topics;
this.teamMemberships = options.teamMemberships;
this.topicUrl = options.topicUrl; this.topicUrl = options.topicUrl;
this.teamsUrl = options.teamsUrl; this.teamsUrl = options.teamsUrl;
this.teamMembershipsUrl = options.teamMembershipsUrl; this.teamMembershipsUrl = options.teamMembershipsUrl;
this.maxTeamSize = options.maxTeamSize; this.maxTeamSize = options.maxTeamSize;
this.languages = options.languages; this.languages = options.languages;
this.countries = options.countries; this.countries = options.countries;
this.username = options.username; this.userInfo = options.userInfo;
// This slightly tedious approach is necessary // This slightly tedious approach is necessary
// to use regular expressions within Backbone // to use regular expressions within Backbone
// routes, allowing us to capture which tab // routes, allowing us to capture which tab
// name is being routed to // name is being routed to.
router = this.router = new Backbone.Router(); router = this.router = new Backbone.Router();
_.each([ _.each([
[':default', _.bind(this.routeNotFound, this)], [':default', _.bind(this.routeNotFound, this)],
...@@ -65,20 +65,21 @@ ...@@ -65,20 +65,21 @@
router.route.apply(router, route); router.route.apply(router, route);
}); });
this.teamMembershipsCollection = new TeamMembershipCollection( this.teamMemberships = new TeamMembershipCollection(
this.teamMemberships, this.userInfo.teamMembershipData,
{ {
url: this.teamMembershipsUrl, url: this.teamMembershipsUrl,
course_id: this.courseID, course_id: this.courseID,
username: this.username, username: this.userInfo.username,
parse: true, privileged: this.userInfo.privileged,
parse: true
} }
).bootstrap(); ).bootstrap();
this.myTeamsView = new TeamsView({ this.myTeamsView = new TeamsView({
router: this.router, router: this.router,
collection: this.teamMembershipsCollection, collection: this.teamMemberships,
teamMemberships: this.teamMemberships,
maxTeamSize: this.maxTeamSize, maxTeamSize: this.maxTeamSize,
teamParams: { teamParams: {
courseId: this.courseID, courseId: this.courseID,
...@@ -186,14 +187,14 @@ ...@@ -186,14 +187,14 @@
url: self.teamsUrl, url: self.teamsUrl,
per_page: 10 per_page: 10
}); });
this.teamsCollection = collection; self.teamsCollection = collection;
collection.goTo(1) collection.goTo(1)
.done(function() { .done(function() {
var teamsView = new TeamsView({ var teamsView = new TeamsView({
router: router, router: router,
collection: collection, collection: collection,
teamMemberships: self.teamMemberships,
maxTeamSize: self.maxTeamSize, maxTeamSize: self.maxTeamSize,
showActions: true,
teamParams: { teamParams: {
courseId: self.courseID, courseId: self.courseID,
teamsUrl: self.teamsUrl, teamsUrl: self.teamsUrl,
...@@ -412,9 +413,9 @@ ...@@ -412,9 +413,9 @@
readOnlyDiscussion: function (team) { readOnlyDiscussion: function (team) {
var self = this; var self = this;
return !( return !(
this.$el.data('privileged') || self.userInfo.privileged ||
_.any(team.attributes.membership, function (membership) { _.any(team.attributes.membership, function (membership) {
return membership.user.username === self.$el.data('username'); return membership.user.username === self.userInfo.username;
}) })
); );
} }
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
<div class="container"> <div class="container">
<div class="teams-wrapper"> <div class="teams-wrapper">
<section class="teams-content" data-username=${json.dumps(username, cls=EscapedEdxJSONEncoder)} data-privileged="${json.dumps(privileged)}"> <section class="teams-content">
</section> </section>
</div> </div>
</div> </div>
...@@ -35,15 +35,14 @@ ...@@ -35,15 +35,14 @@
TeamsTabFactory({ TeamsTabFactory({
courseID: '${ unicode(course.id) }', courseID: '${ unicode(course.id) }',
topics: ${ json.dumps(topics, cls=EscapedEdxJSONEncoder) }, topics: ${ json.dumps(topics, cls=EscapedEdxJSONEncoder) },
teamMemberships: ${ json.dumps(team_memberships, cls=EscapedEdxJSONEncoder) }, userInfo: ${ json.dumps(user_info, cls=EscapedEdxJSONEncoder) },
topicUrl: '${ topic_url }', topicUrl: '${ topic_url }',
topicsUrl: '${ topics_url }', topicsUrl: '${ topics_url }',
teamsUrl: '${ teams_url }', teamsUrl: '${ teams_url }',
teamMembershipsUrl: '${ team_memberships_url }', teamMembershipsUrl: '${ team_memberships_url }',
maxTeamSize: ${ course.teams_max_size }, maxTeamSize: ${ course.teams_max_size },
languages: ${ json.dumps(languages, cls=EscapedEdxJSONEncoder) }, languages: ${ json.dumps(languages, cls=EscapedEdxJSONEncoder) },
countries: ${ json.dumps(countries, cls=EscapedEdxJSONEncoder) }, countries: ${ json.dumps(countries, cls=EscapedEdxJSONEncoder) }
username: '${ username }'
}); });
</%static:require_module> </%static:require_module>
</%block> </%block>
......
...@@ -97,17 +97,19 @@ class TeamsDashboardView(View): ...@@ -97,17 +97,19 @@ class TeamsDashboardView(View):
context = { context = {
"course": course, "course": course,
"topics": topics_serializer.data, "topics": topics_serializer.data,
"user_info": {
"username": user.username,
"privileged": has_discussion_privileges(user, course_key),
"team_memberships_data": team_memberships_serializer.data,
},
"topic_url": reverse( "topic_url": reverse(
'topics_detail', kwargs={'topic_id': 'topic_id', 'course_id': str(course_id)}, request=request 'topics_detail', kwargs={'topic_id': 'topic_id', 'course_id': str(course_id)}, request=request
), ),
"team_memberships": team_memberships_serializer.data,
"topics_url": reverse('topics_list', request=request), "topics_url": reverse('topics_list', request=request),
"teams_url": reverse('teams_list', request=request), "teams_url": reverse('teams_list', request=request),
"team_memberships_url": reverse('team_membership_list', request=request), "team_memberships_url": reverse('team_membership_list', request=request),
"languages": settings.ALL_LANGUAGES, "languages": settings.ALL_LANGUAGES,
"countries": list(countries), "countries": list(countries),
"username": user.username,
"privileged": has_discussion_privileges(user, course_key),
"disable_courseware_js": True, "disable_courseware_js": True,
} }
return render_to_response("teams/teams.html", context) return render_to_response("teams/teams.html", context)
......
...@@ -790,9 +790,8 @@ ...@@ -790,9 +790,8 @@
'lms/include/js/spec/discovery/discovery_factory_spec.js', 'lms/include/js/spec/discovery/discovery_factory_spec.js',
'lms/include/js/spec/ccx/schedule_spec.js', 'lms/include/js/spec/ccx/schedule_spec.js',
'lms/include/teams/js/spec/collections/topic_collection_spec.js', 'lms/include/teams/js/spec/collections/topic_collection_spec.js',
'lms/include/teams/js/spec/edit_team_spec.js', 'lms/include/teams/js/spec/teams_tab_factory_spec.js',
'lms/include/teams/js/spec/team_actions_spec.js', 'lms/include/teams/js/spec/views/edit_team_spec.js',
'lms/include/teams/js/spec/teams_factory_spec.js',
'lms/include/teams/js/spec/views/team_discussion_spec.js', 'lms/include/teams/js/spec/views/team_discussion_spec.js',
'lms/include/teams/js/spec/views/team_profile_spec.js', 'lms/include/teams/js/spec/views/team_profile_spec.js',
'lms/include/teams/js/spec/views/teams_spec.js', 'lms/include/teams/js/spec/views/teams_spec.js',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment