Ui updates, Error messaging shown when discussion scheme is not selected
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* 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;
|
||||
}());
|
||||
|
||||
@@ -250,26 +250,25 @@ from django.utils.translation import ugettext as _
|
||||
|
||||
<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'] }"
|
||||
|
||||
Reference in New Issue
Block a user