Merge pull request #12832 from open-craft/mtyaka/ccx-discussions
Enable discussion forums on CCX courses.
This commit is contained in:
@@ -46,7 +46,14 @@ def assign_default_role(course_id, user):
|
||||
"""
|
||||
Assign forum default role 'Student' to user
|
||||
"""
|
||||
role, __ = Role.objects.get_or_create(course_id=course_id, name=FORUM_ROLE_STUDENT)
|
||||
assign_role(course_id, user, FORUM_ROLE_STUDENT)
|
||||
|
||||
|
||||
def assign_role(course_id, user, rolename):
|
||||
"""
|
||||
Assign forum role `rolename` to user
|
||||
"""
|
||||
role, __ = Role.objects.get_or_create(course_id=course_id, name=rolename)
|
||||
user.roles.add(role)
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
from django_comment_common.models import Role
|
||||
"""
|
||||
Common comment client utility functions.
|
||||
"""
|
||||
|
||||
from django_comment_common.models import Role, FORUM_ROLE_ADMINISTRATOR, FORUM_ROLE_MODERATOR, \
|
||||
FORUM_ROLE_COMMUNITY_TA, FORUM_ROLE_STUDENT
|
||||
|
||||
|
||||
class ThreadContext(object):
|
||||
@@ -7,14 +12,14 @@ class ThreadContext(object):
|
||||
COURSE = 'course'
|
||||
|
||||
|
||||
_STUDENT_ROLE_PERMISSIONS = ["vote", "update_thread", "follow_thread", "unfollow_thread",
|
||||
"update_comment", "create_sub_comment", "unvote", "create_thread",
|
||||
"follow_commentable", "unfollow_commentable", "create_comment", ]
|
||||
STUDENT_ROLE_PERMISSIONS = ["vote", "update_thread", "follow_thread", "unfollow_thread",
|
||||
"update_comment", "create_sub_comment", "unvote", "create_thread",
|
||||
"follow_commentable", "unfollow_commentable", "create_comment", ]
|
||||
|
||||
_MODERATOR_ROLE_PERMISSIONS = ["edit_content", "delete_thread", "openclose_thread",
|
||||
"endorse_comment", "delete_comment", "see_all_cohorts"]
|
||||
MODERATOR_ROLE_PERMISSIONS = ["edit_content", "delete_thread", "openclose_thread",
|
||||
"endorse_comment", "delete_comment", "see_all_cohorts"]
|
||||
|
||||
_ADMINISTRATOR_ROLE_PERMISSIONS = ["manage_moderator"]
|
||||
ADMINISTRATOR_ROLE_PERMISSIONS = ["manage_moderator"]
|
||||
|
||||
|
||||
def _save_forum_role(course_key, name):
|
||||
@@ -34,18 +39,18 @@ def seed_permissions_roles(course_key):
|
||||
"""
|
||||
Create and assign permissions for forum roles
|
||||
"""
|
||||
administrator_role = _save_forum_role(course_key, "Administrator")
|
||||
moderator_role = _save_forum_role(course_key, "Moderator")
|
||||
community_ta_role = _save_forum_role(course_key, "Community TA")
|
||||
student_role = _save_forum_role(course_key, "Student")
|
||||
administrator_role = _save_forum_role(course_key, FORUM_ROLE_ADMINISTRATOR)
|
||||
moderator_role = _save_forum_role(course_key, FORUM_ROLE_MODERATOR)
|
||||
community_ta_role = _save_forum_role(course_key, FORUM_ROLE_COMMUNITY_TA)
|
||||
student_role = _save_forum_role(course_key, FORUM_ROLE_STUDENT)
|
||||
|
||||
for per in _STUDENT_ROLE_PERMISSIONS:
|
||||
for per in STUDENT_ROLE_PERMISSIONS:
|
||||
student_role.add_permission(per)
|
||||
|
||||
for per in _MODERATOR_ROLE_PERMISSIONS:
|
||||
for per in MODERATOR_ROLE_PERMISSIONS:
|
||||
moderator_role.add_permission(per)
|
||||
|
||||
for per in _ADMINISTRATOR_ROLE_PERMISSIONS:
|
||||
for per in ADMINISTRATOR_ROLE_PERMISSIONS:
|
||||
administrator_role.add_permission(per)
|
||||
|
||||
moderator_role.inherit_permissions(student_role)
|
||||
@@ -62,21 +67,21 @@ def are_permissions_roles_seeded(course_id):
|
||||
the database
|
||||
"""
|
||||
try:
|
||||
administrator_role = Role.objects.get(name="Administrator", course_id=course_id)
|
||||
moderator_role = Role.objects.get(name="Moderator", course_id=course_id)
|
||||
student_role = Role.objects.get(name="Student", course_id=course_id)
|
||||
administrator_role = Role.objects.get(name=FORUM_ROLE_ADMINISTRATOR, course_id=course_id)
|
||||
moderator_role = Role.objects.get(name=FORUM_ROLE_MODERATOR, course_id=course_id)
|
||||
student_role = Role.objects.get(name=FORUM_ROLE_STUDENT, course_id=course_id)
|
||||
except:
|
||||
return False
|
||||
|
||||
for per in _STUDENT_ROLE_PERMISSIONS:
|
||||
for per in STUDENT_ROLE_PERMISSIONS:
|
||||
if not student_role.has_permission(per):
|
||||
return False
|
||||
|
||||
for per in _MODERATOR_ROLE_PERMISSIONS + _STUDENT_ROLE_PERMISSIONS:
|
||||
for per in MODERATOR_ROLE_PERMISSIONS + STUDENT_ROLE_PERMISSIONS:
|
||||
if not moderator_role.has_permission(per):
|
||||
return False
|
||||
|
||||
for per in _ADMINISTRATOR_ROLE_PERMISSIONS + _MODERATOR_ROLE_PERMISSIONS + _STUDENT_ROLE_PERMISSIONS:
|
||||
for per in ADMINISTRATOR_ROLE_PERMISSIONS + MODERATOR_ROLE_PERMISSIONS + STUDENT_ROLE_PERMISSIONS:
|
||||
if not administrator_role.has_permission(per):
|
||||
return False
|
||||
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
|
||||
from ccx_keys.locator import CCXLocator
|
||||
from courseware.courses import get_course_by_id
|
||||
from django.db import migrations
|
||||
from django.http import Http404
|
||||
|
||||
from django_comment_common.models import FORUM_ROLE_ADMINISTRATOR, FORUM_ROLE_MODERATOR, \
|
||||
FORUM_ROLE_COMMUNITY_TA, FORUM_ROLE_STUDENT
|
||||
from django_comment_common.utils import STUDENT_ROLE_PERMISSIONS, MODERATOR_ROLE_PERMISSIONS, \
|
||||
ADMINISTRATOR_ROLE_PERMISSIONS
|
||||
|
||||
log = logging.getLogger("edx.ccx")
|
||||
|
||||
|
||||
def seed_forum_roles_for_existing_ccx(apps, schema_editor):
|
||||
"""
|
||||
Seed forum roles and make CCX coach forum admin for respective CCX(s).
|
||||
|
||||
Arguments:
|
||||
apps (Applications): Apps in edX platform.
|
||||
schema_editor (SchemaEditor): For editing database schema i.e create, delete field (column)
|
||||
|
||||
"""
|
||||
CustomCourseForEdX = apps.get_model("ccx", "CustomCourseForEdX")
|
||||
Role = apps.get_model("django_comment_common", "Role")
|
||||
Permission = apps.get_model("django_comment_common", "Permission")
|
||||
db_alias = schema_editor.connection.alias
|
||||
# This will need to be changed if ccx gets moved out of the default db for some reason.
|
||||
if db_alias != 'default':
|
||||
log.info("Skipping CCX migration on non-default database.")
|
||||
return
|
||||
|
||||
for ccx in CustomCourseForEdX.objects.all():
|
||||
if not ccx.course_id or ccx.course_id.deprecated:
|
||||
# prevent migration for deprecated course ids or invalid ids.
|
||||
log.warning(
|
||||
"Skipping CCX %s due to invalid or deprecated course_id: %s.",
|
||||
ccx.id,
|
||||
ccx.course_id
|
||||
)
|
||||
continue
|
||||
|
||||
ccx_locator = CCXLocator.from_course_locator(ccx.course_id, unicode(ccx.id))
|
||||
|
||||
# Create forum roles.
|
||||
admin_role, _ = Role.objects.get_or_create(name=FORUM_ROLE_ADMINISTRATOR, course_id=ccx_locator)
|
||||
moderator_role, _ = Role.objects.get_or_create(name=FORUM_ROLE_MODERATOR, course_id=ccx_locator)
|
||||
community_ta_role, _ = Role.objects.get_or_create(name=FORUM_ROLE_COMMUNITY_TA, course_id=ccx_locator)
|
||||
student_role, _ = Role.objects.get_or_create(name=FORUM_ROLE_STUDENT, course_id=ccx_locator)
|
||||
|
||||
# Add permissions for each role.
|
||||
for name in ADMINISTRATOR_ROLE_PERMISSIONS:
|
||||
admin_role.permissions.add(Permission.objects.get_or_create(name=name)[0])
|
||||
for name in MODERATOR_ROLE_PERMISSIONS:
|
||||
moderator_role.permissions.add(Permission.objects.get_or_create(name=name)[0])
|
||||
for name in STUDENT_ROLE_PERMISSIONS:
|
||||
student_role.permissions.add(Permission.objects.get_or_create(name=name)[0])
|
||||
for permission in student_role.permissions.all():
|
||||
moderator_role.permissions.add(permission)
|
||||
for permission in moderator_role.permissions.all():
|
||||
community_ta_role.permissions.add(permission)
|
||||
for permission in moderator_role.permissions.all():
|
||||
admin_role.permissions.add(permission)
|
||||
|
||||
# Make CCX coach forum admin.
|
||||
ccx.coach.roles.add(admin_role)
|
||||
|
||||
log.info("Seeded forum permissions for CCX %s", ccx_locator)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ccx', '0003_add_master_course_staff_in_ccx'),
|
||||
('django_comment_common', '0002_forumsconfig'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(code=seed_forum_roles_for_existing_ccx, reverse_code=migrations.RunPython.noop)
|
||||
]
|
||||
@@ -17,6 +17,9 @@ from courseware.tests.factories import StudentModuleFactory
|
||||
from courseware.tests.helpers import LoginEnrollmentTestCase
|
||||
from courseware.tabs import get_course_tab_list
|
||||
from courseware.testutils import FieldOverrideTestMixin
|
||||
from django_comment_client.utils import has_forum_access
|
||||
from django_comment_common.models import FORUM_ROLE_ADMINISTRATOR
|
||||
from django_comment_common.utils import are_permissions_roles_seeded
|
||||
from instructor.access import (
|
||||
allow_access,
|
||||
list_with_level,
|
||||
@@ -423,6 +426,10 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
list_staff_master_course = list_with_level(self.course, 'staff')
|
||||
list_instructor_master_course = list_with_level(self.course, 'instructor')
|
||||
|
||||
# assert that forum roles are seeded
|
||||
self.assertTrue(are_permissions_roles_seeded(course_key))
|
||||
self.assertTrue(has_forum_access(self.coach.username, course_key, FORUM_ROLE_ADMINISTRATOR))
|
||||
|
||||
with ccx_course(course_key) as course_ccx:
|
||||
list_staff_ccx_course = list_with_level(course_ccx, 'staff')
|
||||
self.assertEqual(len(list_staff_master_course), len(list_staff_ccx_course))
|
||||
|
||||
@@ -30,6 +30,8 @@ from courseware.access import has_access
|
||||
from courseware.courses import get_course_by_id
|
||||
|
||||
from courseware.field_overrides import disable_overrides
|
||||
from django_comment_common.models import FORUM_ROLE_ADMINISTRATOR, assign_role
|
||||
from django_comment_common.utils import seed_permissions_roles
|
||||
from edxmako.shortcuts import render_to_response
|
||||
from lms.djangoapps.grades.course_grades import iterate_grades_for
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
@@ -220,6 +222,11 @@ def create_ccx(request, course, ccx=None):
|
||||
|
||||
ccx_id = CCXLocator.from_course_locator(course.id, unicode(ccx.id))
|
||||
|
||||
# Create forum roles
|
||||
seed_permissions_roles(ccx_id)
|
||||
# Assign administrator forum role to CCX coach
|
||||
assign_role(ccx_id, request.user, FORUM_ROLE_ADMINISTRATOR)
|
||||
|
||||
url = reverse('ccx_coach_dashboard', kwargs={'course_id': ccx_id})
|
||||
|
||||
# Enroll the coach in the course
|
||||
|
||||
@@ -14,7 +14,6 @@ import pystache_custom as pystache
|
||||
from opaque_keys.edx.locations import i4xEncoder
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from lms.djangoapps.ccx.overrides import get_current_ccx
|
||||
|
||||
from django_comment_common.models import Role, FORUM_ROLE_STUDENT
|
||||
from django_comment_client.permissions import check_permissions_by_view, has_permission, get_team
|
||||
@@ -806,11 +805,8 @@ def is_commentable_cohorted(course_key, commentable_id):
|
||||
|
||||
def is_discussion_enabled(course_id):
|
||||
"""
|
||||
Return True if Discussion is enabled for a course; else False
|
||||
Return True if discussions are enabled; else False
|
||||
"""
|
||||
if settings.FEATURES.get('CUSTOM_COURSES_EDX', False):
|
||||
if get_current_ccx(course_id):
|
||||
return False
|
||||
return settings.FEATURES.get('ENABLE_DISCUSSION_SERVICE')
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user