Commit cfe855f1 by Matjaz Gregoric Committed by GitHub

Merge pull request #12832 from open-craft/mtyaka/ccx-discussions

Enable discussion forums on CCX courses.
parents 2251097c 8dc84bec
......@@ -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)
......
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
......
# -*- 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')
......
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