Commit c78b84ca by Albert (AJ) St. Aubin Committed by GitHub

Merge pull request #15480 from edx/staubina/ed-592

Staubina/ed 592
parents 1f6a4f22 b8b0110d
......@@ -122,7 +122,7 @@
userId = this.get('user_id');
if (userId) {
this.set('staff_authored', DiscussionUtil.isStaff(userId));
this.set('community_ta_authored', DiscussionUtil.isTA(userId));
this.set('community_ta_authored', DiscussionUtil.isTA(userId) || DiscussionUtil.isGroupTA(userId));
} else {
this.set('staff_authored', false);
this.set('community_ta_authored', false);
......
/* globals $$course_id, Content, Markdown, MathJax, URI */
/* globals $$course_id, Content, Markdown, MathJax, URI, _ */
(function() {
'use strict';
this.DiscussionUtil = (function() {
......@@ -41,6 +41,16 @@
return _.include(ta, parseInt(userId));
};
DiscussionUtil.isGroupTA = function(userId) {
var groupTa,
localUserId = userId;
if (_.isUndefined(userId)) {
localUserId = this.user ? this.user.id : void 0;
}
groupTa = _.union(this.roleIds['Group Moderator']);
return _.include(groupTa, parseInt(localUserId, 10));
};
DiscussionUtil.isPrivilegedUser = function(userId) {
return this.isStaff(userId) || this.isTA(userId);
};
......
......@@ -508,7 +508,8 @@
return _.template($('#post-user-display-template').html())({
username: endorsement.username,
user_url: DiscussionUtil.urlFor('user_profile', endorsement.user_id),
is_community_ta: DiscussionUtil.isTA(endorsement.user_id),
is_community_ta: DiscussionUtil.isTA(endorsement.user_id) ||
DiscussionUtil.isGroupTA(endorsement.user_id),
is_staff: DiscussionUtil.isStaff(endorsement.user_id)
});
} else {
......
......@@ -45,7 +45,12 @@ from certificates.models import CertificateInvalidation, CertificateStatuses, Ce
from courseware.access import has_access
from courseware.courses import get_course_by_id, get_course_with_access
from courseware.models import StudentModule
from django_comment_client.utils import has_forum_access
from django_comment_client.utils import (
has_forum_access,
get_course_discussion_settings,
get_group_name,
get_group_id_for_user
)
from django_comment_common.models import (
Role,
FORUM_ROLE_ADMINISTRATOR,
......@@ -933,6 +938,7 @@ def list_course_role_members(request, course_id):
def extract_user_info(user):
""" convert user into dicts for json view """
return {
'username': user.username,
'email': user.email,
......@@ -2505,18 +2511,25 @@ def list_forum_members(request, course_id):
except Role.DoesNotExist:
users = []
course_discussion_settings = get_course_discussion_settings(course_id)
def extract_user_info(user):
""" Convert user to dict for json rendering. """
group_id = get_group_id_for_user(user, course_discussion_settings)
group_name = get_group_name(group_id, course_discussion_settings)
return {
'username': user.username,
'email': user.email,
'first_name': user.first_name,
'last_name': user.last_name,
'group_name': group_name,
}
response_payload = {
'course_id': course_id.to_deprecated_string(),
rolename: map(extract_user_info, users),
'division_scheme': course_discussion_settings.division_scheme,
}
return JsonResponse(response_payload)
......
......@@ -12,7 +12,7 @@ such that the value can be defined later than this assignment (file load order).
(function() {
'use strict';
var AuthListWidget, BatchEnrollment, BetaTesterBulkAddition,
MemberListWidget, Membership, emailStudents, plantTimeout, statusAjaxError,
MemberListWidget, Membership, emailStudents, plantTimeout, statusAjaxError, enableAddButton,
/* eslint-disable */
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
......@@ -26,6 +26,18 @@ such that the value can be defined later than this assignment (file load order).
return window.InstructorDashboard.util.statusAjaxError.apply(this, arguments);
};
enableAddButton = function(enable, parent) {
var $addButton = parent.$('input[type="button"].add');
var $addField = parent.$('input[type="text"].add-field');
if (enable) {
$addButton.removeAttr('disabled');
$addField.removeAttr('disabled');
} else {
$addButton.attr('disabled', true);
$addField.attr('disabled', true);
}
};
emailStudents = false;
MemberListWidget = (function() {
......@@ -92,17 +104,22 @@ such that the value can be defined later than this assignment (file load order).
__extends(AuthListWidget, _super); // eslint-disable-line no-use-before-define
function AuthListWidget($container, rolename, $errorSection) { // eslint-disable-line no-shadow
var msg,
authlistwidget = this;
authListWidget = this,
labelsList = [gettext('Username'), gettext('Email'), gettext('Revoke access')];
this.rolename = rolename;
this.$errorSection = $errorSection;
this.list_enabled = true;
if (this.rolename === 'Group Moderator') {
labelsList = [gettext('Username'), gettext('Email'), gettext('Group'), gettext('Revoke access')];
}
AuthListWidget.__super__.constructor.call(this, $container, { // eslint-disable-line no-underscore-dangle
title: $container.data('display-name'),
info: $container.data('info-text'),
labels: [gettext('Username'), gettext('Email'), gettext('Revoke access')],
labels: labelsList,
add_placeholder: gettext('Enter username or email'),
add_btn_label: $container.data('add-button-label'),
add_handler: function(input) {
return authlistwidget.add_handler(input);
return authListWidget.add_handler(input);
}
});
this.debug = true;
......@@ -122,15 +139,15 @@ such that the value can be defined later than this assignment (file load order).
};
AuthListWidget.prototype.add_handler = function(input) {
var authlistwidgetaddhandler = this;
var authListWidgetAddHandler = this;
if ((input != null) && input !== '') {
return this.modify_member_access(input, 'allow', function(error) {
if (error !== null) {
return authlistwidgetaddhandler.show_errors(error);
return authListWidgetAddHandler.show_errors(error);
}
authlistwidgetaddhandler.clear_errors();
authlistwidgetaddhandler.clear_input();
return authlistwidgetaddhandler.reload_list();
authListWidgetAddHandler.clear_errors();
authListWidgetAddHandler.clear_input();
return authListWidgetAddHandler.reload_list();
});
} else {
return this.show_errors(gettext('Please enter a username or email.'));
......@@ -138,43 +155,69 @@ such that the value can be defined later than this assignment (file load order).
};
AuthListWidget.prototype.reload_list = function() {
var authlistwidgetreloadlist = this;
return this.get_member_list(function(error, memberList) {
var authListWidgetReloadList = this,
$selectedOption;
return this.get_member_list(function(error, memberList, divisionScheme) {
if (error !== null) {
return authlistwidgetreloadlist.show_errors(error);
authListWidgetReloadList.show_errors(error);
return;
}
authlistwidgetreloadlist.clear_rows();
return _.each(memberList, function(member) {
authListWidgetReloadList.clear_rows();
_.each(memberList, function(member) {
var $revokeBtn, labelTrans;
labelTrans = gettext('Revoke access');
$revokeBtn = $(_.template('<div class="revoke"><span class="icon fa fa-times-circle" aria-hidden="true"></span> <%- label %></div>')({ // eslint-disable-line max-len
label: labelTrans
}), {
class: 'revoke'
});
$revokeBtn.click(function() {
return authlistwidgetreloadlist.modify_member_access(member.email, 'revoke', function(err) {
authListWidgetReloadList.modify_member_access(member.email, 'revoke', function(err) {
if (err !== null) {
return authlistwidgetreloadlist.show_errors(err);
authListWidgetReloadList.show_errors(err);
return;
}
authlistwidgetreloadlist.clear_errors();
return authlistwidgetreloadlist.reload_list();
authListWidgetReloadList.clear_errors();
authListWidgetReloadList.reload_list();
});
});
return authlistwidgetreloadlist.add_row([member.username, member.email, $revokeBtn]);
if (authListWidgetReloadList.rolename === 'Group Moderator') {
if (divisionScheme !== undefined && divisionScheme === 'none') {
// There is No discussion division scheme selected so the Group Moderator role
// should be disabled
authListWidgetReloadList.list_enabled = false;
$selectedOption = $('select#member-lists-selector').children('option:selected');
if ($selectedOption[0].value === authListWidgetReloadList.rolename) {
authListWidgetReloadList.show_errors(
gettext('This role requires a divided discussions scheme.')
);
enableAddButton(false, authListWidgetReloadList);
}
} else {
authListWidgetReloadList.list_enabled = true;
enableAddButton(true, authListWidgetReloadList);
authListWidgetReloadList.add_row([member.username, member.email,
member.group_name, $revokeBtn]
);
}
} else {
authListWidgetReloadList.add_row([member.username, member.email, $revokeBtn]);
}
});
});
};
AuthListWidget.prototype.clear_errors = function() {
var ref, result;
result = (this.$error_section) != null ? ref.text('') : undefined;
var result;
result = this.$errorSection !== undefined ? this.$errorSection.text('') : undefined;
return result;
};
AuthListWidget.prototype.show_errors = function(msg) {
var ref, result;
result = (this.$error_section) != null ? ref.text(msg) : undefined;
var result;
result = this.$errorSection !== undefined ? this.$errorSection.text(msg) : undefined;
return result;
};
......@@ -188,7 +231,11 @@ such that the value can be defined later than this assignment (file load order).
rolename: this.rolename
},
success: function(data) {
return typeof cb === 'function' ? cb(null, data[authlistwidgetgetmemberlist.rolename]) : undefined;
return typeof cb === 'function' ? cb(
null,
data[authlistwidgetgetmemberlist.rolename],
data.division_scheme
) : undefined;
}
});
};
......@@ -933,6 +980,7 @@ such that the value can be defined later than this assignment (file load order).
this.$list_selector = this.$section.find('select#member-lists-selector');
this.$auth_list_containers = this.$section.find('.auth-list-container');
this.$auth_list_errors = this.$section.find('.member-lists-management .request-response-error');
this.auth_lists = _.map(this.$auth_list_containers, function(authListContainer) {
var rolename;
rolename = $(authListContainer).data('rolename');
......@@ -944,6 +992,7 @@ such that the value can be defined later than this assignment (file load order).
authList = ref[i];
this.$list_selector.append($('<option/>', {
text: authList.$container.data('display-name'),
value: authList.rolename,
data: {
auth_list: authList
}
......@@ -955,6 +1004,7 @@ such that the value can be defined later than this assignment (file load order).
this.$list_selector.change(function() {
var $opt, j, len1, ref1;
$opt = thismembership.$list_selector.children('option:selected');
if (!($opt.length > 0)) {
return;
}
......@@ -966,11 +1016,28 @@ such that the value can be defined later than this assignment (file load order).
authList = $opt.data('auth_list');
authList.$container.addClass('active');
authList.re_view();
// On Change update the Group Moderation list
if ($opt[0].value === 'Group Moderator') {
if (!authList.list_enabled) {
authList.show_errors(gettext('This role requires a divided discussions scheme.'));
enableAddButton(false, authList);
} else {
enableAddButton(true, authList);
}
}
});
this.$list_selector.change();
}
membership.prototype.onClickTitle = function() {};
membership.prototype.onClickTitle = function() {
var list;
// When the title is clicked refresh all the authorization lists as the member list
// may have changed since render.
for (list = 0; list < this.auth_lists.length; list++) {
this.auth_lists[list].re_view();
}
};
return membership;
}());
......
......@@ -223,26 +223,25 @@ from openedx.core.djangolib.markup import HTML, Text
<div class="auth-list-container"
data-rolename="Group Moderator"
data-display-name="${_("Discussion Group Moderators")}"
data-display-name="${_("Group Community TA")}"
data-info-text="
${_("Discussion Group Moderators can edit or delete any post, clear misuse flags, close "
"and re-open threads, endorse responses, and see posts from all groups. "
"Their posts are marked as 'staff'. They cannot manage course team membership by "
"adding or removing discussion moderation roles. Only enrolled users can be "
"added as Discussion Moderators.")}"
${_("Group Community TAs are members of the community who help course teams moderate discussions. Group "
"Community TAs see only posts by learners in their assigned group. They can edit or delete posts, "
"clear flags, close and re-open threads, and endorse responses, but only for posts by learners in "
"their group. Their posts are marked as 'Community TA'. Only enrolled learners can be added as Group "
"Community TAs.")}"
data-list-endpoint="${ section_data['list_forum_members_url'] }"
data-modify-endpoint="${ section_data['update_forum_role_membership_url'] }"
data-add-button-label="${_("Add Group Moderator")}"
data-add-button-label="${_("Add Group Community TA")}"
></div>
<div class="auth-list-container"
data-rolename="Community TA"
data-display-name="${_("Discussion Community TAs")}"
data-display-name="${_("Community TA")}"
data-info-text="
${_("Community TAs are members of the community whom you deem particularly "
"helpful on the discussion boards. They can edit or delete any post, clear "
"misuse flags, close and re-open threads, endorse responses, and see posts from "
"all groups. Their posts are marked as 'Community TA'. Only enrolled users can "
${_("Community TAs are members of the community who help course teams moderate discussions. "
"They can see posts by all learners, and can edit or delete posts, clear flags, close or re-open "
"threads, and endorse responses. Their posts are marked as 'Community TA'. Only enrolled learners can "
"be added as Community TAs.")}"
data-list-endpoint="${ section_data['list_forum_members_url'] }"
data-modify-endpoint="${ section_data['update_forum_role_membership_url'] }"
......
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