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 @@
this.course_id = options.course_id;
this.username = options.username;
this.privileged = options.privileged;
this.perPage = options.per_page || 10;
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;
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
},
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;
});
......
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"],
describe("Teams Tab Factory", function() {
var teamsTab;
beforeEach(function() {
setFixtures('<section class="teams-content"></section>');
teamsTab = new TeamsTabFactory({
var initializeTeamsTabFactory = function() {
TeamsTabFactory({
topics: {results: []},
topicsUrl: '',
teamsUrl: '',
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() {
......@@ -21,12 +29,14 @@ define(["jquery", "backbone", "teams/js/teams_tab_factory"],
});
it("can load templates", function() {
expect($("body").text()).toContain("My Teams");
expect($("body").text()).toContain("Showing 0 out of 0 total");
initializeTeamsTabFactory();
expect($('.teams-content').text()).toContain("My Teams");
expect($('.teams-content').text()).toContain("Showing 0 out of 0 total");
});
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");
});
});
}
......
......@@ -6,102 +6,113 @@ define([
], function (Backbone, TeamCollection, TeamMembershipCollection, TeamsView) {
'use strict';
describe('Teams View', function () {
var teamsView, teamCollection, initialTeams,
initialTeamMemberships, teamMembershipCollection;
var createTeams = function (startIndex, stopIndex) {
return _.map(_.range(startIndex, stopIndex + 1), function (i) {
return {
name: "team " + i,
id: "id " + i,
language: languages[i%4][0],
country: countries[i%4][0],
is_active: true,
membership: []
};
});
},
countries = [
['', ''],
['US', 'United States'],
['CA', 'Canada'],
['MX', 'Mexico']
],
languages = [
['', ''],
['en', 'English'],
['es', 'Spanish'],
['fr', 'French']
];
var createTeamMemberships = function(startIndex, stopIndex) {
var teams = createTeams(startIndex, stopIndex)
var countries = [
['', ''],
['US', 'United States'],
['CA', 'Canada'],
['MX', 'Mexico']
];
var languages = [
['', ''],
['en', 'English'],
['es', 'Spanish'],
['fr', 'French']
];
var createTeamData = function (startIndex, stopIndex) {
return _.map(_.range(startIndex, stopIndex + 1), function (i) {
return {
user: {
'username': 'andya',
'url': 'https://openedx.example.com/api/user/v1/accounts/andya'
},
team: teams[i-1]
name: "team " + i,
id: "id " + i,
language: languages[i%4][0],
country: countries[i%4][0],
is_active: true,
membership: []
};
});
};
var verifyCards = function(view, teams) {
var teamCards = view.$('.team-card');
_.each(teams, function (team, index) {
var currentCard = teamCards.eq(index);
expect(currentCard.text()).toMatch(team.name);
expect(currentCard.text()).toMatch(_.object(languages)[team.language]);
expect(currentCard.text()).toMatch(_.object(countries)[team.country]);
});
}
beforeEach(function () {
setFixtures('<div class="teams-container"></div>');
initialTeams = createTeams(1, 5);
teamCollection = new TeamCollection(
var createTeams = function(teamData) {
return new TeamCollection(
{
count: 6,
num_pages: 2,
current_page: 1,
start: 0,
results: initialTeams
results: teamData
},
{
course_id: 'my/course/id',
parse: true
}
);
};
initialTeamMemberships = createTeamMemberships(1, 5);
teamMembershipCollection = new TeamMembershipCollection(
var createTeamMembershipsData = function(startIndex, stopIndex) {
var teams = createTeamData(startIndex, stopIndex);
return _.map(_.range(startIndex, stopIndex + 1), function (i) {
return {
user: {
'username': 'andya',
'url': 'https://openedx.example.com/api/user/v1/accounts/andya'
},
team: teams[i-1]
};
});
};
var createTeamMemberships = function(teamMembershipData, options) {
return new TeamMembershipCollection(
{
count: 11,
num_pages: 3,
current_page: 1,
start: 0,
results: initialTeamMemberships
results: teamMembershipData
},
{
course_id: 'my/course/id',
parse: true,
url: 'api/teams/team_memberships',
username: 'andya',
}
_.extend(_.extend({}, {
course_id: 'my/course/id',
parse: true,
url: 'api/teams/team_memberships',
username: 'andya',
privileged: false
}),
options)
);
});
};
it('can render itself with teams collection', function () {
teamsView = new TeamsView({
var verifyCards = function(view, teams) {
var teamCards = view.$('.team-card');
_.each(teams, function (team, index) {
var currentCard = teamCards.eq(index);
expect(currentCard.text()).toMatch(team.name);
expect(currentCard.text()).toMatch(_.object(languages)[team.language]);
expect(currentCard.text()).toMatch(_.object(countries)[team.country]);
});
};
var createTeamsView = function(options) {
return new TeamsView({
el: '.teams-container',
collection: teamCollection,
collection: options.teams || createTeams(createTeamData(1, 5)),
teamMemberships: options.teamMemberships || createTeamMemberships(createTeamMembershipsData(1, 5)),
teamParams: {
topicID: 'test-topic',
countries: countries,
languages: languages
}
}).render();
};
beforeEach(function () {
setFixtures('<div class="teams-container"></div>');
});
it('can render itself with team collection', function () {
var testTeamData = createTeamData(1, 5),
teamsView = createTeamsView({
teams: createTeams(testTeamData)
});
expect(teamsView.$('.teams-paging-header').text()).toMatch('Showing 1-5 out of 6 total');
......@@ -109,45 +120,69 @@ define([
expect(footerEl.text()).toMatch('1\\s+out of\\s+\/\\s+2');
expect(footerEl).not.toHaveClass('hidden');
verifyCards(teamsView, initialTeams);
verifyCards(teamsView, testTeamData);
});
it('can render itself with team memberships collection', function () {
teamsView = new TeamsView({
el: '.teams-container',
collection: teamMembershipCollection,
teamParams: {}
}).render();
it('can render itself with team membership collection', function () {
var teamMembershipsData = createTeamMembershipsData(1, 5),
teamMemberships = createTeamMemberships(teamMembershipsData),
teamsView = createTeamsView({
teams: teamMemberships,
teamMemberships: teamMemberships
});
expect(teamsView.$('.teams-paging-header').text()).toMatch('Showing 1-5 out of 11 total');
var footerEl = teamsView.$('.teams-paging-footer');
expect(footerEl.text()).toMatch('1\\s+out of\\s+\/\\s+3');
expect(footerEl).not.toHaveClass('hidden');
verifyCards(teamsView, initialTeamMemberships);
verifyCards(teamsView, teamMembershipsData);
});
it ('can render the actions view', function () {
teamsView = new TeamsView({
el: '.teams-container',
collection: teamCollection,
teamParams: {},
}).render();
describe("Team Actions View", function() {
it('can render itself correctly', function () {
var emptyMembership = createTeamMemberships([]),
teamsView = createTeamsView({ teamMemberships: emptyMembership });
expect(teamsView.$('.title').text()).toBe('Are you having trouble finding a team to join?');
expect(teamsView.$('.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."
);
});
expect(teamsView.$el.text()).not.toContain(
'Are you having trouble finding a team to join?'
);
teamsView = new TeamsView({
el: '.teams-container',
collection: teamCollection,
teamParams: {},
showActions: true
}).render();
it('can navigate to correct routes', function () {
var emptyMembership = createTeamMemberships([]),
teamsView = createTeamsView({ teamMemberships: emptyMembership });
spyOn(Backbone.history, 'navigate');
teamsView.$('a.browse-teams').click();
expect(Backbone.history.navigate.calls[0].args).toContain('browse');
expect(teamsView.$el.text()).toContain(
'Are you having trouble finding a team to join?'
);
teamsView.$('a.search-teams').click();
// TODO! Should be updated once team description search feature is available
expect(Backbone.history.navigate.calls[1].args).toContain('browse');
teamsView.$('a.create-team').click();
expect(Backbone.history.navigate.calls[2].args).toContain('topics/test-topic/create-team');
});
it('does not show for a user already in a team', function () {
var teamsView = createTeamsView({});
expect(teamsView.$el.text()).not.toContain(
'Are you having trouble finding a team to join?'
);
});
it('shows for a privileged user already in a team', function () {
var staffMembership = createTeamMemberships(
createTeamMembershipsData(1, 5),
{ privileged: true }
),
teamsView = createTeamsView({ teamMemberships: staffMembership });
expect(teamsView.$el.text()).toContain(
'Are you having trouble finding a team to join?'
);
});
});
});
});
......@@ -2,31 +2,62 @@ define([
'jquery',
'backbone',
'common/js/spec_helpers/ajax_helpers',
'teams/js/views/teams_tab',
'URI'
], function ($, Backbone, AjaxHelpers, TeamsTabView, URI) {
'teams/js/views/teams_tab'
], function ($, Backbone, AjaxHelpers, TeamsTabView) {
'use strict';
describe('TeamsTab', function () {
var teamsTabView,
expectContent = function (text) {
expect(teamsTabView.$('.page-content-main').text()).toContain(text);
},
expectHeader = function (text) {
expect(teamsTabView.$('.teams-header').text()).toContain(text);
},
expectError = function (text) {
expect(teamsTabView.$('.warning').text()).toContain(text);
},
expectFocus = function (element) {
expect(element.focus).toHaveBeenCalled();
var expectContent = function (teamsTabView, text) {
expect(teamsTabView.$('.page-content-main').text()).toContain(text);
};
var expectHeader = function (teamsTabView, text) {
expect(teamsTabView.$('.teams-header').text()).toContain(text);
};
var expectError = function (teamsTabView, text) {
expect(teamsTabView.$('.warning').text()).toContain(text);
};
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 () {
setFixtures('<div class="teams-content"></div>');
teamsTabView = new TeamsTabView({
el: $('.teams-content'),
topics: {
var createTeamsTabView = function(options) {
var defaultTopics = {
count: 1,
num_pages: 1,
current_page: 1,
......@@ -38,33 +69,25 @@ define([
team_count: 0
}]
},
teamMemberships: {
count: 1,
currentPage: 1,
numPages: 1,
next: null,
previous: null,
results: [
{
user: {
username: 'andya',
url: 'https://openedx.example.com/api/user/v1/accounts/andya'
teamsTabView = new TeamsTabView(
_.extend(
{
el: $('.teams-content'),
topics: defaultTopics,
userInfo: createUserInfo(),
topicsUrl: 'api/topics/',
topicUrl: 'api/topics/topic_id,test/course/id',
teamsUrl: 'api/teams/',
courseID: 'test/course/id'
},
team: {
description: '',
name: 'Discrete Maths',
id: 'dm',
topic_id: 'algorithms'
},
date_joined: '2015-04-09T17:31:56Z'
},
]
},
topicsUrl: 'api/topics/',
topicUrl: 'api/topics/topic_id,test/course/id',
teamsUrl: 'api/teams/',
courseID: 'test/course/id'
}).render();
options || {}
)
).render();
return teamsTabView;
};
beforeEach(function () {
setFixtures('<div class="teams-content"></div>');
Backbone.history.start();
spyOn($.fn, 'focus');
});
......@@ -74,48 +97,55 @@ define([
});
it('shows the my teams tab initially', function () {
expectHeader('See all teams in your course, organized by topic');
expectContent('Showing 1 out of 1 total');
expectContent('Discrete Maths');
var teamsTabView = createTeamsTabView();
expectHeader(teamsTabView, 'See all teams in your course, organized by topic');
expectContent(teamsTabView, 'Showing 1 out of 1 total');
expectContent(teamsTabView, 'Discrete Maths');
});
describe('Navigation', function () {
it('can switch tabs', function () {
var teamsTabView = createTeamsTabView();
teamsTabView.$('a.nav-item[data-url="browse"]').click();
expectContent('test description');
expectContent(teamsTabView, 'test description');
teamsTabView.$('a.nav-item[data-url="my-teams"]').click();
expectContent('Showing 1 out of 1 total');
expectContent('Discrete Maths');
expectContent(teamsTabView, 'Showing 1 out of 1 total');
expectContent(teamsTabView, 'Discrete Maths');
});
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});
expectError('The page "no_such_page" could not be found.');
expectError(teamsTabView, 'The page "no_such_page" could not be found.');
expectFocus(teamsTabView.$('.warning'));
});
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});
AjaxHelpers.expectRequest(requests, 'GET', 'api/topics/no_such_topic,test/course/id', null);
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'));
});
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});
AjaxHelpers.expectRequest(requests, 'GET', 'api/teams/no_such_team', null);
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'));
});
});
describe('Discussion privileges', 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
// don't even look at the team when the user is
// privileged
......@@ -123,7 +153,12 @@ define([
});
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({
attributes: {
membership: [{
......@@ -136,7 +171,9 @@ define([
});
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({
attributes: { membership: [] }
})).toBe(true);
......
define([
'underscore', 'common/js/spec_helpers/ajax_helpers'
], function (_, AjaxHelpers) {
define(['underscore'], function (_) {
'use strict';
var createMockPostResponse, createMockDiscussionResponse, createAnnotatedContentInfo, createMockThreadResponse,
testCourseID = 'course/1',
......
......@@ -7,7 +7,7 @@
'js/views/fields',
'teams/js/models/team',
'text!teams/templates/edit-team.underscore'],
function (Backbone, _, gettext, FieldViews, TeamModel, edit_team_template) {
function (Backbone, _, gettext, FieldViews, TeamModel, editTeamTemplate) {
return Backbone.View.extend({
maxTeamNameLength: 255,
......@@ -79,7 +79,7 @@
},
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.teamDescriptionField, '.team-required-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 @@
'backbone',
'teams/js/views/team_card',
'common/js/components/views/paginated_view',
'teams/js/views/team_actions'
], function (Backbone, TeamCardView, PaginatedView, TeamActionsView) {
'text!teams/templates/team-actions.underscore'
], function (Backbone, TeamCardView, PaginatedView, teamActionsTemplate) {
var TeamsView = PaginatedView.extend({
type: 'teams',
events: {
'click a.browse-teams': 'browseTeams',
'click a.search-teams': 'searchTeams',
'click a.create-team': 'showCreateTeamForm'
},
initialize: function (options) {
this.topic = options.topic;
this.teamMemberships = options.teamMemberships;
this.teamParams = options.teamParams;
this.itemViewClass = TeamCardView.extend({
router: options.router,
topic: options.topic,
maxTeamSize: options.maxTeamSize,
countries: this.selectorOptionsArrayToHashWithBlank(options.teamParams.countries),
languages: this.selectorOptionsArrayToHashWithBlank(options.teamParams.languages),
languages: this.selectorOptionsArrayToHashWithBlank(options.teamParams.languages)
});
PaginatedView.prototype.initialize.call(this);
this.teamParams = options.teamParams;
this.showActions = options.showActions;
},
render: function () {
PaginatedView.prototype.render.call(this);
if (this.showActions === true) {
var teamActionsView = new TeamActionsView({
teamParams: this.teamParams
});
this.$el.append(teamActionsView.$el);
teamActionsView.render();
if (this.teamMemberships.canUserCreateTeam()) {
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-teams" href="">',
'create_span_start': '<a class="create-team" href="">',
'span_end': '</a>'
}
);
this.$el.append(_.template(teamActionsTemplate, {message: message}));
}
return this;
......@@ -49,6 +60,22 @@
var map = _.object(options);
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;
......
......@@ -41,18 +41,18 @@
var router;
this.courseID = options.courseID;
this.topics = options.topics;
this.teamMemberships = options.teamMemberships;
this.topicUrl = options.topicUrl;
this.teamsUrl = options.teamsUrl;
this.teamMembershipsUrl = options.teamMembershipsUrl;
this.maxTeamSize = options.maxTeamSize;
this.languages = options.languages;
this.countries = options.countries;
this.username = options.username;
this.userInfo = options.userInfo;
// This slightly tedious approach is necessary
// to use regular expressions within Backbone
// routes, allowing us to capture which tab
// name is being routed to
// name is being routed to.
router = this.router = new Backbone.Router();
_.each([
[':default', _.bind(this.routeNotFound, this)],
......@@ -65,20 +65,21 @@
router.route.apply(router, route);
});
this.teamMembershipsCollection = new TeamMembershipCollection(
this.teamMemberships,
this.teamMemberships = new TeamMembershipCollection(
this.userInfo.teamMembershipData,
{
url: this.teamMembershipsUrl,
course_id: this.courseID,
username: this.username,
parse: true,
username: this.userInfo.username,
privileged: this.userInfo.privileged,
parse: true
}
).bootstrap();
this.myTeamsView = new TeamsView({
router: this.router,
collection: this.teamMembershipsCollection,
collection: this.teamMemberships,
teamMemberships: this.teamMemberships,
maxTeamSize: this.maxTeamSize,
teamParams: {
courseId: this.courseID,
......@@ -186,14 +187,14 @@
url: self.teamsUrl,
per_page: 10
});
this.teamsCollection = collection;
self.teamsCollection = collection;
collection.goTo(1)
.done(function() {
var teamsView = new TeamsView({
router: router,
collection: collection,
teamMemberships: self.teamMemberships,
maxTeamSize: self.maxTeamSize,
showActions: true,
teamParams: {
courseId: self.courseID,
teamsUrl: self.teamsUrl,
......@@ -412,9 +413,9 @@
readOnlyDiscussion: function (team) {
var self = this;
return !(
this.$el.data('privileged') ||
self.userInfo.privileged ||
_.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 @@
<div class="container">
<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>
</div>
</div>
......@@ -35,15 +35,14 @@
TeamsTabFactory({
courseID: '${ unicode(course.id) }',
topics: ${ json.dumps(topics, cls=EscapedEdxJSONEncoder) },
teamMemberships: ${ json.dumps(team_memberships, cls=EscapedEdxJSONEncoder) },
userInfo: ${ json.dumps(user_info, cls=EscapedEdxJSONEncoder) },
topicUrl: '${ topic_url }',
topicsUrl: '${ topics_url }',
teamsUrl: '${ teams_url }',
teamMembershipsUrl: '${ team_memberships_url }',
maxTeamSize: ${ course.teams_max_size },
languages: ${ json.dumps(languages, cls=EscapedEdxJSONEncoder) },
countries: ${ json.dumps(countries, cls=EscapedEdxJSONEncoder) },
username: '${ username }'
countries: ${ json.dumps(countries, cls=EscapedEdxJSONEncoder) }
});
</%static:require_module>
</%block>
......
......@@ -97,17 +97,19 @@ class TeamsDashboardView(View):
context = {
"course": course,
"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(
'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),
"teams_url": reverse('teams_list', request=request),
"team_memberships_url": reverse('team_membership_list', request=request),
"languages": settings.ALL_LANGUAGES,
"countries": list(countries),
"username": user.username,
"privileged": has_discussion_privileges(user, course_key),
"disable_courseware_js": True,
}
return render_to_response("teams/teams.html", context)
......
......@@ -790,9 +790,8 @@
'lms/include/js/spec/discovery/discovery_factory_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/edit_team_spec.js',
'lms/include/teams/js/spec/team_actions_spec.js',
'lms/include/teams/js/spec/teams_factory_spec.js',
'lms/include/teams/js/spec/teams_tab_factory_spec.js',
'lms/include/teams/js/spec/views/edit_team_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/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