Commit 7f691e4a by cewing

MIT: CCX. Rename POC to CCX

Final official name is Custom Courses for EdX (CCX), rename all code to remove previous name.

Rename the FEATURE constant used to identify this feature

Rename the middleware for the CCX change

rename the constant used for storing the current poc id on the session.

rename the _PocContext threading local

rename the override provider in all places where it is referenced

`PersonalOnlineCoursesOverrideProvider` -> `CustomCoursesForEdxOverrideProvider`

generally rename symbols from overrides.py to replace `poc` with `ccx` where possible without changing model names or attributes

rename more symbols from poc to ccx
rename util functions from app utils module

general symbol renaming poc -> ccx in views.py and related url changes

Rename the coach role wherever it is used.

reword poc_coach to ccx_coach

UI rename

replace POC with CCX globally

template context variable renamed

rename poc_ to ccx_ in urls and all related locations (views, js, scss etc)

remove pocs migrations

Final massive renaming, including models.  Re-built migration.

cleaning up a few tailing references

Fix reference typo in schedule template JS

undo modifications made on the fly in test setup to ensure that our tests are properly isolated from the rest of the system tests.

Fixes jazkarta/edx-platform#38

Clean up some leftover strings and comments

fixing more strings and comments in python files

fix a naming error in the schedule tab that was causing problems in deleting courseware items.

Fixes jazkarta/edx-platform#36

updating tests and utility code to match changes in infrastructure from latest rebase
parent fbaab967
...@@ -267,12 +267,12 @@ class LibraryUserRole(CourseRole): ...@@ -267,12 +267,12 @@ class LibraryUserRole(CourseRole):
super(LibraryUserRole, self).__init__(self.ROLE, *args, **kwargs) super(LibraryUserRole, self).__init__(self.ROLE, *args, **kwargs)
class CoursePocCoachRole(CourseRole): class CourseCcxCoachRole(CourseRole):
"""A POC Coach""" """A CCX Coach"""
ROLE = 'poc_coach' ROLE = 'ccx_coach'
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(CoursePocCoachRole, self).__init__(self.ROLE, *args, **kwargs) super(CourseCcxCoachRole, self).__init__(self.ROLE, *args, **kwargs)
class OrgStaffRole(OrgRole): class OrgStaffRole(OrgRole):
......
...@@ -660,16 +660,16 @@ def dashboard(request): ...@@ -660,16 +660,16 @@ def dashboard(request):
if course.pre_requisite_courses) if course.pre_requisite_courses)
courses_requirements_not_met = get_pre_requisite_courses_not_completed(user, courses_having_prerequisites) courses_requirements_not_met = get_pre_requisite_courses_not_completed(user, courses_having_prerequisites)
poc_membership_triplets = [] ccx_membership_triplets = []
if settings.FEATURES.get('PERSONAL_ONLINE_COURSES', False): if settings.FEATURES.get('CUSTOM_COURSES_EDX', False):
from pocs import ACTIVE_POC_KEY from ccx import ACTIVE_CCX_KEY
from pocs.utils import get_poc_membership_triplets from ccx.utils import get_ccx_membership_triplets
poc_membership_triplets = get_poc_membership_triplets( ccx_membership_triplets = get_ccx_membership_triplets(
user, course_org_filter, org_filter_out_set user, course_org_filter, org_filter_out_set
) )
# should we deselect any active POC at this time so that we don't have # should we deselect any active CCX at this time so that we don't have
# to change the URL for viewing a course? I think so. # to change the URL for viewing a course? I think so.
request.session[ACTIVE_POC_KEY] = None request.session[ACTIVE_CCX_KEY] = None
context = { context = {
'enrollment_message': enrollment_message, 'enrollment_message': enrollment_message,
...@@ -702,7 +702,7 @@ def dashboard(request): ...@@ -702,7 +702,7 @@ def dashboard(request):
'provider_states': [], 'provider_states': [],
'order_history_list': order_history_list, 'order_history_list': order_history_list,
'courses_requirements_not_met': courses_requirements_not_met, 'courses_requirements_not_met': courses_requirements_not_met,
'poc_membership_triplets': poc_membership_triplets, 'ccx_membership_triplets': ccx_membership_triplets,
} }
if third_party_auth.is_enabled(): if third_party_auth.is_enabled():
...@@ -1818,15 +1818,15 @@ def activate_account(request, key): ...@@ -1818,15 +1818,15 @@ def activate_account(request, key):
if cea.auto_enroll: if cea.auto_enroll:
CourseEnrollment.enroll(student[0], cea.course_id) CourseEnrollment.enroll(student[0], cea.course_id)
# enroll student in any pending POCs he/she may have if auto_enroll flag is set # enroll student in any pending CCXs he/she may have if auto_enroll flag is set
if settings.FEATURES.get('PERSONAL_ONLINE_COURSES'): if settings.FEATURES.get('CUSTOM_COURSES_EDX'):
from pocs.models import PocMembership, PocFutureMembership from ccx.models import CcxMembership, CcxFutureMembership
pfms = PocFutureMembership.objects.filter( pfms = CcxFutureMembership.objects.filter(
email=student[0].email email=student[0].email
) )
for pfm in pfms: for pfm in pfms:
if pfm.auto_enroll: if pfm.auto_enroll:
PocMembership.auto_enroll(student[0], pfm) CcxMembership.auto_enroll(student[0], pfm)
resp = render_to_response( resp = render_to_response(
"registration/activation_complete.html", "registration/activation_complete.html",
......
...@@ -193,7 +193,7 @@ class CourseTab(object): ...@@ -193,7 +193,7 @@ class CourseTab(object):
'edxnotes': EdxNotesTab, 'edxnotes': EdxNotesTab,
'syllabus': SyllabusTab, 'syllabus': SyllabusTab,
'instructor': InstructorTab, # not persisted 'instructor': InstructorTab, # not persisted
'poc_coach': PocCoachTab, # not persisted 'ccx_coach': CcxCoachTab, # not persisted
} }
tab_type = tab_dict.get('type') tab_type = tab_dict.get('type')
...@@ -376,9 +376,9 @@ class DiscussionTab(EnrolledOrStaffTab): ...@@ -376,9 +376,9 @@ class DiscussionTab(EnrolledOrStaffTab):
) )
def can_display(self, course, settings, is_user_authenticated, is_user_staff, is_user_enrolled): def can_display(self, course, settings, is_user_authenticated, is_user_staff, is_user_enrolled):
if settings.FEATURES.get('PERSONAL_ONLINE_COURSES', False): if settings.FEATURES.get('CUSTOM_COURSES_EDX', False):
from pocs.overrides import get_current_poc from ccx.overrides import get_current_ccx
if get_current_poc(): if get_current_ccx():
return False return False
super_can_display = super(DiscussionTab, self).can_display( super_can_display = super(DiscussionTab, self).can_display(
course, settings, is_user_authenticated, is_user_staff, is_user_enrolled course, settings, is_user_authenticated, is_user_staff, is_user_enrolled
...@@ -738,26 +738,26 @@ class InstructorTab(StaffTab): ...@@ -738,26 +738,26 @@ class InstructorTab(StaffTab):
) )
class PocCoachTab(CourseTab): class CcxCoachTab(CourseTab):
""" """
A tab for the personal online course coaches. A tab for the custom course coaches.
""" """
type = 'poc_coach' type = 'ccx_coach'
def __init__(self, tab_dict=None): # pylint: disable=unused-argument def __init__(self, tab_dict=None): # pylint: disable=unused-argument
super(PocCoachTab, self).__init__( super(CcxCoachTab, self).__init__(
name=_('POC Coach'), name=_('CCX Coach'),
tab_id=self.type, tab_id=self.type,
link_func=link_reverse_func('poc_coach_dashboard'), link_func=link_reverse_func('ccx_coach_dashboard'),
) )
def can_display(self, course, settings, *args, **kw): def can_display(self, course, settings, *args, **kw):
# TODO Check that user actually has 'poc_coach' role on course # TODO Check that user actually has 'ccx_coach' role on course
# this is difficult to do because the user isn't passed in. # this is difficult to do because the user isn't passed in.
# We need either a hack or an architectural realignment. # We need either a hack or an architectural realignment.
return ( return (
settings.FEATURES.get('PERSONAL_ONLINE_COURSES', False) and settings.FEATURES.get('CUSTOM_COURSES_EDX', False) and
super(PocCoachTab, self).can_display(course, settings, *args, **kw)) super(CcxCoachTab, self).can_display(course, settings, *args, **kw))
class CourseTabList(List): class CourseTabList(List):
...@@ -860,9 +860,9 @@ class CourseTabList(List): ...@@ -860,9 +860,9 @@ class CourseTabList(List):
instructor_tab = InstructorTab() instructor_tab = InstructorTab()
if instructor_tab.can_display(course, settings, is_user_authenticated, is_user_staff, is_user_enrolled): if instructor_tab.can_display(course, settings, is_user_authenticated, is_user_staff, is_user_enrolled):
yield instructor_tab yield instructor_tab
poc_coach_tab = PocCoachTab() ccx_coach_tab = CcxCoachTab()
if poc_coach_tab.can_display(course, settings, is_user_authenticated, is_user_staff, is_user_enrolled): if ccx_coach_tab.can_display(course, settings, is_user_authenticated, is_user_staff, is_user_enrolled):
yield poc_coach_tab yield ccx_coach_tab
@staticmethod @staticmethod
def iterate_displayable_cms( def iterate_displayable_cms(
......
ACTIVE_CCX_KEY = '_ccx_id'
...@@ -8,49 +8,62 @@ from django.db import models ...@@ -8,49 +8,62 @@ from django.db import models
class Migration(SchemaMigration): class Migration(SchemaMigration):
def forwards(self, orm): def forwards(self, orm):
# Adding model 'PersonalOnlineCourse' # Adding model 'CustomCourseForEdX'
db.create_table('pocs_personalonlinecourse', ( db.create_table('ccx_customcourseforedx', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('course_id', self.gf('xmodule_django.models.CourseKeyField')(max_length=255, db_index=True)), ('course_id', self.gf('xmodule_django.models.CourseKeyField')(max_length=255, db_index=True)),
('display_name', self.gf('django.db.models.fields.CharField')(max_length=255)), ('display_name', self.gf('django.db.models.fields.CharField')(max_length=255)),
('coach', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), ('coach', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
)) ))
db.send_create_signal('pocs', ['PersonalOnlineCourse']) db.send_create_signal('ccx', ['CustomCourseForEdX'])
# Adding model 'PocMembership' # Adding model 'CcxMembership'
db.create_table('pocs_pocmembership', ( db.create_table('ccx_ccxmembership', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('poc', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['pocs.PersonalOnlineCourse'])), ('ccx', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['ccx.CustomCourseForEdX'])),
('student', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), ('student', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
('active', self.gf('django.db.models.fields.BooleanField')(default=False)),
)) ))
db.send_create_signal('pocs', ['PocMembership']) db.send_create_signal('ccx', ['CcxMembership'])
# Adding model 'PocFieldOverride' # Adding model 'CcxFutureMembership'
db.create_table('pocs_pocfieldoverride', ( db.create_table('ccx_ccxfuturemembership', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('poc', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['pocs.PersonalOnlineCourse'])), ('ccx', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['ccx.CustomCourseForEdX'])),
('email', self.gf('django.db.models.fields.CharField')(max_length=255)),
('auto_enroll', self.gf('django.db.models.fields.BooleanField')(default=False)),
))
db.send_create_signal('ccx', ['CcxFutureMembership'])
# Adding model 'CcxFieldOverride'
db.create_table('ccx_ccxfieldoverride', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('ccx', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['ccx.CustomCourseForEdX'])),
('location', self.gf('xmodule_django.models.LocationKeyField')(max_length=255, db_index=True)), ('location', self.gf('xmodule_django.models.LocationKeyField')(max_length=255, db_index=True)),
('field', self.gf('django.db.models.fields.CharField')(max_length=255)), ('field', self.gf('django.db.models.fields.CharField')(max_length=255)),
('value', self.gf('django.db.models.fields.TextField')(default='null')), ('value', self.gf('django.db.models.fields.TextField')(default='null')),
)) ))
db.send_create_signal('pocs', ['PocFieldOverride']) db.send_create_signal('ccx', ['CcxFieldOverride'])
# Adding unique constraint on 'PocFieldOverride', fields ['poc', 'location', 'field'] # Adding unique constraint on 'CcxFieldOverride', fields ['ccx', 'location', 'field']
db.create_unique('pocs_pocfieldoverride', ['poc_id', 'location', 'field']) db.create_unique('ccx_ccxfieldoverride', ['ccx_id', 'location', 'field'])
def backwards(self, orm): def backwards(self, orm):
# Removing unique constraint on 'PocFieldOverride', fields ['poc', 'location', 'field'] # Removing unique constraint on 'CcxFieldOverride', fields ['ccx', 'location', 'field']
db.delete_unique('pocs_pocfieldoverride', ['poc_id', 'location', 'field']) db.delete_unique('ccx_ccxfieldoverride', ['ccx_id', 'location', 'field'])
# Deleting model 'CustomCourseForEdX'
db.delete_table('ccx_customcourseforedx')
# Deleting model 'PersonalOnlineCourse' # Deleting model 'CcxMembership'
db.delete_table('pocs_personalonlinecourse') db.delete_table('ccx_ccxmembership')
# Deleting model 'PocMembership' # Deleting model 'CcxFutureMembership'
db.delete_table('pocs_pocmembership') db.delete_table('ccx_ccxfuturemembership')
# Deleting model 'PocFieldOverride' # Deleting model 'CcxFieldOverride'
db.delete_table('pocs_pocfieldoverride') db.delete_table('ccx_ccxfieldoverride')
models = { models = {
...@@ -83,34 +96,42 @@ class Migration(SchemaMigration): ...@@ -83,34 +96,42 @@ class Migration(SchemaMigration):
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
}, },
'contenttypes.contenttype': { 'ccx.ccxfieldoverride': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, 'Meta': {'unique_together': "(('ccx', 'location', 'field'),)", 'object_name': 'CcxFieldOverride'},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), 'ccx': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ccx.CustomCourseForEdX']"}),
'field': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), 'location': ('xmodule_django.models.LocationKeyField', [], {'max_length': '255', 'db_index': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) 'value': ('django.db.models.fields.TextField', [], {'default': "'null'"})
},
'ccx.ccxfuturemembership': {
'Meta': {'object_name': 'CcxFutureMembership'},
'auto_enroll': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'ccx': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ccx.CustomCourseForEdX']"}),
'email': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
}, },
'pocs.personalonlinecourse': { 'ccx.ccxmembership': {
'Meta': {'object_name': 'PersonalOnlineCourse'}, 'Meta': {'object_name': 'CcxMembership'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'ccx': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ccx.CustomCourseForEdX']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'student': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
},
'ccx.customcourseforedx': {
'Meta': {'object_name': 'CustomCourseForEdX'},
'coach': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), 'coach': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}), 'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
'display_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), 'display_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
}, },
'pocs.pocfieldoverride': { 'contenttypes.contenttype': {
'Meta': {'unique_together': "(('poc', 'location', 'field'),)", 'object_name': 'PocFieldOverride'}, 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'field': ('django.db.models.fields.CharField', [], {'max_length': '255'}), 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'location': ('xmodule_django.models.LocationKeyField', [], {'max_length': '255', 'db_index': 'True'}),
'poc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['pocs.PersonalOnlineCourse']"}),
'value': ('django.db.models.fields.TextField', [], {'default': "'null'"})
},
'pocs.pocmembership': {
'Meta': {'object_name': 'PocMembership'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'poc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['pocs.PersonalOnlineCourse']"}), 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'student': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
} }
} }
complete_apps = ['pocs'] complete_apps = ['ccx']
\ No newline at end of file \ No newline at end of file
...@@ -5,20 +5,20 @@ from student.models import CourseEnrollment, AlreadyEnrolledError ...@@ -5,20 +5,20 @@ from student.models import CourseEnrollment, AlreadyEnrolledError
from xmodule_django.models import CourseKeyField, LocationKeyField from xmodule_django.models import CourseKeyField, LocationKeyField
class PersonalOnlineCourse(models.Model): class CustomCourseForEdX(models.Model):
""" """
A Personal Online Course. A Custom Course.
""" """
course_id = CourseKeyField(max_length=255, db_index=True) course_id = CourseKeyField(max_length=255, db_index=True)
display_name = models.CharField(max_length=255) display_name = models.CharField(max_length=255)
coach = models.ForeignKey(User, db_index=True) coach = models.ForeignKey(User, db_index=True)
class PocMembership(models.Model): class CcxMembership(models.Model):
""" """
Which students are in a POC? Which students are in a CCX?
""" """
poc = models.ForeignKey(PersonalOnlineCourse, db_index=True) ccx = models.ForeignKey(CustomCourseForEdX, db_index=True)
student = models.ForeignKey(User, db_index=True) student = models.ForeignKey(User, db_index=True)
active = models.BooleanField(default=False) active = models.BooleanField(default=False)
...@@ -30,11 +30,11 @@ class PocMembership(models.Model): ...@@ -30,11 +30,11 @@ class PocMembership(models.Model):
msg = "auto enrollment not allowed for {}" msg = "auto enrollment not allowed for {}"
raise ValueError(msg.format(future_membership)) raise ValueError(msg.format(future_membership))
membership = cls( membership = cls(
poc=future_membership.poc, student=student, active=True ccx=future_membership.ccx, student=student, active=True
) )
try: try:
CourseEnrollment.enroll( CourseEnrollment.enroll(
student, future_membership.poc.course_id, check_access=True student, future_membership.ccx.course_id, check_access=True
) )
except AlreadyEnrolledError: except AlreadyEnrolledError:
# if the user is already enrolled in the course, great! # if the user is already enrolled in the course, great!
...@@ -48,24 +48,24 @@ class PocMembership(models.Model): ...@@ -48,24 +48,24 @@ class PocMembership(models.Model):
return cls.objects.filter(student=user, active__exact=active) return cls.objects.filter(student=user, active__exact=active)
class PocFutureMembership(models.Model): class CcxFutureMembership(models.Model):
""" """
Which emails for non-users are waiting to be added to POC on registration Which emails for non-users are waiting to be added to CCX on registration
""" """
poc = models.ForeignKey(PersonalOnlineCourse, db_index=True) ccx = models.ForeignKey(CustomCourseForEdX, db_index=True)
email = models.CharField(max_length=255) email = models.CharField(max_length=255)
auto_enroll = models.BooleanField(default=0) auto_enroll = models.BooleanField(default=0)
class PocFieldOverride(models.Model): class CcxFieldOverride(models.Model):
""" """
Field overrides for personal online courses. Field overrides for custom courses.
""" """
poc = models.ForeignKey(PersonalOnlineCourse, db_index=True) ccx = models.ForeignKey(CustomCourseForEdX, db_index=True)
location = LocationKeyField(max_length=255, db_index=True) location = LocationKeyField(max_length=255, db_index=True)
field = models.CharField(max_length=255) field = models.CharField(max_length=255)
class Meta: class Meta:
unique_together = (('poc', 'location', 'field'),) unique_together = (('ccx', 'location', 'field'),)
value = models.TextField(default='null') value = models.TextField(default='null')
...@@ -8,81 +8,81 @@ import threading ...@@ -8,81 +8,81 @@ import threading
from contextlib import contextmanager from contextlib import contextmanager
from courseware.field_overrides import FieldOverrideProvider from courseware.field_overrides import FieldOverrideProvider
from pocs import ACTIVE_POC_KEY from ccx import ACTIVE_CCX_KEY
from .models import PocMembership, PocFieldOverride from .models import CcxMembership, CcxFieldOverride
class PersonalOnlineCoursesOverrideProvider(FieldOverrideProvider): class CustomCoursesForEdxOverrideProvider(FieldOverrideProvider):
""" """
A concrete implementation of A concrete implementation of
:class:`~courseware.field_overrides.FieldOverrideProvider` which allows for :class:`~courseware.field_overrides.FieldOverrideProvider` which allows for
overrides to be made on a per user basis. overrides to be made on a per user basis.
""" """
def get(self, block, name, default): def get(self, block, name, default):
poc = get_current_poc() ccx = get_current_ccx()
if poc: if ccx:
return get_override_for_poc(poc, block, name, default) return get_override_for_ccx(ccx, block, name, default)
return default return default
class _PocContext(threading.local): class _CcxContext(threading.local):
""" """
A threading local used to implement the `with_poc` context manager, that A threading local used to implement the `with_ccx` context manager, that
keeps track of the POC currently set as the context. keeps track of the CCX currently set as the context.
""" """
poc = None ccx = None
_POC_CONTEXT = _PocContext() _CCX_CONTEXT = _CcxContext()
@contextmanager @contextmanager
def poc_context(poc): def ccx_context(ccx):
""" """
A context manager which can be used to explicitly set the POC that is in A context manager which can be used to explicitly set the CCX that is in
play for field overrides. This mechanism overrides the standard mechanism play for field overrides. This mechanism overrides the standard mechanism
of looking in the user's session to see if they are enrolled in a POC and of looking in the user's session to see if they are enrolled in a CCX and
viewing that POC. viewing that CCX.
""" """
prev = _POC_CONTEXT.poc prev = _CCX_CONTEXT.ccx
_POC_CONTEXT.poc = poc _CCX_CONTEXT.ccx = ccx
yield yield
_POC_CONTEXT.poc = prev _CCX_CONTEXT.ccx = prev
def get_current_poc(): def get_current_ccx():
""" """
Return the poc that is active for this request. Return the ccx that is active for this request.
""" """
poc = _POC_CONTEXT.poc ccx = _CCX_CONTEXT.ccx
if poc: if ccx:
return poc return ccx
def get_override_for_poc(poc, block, name, default=None): def get_override_for_ccx(ccx, block, name, default=None):
""" """
Gets the value of the overridden field for the `poc`. `block` and `name` Gets the value of the overridden field for the `ccx`. `block` and `name`
specify the block and the name of the field. If the field is not specify the block and the name of the field. If the field is not
overridden for the given poc, returns `default`. overridden for the given ccx, returns `default`.
""" """
if not hasattr(block, '_poc_overrides'): if not hasattr(block, '_ccx_overrides'):
block._poc_overrides = {} block._ccx_overrides = {}
overrides = block._poc_overrides.get(poc.id) overrides = block._ccx_overrides.get(ccx.id)
if overrides is None: if overrides is None:
overrides = _get_overrides_for_poc(poc, block) overrides = _get_overrides_for_ccx(ccx, block)
block._poc_overrides[poc.id] = overrides block._ccx_overrides[ccx.id] = overrides
return overrides.get(name, default) return overrides.get(name, default)
def _get_overrides_for_poc(poc, block): def _get_overrides_for_ccx(ccx, block):
""" """
Returns a dictionary mapping field name to overriden value for any Returns a dictionary mapping field name to overriden value for any
overrides set on this block for this POC. overrides set on this block for this CCX.
""" """
overrides = {} overrides = {}
query = PocFieldOverride.objects.filter( query = CcxFieldOverride.objects.filter(
poc=poc, ccx=ccx,
location=block.location location=block.location
) )
for override in query: for override in query:
...@@ -92,68 +92,68 @@ def _get_overrides_for_poc(poc, block): ...@@ -92,68 +92,68 @@ def _get_overrides_for_poc(poc, block):
return overrides return overrides
def override_field_for_poc(poc, block, name, value): def override_field_for_ccx(ccx, block, name, value):
""" """
Overrides a field for the `poc`. `block` and `name` specify the block Overrides a field for the `ccx`. `block` and `name` specify the block
and the name of the field on that block to override. `value` is the and the name of the field on that block to override. `value` is the
value to set for the given field. value to set for the given field.
""" """
override, created = PocFieldOverride.objects.get_or_create( override, created = CcxFieldOverride.objects.get_or_create(
poc=poc, ccx=ccx,
location=block.location, location=block.location,
field=name) field=name)
field = block.fields[name] field = block.fields[name]
override.value = json.dumps(field.to_json(value)) override.value = json.dumps(field.to_json(value))
override.save() override.save()
if hasattr(block, '_poc_overrides'): if hasattr(block, '_ccx_overrides'):
del block._poc_overrides[poc.id] del block._ccx_overrides[ccx.id]
def clear_override_for_poc(poc, block, name): def clear_override_for_ccx(ccx, block, name):
""" """
Clears a previously set field override for the `poc`. `block` and `name` Clears a previously set field override for the `ccx`. `block` and `name`
specify the block and the name of the field on that block to clear. specify the block and the name of the field on that block to clear.
This function is idempotent--if no override is set, nothing action is This function is idempotent--if no override is set, nothing action is
performed. performed.
""" """
try: try:
PocFieldOverride.objects.get( CcxFieldOverride.objects.get(
poc=poc, ccx=ccx,
location=block.location, location=block.location,
field=name).delete() field=name).delete()
if hasattr(block, '_poc_overrides'): if hasattr(block, '_ccx_overrides'):
del block._poc_overrides[poc.id] del block._ccx_overrides[ccx.id]
except PocFieldOverride.DoesNotExist: except CcxFieldOverride.DoesNotExist:
pass pass
class PocMiddleware(object): class CcxMiddleware(object):
""" """
Checks to see if current session is examining a POC and sets the POC as Checks to see if current session is examining a CCX and sets the CCX as
the current POC for the override machinery if so. the current CCX for the override machinery if so.
""" """
def process_request(self, request): def process_request(self, request):
""" """
Do the check. Do the check.
""" """
poc_id = request.session.get(ACTIVE_POC_KEY, None) ccx_id = request.session.get(ACTIVE_CCX_KEY, None)
if poc_id is not None: if ccx_id is not None:
try: try:
membership = PocMembership.objects.get( membership = CcxMembership.objects.get(
student=request.user, active=True, poc__id__exact=poc_id student=request.user, active=True, ccx__id__exact=ccx_id
) )
_POC_CONTEXT.poc = membership.poc _CCX_CONTEXT.ccx = membership.ccx
except PocMembership.DoesNotExist: except CcxMembership.DoesNotExist:
# if there is no membership, be sure to unset the active poc # if there is no membership, be sure to unset the active ccx
_POC_CONTEXT.poc = None _CCX_CONTEXT.ccx = None
request.session.pop(ACTIVE_POC_KEY) request.session.pop(ACTIVE_CCX_KEY)
def process_response(self, request, response): def process_response(self, request, response):
""" """
Clean up afterwards. Clean up afterwards.
""" """
_POC_CONTEXT.poc = None _CCX_CONTEXT.ccx = None
return response return response
from factory.django import DjangoModelFactory
from ccx.models import CustomCourseForEdX
from ccx.models import CcxMembership
from ccx.models import CcxFutureMembership
class CcxFactory(DjangoModelFactory):
FACTORY_FOR = CustomCourseForEdX
display_name = "Test CCX"
class CcxMembershipFactory(DjangoModelFactory):
FACTORY_FOR = CcxMembership
active = False
class CcxFutureMembershipFactory(DjangoModelFactory):
FACTORY_FOR = CcxFutureMembership
from student.models import CourseEnrollment from student.models import CourseEnrollment
from student.roles import CoursePocCoachRole from student.roles import CourseCcxCoachRole
from student.tests.factories import ( from student.tests.factories import (
AdminFactory, AdminFactory,
CourseEnrollmentFactory, CourseEnrollmentFactory,
...@@ -9,34 +9,35 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase ...@@ -9,34 +9,35 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory from xmodule.modulestore.tests.factories import CourseFactory
from .factories import ( from .factories import (
PocFactory, CcxFactory,
PocMembershipFactory, CcxMembershipFactory,
PocFutureMembershipFactory, CcxFutureMembershipFactory,
) )
from ..models import ( from ..models import (
PocMembership, CcxMembership,
PocFutureMembership, CcxFutureMembership,
) )
class TestPocMembership(ModuleStoreTestCase): class TestCcxMembership(ModuleStoreTestCase):
"""Unit tests for the PocMembership model """Unit tests for the CcxMembership model
""" """
def setUp(self): def setUp(self):
"""common setup for all tests""" """common setup for all tests"""
super(TestCcxMembership, self).setUp()
self.course = course = CourseFactory.create() self.course = course = CourseFactory.create()
coach = AdminFactory.create() coach = AdminFactory.create()
role = CoursePocCoachRole(course.id) role = CourseCcxCoachRole(course.id)
role.add_users(coach) role.add_users(coach)
self.poc = PocFactory(course_id=course.id, coach=coach) self.ccx = CcxFactory(course_id=course.id, coach=coach)
enrollment = CourseEnrollmentFactory.create(course_id=course.id) enrollment = CourseEnrollmentFactory.create(course_id=course.id)
self.enrolled_user = enrollment.user self.enrolled_user = enrollment.user
self.unenrolled_user = UserFactory.create() self.unenrolled_user = UserFactory.create()
def create_future_enrollment(self, user, auto_enroll=True): def create_future_enrollment(self, user, auto_enroll=True):
pfm = PocFutureMembershipFactory.create( pfm = CcxFutureMembershipFactory.create(
poc=self.poc, ccx=self.ccx,
email=user.email, email=user.email,
auto_enroll=auto_enroll auto_enroll=auto_enroll
) )
...@@ -48,62 +49,62 @@ class TestPocMembership(ModuleStoreTestCase): ...@@ -48,62 +49,62 @@ class TestPocMembership(ModuleStoreTestCase):
) )
return enrollment.exists() return enrollment.exists()
def has_poc_membership(self, user): def has_ccx_membership(self, user):
membership = PocMembership.objects.filter( membership = CcxMembership.objects.filter(
student=user, poc=self.poc, active=True student=user, ccx=self.ccx, active=True
) )
return membership.exists() return membership.exists()
def has_poc_future_membership(self, user): def has_ccx_future_membership(self, user):
future_membership = PocFutureMembership.objects.filter( future_membership = CcxFutureMembership.objects.filter(
email=user.email, poc=self.poc email=user.email, ccx=self.ccx
) )
return future_membership.exists() return future_membership.exists()
def call_MUT(self, student, future_membership): def call_MUT(self, student, future_membership):
PocMembership.auto_enroll(student, future_membership) CcxMembership.auto_enroll(student, future_membership)
def test_poc_auto_enroll_unregistered_user(self): def test_ccx_auto_enroll_unregistered_user(self):
"""verify auto_enroll works when user is not enrolled in the MOOC """verify auto_enroll works when user is not enrolled in the MOOC
n.b. After auto_enroll, user will have both a MOOC enrollment and a n.b. After auto_enroll, user will have both a MOOC enrollment and a
POC membership CCX membership
""" """
user = self.unenrolled_user user = self.unenrolled_user
pfm = self.create_future_enrollment(user) pfm = self.create_future_enrollment(user)
self.assertTrue(self.has_poc_future_membership(user)) self.assertTrue(self.has_ccx_future_membership(user))
self.assertFalse(self.has_course_enrollment(user)) self.assertFalse(self.has_course_enrollment(user))
# auto_enroll user # auto_enroll user
self.call_MUT(user, pfm) self.call_MUT(user, pfm)
self.assertTrue(self.has_course_enrollment(user)) self.assertTrue(self.has_course_enrollment(user))
self.assertTrue(self.has_poc_membership(user)) self.assertTrue(self.has_ccx_membership(user))
self.assertFalse(self.has_poc_future_membership(user)) self.assertFalse(self.has_ccx_future_membership(user))
def test_poc_auto_enroll_registered_user(self): def test_ccx_auto_enroll_registered_user(self):
"""verify auto_enroll works when user is enrolled in the MOOC """verify auto_enroll works when user is enrolled in the MOOC
""" """
user = self.enrolled_user user = self.enrolled_user
pfm = self.create_future_enrollment(user) pfm = self.create_future_enrollment(user)
self.assertTrue(self.has_poc_future_membership(user)) self.assertTrue(self.has_ccx_future_membership(user))
self.assertTrue(self.has_course_enrollment(user)) self.assertTrue(self.has_course_enrollment(user))
self.call_MUT(user, pfm) self.call_MUT(user, pfm)
self.assertTrue(self.has_course_enrollment(user)) self.assertTrue(self.has_course_enrollment(user))
self.assertTrue(self.has_poc_membership(user)) self.assertTrue(self.has_ccx_membership(user))
self.assertFalse(self.has_poc_future_membership(user)) self.assertFalse(self.has_ccx_future_membership(user))
def test_future_membership_disallows_auto_enroll(self): def test_future_membership_disallows_auto_enroll(self):
"""verify that the PocFutureMembership can veto auto_enroll """verify that the CcxFutureMembership can veto auto_enroll
""" """
user = self.unenrolled_user user = self.unenrolled_user
pfm = self.create_future_enrollment(user, auto_enroll=False) pfm = self.create_future_enrollment(user, auto_enroll=False)
self.assertTrue(self.has_poc_future_membership(user)) self.assertTrue(self.has_ccx_future_membership(user))
self.assertFalse(self.has_course_enrollment(user)) self.assertFalse(self.has_course_enrollment(user))
self.assertRaises(ValueError, self.call_MUT, user, pfm) self.assertRaises(ValueError, self.call_MUT, user, pfm)
self.assertFalse(self.has_course_enrollment(user)) self.assertFalse(self.has_course_enrollment(user))
self.assertFalse(self.has_poc_membership(user)) self.assertFalse(self.has_ccx_membership(user))
self.assertTrue(self.has_poc_future_membership(user)) self.assertTrue(self.has_ccx_future_membership(user))
...@@ -8,12 +8,12 @@ from student.tests.factories import AdminFactory ...@@ -8,12 +8,12 @@ from student.tests.factories import AdminFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from ..models import PersonalOnlineCourse from ..models import CustomCourseForEdX
from ..overrides import override_field_for_poc from ..overrides import override_field_for_ccx
@override_settings(FIELD_OVERRIDE_PROVIDERS=( @override_settings(FIELD_OVERRIDE_PROVIDERS=(
'pocs.overrides.PersonalOnlineCoursesOverrideProvider',)) 'ccx.overrides.CustomCoursesForEdxOverrideProvider',))
class TestFieldOverrides(ModuleStoreTestCase): class TestFieldOverrides(ModuleStoreTestCase):
""" """
Make sure field overrides behave in the expected manner. Make sure field overrides behave in the expected manner.
...@@ -22,6 +22,7 @@ class TestFieldOverrides(ModuleStoreTestCase): ...@@ -22,6 +22,7 @@ class TestFieldOverrides(ModuleStoreTestCase):
""" """
Set up tests Set up tests
""" """
super(TestFieldOverrides, self).setUp()
self.course = course = CourseFactory.create() self.course = course = CourseFactory.create()
# Create a course outline # Create a course outline
...@@ -41,15 +42,15 @@ class TestFieldOverrides(ModuleStoreTestCase): ...@@ -41,15 +42,15 @@ class TestFieldOverrides(ModuleStoreTestCase):
[ItemFactory.create(parent=vertical) for _ in xrange(2)] [ItemFactory.create(parent=vertical) for _ in xrange(2)]
for vertical in verticals]) for vertical in verticals])
self.poc = poc = PersonalOnlineCourse( self.ccx = ccx = CustomCourseForEdX(
course_id=course.id, course_id=course.id,
display_name='Test POC', display_name='Test CCX',
coach=AdminFactory.create()) coach=AdminFactory.create())
poc.save() ccx.save()
patch = mock.patch('pocs.overrides.get_current_poc') patch = mock.patch('ccx.overrides.get_current_ccx')
self.get_poc = get_poc = patch.start() self.get_ccx = get_ccx = patch.start()
get_poc.return_value = poc get_ccx.return_value = ccx
self.addCleanup(patch.stop) self.addCleanup(patch.stop)
# Apparently the test harness doesn't use LmsFieldStorage, and I'm not # Apparently the test harness doesn't use LmsFieldStorage, and I'm not
...@@ -60,24 +61,30 @@ class TestFieldOverrides(ModuleStoreTestCase): ...@@ -60,24 +61,30 @@ class TestFieldOverrides(ModuleStoreTestCase):
block._field_data = OverrideFieldData.wrap( # pylint: disable=protected-access block._field_data = OverrideFieldData.wrap( # pylint: disable=protected-access
AdminFactory.create(), block._field_data) # pylint: disable=protected-access AdminFactory.create(), block._field_data) # pylint: disable=protected-access
# and after everything is done, clean up by un-doing the change to the
# OverrideFieldData object that is done during the wrap method.
def cleanup_provider_classes():
OverrideFieldData.provider_classes = None
self.addCleanup(cleanup_provider_classes)
def test_override_start(self): def test_override_start(self):
""" """
Test that overriding start date on a chapter works. Test that overriding start date on a chapter works.
""" """
poc_start = datetime.datetime(2014, 12, 25, 00, 00, tzinfo=pytz.UTC) ccx_start = datetime.datetime(2014, 12, 25, 00, 00, tzinfo=pytz.UTC)
chapter = self.course.get_children()[0] chapter = self.course.get_children()[0]
override_field_for_poc(self.poc, chapter, 'start', poc_start) override_field_for_ccx(self.ccx, chapter, 'start', ccx_start)
self.assertEquals(chapter.start, poc_start) self.assertEquals(chapter.start, ccx_start)
def test_override_is_inherited(self): def test_override_is_inherited(self):
""" """
Test that sequentials inherit overridden start date from chapter. Test that sequentials inherit overridden start date from chapter.
""" """
poc_start = datetime.datetime(2014, 12, 25, 00, 00, tzinfo=pytz.UTC) ccx_start = datetime.datetime(2014, 12, 25, 00, 00, tzinfo=pytz.UTC)
chapter = self.course.get_children()[0] chapter = self.course.get_children()[0]
override_field_for_poc(self.poc, chapter, 'start', poc_start) override_field_for_ccx(self.ccx, chapter, 'start', ccx_start)
self.assertEquals(chapter.get_children()[0].start, poc_start) self.assertEquals(chapter.get_children()[0].start, ccx_start)
self.assertEquals(chapter.get_children()[1].start, poc_start) self.assertEquals(chapter.get_children()[1].start, ccx_start)
def test_override_is_inherited_even_if_set_in_mooc(self): def test_override_is_inherited_even_if_set_in_mooc(self):
""" """
...@@ -85,12 +92,12 @@ class TestFieldOverrides(ModuleStoreTestCase): ...@@ -85,12 +92,12 @@ class TestFieldOverrides(ModuleStoreTestCase):
(verticals) even if a due date is set explicitly on grandchildren in (verticals) even if a due date is set explicitly on grandchildren in
the mooc. the mooc.
""" """
poc_due = datetime.datetime(2015, 1, 1, 00, 00, tzinfo=pytz.UTC) ccx_due = datetime.datetime(2015, 1, 1, 00, 00, tzinfo=pytz.UTC)
chapter = self.course.get_children()[0] chapter = self.course.get_children()[0]
chapter.display_name = 'itsme!' chapter.display_name = 'itsme!'
override_field_for_poc(self.poc, chapter, 'due', poc_due) override_field_for_ccx(self.ccx, chapter, 'due', ccx_due)
vertical = chapter.get_children()[0].get_children()[0] vertical = chapter.get_children()[0].get_children()[0]
self.assertEqual(vertical.due, poc_due) self.assertEqual(vertical.due, ccx_due)
def flatten(seq): def flatten(seq):
......
from pocs.models import ( from ccx.models import (
PocMembership, CcxMembership,
PocFutureMembership, CcxFutureMembership,
) )
from pocs.tests.factories import ( from ccx.tests.factories import (
PocFactory, CcxFactory,
PocMembershipFactory, CcxMembershipFactory,
PocFutureMembershipFactory, CcxFutureMembershipFactory,
) )
from student.roles import CoursePocCoachRole from student.roles import CourseCcxCoachRole
from student.tests.factories import ( from student.tests.factories import (
AdminFactory, AdminFactory,
UserFactory, UserFactory,
...@@ -26,11 +26,15 @@ class TestEmailEnrollmentState(ModuleStoreTestCase): ...@@ -26,11 +26,15 @@ class TestEmailEnrollmentState(ModuleStoreTestCase):
""" """
Set up tests Set up tests
""" """
super(TestEmailEnrollmentState, self).setUp()
# remove user provided by the parent test case so we can make our own
# when needed.
self.user = None
course = CourseFactory.create() course = CourseFactory.create()
coach = AdminFactory.create() coach = AdminFactory.create()
role = CoursePocCoachRole(course.id) role = CourseCcxCoachRole(course.id)
role.add_users(coach) role.add_users(coach)
self.poc = PocFactory(course_id=course.id, coach=coach) self.ccx = CcxFactory(course_id=course.id, coach=coach)
def create_user(self): def create_user(self):
"""provide a legitimate django user for testing """provide a legitimate django user for testing
...@@ -38,47 +42,47 @@ class TestEmailEnrollmentState(ModuleStoreTestCase): ...@@ -38,47 +42,47 @@ class TestEmailEnrollmentState(ModuleStoreTestCase):
if getattr(self, 'user', None) is None: if getattr(self, 'user', None) is None:
self.user = UserFactory() self.user = UserFactory()
def register_user_in_poc(self): def register_user_in_ccx(self):
"""create registration of self.user in self.poc """create registration of self.user in self.ccx
registration will be inactive registration will be inactive
""" """
self.create_user() self.create_user()
PocMembershipFactory(poc=self.poc, student=self.user) CcxMembershipFactory(ccx=self.ccx, student=self.user)
def create_one(self, email=None): def create_one(self, email=None):
"""Create a single EmailEnrollmentState object and return it """Create a single EmailEnrollmentState object and return it
""" """
from pocs.utils import EmailEnrollmentState from ccx.utils import EmailEnrollmentState
if email is None: if email is None:
email = self.user.email email = self.user.email
return EmailEnrollmentState(self.poc, email) return EmailEnrollmentState(self.ccx, email)
def test_enrollment_state_for_non_user(self): def test_enrollment_state_for_non_user(self):
"""verify behavior for non-user email address """verify behavior for non-user email address
""" """
ee_state = self.create_one(email='nobody@nowhere.com') ee_state = self.create_one(email='nobody@nowhere.com')
for attr in ['user', 'member', 'full_name', 'in_poc']: for attr in ['user', 'member', 'full_name', 'in_ccx']:
value = getattr(ee_state, attr, 'missing attribute') value = getattr(ee_state, attr, 'missing attribute')
self.assertFalse(value, "{}: {}".format(value, attr)) self.assertFalse(value, "{}: {}".format(value, attr))
def test_enrollment_state_for_non_member_user(self): def test_enrollment_state_for_non_member_user(self):
"""verify behavior for email address of user who is not a poc memeber """verify behavior for email address of user who is not a ccx memeber
""" """
self.create_user() self.create_user()
ee_state = self.create_one() ee_state = self.create_one()
self.assertTrue(ee_state.user) self.assertTrue(ee_state.user)
self.assertFalse(ee_state.in_poc) self.assertFalse(ee_state.in_ccx)
self.assertEqual(ee_state.member, self.user) self.assertEqual(ee_state.member, self.user)
self.assertEqual(ee_state.full_name, self.user.profile.name) self.assertEqual(ee_state.full_name, self.user.profile.name)
def test_enrollment_state_for_member_user(self): def test_enrollment_state_for_member_user(self):
"""verify behavior for email address of user who is a poc member """verify behavior for email address of user who is a ccx member
""" """
self.create_user() self.create_user()
self.register_user_in_poc() self.register_user_in_ccx()
ee_state = self.create_one() ee_state = self.create_one()
for attr in ['user', 'in_poc']: for attr in ['user', 'in_ccx']:
self.assertTrue( self.assertTrue(
getattr(ee_state, attr, False), getattr(ee_state, attr, False),
"attribute {} is missing or False".format(attr) "attribute {} is missing or False".format(attr)
...@@ -90,13 +94,13 @@ class TestEmailEnrollmentState(ModuleStoreTestCase): ...@@ -90,13 +94,13 @@ class TestEmailEnrollmentState(ModuleStoreTestCase):
"""verify dict representation of EmailEnrollmentState """verify dict representation of EmailEnrollmentState
""" """
self.create_user() self.create_user()
self.register_user_in_poc() self.register_user_in_ccx()
ee_state = self.create_one() ee_state = self.create_one()
ee_dict = ee_state.to_dict() ee_dict = ee_state.to_dict()
expected = { expected = {
'user': True, 'user': True,
'member': self.user, 'member': self.user,
'in_poc': True, 'in_ccx': True,
} }
for expected_key, expected_value in expected.iteritems(): for expected_key, expected_value in expected.iteritems():
self.assertTrue(expected_key in ee_dict) self.assertTrue(expected_key in ee_dict)
...@@ -104,28 +108,29 @@ class TestEmailEnrollmentState(ModuleStoreTestCase): ...@@ -104,28 +108,29 @@ class TestEmailEnrollmentState(ModuleStoreTestCase):
def test_enrollment_state_repr(self): def test_enrollment_state_repr(self):
self.create_user() self.create_user()
self.register_user_in_poc() self.register_user_in_ccx()
ee_state = self.create_one() ee_state = self.create_one()
representation = repr(ee_state) representation = repr(ee_state)
self.assertTrue('user=True' in representation) self.assertTrue('user=True' in representation)
self.assertTrue('in_poc=True' in representation) self.assertTrue('in_ccx=True' in representation)
member = 'member={}'.format(self.user) member = 'member={}'.format(self.user)
self.assertTrue(member in representation) self.assertTrue(member in representation)
# TODO: deal with changes in behavior for auto_enroll # TODO: deal with changes in behavior for auto_enroll
class TestGetEmailParams(ModuleStoreTestCase): class TestGetEmailParams(ModuleStoreTestCase):
"""tests for pocs.utils.get_email_params """tests for ccx.utils.get_email_params
""" """
def setUp(self): def setUp(self):
""" """
Set up tests Set up tests
""" """
super(TestGetEmailParams, self).setUp()
course = CourseFactory.create() course = CourseFactory.create()
coach = AdminFactory.create() coach = AdminFactory.create()
role = CoursePocCoachRole(course.id) role = CourseCcxCoachRole(course.id)
role.add_users(coach) role.add_users(coach)
self.poc = PocFactory(course_id=course.id, coach=coach) self.ccx = CcxFactory(course_id=course.id, coach=coach)
self.all_keys = [ self.all_keys = [
'site_name', 'course', 'course_url', 'registration_url', 'site_name', 'course', 'course_url', 'registration_url',
'course_about_url', 'auto_enroll' 'course_about_url', 'auto_enroll'
...@@ -134,17 +139,17 @@ class TestGetEmailParams(ModuleStoreTestCase): ...@@ -134,17 +139,17 @@ class TestGetEmailParams(ModuleStoreTestCase):
self.course_keys = [k for k in self.url_keys if 'course' in k] self.course_keys = [k for k in self.url_keys if 'course' in k]
def call_FUT(self, auto_enroll=False, secure=False): def call_FUT(self, auto_enroll=False, secure=False):
from pocs.utils import get_email_params from ccx.utils import get_email_params
return get_email_params(self.poc, auto_enroll, secure) return get_email_params(self.ccx, auto_enroll, secure)
def test_params_have_expected_keys(self): def test_params_have_expected_keys(self):
params = self.call_FUT() params = self.call_FUT()
self.assertFalse(set(params.keys()) - set(self.all_keys)) self.assertFalse(set(params.keys()) - set(self.all_keys))
def test_poc_id_in_params(self): def test_ccx_id_in_params(self):
expected_course_id = self.poc.course_id.to_deprecated_string() expected_course_id = self.ccx.course_id.to_deprecated_string()
params = self.call_FUT() params = self.call_FUT()
self.assertEqual(params['course'], self.poc) self.assertEqual(params['course'], self.ccx)
for url_key in self.url_keys: for url_key in self.url_keys:
self.assertTrue('http://' in params[url_key]) self.assertTrue('http://' in params[url_key])
for url_key in self.course_keys: for url_key in self.course_keys:
...@@ -167,14 +172,18 @@ class TestGetEmailParams(ModuleStoreTestCase): ...@@ -167,14 +172,18 @@ class TestGetEmailParams(ModuleStoreTestCase):
# TODO: deal with changes in behavior for auto_enroll # TODO: deal with changes in behavior for auto_enroll
class TestEnrollEmail(ModuleStoreTestCase): class TestEnrollEmail(ModuleStoreTestCase):
"""tests for the enroll_email function from pocs.utils """tests for the enroll_email function from ccx.utils
""" """
def setUp(self): def setUp(self):
super(TestEnrollEmail, self).setUp()
# unbind the user created by the parent, so we can create our own when
# needed.
self.user = None
course = CourseFactory.create() course = CourseFactory.create()
coach = AdminFactory.create() coach = AdminFactory.create()
role = CoursePocCoachRole(course.id) role = CourseCcxCoachRole(course.id)
role.add_users(coach) role.add_users(coach)
self.poc = PocFactory(course_id=course.id, coach=coach) self.ccx = CcxFactory(course_id=course.id, coach=coach)
self.outbox = self.get_outbox() self.outbox = self.get_outbox()
def create_user(self): def create_user(self):
...@@ -183,13 +192,13 @@ class TestEnrollEmail(ModuleStoreTestCase): ...@@ -183,13 +192,13 @@ class TestEnrollEmail(ModuleStoreTestCase):
if getattr(self, 'user', None) is None: if getattr(self, 'user', None) is None:
self.user = UserFactory() self.user = UserFactory()
def register_user_in_poc(self): def register_user_in_ccx(self):
"""create registration of self.user in self.poc """create registration of self.user in self.ccx
registration will be inactive registration will be inactive
""" """
self.create_user() self.create_user()
PocMembershipFactory(poc=self.poc, student=self.user) CcxMembershipFactory(ccx=self.ccx, student=self.user)
def get_outbox(self): def get_outbox(self):
"""Return the django mail outbox""" """Return the django mail outbox"""
...@@ -197,31 +206,31 @@ class TestEnrollEmail(ModuleStoreTestCase): ...@@ -197,31 +206,31 @@ class TestEnrollEmail(ModuleStoreTestCase):
return mail.outbox return mail.outbox
def check_membership(self, email=None, user=None, future=False): def check_membership(self, email=None, user=None, future=False):
"""Verify tjat an appropriate Poc Membership exists""" """Verify tjat an appropriate CCX Membership exists"""
if not email and not user: if not email and not user:
self.fail( self.fail(
"must provide user or email address to check Poc Membership" "must provide user or email address to check CCX Membership"
) )
if future and email: if future and email:
membership = PocFutureMembership.objects.filter( membership = CcxFutureMembership.objects.filter(
poc=self.poc, email=email ccx=self.ccx, email=email
) )
elif not future: elif not future:
if not user: if not user:
user = self.user user = self.user
membership = PocMembership.objects.filter( membership = CcxMembership.objects.filter(
poc=self.poc, student=user ccx=self.ccx, student=user
) )
self.assertTrue(membership.exists()) self.assertTrue(membership.exists())
def check_enrollment_state(self, state, in_poc, member, user): def check_enrollment_state(self, state, in_ccx, member, user):
"""Verify an enrollment state object against provided arguments """Verify an enrollment state object against provided arguments
state.in_poc will always be a boolean state.in_ccx will always be a boolean
state.user will always be a boolean state.user will always be a boolean
state.member will be a Django user object or None state.member will be a Django user object or None
""" """
self.assertEqual(in_poc, state.in_poc) self.assertEqual(in_ccx, state.in_ccx)
self.assertEqual(member, state.member) self.assertEqual(member, state.member)
self.assertEqual(user, state.user) self.assertEqual(user, state.user)
...@@ -232,11 +241,11 @@ class TestEnrollEmail(ModuleStoreTestCase): ...@@ -232,11 +241,11 @@ class TestEnrollEmail(ModuleStoreTestCase):
email_students=False, email_students=False,
email_params=None email_params=None
): ):
from pocs.utils import enroll_email from ccx.utils import enroll_email
if student_email is None: if student_email is None:
student_email = self.user.email student_email = self.user.email
before, after = enroll_email( before, after = enroll_email(
self.poc, student_email, auto_enroll, email_students, email_params self.ccx, student_email, auto_enroll, email_students, email_params
) )
return before, after return before, after
...@@ -279,7 +288,7 @@ class TestEnrollEmail(ModuleStoreTestCase): ...@@ -279,7 +288,7 @@ class TestEnrollEmail(ModuleStoreTestCase):
def test_enroll_member_sending_email(self): def test_enroll_member_sending_email(self):
"""register a member and send an enrollment email to them """register a member and send an enrollment email to them
""" """
self.register_user_in_poc() self.register_user_in_ccx()
# ensure no emails are in the outbox now # ensure no emails are in the outbox now
self.assertEqual(len(self.outbox), 0) self.assertEqual(len(self.outbox), 0)
before, after = self.call_FUT(email_students=True) before, after = self.call_FUT(email_students=True)
...@@ -327,7 +336,7 @@ class TestEnrollEmail(ModuleStoreTestCase): ...@@ -327,7 +336,7 @@ class TestEnrollEmail(ModuleStoreTestCase):
def test_enroll_member_no_email(self): def test_enroll_member_no_email(self):
"""enroll a member but send no email """enroll a member but send no email
""" """
self.register_user_in_poc() self.register_user_in_ccx()
# ensure no emails are in the outbox now # ensure no emails are in the outbox now
self.assertEqual(len(self.outbox), 0) self.assertEqual(len(self.outbox), 0)
before, after = self.call_FUT(email_students=False) before, after = self.call_FUT(email_students=False)
...@@ -342,13 +351,17 @@ class TestEnrollEmail(ModuleStoreTestCase): ...@@ -342,13 +351,17 @@ class TestEnrollEmail(ModuleStoreTestCase):
# TODO: deal with changes in behavior for auto_enroll # TODO: deal with changes in behavior for auto_enroll
class TestUnenrollEmail(ModuleStoreTestCase): class TestUnenrollEmail(ModuleStoreTestCase):
"""Tests for the unenroll_email function from pocs.utils""" """Tests for the unenroll_email function from ccx.utils"""
def setUp(self): def setUp(self):
super(TestUnenrollEmail, self).setUp()
# unbind the user created by the parent, so we can create our own when
# needed.
self.user = None
course = CourseFactory.create() course = CourseFactory.create()
coach = AdminFactory.create() coach = AdminFactory.create()
role = CoursePocCoachRole(course.id) role = CourseCcxCoachRole(course.id)
role.add_users(coach) role.add_users(coach)
self.poc = PocFactory(course_id=course.id, coach=coach) self.ccx = CcxFactory(course_id=course.id, coach=coach)
self.outbox = self.get_outbox() self.outbox = self.get_outbox()
def tearDown(self): def tearDown(self):
...@@ -367,52 +380,52 @@ class TestUnenrollEmail(ModuleStoreTestCase): ...@@ -367,52 +380,52 @@ class TestUnenrollEmail(ModuleStoreTestCase):
if getattr(self, 'user', None) is None: if getattr(self, 'user', None) is None:
self.user = UserFactory() self.user = UserFactory()
def make_poc_membership(self): def make_ccx_membership(self):
"""create registration of self.user in self.poc """create registration of self.user in self.ccx
registration will be inactive registration will be inactive
""" """
self.create_user() self.create_user()
PocMembershipFactory.create(poc=self.poc, student=self.user) CcxMembershipFactory.create(ccx=self.ccx, student=self.user)
def make_poc_future_membership(self): def make_ccx_future_membership(self):
"""create future registration for email in self.poc""" """create future registration for email in self.ccx"""
self.email = "nobody@nowhere.com" self.email = "nobody@nowhere.com"
PocFutureMembershipFactory.create( CcxFutureMembershipFactory.create(
poc=self.poc, email=self.email ccx=self.ccx, email=self.email
) )
def check_enrollment_state(self, state, in_poc, member, user): def check_enrollment_state(self, state, in_ccx, member, user):
"""Verify an enrollment state object against provided arguments """Verify an enrollment state object against provided arguments
state.in_poc will always be a boolean state.in_ccx will always be a boolean
state.user will always be a boolean state.user will always be a boolean
state.member will be a Django user object or None state.member will be a Django user object or None
""" """
self.assertEqual(in_poc, state.in_poc) self.assertEqual(in_ccx, state.in_ccx)
self.assertEqual(member, state.member) self.assertEqual(member, state.member)
self.assertEqual(user, state.user) self.assertEqual(user, state.user)
def check_membership(self, future=False): def check_membership(self, future=False):
if future: if future:
membership = PocFutureMembership.objects.filter( membership = CcxFutureMembership.objects.filter(
poc=self.poc, email=self.email ccx=self.ccx, email=self.email
) )
else: else:
membership = PocMembership.objects.filter( membership = CcxMembership.objects.filter(
poc=self.poc, student=self.user ccx=self.ccx, student=self.user
) )
return membership.exists() return membership.exists()
def call_FUT(self, email_students=False): def call_FUT(self, email_students=False):
from pocs.utils import unenroll_email from ccx.utils import unenroll_email
email = hasattr(self, 'user') and self.user.email or self.email email = getattr(self, 'user', None) and self.user.email or self.email
return unenroll_email(self.poc, email, email_students=email_students) return unenroll_email(self.ccx, email, email_students=email_students)
def test_unenroll_future_member_with_email(self): def test_unenroll_future_member_with_email(self):
"""unenroll a future member and send an email """unenroll a future member and send an email
""" """
self.make_poc_future_membership() self.make_ccx_future_membership()
# assert that a membership exists and that no emails have been sent # assert that a membership exists and that no emails have been sent
self.assertTrue(self.check_membership(future=True)) self.assertTrue(self.check_membership(future=True))
self.assertEqual(len(self.outbox), 0) self.assertEqual(len(self.outbox), 0)
...@@ -431,7 +444,7 @@ class TestUnenrollEmail(ModuleStoreTestCase): ...@@ -431,7 +444,7 @@ class TestUnenrollEmail(ModuleStoreTestCase):
def test_unenroll_member_with_email(self): def test_unenroll_member_with_email(self):
"""unenroll a current member and send an email""" """unenroll a current member and send an email"""
self.make_poc_membership() self.make_ccx_membership()
# assert that a membership exists and that no emails have been sent # assert that a membership exists and that no emails have been sent
self.assertTrue(self.check_membership()) self.assertTrue(self.check_membership())
self.assertEqual(len(self.outbox), 0) self.assertEqual(len(self.outbox), 0)
...@@ -451,7 +464,7 @@ class TestUnenrollEmail(ModuleStoreTestCase): ...@@ -451,7 +464,7 @@ class TestUnenrollEmail(ModuleStoreTestCase):
def test_unenroll_future_member_no_email(self): def test_unenroll_future_member_no_email(self):
"""unenroll a future member but send no email """unenroll a future member but send no email
""" """
self.make_poc_future_membership() self.make_ccx_future_membership()
# assert that a membership exists and that no emails have been sent # assert that a membership exists and that no emails have been sent
self.assertTrue(self.check_membership(future=True)) self.assertTrue(self.check_membership(future=True))
self.assertEqual(len(self.outbox), 0) self.assertEqual(len(self.outbox), 0)
...@@ -469,7 +482,7 @@ class TestUnenrollEmail(ModuleStoreTestCase): ...@@ -469,7 +482,7 @@ class TestUnenrollEmail(ModuleStoreTestCase):
def test_unenroll_member_no_email(self): def test_unenroll_member_no_email(self):
"""unenroll a current member but send no email """unenroll a current member but send no email
""" """
self.make_poc_membership() self.make_ccx_membership()
# assert that a membership exists and that no emails have been sent # assert that a membership exists and that no emails have been sent
self.assertTrue(self.check_membership()) self.assertTrue(self.check_membership())
self.assertEqual(len(self.outbox), 0) self.assertEqual(len(self.outbox), 0)
...@@ -485,64 +498,65 @@ class TestUnenrollEmail(ModuleStoreTestCase): ...@@ -485,64 +498,65 @@ class TestUnenrollEmail(ModuleStoreTestCase):
self.assertEqual(len(self.outbox), 0) self.assertEqual(len(self.outbox), 0)
class TestUserPocList(ModuleStoreTestCase): class TestUserCCXList(ModuleStoreTestCase):
"""Unit tests for poc.utils.get_all_pocs_for_user""" """Unit tests for ccx.utils.get_all_ccx_for_user"""
def setUp(self): def setUp(self):
"""Create required infrastructure for tests""" """Create required infrastructure for tests"""
super(TestUserCCXList, self).setUp()
self.course = CourseFactory.create() self.course = CourseFactory.create()
coach = AdminFactory.create() coach = AdminFactory.create()
role = CoursePocCoachRole(self.course.id) role = CourseCcxCoachRole(self.course.id)
role.add_users(coach) role.add_users(coach)
self.poc = PocFactory(course_id=self.course.id, coach=coach) self.ccx = CcxFactory(course_id=self.course.id, coach=coach)
enrollment = CourseEnrollmentFactory.create(course_id=self.course.id) enrollment = CourseEnrollmentFactory.create(course_id=self.course.id)
self.user = enrollment.user self.user = enrollment.user
self.anonymous = AnonymousUserFactory.create() self.anonymous = AnonymousUserFactory.create()
def register_user_in_poc(self, active=False): def register_user_in_ccx(self, active=False):
"""create registration of self.user in self.poc """create registration of self.user in self.ccx
registration will be inactive unless active=True registration will be inactive unless active=True
""" """
PocMembershipFactory(poc=self.poc, student=self.user, active=active) CcxMembershipFactory(ccx=self.ccx, student=self.user, active=active)
def get_course_title(self): def get_course_title(self):
from courseware.courses import get_course_about_section from courseware.courses import get_course_about_section
return get_course_about_section(self.course, 'title') return get_course_about_section(self.course, 'title')
def call_FUT(self, user): def call_FUT(self, user):
from pocs.utils import get_all_pocs_for_user from ccx.utils import get_all_ccx_for_user
return get_all_pocs_for_user(user) return get_all_ccx_for_user(user)
def test_anonymous_sees_no_pocs(self): def test_anonymous_sees_no_ccx(self):
memberships = self.call_FUT(self.anonymous) memberships = self.call_FUT(self.anonymous)
self.assertEqual(len(memberships), 0) self.assertEqual(len(memberships), 0)
def test_unenrolled_sees_no_pocs(self): def test_unenrolled_sees_no_ccx(self):
memberships = self.call_FUT(self.user) memberships = self.call_FUT(self.user)
self.assertEqual(len(memberships), 0) self.assertEqual(len(memberships), 0)
def test_enrolled_inactive_sees_no_pocs(self): def test_enrolled_inactive_sees_no_ccx(self):
self.register_user_in_poc() self.register_user_in_ccx()
memberships = self.call_FUT(self.user) memberships = self.call_FUT(self.user)
self.assertEqual(len(memberships), 0) self.assertEqual(len(memberships), 0)
def test_enrolled_sees_a_poc(self): def test_enrolled_sees_a_ccx(self):
self.register_user_in_poc(active=True) self.register_user_in_ccx(active=True)
memberships = self.call_FUT(self.user) memberships = self.call_FUT(self.user)
self.assertEqual(len(memberships), 1) self.assertEqual(len(memberships), 1)
def test_data_structure(self): def test_data_structure(self):
self.register_user_in_poc(active=True) self.register_user_in_ccx(active=True)
memberships = self.call_FUT(self.user) memberships = self.call_FUT(self.user)
this_membership = memberships[0] this_membership = memberships[0]
self.assertTrue(this_membership) self.assertTrue(this_membership)
# structure contains the expected keys # structure contains the expected keys
for key in ['poc_name', 'poc_url']: for key in ['ccx_name', 'ccx_url']:
self.assertTrue(key in this_membership.keys()) self.assertTrue(key in this_membership.keys())
url_parts = [self.course.id.to_deprecated_string(), str(self.poc.id)] url_parts = [self.course.id.to_deprecated_string(), str(self.ccx.id)]
# all parts of the poc url are present # all parts of the ccx url are present
for part in url_parts: for part in url_parts:
self.assertTrue(part in this_membership['poc_url']) self.assertTrue(part in this_membership['ccx_url'])
actual_name = self.poc.display_name actual_name = self.ccx.display_name
self.assertEqual(actual_name, this_membership['poc_name']) self.assertEqual(actual_name, this_membership['ccx_name'])
...@@ -11,7 +11,7 @@ from courseware.tests.helpers import LoginEnrollmentTestCase ...@@ -11,7 +11,7 @@ from courseware.tests.helpers import LoginEnrollmentTestCase
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.test.utils import override_settings from django.test.utils import override_settings
from edxmako.shortcuts import render_to_response from edxmako.shortcuts import render_to_response
from student.roles import CoursePocCoachRole from student.roles import CourseCcxCoachRole
from student.tests.factories import ( from student.tests.factories import (
AdminFactory, AdminFactory,
CourseEnrollmentFactory, CourseEnrollmentFactory,
...@@ -23,18 +23,18 @@ from xmodule.modulestore.tests.factories import ( ...@@ -23,18 +23,18 @@ from xmodule.modulestore.tests.factories import (
CourseFactory, CourseFactory,
ItemFactory, ItemFactory,
) )
from pocs import ACTIVE_POC_KEY from ccx import ACTIVE_CCX_KEY
from ..models import ( from ..models import (
PersonalOnlineCourse, CustomCourseForEdX,
PocMembership, CcxMembership,
PocFutureMembership, CcxFutureMembership,
) )
from ..overrides import get_override_for_poc, override_field_for_poc from ..overrides import get_override_for_ccx, override_field_for_ccx
from .. import ACTIVE_POC_KEY from .. import ACTIVE_CCX_KEY
from .factories import ( from .factories import (
PocFactory, CcxFactory,
PocMembershipFactory, CcxMembershipFactory,
PocFutureMembershipFactory, CcxFutureMembershipFactory,
) )
...@@ -54,12 +54,13 @@ def intercept_renderer(path, context): ...@@ -54,12 +54,13 @@ def intercept_renderer(path, context):
class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase): class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
""" """
Tests for Personal Online Courses views. Tests for Custom Courses views.
""" """
def setUp(self): def setUp(self):
""" """
Set up tests Set up tests
""" """
super(TestCoachDashboard, self).setUp()
self.course = course = CourseFactory.create() self.course = course = CourseFactory.create()
# Create instructor account # Create instructor account
...@@ -89,12 +90,12 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -89,12 +90,12 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
) )
def make_coach(self): def make_coach(self):
role = CoursePocCoachRole(self.course.id) role = CourseCcxCoachRole(self.course.id)
role.add_users(self.coach) role.add_users(self.coach)
def make_poc(self): def make_ccx(self):
poc = PocFactory(course_id=self.course.id, coach=self.coach) ccx = CcxFactory(course_id=self.course.id, coach=self.coach)
return poc return ccx
def get_outbox(self): def get_outbox(self):
from django.core import mail from django.core import mail
...@@ -111,51 +112,51 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -111,51 +112,51 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
User is not a coach, should get Forbidden response. User is not a coach, should get Forbidden response.
""" """
url = reverse( url = reverse(
'poc_coach_dashboard', 'ccx_coach_dashboard',
kwargs={'course_id': self.course.id.to_deprecated_string()}) kwargs={'course_id': self.course.id.to_deprecated_string()})
response = self.client.get(url) response = self.client.get(url)
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
def test_no_poc_created(self): def test_no_ccx_created(self):
""" """
No POC is created, coach should see form to add a POC. No CCX is created, coach should see form to add a CCX.
""" """
self.make_coach() self.make_coach()
url = reverse( url = reverse(
'poc_coach_dashboard', 'ccx_coach_dashboard',
kwargs={'course_id': self.course.id.to_deprecated_string()}) kwargs={'course_id': self.course.id.to_deprecated_string()})
response = self.client.get(url) response = self.client.get(url)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertTrue(re.search( self.assertTrue(re.search(
'<form action=".+create_poc"', '<form action=".+create_ccx"',
response.content)) response.content))
def test_create_poc(self): def test_create_ccx(self):
""" """
Create POC. Follow redirect to coach dashboard, confirm we see Create CCX. Follow redirect to coach dashboard, confirm we see
the coach dashboard for the new POC. the coach dashboard for the new CCX.
""" """
self.make_coach() self.make_coach()
url = reverse( url = reverse(
'create_poc', 'create_ccx',
kwargs={'course_id': self.course.id.to_deprecated_string()}) kwargs={'course_id': self.course.id.to_deprecated_string()})
response = self.client.post(url, {'name': 'New POC'}) response = self.client.post(url, {'name': 'New CCX'})
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
url = response.get('location') url = response.get('location')
response = self.client.get(url) response = self.client.get(url)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertTrue(re.search('id="poc-schedule"', response.content)) self.assertTrue(re.search('id="ccx-schedule"', response.content))
@patch('pocs.views.render_to_response', intercept_renderer) @patch('ccx.views.render_to_response', intercept_renderer)
@patch('pocs.views.TODAY') @patch('ccx.views.TODAY')
def test_edit_schedule(self, today): def test_edit_schedule(self, today):
""" """
Get POC schedule, modify it, save it. Get CCX schedule, modify it, save it.
""" """
today.return_value = datetime.datetime(2014, 11, 25, tzinfo=pytz.UTC) today.return_value = datetime.datetime(2014, 11, 25, tzinfo=pytz.UTC)
self.test_create_poc() self.test_create_ccx()
url = reverse( url = reverse(
'poc_coach_dashboard', 'ccx_coach_dashboard',
kwargs={'course_id': self.course.id.to_deprecated_string()}) kwargs={'course_id': self.course.id.to_deprecated_string()})
response = self.client.get(url) response = self.client.get(url)
schedule = json.loads(response.mako_context['schedule']) schedule = json.loads(response.mako_context['schedule'])
...@@ -170,12 +171,12 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -170,12 +171,12 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
) )
url = reverse( url = reverse(
'save_poc', 'save_ccx',
kwargs={'course_id': self.course.id.to_deprecated_string()}) kwargs={'course_id': self.course.id.to_deprecated_string()})
def unhide(unit): def unhide(unit):
""" """
Recursively unhide a unit and all of its children in the POC Recursively unhide a unit and all of its children in the CCX
schedule. schedule.
""" """
unit['hidden'] = False unit['hidden'] = False
...@@ -198,12 +199,12 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -198,12 +199,12 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
# Make sure start date set on course, follows start date of earliest # Make sure start date set on course, follows start date of earliest
# scheduled chapter # scheduled chapter
poc = PersonalOnlineCourse.objects.get() ccx = CustomCourseForEdX.objects.get()
course_start = get_override_for_poc(poc, self.course, 'start') course_start = get_override_for_ccx(ccx, self.course, 'start')
self.assertEqual(str(course_start)[:-9], u'2014-11-20 00:00') self.assertEqual(str(course_start)[:-9], u'2014-11-20 00:00')
# Make sure grading policy adjusted # Make sure grading policy adjusted
policy = get_override_for_poc(poc, self.course, 'grading_policy', policy = get_override_for_ccx(ccx, self.course, 'grading_policy',
self.course.grading_policy) self.course.grading_policy)
self.assertEqual(policy['GRADER'][0]['type'], 'Homework') self.assertEqual(policy['GRADER'][0]['type'], 'Homework')
self.assertEqual(policy['GRADER'][0]['min_count'], 4) self.assertEqual(policy['GRADER'][0]['min_count'], 4)
...@@ -218,14 +219,14 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -218,14 +219,14 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
"""enroll a list of students who are members of the class """enroll a list of students who are members of the class
""" """
self.make_coach() self.make_coach()
poc = self.make_poc() ccx = self.make_ccx()
enrollment = CourseEnrollmentFactory(course_id=self.course.id) enrollment = CourseEnrollmentFactory(course_id=self.course.id)
student = enrollment.user student = enrollment.user
outbox = self.get_outbox() outbox = self.get_outbox()
self.assertEqual(len(outbox), 0) self.assertEqual(len(outbox), 0)
url = reverse( url = reverse(
'poc_invite', 'ccx_invite',
kwargs={'course_id': self.course.id.to_deprecated_string()} kwargs={'course_id': self.course.id.to_deprecated_string()}
) )
data = { data = {
...@@ -240,25 +241,25 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -240,25 +241,25 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
self.assertTrue(302 in response.redirect_chain[0]) self.assertTrue(302 in response.redirect_chain[0])
self.assertEqual(len(outbox), 1) self.assertEqual(len(outbox), 1)
self.assertTrue(student.email in outbox[0].recipients()) self.assertTrue(student.email in outbox[0].recipients())
# a PocMembership exists for this student # a CcxMembership exists for this student
self.assertTrue( self.assertTrue(
PocMembership.objects.filter(poc=poc, student=student).exists() CcxMembership.objects.filter(ccx=ccx, student=student).exists()
) )
def test_unenroll_member_student(self): def test_unenroll_member_student(self):
"""unenroll a list of students who are members of the class """unenroll a list of students who are members of the class
""" """
self.make_coach() self.make_coach()
poc = self.make_poc() ccx = self.make_ccx()
enrollment = CourseEnrollmentFactory(course_id=self.course.id) enrollment = CourseEnrollmentFactory(course_id=self.course.id)
student = enrollment.user student = enrollment.user
outbox = self.get_outbox() outbox = self.get_outbox()
self.assertEqual(len(outbox), 0) self.assertEqual(len(outbox), 0)
# student is member of POC: # student is member of CCX:
PocMembershipFactory(poc=poc, student=student) CcxMembershipFactory(ccx=ccx, student=student)
url = reverse( url = reverse(
'poc_invite', 'ccx_invite',
kwargs={'course_id': self.course.id.to_deprecated_string()} kwargs={'course_id': self.course.id.to_deprecated_string()}
) )
data = { data = {
...@@ -275,7 +276,7 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -275,7 +276,7 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
self.assertTrue(student.email in outbox[0].recipients()) self.assertTrue(student.email in outbox[0].recipients())
# the membership for this student is gone # the membership for this student is gone
self.assertFalse( self.assertFalse(
PocMembership.objects.filter(poc=poc, student=student).exists() CcxMembership.objects.filter(ccx=ccx, student=student).exists()
) )
def test_enroll_non_user_student(self): def test_enroll_non_user_student(self):
...@@ -283,12 +284,12 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -283,12 +284,12 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
""" """
test_email = "nobody@nowhere.com" test_email = "nobody@nowhere.com"
self.make_coach() self.make_coach()
poc = self.make_poc() ccx = self.make_ccx()
outbox = self.get_outbox() outbox = self.get_outbox()
self.assertEqual(len(outbox), 0) self.assertEqual(len(outbox), 0)
url = reverse( url = reverse(
'poc_invite', 'ccx_invite',
kwargs={'course_id': self.course.id.to_deprecated_string()} kwargs={'course_id': self.course.id.to_deprecated_string()}
) )
data = { data = {
...@@ -304,8 +305,8 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -304,8 +305,8 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
self.assertEqual(len(outbox), 1) self.assertEqual(len(outbox), 1)
self.assertTrue(test_email in outbox[0].recipients()) self.assertTrue(test_email in outbox[0].recipients())
self.assertTrue( self.assertTrue(
PocFutureMembership.objects.filter( CcxFutureMembership.objects.filter(
poc=poc, email=test_email ccx=ccx, email=test_email
).exists() ).exists()
) )
...@@ -314,13 +315,13 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -314,13 +315,13 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
""" """
test_email = "nobody@nowhere.com" test_email = "nobody@nowhere.com"
self.make_coach() self.make_coach()
poc = self.make_poc() ccx = self.make_ccx()
outbox = self.get_outbox() outbox = self.get_outbox()
PocFutureMembershipFactory(poc=poc, email=test_email) CcxFutureMembershipFactory(ccx=ccx, email=test_email)
self.assertEqual(len(outbox), 0) self.assertEqual(len(outbox), 0)
url = reverse( url = reverse(
'poc_invite', 'ccx_invite',
kwargs={'course_id': self.course.id.to_deprecated_string()} kwargs={'course_id': self.course.id.to_deprecated_string()}
) )
data = { data = {
...@@ -336,8 +337,8 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -336,8 +337,8 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
self.assertEqual(len(outbox), 1) self.assertEqual(len(outbox), 1)
self.assertTrue(test_email in outbox[0].recipients()) self.assertTrue(test_email in outbox[0].recipients())
self.assertFalse( self.assertFalse(
PocFutureMembership.objects.filter( CcxFutureMembership.objects.filter(
poc=poc, email=test_email ccx=ccx, email=test_email
).exists() ).exists()
) )
...@@ -345,7 +346,7 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -345,7 +346,7 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
"""enroll a single student who is a member of the class already """enroll a single student who is a member of the class already
""" """
self.make_coach() self.make_coach()
poc = self.make_poc() ccx = self.make_ccx()
enrollment = CourseEnrollmentFactory(course_id=self.course.id) enrollment = CourseEnrollmentFactory(course_id=self.course.id)
student = enrollment.user student = enrollment.user
# no emails have been sent so far # no emails have been sent so far
...@@ -353,7 +354,7 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -353,7 +354,7 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
self.assertEqual(len(outbox), 0) self.assertEqual(len(outbox), 0)
url = reverse( url = reverse(
'poc_manage_student', 'ccx_manage_student',
kwargs={'course_id': self.course.id.to_deprecated_string()} kwargs={'course_id': self.course.id.to_deprecated_string()}
) )
data = { data = {
...@@ -366,25 +367,25 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -366,25 +367,25 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
self.assertEqual(len(response.redirect_chain), 1) self.assertEqual(len(response.redirect_chain), 1)
self.assertTrue(302 in response.redirect_chain[0]) self.assertTrue(302 in response.redirect_chain[0])
self.assertEqual(len(outbox), 0) self.assertEqual(len(outbox), 0)
# a PocMembership exists for this student # a CcxMembership exists for this student
self.assertTrue( self.assertTrue(
PocMembership.objects.filter(poc=poc, student=student).exists() CcxMembership.objects.filter(ccx=ccx, student=student).exists()
) )
def test_manage_remove_single_student(self): def test_manage_remove_single_student(self):
"""unenroll a single student who is a member of the class already """unenroll a single student who is a member of the class already
""" """
self.make_coach() self.make_coach()
poc = self.make_poc() ccx = self.make_ccx()
enrollment = CourseEnrollmentFactory(course_id=self.course.id) enrollment = CourseEnrollmentFactory(course_id=self.course.id)
student = enrollment.user student = enrollment.user
PocMembershipFactory(poc=poc, student=student) CcxMembershipFactory(ccx=ccx, student=student)
# no emails have been sent so far # no emails have been sent so far
outbox = self.get_outbox() outbox = self.get_outbox()
self.assertEqual(len(outbox), 0) self.assertEqual(len(outbox), 0)
url = reverse( url = reverse(
'poc_manage_student', 'ccx_manage_student',
kwargs={'course_id': self.course.id.to_deprecated_string()} kwargs={'course_id': self.course.id.to_deprecated_string()}
) )
data = { data = {
...@@ -397,22 +398,23 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -397,22 +398,23 @@ class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
self.assertEqual(len(response.redirect_chain), 1) self.assertEqual(len(response.redirect_chain), 1)
self.assertTrue(302 in response.redirect_chain[0]) self.assertTrue(302 in response.redirect_chain[0])
self.assertEqual(len(outbox), 0) self.assertEqual(len(outbox), 0)
# a PocMembership exists for this student # a CcxMembership exists for this student
self.assertFalse( self.assertFalse(
PocMembership.objects.filter(poc=poc, student=student).exists() CcxMembership.objects.filter(ccx=ccx, student=student).exists()
) )
@override_settings(FIELD_OVERRIDE_PROVIDERS=( @override_settings(FIELD_OVERRIDE_PROVIDERS=(
'pocs.overrides.PersonalOnlineCoursesOverrideProvider',)) 'ccx.overrides.CustomCoursesForEdxOverrideProvider',))
class TestPocGrades(ModuleStoreTestCase, LoginEnrollmentTestCase): class TestCCXGrades(ModuleStoreTestCase, LoginEnrollmentTestCase):
""" """
Tests for Personal Online Courses views. Tests for Custom Courses views.
""" """
def setUp(self): def setUp(self):
""" """
Set up tests Set up tests
""" """
super(TestCCXGrades, self).setUp()
self.course = course = CourseFactory.create() self.course = course = CourseFactory.create()
# Create instructor account # Create instructor account
...@@ -431,13 +433,13 @@ class TestPocGrades(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -431,13 +433,13 @@ class TestPocGrades(ModuleStoreTestCase, LoginEnrollmentTestCase):
metadata={'graded': True, 'format': 'Homework'}) metadata={'graded': True, 'format': 'Homework'})
for _ in xrange(4)] for _ in xrange(4)]
role = CoursePocCoachRole(self.course.id) role = CourseCcxCoachRole(self.course.id)
role.add_users(coach) role.add_users(coach)
self.poc = poc = PocFactory(course_id=self.course.id, coach=self.coach) self.ccx = ccx = CcxFactory(course_id=self.course.id, coach=self.coach)
self.student = student = UserFactory.create() self.student = student = UserFactory.create()
CourseEnrollmentFactory.create(user=student, course_id=self.course.id) CourseEnrollmentFactory.create(user=student, course_id=self.course.id)
PocMembershipFactory(poc=poc, student=student, active=True) CcxMembershipFactory(ccx=ccx, student=student, active=True)
for i, section in enumerate(sections): for i, section in enumerate(sections):
for j in xrange(4): for j in xrange(4):
...@@ -466,12 +468,18 @@ class TestPocGrades(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -466,12 +468,18 @@ class TestPocGrades(ModuleStoreTestCase, LoginEnrollmentTestCase):
block._field_data_cache = {} block._field_data_cache = {}
visible_children(block) visible_children(block)
patch_context = patch('pocs.views.get_course_by_id') # and after everything is done, clean up by un-doing the change to the
# OverrideFieldData object that is done during the wrap method.
def cleanup_provider_classes():
OverrideFieldData.provider_classes = None
self.addCleanup(cleanup_provider_classes)
patch_context = patch('ccx.views.get_course_by_id')
get_course = patch_context.start() get_course = patch_context.start()
get_course.return_value = course get_course.return_value = course
self.addCleanup(patch_context.stop) self.addCleanup(patch_context.stop)
override_field_for_poc(poc, course, 'grading_policy', { override_field_for_ccx(ccx, course, 'grading_policy', {
'GRADER': [ 'GRADER': [
{'drop_count': 0, {'drop_count': 0,
'min_count': 2, 'min_count': 2,
...@@ -481,13 +489,13 @@ class TestPocGrades(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -481,13 +489,13 @@ class TestPocGrades(ModuleStoreTestCase, LoginEnrollmentTestCase):
], ],
'GRADE_CUTOFFS': {'Pass': 0.75}, 'GRADE_CUTOFFS': {'Pass': 0.75},
}) })
override_field_for_poc( override_field_for_ccx(
poc, sections[-1], 'visible_to_staff_only', True) ccx, sections[-1], 'visible_to_staff_only', True)
@patch('pocs.views.render_to_response', intercept_renderer) @patch('ccx.views.render_to_response', intercept_renderer)
def test_gradebook(self): def test_gradebook(self):
url = reverse( url = reverse(
'poc_gradebook', 'ccx_gradebook',
kwargs={'course_id': self.course.id.to_deprecated_string()} kwargs={'course_id': self.course.id.to_deprecated_string()}
) )
response = self.client.get(url) response = self.client.get(url)
...@@ -502,7 +510,7 @@ class TestPocGrades(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -502,7 +510,7 @@ class TestPocGrades(ModuleStoreTestCase, LoginEnrollmentTestCase):
def test_grades_csv(self): def test_grades_csv(self):
url = reverse( url = reverse(
'poc_grades_csv', 'ccx_grades_csv',
kwargs={'course_id': self.course.id.to_deprecated_string()} kwargs={'course_id': self.course.id.to_deprecated_string()}
) )
response = self.client.get(url) response = self.client.get(url)
...@@ -527,9 +535,9 @@ class TestPocGrades(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -527,9 +535,9 @@ class TestPocGrades(ModuleStoreTestCase, LoginEnrollmentTestCase):
self.client.login(username=self.student.username, password="test") self.client.login(username=self.student.username, password="test")
session = self.client.session session = self.client.session
session[ACTIVE_POC_KEY] = self.poc.id session[ACTIVE_CCX_KEY] = self.ccx.id
session.save() session.save()
self.client.session.get(ACTIVE_POC_KEY) self.client.session.get(ACTIVE_CCX_KEY)
url = reverse( url = reverse(
'progress', 'progress',
kwargs={'course_id': self.course.id.to_deprecated_string()} kwargs={'course_id': self.course.id.to_deprecated_string()}
...@@ -542,175 +550,176 @@ class TestPocGrades(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -542,175 +550,176 @@ class TestPocGrades(ModuleStoreTestCase, LoginEnrollmentTestCase):
self.assertEqual(len(grades['section_breakdown']), 4) self.assertEqual(len(grades['section_breakdown']), 4)
class TestSwitchActivePoc(ModuleStoreTestCase, LoginEnrollmentTestCase): class TestSwitchActiveCCX(ModuleStoreTestCase, LoginEnrollmentTestCase):
"""Verify the view for switching which POC is active, if any """Verify the view for switching which CCX is active, if any
""" """
def setUp(self): def setUp(self):
super(TestSwitchActiveCCX, self).setUp()
self.course = course = CourseFactory.create() self.course = course = CourseFactory.create()
coach = AdminFactory.create() coach = AdminFactory.create()
role = CoursePocCoachRole(course.id) role = CourseCcxCoachRole(course.id)
role.add_users(coach) role.add_users(coach)
self.poc = PocFactory(course_id=course.id, coach=coach) self.ccx = CcxFactory(course_id=course.id, coach=coach)
enrollment = CourseEnrollmentFactory.create(course_id=course.id) enrollment = CourseEnrollmentFactory.create(course_id=course.id)
self.user = enrollment.user self.user = enrollment.user
self.target_url = reverse( self.target_url = reverse(
'course_root', args=[course.id.to_deprecated_string()] 'course_root', args=[course.id.to_deprecated_string()]
) )
def register_user_in_poc(self, active=False): def register_user_in_ccx(self, active=False):
"""create registration of self.user in self.poc """create registration of self.user in self.ccx
registration will be inactive unless active=True registration will be inactive unless active=True
""" """
PocMembershipFactory(poc=self.poc, student=self.user, active=active) CcxMembershipFactory(ccx=self.ccx, student=self.user, active=active)
def revoke_poc_registration(self): def revoke_ccx_registration(self):
from ..models import PocMembership from ..models import CcxMembership
membership = PocMembership.objects.filter( membership = CcxMembership.objects.filter(
poc=self.poc, student=self.user ccx=self.ccx, student=self.user
) )
membership.delete() membership.delete()
def verify_active_poc(self, request, id=None): def verify_active_ccx(self, request, id=None):
if id: if id:
id = str(id) id = str(id)
self.assertEqual(id, request.session.get(ACTIVE_POC_KEY, None)) self.assertEqual(id, request.session.get(ACTIVE_CCX_KEY, None))
def test_unauthorized_cannot_switch_to_poc(self): def test_unauthorized_cannot_switch_to_ccx(self):
switch_url = reverse( switch_url = reverse(
'switch_active_poc', 'switch_active_ccx',
args=[self.course.id.to_deprecated_string(), self.poc.id] args=[self.course.id.to_deprecated_string(), self.ccx.id]
) )
response = self.client.get(switch_url) response = self.client.get(switch_url)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
def test_unauthorized_cannot_switch_to_mooc(self): def test_unauthorized_cannot_switch_to_mooc(self):
switch_url = reverse( switch_url = reverse(
'switch_active_poc', 'switch_active_ccx',
args=[self.course.id.to_deprecated_string()] args=[self.course.id.to_deprecated_string()]
) )
response = self.client.get(switch_url) response = self.client.get(switch_url)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
def test_enrolled_inactive_user_cannot_select_poc(self): def test_enrolled_inactive_user_cannot_select_ccx(self):
self.register_user_in_poc(active=False) self.register_user_in_ccx(active=False)
self.client.login(username=self.user.username, password="test") self.client.login(username=self.user.username, password="test")
switch_url = reverse( switch_url = reverse(
'switch_active_poc', 'switch_active_ccx',
args=[self.course.id.to_deprecated_string(), self.poc.id] args=[self.course.id.to_deprecated_string(), self.ccx.id]
) )
response = self.client.get(switch_url) response = self.client.get(switch_url)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertTrue(response.get('Location', '').endswith(self.target_url)) self.assertTrue(response.get('Location', '').endswith(self.target_url))
# if the poc were active, we'd need to pass the ID of the poc here. # if the ccx were active, we'd need to pass the ID of the ccx here.
self.verify_active_poc(self.client) self.verify_active_ccx(self.client)
def test_enrolled_user_can_select_poc(self): def test_enrolled_user_can_select_ccx(self):
self.register_user_in_poc(active=True) self.register_user_in_ccx(active=True)
self.client.login(username=self.user.username, password="test") self.client.login(username=self.user.username, password="test")
switch_url = reverse( switch_url = reverse(
'switch_active_poc', 'switch_active_ccx',
args=[self.course.id.to_deprecated_string(), self.poc.id] args=[self.course.id.to_deprecated_string(), self.ccx.id]
) )
response = self.client.get(switch_url) response = self.client.get(switch_url)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertTrue(response.get('Location', '').endswith(self.target_url)) self.assertTrue(response.get('Location', '').endswith(self.target_url))
self.verify_active_poc(self.client, self.poc.id) self.verify_active_ccx(self.client, self.ccx.id)
def test_enrolled_user_can_select_mooc(self): def test_enrolled_user_can_select_mooc(self):
self.register_user_in_poc(active=True) self.register_user_in_ccx(active=True)
self.client.login(username=self.user.username, password="test") self.client.login(username=self.user.username, password="test")
# pre-seed the session with the poc id # pre-seed the session with the ccx id
session = self.client.session session = self.client.session
session[ACTIVE_POC_KEY] = str(self.poc.id) session[ACTIVE_CCX_KEY] = str(self.ccx.id)
session.save() session.save()
switch_url = reverse( switch_url = reverse(
'switch_active_poc', 'switch_active_ccx',
args=[self.course.id.to_deprecated_string()] args=[self.course.id.to_deprecated_string()]
) )
response = self.client.get(switch_url) response = self.client.get(switch_url)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertTrue(response.get('Location', '').endswith(self.target_url)) self.assertTrue(response.get('Location', '').endswith(self.target_url))
self.verify_active_poc(self.client) self.verify_active_ccx(self.client)
def test_unenrolled_user_cannot_select_poc(self): def test_unenrolled_user_cannot_select_ccx(self):
self.client.login(username=self.user.username, password="test") self.client.login(username=self.user.username, password="test")
switch_url = reverse( switch_url = reverse(
'switch_active_poc', 'switch_active_ccx',
args=[self.course.id.to_deprecated_string(), self.poc.id] args=[self.course.id.to_deprecated_string(), self.ccx.id]
) )
response = self.client.get(switch_url) response = self.client.get(switch_url)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertTrue(response.get('Location', '').endswith(self.target_url)) self.assertTrue(response.get('Location', '').endswith(self.target_url))
# if the poc were active, we'd need to pass the ID of the poc here. # if the ccx were active, we'd need to pass the ID of the ccx here.
self.verify_active_poc(self.client) self.verify_active_ccx(self.client)
def test_unenrolled_user_switched_to_mooc(self): def test_unenrolled_user_switched_to_mooc(self):
self.client.login(username=self.user.username, password="test") self.client.login(username=self.user.username, password="test")
# pre-seed the session with the poc id # pre-seed the session with the ccx id
session = self.client.session session = self.client.session
session[ACTIVE_POC_KEY] = str(self.poc.id) session[ACTIVE_CCX_KEY] = str(self.ccx.id)
session.save() session.save()
switch_url = reverse( switch_url = reverse(
'switch_active_poc', 'switch_active_ccx',
args=[self.course.id.to_deprecated_string(), self.poc.id] args=[self.course.id.to_deprecated_string(), self.ccx.id]
) )
response = self.client.get(switch_url) response = self.client.get(switch_url)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertTrue(response.get('Location', '').endswith(self.target_url)) self.assertTrue(response.get('Location', '').endswith(self.target_url))
# we tried to select the poc but are not registered, so we are switched # we tried to select the ccx but are not registered, so we are switched
# back to the mooc view # back to the mooc view
self.verify_active_poc(self.client) self.verify_active_ccx(self.client)
def test_unassociated_course_and_poc_not_selected(self): def test_unassociated_course_and_ccx_not_selected(self):
new_course = CourseFactory.create() new_course = CourseFactory.create()
self.client.login(username=self.user.username, password="test") self.client.login(username=self.user.username, password="test")
expected_url = reverse( expected_url = reverse(
'course_root', args=[new_course.id.to_deprecated_string()] 'course_root', args=[new_course.id.to_deprecated_string()]
) )
# the poc and the course are not related. # the ccx and the course are not related.
switch_url = reverse( switch_url = reverse(
'switch_active_poc', 'switch_active_ccx',
args=[new_course.id.to_deprecated_string(), self.poc.id] args=[new_course.id.to_deprecated_string(), self.ccx.id]
) )
response = self.client.get(switch_url) response = self.client.get(switch_url)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertTrue(response.get('Location', '').endswith(expected_url)) self.assertTrue(response.get('Location', '').endswith(expected_url))
# the mooc should be active # the mooc should be active
self.verify_active_poc(self.client) self.verify_active_ccx(self.client)
def test_missing_poc_cannot_be_selected(self): def test_missing_ccx_cannot_be_selected(self):
self.register_user_in_poc() self.register_user_in_ccx()
self.client.login(username=self.user.username, password="test") self.client.login(username=self.user.username, password="test")
switch_url = reverse( switch_url = reverse(
'switch_active_poc', 'switch_active_ccx',
args=[self.course.id.to_deprecated_string(), self.poc.id] args=[self.course.id.to_deprecated_string(), self.ccx.id]
) )
# delete the poc # delete the ccx
self.poc.delete() self.ccx.delete()
response = self.client.get(switch_url) response = self.client.get(switch_url)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertTrue(response.get('Location', '').endswith(self.target_url)) self.assertTrue(response.get('Location', '').endswith(self.target_url))
# we tried to select the poc it doesn't exist anymore, so we are # we tried to select the ccx it doesn't exist anymore, so we are
# switched back to the mooc view # switched back to the mooc view
self.verify_active_poc(self.client) self.verify_active_ccx(self.client)
def test_revoking_poc_membership_revokes_active_poc(self): def test_revoking_ccx_membership_revokes_active_ccx(self):
self.register_user_in_poc(active=True) self.register_user_in_ccx(active=True)
self.client.login(username=self.user.username, password="test") self.client.login(username=self.user.username, password="test")
# ensure poc is active in the request session # ensure ccx is active in the request session
switch_url = reverse( switch_url = reverse(
'switch_active_poc', 'switch_active_ccx',
args=[self.course.id.to_deprecated_string(), self.poc.id] args=[self.course.id.to_deprecated_string(), self.ccx.id]
) )
self.client.get(switch_url) self.client.get(switch_url)
self.verify_active_poc(self.client, self.poc.id) self.verify_active_ccx(self.client, self.ccx.id)
# unenroll the user from the poc # unenroll the user from the ccx
self.revoke_poc_registration() self.revoke_ccx_registration()
# request the course root and verify that the poc is not active # request the course root and verify that the ccx is not active
self.client.get(self.target_url) self.client.get(self.target_url)
self.verify_active_poc(self.client) self.verify_active_ccx(self.client)
def flatten(seq): def flatten(seq):
......
""" """
POC Enrollment operations for use by Coach APIs. CCX Enrollment operations for use by Coach APIs.
Does not include any access control, be sure to check access before calling. Does not include any access control, be sure to check access before calling.
""" """
import logging
from courseware.courses import get_course_about_section from courseware.courses import get_course_about_section
from courseware.courses import get_course_by_id from courseware.courses import get_course_by_id
from django.contrib.auth.models import User from django.contrib.auth.models import User
...@@ -16,61 +16,64 @@ from xmodule.modulestore.django import modulestore ...@@ -16,61 +16,64 @@ from xmodule.modulestore.django import modulestore
from xmodule.error_module import ErrorDescriptor from xmodule.error_module import ErrorDescriptor
from .models import ( from .models import (
PocMembership, CcxMembership,
PocFutureMembership, CcxFutureMembership,
) )
from .overrides import get_current_poc from .overrides import get_current_ccx
log = logging.getLogger("edx.ccx")
class EmailEnrollmentState(object): class EmailEnrollmentState(object):
""" Store the complete enrollment state of an email in a class """ """ Store the complete enrollment state of an email in a class """
def __init__(self, poc, email): def __init__(self, ccx, email):
exists_user = User.objects.filter(email=email).exists() exists_user = User.objects.filter(email=email).exists()
if exists_user: if exists_user:
user = User.objects.get(email=email) user = User.objects.get(email=email)
poc_member = PocMembership.objects.filter(poc=poc, student=user) ccx_member = CcxMembership.objects.filter(ccx=ccx, student=user)
in_poc = poc_member.exists() in_ccx = ccx_member.exists()
full_name = user.profile.name full_name = user.profile.name
else: else:
user = None user = None
in_poc = False in_ccx = False
full_name = None full_name = None
self.user = exists_user self.user = exists_user
self.member = user self.member = user
self.full_name = full_name self.full_name = full_name
self.in_poc = in_poc self.in_ccx = in_ccx
def __repr__(self): def __repr__(self):
return "{}(user={}, member={}, in_poc={}".format( return "{}(user={}, member={}, in_ccx={}".format(
self.__class__.__name__, self.__class__.__name__,
self.user, self.user,
self.member, self.member,
self.in_poc, self.in_ccx,
) )
def to_dict(self): def to_dict(self):
return { return {
'user': self.user, 'user': self.user,
'member': self.member, 'member': self.member,
'in_poc': self.in_poc, 'in_ccx': self.in_ccx,
} }
def enroll_email(poc, student_email, auto_enroll=False, email_students=False, email_params=None): def enroll_email(ccx, student_email, auto_enroll=False, email_students=False, email_params=None):
if email_params is None: if email_params is None:
email_params = get_email_params(poc, True) email_params = get_email_params(ccx, True)
previous_state = EmailEnrollmentState(poc, student_email) previous_state = EmailEnrollmentState(ccx, student_email)
if previous_state.user: if previous_state.user:
if not previous_state.in_poc: if not previous_state.in_ccx:
user = User.objects.get(email=student_email) user = User.objects.get(email=student_email)
membership = PocMembership( membership = CcxMembership(
poc=poc, student=user, active=True ccx=ccx, student=user, active=True
) )
membership.save() membership.save()
elif auto_enroll: elif auto_enroll:
# activate existing memberships # activate existing memberships
membership = PocMembership.objects.get(student=user, poc=poc) membership = CcxMembership.objects.get(student=user, ccx=ccx)
membership.active = True membership.active = True
membership.save() membership.save()
if email_students: if email_students:
...@@ -79,8 +82,8 @@ def enroll_email(poc, student_email, auto_enroll=False, email_students=False, em ...@@ -79,8 +82,8 @@ def enroll_email(poc, student_email, auto_enroll=False, email_students=False, em
email_params['full_name'] = previous_state.full_name email_params['full_name'] = previous_state.full_name
send_mail_to_student(student_email, email_params) send_mail_to_student(student_email, email_params)
else: else:
membership = PocFutureMembership( membership = CcxFutureMembership(
poc=poc, auto_enroll=auto_enroll, email=student_email ccx=ccx, auto_enroll=auto_enroll, email=student_email
) )
membership.save() membership.save()
if email_students: if email_students:
...@@ -88,19 +91,19 @@ def enroll_email(poc, student_email, auto_enroll=False, email_students=False, em ...@@ -88,19 +91,19 @@ def enroll_email(poc, student_email, auto_enroll=False, email_students=False, em
email_params['email_address'] = student_email email_params['email_address'] = student_email
send_mail_to_student(student_email, email_params) send_mail_to_student(student_email, email_params)
after_state = EmailEnrollmentState(poc, student_email) after_state = EmailEnrollmentState(ccx, student_email)
return previous_state, after_state return previous_state, after_state
def unenroll_email(poc, student_email, email_students=False, email_params=None): def unenroll_email(ccx, student_email, email_students=False, email_params=None):
if email_params is None: if email_params is None:
email_params = get_email_params(poc, True) email_params = get_email_params(ccx, True)
previous_state = EmailEnrollmentState(poc, student_email) previous_state = EmailEnrollmentState(ccx, student_email)
if previous_state.in_poc: if previous_state.in_ccx:
PocMembership.objects.get( CcxMembership.objects.get(
poc=poc, student=previous_state.member ccx=ccx, student=previous_state.member
).delete() ).delete()
if email_students: if email_students:
email_params['message'] = 'enrolled_unenroll' email_params['message'] = 'enrolled_unenroll'
...@@ -108,25 +111,25 @@ def unenroll_email(poc, student_email, email_students=False, email_params=None): ...@@ -108,25 +111,25 @@ def unenroll_email(poc, student_email, email_students=False, email_params=None):
email_params['full_name'] = previous_state.full_name email_params['full_name'] = previous_state.full_name
send_mail_to_student(student_email, email_params) send_mail_to_student(student_email, email_params)
else: else:
if PocFutureMembership.objects.filter( if CcxFutureMembership.objects.filter(
poc=poc, email=student_email ccx=ccx, email=student_email
).exists(): ).exists():
PocFutureMembership.objects.get( CcxFutureMembership.objects.get(
poc=poc, email=student_email ccx=ccx, email=student_email
).delete() ).delete()
if email_students: if email_students:
email_params['message'] = 'allowed_unenroll' email_params['message'] = 'allowed_unenroll'
email_params['email_address'] = student_email email_params['email_address'] = student_email
send_mail_to_student(student_email, email_params) send_mail_to_student(student_email, email_params)
after_state = EmailEnrollmentState(poc, student_email) after_state = EmailEnrollmentState(ccx, student_email)
return previous_state, after_state return previous_state, after_state
def get_email_params(poc, auto_enroll, secure=True): def get_email_params(ccx, auto_enroll, secure=True):
protocol = 'https' if secure else 'http' protocol = 'https' if secure else 'http'
course_id = poc.course_id course_id = ccx.course_id
stripped_site_name = microsite.get_value( stripped_site_name = microsite.get_value(
'SITE_NAME', 'SITE_NAME',
...@@ -135,7 +138,7 @@ def get_email_params(poc, auto_enroll, secure=True): ...@@ -135,7 +138,7 @@ def get_email_params(poc, auto_enroll, secure=True):
registration_url = u'{proto}://{site}{path}'.format( registration_url = u'{proto}://{site}{path}'.format(
proto=protocol, proto=protocol,
site=stripped_site_name, site=stripped_site_name,
path=reverse('student.views.register_user') path=reverse('register_user')
) )
course_url = u'{proto}://{site}{path}'.format( course_url = u'{proto}://{site}{path}'.format(
proto=protocol, proto=protocol,
...@@ -160,7 +163,7 @@ def get_email_params(poc, auto_enroll, secure=True): ...@@ -160,7 +163,7 @@ def get_email_params(poc, auto_enroll, secure=True):
email_params = { email_params = {
'site_name': stripped_site_name, 'site_name': stripped_site_name,
'registration_url': registration_url, 'registration_url': registration_url,
'course': poc, 'course': ccx,
'auto_enroll': auto_enroll, 'auto_enroll': auto_enroll,
'course_url': course_url, 'course_url': course_url,
'course_about_url': course_about_url, 'course_about_url': course_about_url,
...@@ -184,20 +187,20 @@ def send_mail_to_student(student, param_dict): ...@@ -184,20 +187,20 @@ def send_mail_to_student(student, param_dict):
email_template_dict = { email_template_dict = {
'allowed_enroll': ( 'allowed_enroll': (
'pocs/enroll_email_allowedsubject.txt', 'ccx/enroll_email_allowedsubject.txt',
'pocs/enroll_email_allowedmessage.txt' 'ccx/enroll_email_allowedmessage.txt'
), ),
'enrolled_enroll': ( 'enrolled_enroll': (
'pocs/enroll_email_enrolledsubject.txt', 'ccx/enroll_email_enrolledsubject.txt',
'pocs/enroll_email_enrolledmessage.txt' 'ccx/enroll_email_enrolledmessage.txt'
), ),
'allowed_unenroll': ( 'allowed_unenroll': (
'pocs/unenroll_email_subject.txt', 'ccx/unenroll_email_subject.txt',
'pocs/unenroll_email_allowedmessage.txt' 'ccx/unenroll_email_allowedmessage.txt'
), ),
'enrolled_unenroll': ( 'enrolled_unenroll': (
'pocs/unenroll_email_subject.txt', 'ccx/unenroll_email_subject.txt',
'pocs/unenroll_email_enrolledmessage.txt' 'ccx/unenroll_email_enrolledmessage.txt'
), ),
} }
...@@ -226,54 +229,54 @@ def send_mail_to_student(student, param_dict): ...@@ -226,54 +229,54 @@ def send_mail_to_student(student, param_dict):
) )
def get_all_pocs_for_user(user): def get_all_ccx_for_user(user):
"""return all POCS to which the user is registered """return all CCXS to which the user is registered
Returns a list of dicts: { Returns a list of dicts: {
poc_name: <formatted title of POC course> ccx_name: <formatted title of CCX course>
poc_url: <url to view this POC> ccx_url: <url to view this CCX>
poc_active: True if this poc is currently the 'active' one ccx_active: True if this ccx is currently the 'active' one
mooc_name: <formatted title of the MOOC course for this POC> mooc_name: <formatted title of the MOOC course for this CCX>
mooc_url: <url to view this MOOC> mooc_url: <url to view this MOOC>
} }
""" """
if user.is_anonymous(): if user.is_anonymous():
return [] return []
current_active_poc = get_current_poc() current_active_ccx = get_current_ccx()
memberships = [] memberships = []
for membership in PocMembership.memberships_for_user(user): for membership in CcxMembership.memberships_for_user(user):
course = get_course_by_id(membership.poc.course_id) course = get_course_by_id(membership.ccx.course_id)
poc = membership.poc ccx = membership.ccx
poc_title = poc.display_name ccx_title = ccx.display_name
mooc_title = get_course_about_section(course, 'title') mooc_title = get_course_about_section(course, 'title')
url = reverse( url = reverse(
'switch_active_poc', 'switch_active_ccx',
args=[course.id.to_deprecated_string(), membership.poc.id] args=[course.id.to_deprecated_string(), membership.ccx.id]
) )
mooc_url = reverse( mooc_url = reverse(
'switch_active_poc', 'switch_active_ccx',
args=[course.id.to_deprecated_string(),] args=[course.id.to_deprecated_string(), ]
) )
memberships.append({ memberships.append({
'poc_name': poc_title, 'ccx_name': ccx_title,
'poc_url': url, 'ccx_url': url,
'active': membership.poc == current_active_poc, 'active': membership.ccx == current_active_ccx,
'mooc_name': mooc_title, 'mooc_name': mooc_title,
'mooc_url': mooc_url, 'mooc_url': mooc_url,
}) })
return memberships return memberships
def get_poc_membership_triplets(user, course_org_filter, org_filter_out_set): def get_ccx_membership_triplets(user, course_org_filter, org_filter_out_set):
""" """
Get the relevant set of (PersonalOnlineCourse, PocMembership, Course) Get the relevant set of (CustomCourseForEdX, CcxMembership, Course)
triplets to be displayed on a student's dashboard. triplets to be displayed on a student's dashboard.
""" """
# only active memberships for now # only active memberships for now
for membership in PocMembership.memberships_for_user(user): for membership in CcxMembership.memberships_for_user(user):
poc = membership.poc ccx = membership.ccx
store = modulestore() store = modulestore()
with store.bulk_operations(poc.course_id): with store.bulk_operations(ccx.course_id):
course = store.get_course(poc.course_id) course = store.get_course(ccx.course_id)
if course and not isinstance(course, ErrorDescriptor): if course and not isinstance(course, ErrorDescriptor):
# if we are in a Microsite, then filter out anything that is not # if we are in a Microsite, then filter out anything that is not
# attributed (by ORG) to that Microsite # attributed (by ORG) to that Microsite
...@@ -284,8 +287,8 @@ def get_poc_membership_triplets(user, course_org_filter, org_filter_out_set): ...@@ -284,8 +287,8 @@ def get_poc_membership_triplets(user, course_org_filter, org_filter_out_set):
elif course.location.org in org_filter_out_set: elif course.location.org in org_filter_out_set:
continue continue
yield (poc, membership, course) yield (ccx, membership, course)
else: else:
log.error("User {0} enrolled in {2} course {1}".format( log.error("User {0} enrolled in {2} course {1}".format(
user.username, poc.course_id, "broken" if course else "non-existent" user.username, ccx.course_id, "broken" if course else "non-existent"
)) ))
""" """
Views related to the Personal Online Courses feature. Views related to the Custom Courses feature.
""" """
import csv import csv
import datetime import datetime
...@@ -33,24 +33,24 @@ from courseware.model_data import FieldDataCache ...@@ -33,24 +33,24 @@ from courseware.model_data import FieldDataCache
from courseware.module_render import get_module_for_descriptor from courseware.module_render import get_module_for_descriptor
from edxmako.shortcuts import render_to_response from edxmako.shortcuts import render_to_response
from opaque_keys.edx.locations import SlashSeparatedCourseKey from opaque_keys.edx.locations import SlashSeparatedCourseKey
from student.roles import CoursePocCoachRole from student.roles import CourseCcxCoachRole
from instructor.offline_gradecalc import student_grades from instructor.offline_gradecalc import student_grades
from instructor.views.api import _split_input_list from instructor.views.api import _split_input_list
from instructor.views.tools import get_student_from_identifier from instructor.views.tools import get_student_from_identifier
from .models import PersonalOnlineCourse, PocMembership from .models import CustomCourseForEdX, CcxMembership
from .overrides import ( from .overrides import (
clear_override_for_poc, clear_override_for_ccx,
get_override_for_poc, get_override_for_ccx,
override_field_for_poc, override_field_for_ccx,
poc_context, ccx_context,
) )
from .utils import ( from .utils import (
enroll_email, enroll_email,
unenroll_email, unenroll_email,
) )
from pocs import ACTIVE_POC_KEY from ccx import ACTIVE_CCX_KEY
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -59,7 +59,7 @@ TODAY = datetime.datetime.today # for patching in tests ...@@ -59,7 +59,7 @@ TODAY = datetime.datetime.today # for patching in tests
def coach_dashboard(view): def coach_dashboard(view):
""" """
View decorator which enforces that the user have the POC coach role on the View decorator which enforces that the user have the CCX coach role on the
given course and goes ahead and translates the course_id from the Django given course and goes ahead and translates the course_id from the Django
route into a course object. route into a course object.
""" """
...@@ -70,10 +70,10 @@ def coach_dashboard(view): ...@@ -70,10 +70,10 @@ def coach_dashboard(view):
and modifying the view's call signature. and modifying the view's call signature.
""" """
course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
role = CoursePocCoachRole(course_key) role = CourseCcxCoachRole(course_key)
if not role.has_user(request.user): if not role.has_user(request.user):
return HttpResponseForbidden( return HttpResponseForbidden(
_('You must be a POC Coach to access this view.')) _('You must be a CCX Coach to access this view.'))
course = get_course_by_id(course_key, depth=None) course = get_course_by_id(course_key, depth=None)
return view(request, course) return view(request, course)
return wrapper return wrapper
...@@ -84,79 +84,79 @@ def coach_dashboard(view): ...@@ -84,79 +84,79 @@ def coach_dashboard(view):
@coach_dashboard @coach_dashboard
def dashboard(request, course): def dashboard(request, course):
""" """
Display the POC Coach Dashboard. Display the CCX Coach Dashboard.
""" """
poc = get_poc_for_coach(course, request.user) ccx = get_ccx_for_coach(course, request.user)
context = { context = {
'course': course, 'course': course,
'poc': poc, 'ccx': ccx,
} }
if poc: if ccx:
schedule = get_poc_schedule(course, poc) schedule = get_ccx_schedule(course, ccx)
grading_policy = get_override_for_poc( grading_policy = get_override_for_ccx(
poc, course, 'grading_policy', course.grading_policy) ccx, course, 'grading_policy', course.grading_policy)
context['schedule'] = json.dumps(schedule, indent=4) context['schedule'] = json.dumps(schedule, indent=4)
context['save_url'] = reverse( context['save_url'] = reverse(
'save_poc', kwargs={'course_id': course.id}) 'save_ccx', kwargs={'course_id': course.id})
context['poc_members'] = PocMembership.objects.filter(poc=poc) context['ccx_members'] = CcxMembership.objects.filter(ccx=ccx)
context['gradebook_url'] = reverse( context['gradebook_url'] = reverse(
'poc_gradebook', kwargs={'course_id': course.id}) 'ccx_gradebook', kwargs={'course_id': course.id})
context['grades_csv_url'] = reverse( context['grades_csv_url'] = reverse(
'poc_grades_csv', kwargs={'course_id': course.id}) 'ccx_grades_csv', kwargs={'course_id': course.id})
context['grading_policy'] = json.dumps(grading_policy, indent=4) context['grading_policy'] = json.dumps(grading_policy, indent=4)
context['grading_policy_url'] = reverse( context['grading_policy_url'] = reverse(
'poc_set_grading_policy', kwargs={'course_id': course.id}) 'ccx_set_grading_policy', kwargs={'course_id': course.id})
else: else:
context['create_poc_url'] = reverse( context['create_ccx_url'] = reverse(
'create_poc', kwargs={'course_id': course.id}) 'create_ccx', kwargs={'course_id': course.id})
return render_to_response('pocs/coach_dashboard.html', context) return render_to_response('ccx/coach_dashboard.html', context)
@ensure_csrf_cookie @ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True) @cache_control(no_cache=True, no_store=True, must_revalidate=True)
@coach_dashboard @coach_dashboard
def create_poc(request, course): def create_ccx(request, course):
""" """
Create a new POC Create a new CCX
""" """
name = request.POST.get('name') name = request.POST.get('name')
poc = PersonalOnlineCourse( ccx = CustomCourseForEdX(
course_id=course.id, course_id=course.id,
coach=request.user, coach=request.user,
display_name=name) display_name=name)
poc.save() ccx.save()
# Make sure start/due are overridden for entire course # Make sure start/due are overridden for entire course
start = TODAY().replace(tzinfo=pytz.UTC) start = TODAY().replace(tzinfo=pytz.UTC)
override_field_for_poc(poc, course, 'start', start) override_field_for_ccx(ccx, course, 'start', start)
override_field_for_poc(poc, course, 'due', None) override_field_for_ccx(ccx, course, 'due', None)
# Hide anything that can show up in the schedule # Hide anything that can show up in the schedule
hidden = 'visible_to_staff_only' hidden = 'visible_to_staff_only'
for chapter in course.get_children(): for chapter in course.get_children():
override_field_for_poc(poc, chapter, hidden, True) override_field_for_ccx(ccx, chapter, hidden, True)
for sequential in chapter.get_children(): for sequential in chapter.get_children():
override_field_for_poc(poc, sequential, hidden, True) override_field_for_ccx(ccx, sequential, hidden, True)
for vertical in sequential.get_children(): for vertical in sequential.get_children():
override_field_for_poc(poc, vertical, hidden, True) override_field_for_ccx(ccx, vertical, hidden, True)
url = reverse('poc_coach_dashboard', kwargs={'course_id': course.id}) url = reverse('ccx_coach_dashboard', kwargs={'course_id': course.id})
return redirect(url) return redirect(url)
@ensure_csrf_cookie @ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True) @cache_control(no_cache=True, no_store=True, must_revalidate=True)
@coach_dashboard @coach_dashboard
def save_poc(request, course): def save_ccx(request, course):
""" """
Save changes to POC. Save changes to CCX.
""" """
poc = get_poc_for_coach(course, request.user) ccx = get_ccx_for_coach(course, request.user)
def override_fields(parent, data, graded, earliest=None): def override_fields(parent, data, graded, earliest=None):
""" """
Recursively apply POC schedule data to POC by overriding the Recursively apply CCX schedule data to CCX by overriding the
`visible_to_staff_only`, `start` and `due` fields for units in the `visible_to_staff_only`, `start` and `due` fields for units in the
course. course.
""" """
...@@ -165,20 +165,20 @@ def save_poc(request, course): ...@@ -165,20 +165,20 @@ def save_poc(request, course):
for child in parent.get_children()} for child in parent.get_children()}
for unit in data: for unit in data:
block = blocks[unit['location']] block = blocks[unit['location']]
override_field_for_poc( override_field_for_ccx(
poc, block, 'visible_to_staff_only', unit['hidden']) ccx, block, 'visible_to_staff_only', unit['hidden'])
start = parse_date(unit['start']) start = parse_date(unit['start'])
if start: if start:
if not earliest or start < earliest: if not earliest or start < earliest:
earliest = start earliest = start
override_field_for_poc(poc, block, 'start', start) override_field_for_ccx(ccx, block, 'start', start)
else: else:
clear_override_for_poc(poc, block, 'start') clear_override_for_ccx(ccx, block, 'start')
due = parse_date(unit['due']) due = parse_date(unit['due'])
if due: if due:
override_field_for_poc(poc, block, 'due', due) override_field_for_ccx(ccx, block, 'due', due)
else: else:
clear_override_for_poc(poc, block, 'due') clear_override_for_ccx(ccx, block, 'due')
if not unit['hidden'] and block.graded: if not unit['hidden'] and block.graded:
graded[block.format] = graded.get(block.format, 0) + 1 graded[block.format] = graded.get(block.format, 0) + 1
...@@ -191,12 +191,12 @@ def save_poc(request, course): ...@@ -191,12 +191,12 @@ def save_poc(request, course):
graded = {} graded = {}
earliest = override_fields(course, json.loads(request.body), graded) earliest = override_fields(course, json.loads(request.body), graded)
if earliest: if earliest:
override_field_for_poc(poc, course, 'start', earliest) override_field_for_ccx(ccx, course, 'start', earliest)
# Attempt to automatically adjust grading policy # Attempt to automatically adjust grading policy
changed = False changed = False
policy = get_override_for_poc( policy = get_override_for_ccx(
poc, course, 'grading_policy', course.grading_policy ccx, course, 'grading_policy', course.grading_policy
) )
policy = deepcopy(policy) policy = deepcopy(policy)
grader = policy['GRADER'] grader = policy['GRADER']
...@@ -206,11 +206,11 @@ def save_poc(request, course): ...@@ -206,11 +206,11 @@ def save_poc(request, course):
changed = True changed = True
section['min_count'] = count section['min_count'] = count
if changed: if changed:
override_field_for_poc(poc, course, 'grading_policy', policy) override_field_for_ccx(ccx, course, 'grading_policy', policy)
return HttpResponse( return HttpResponse(
json.dumps({ json.dumps({
'schedule': get_poc_schedule(course, poc), 'schedule': get_ccx_schedule(course, ccx),
'grading_policy': json.dumps(policy, indent=4)}), 'grading_policy': json.dumps(policy, indent=4)}),
content_type='application/json', content_type='application/json',
) )
...@@ -221,13 +221,13 @@ def save_poc(request, course): ...@@ -221,13 +221,13 @@ def save_poc(request, course):
@coach_dashboard @coach_dashboard
def set_grading_policy(request, course): def set_grading_policy(request, course):
""" """
Set grading policy for the POC. Set grading policy for the CCX.
""" """
poc = get_poc_for_coach(course, request.user) ccx = get_ccx_for_coach(course, request.user)
override_field_for_poc( override_field_for_ccx(
poc, course, 'grading_policy', json.loads(request.POST['policy'])) ccx, course, 'grading_policy', json.loads(request.POST['policy']))
url = reverse('poc_coach_dashboard', kwargs={'course_id': course.id}) url = reverse('ccx_coach_dashboard', kwargs={'course_id': course.id})
return redirect(url) return redirect(url)
...@@ -263,36 +263,36 @@ def parse_date(datestring): ...@@ -263,36 +263,36 @@ def parse_date(datestring):
return None return None
def get_poc_for_coach(course, coach): def get_ccx_for_coach(course, coach):
""" """
Looks to see if user is coach of a POC for this course. Returns the POC or Looks to see if user is coach of a CCX for this course. Returns the CCX or
None. None.
""" """
try: try:
return PersonalOnlineCourse.objects.get( return CustomCourseForEdX.objects.get(
course_id=course.id, course_id=course.id,
coach=coach) coach=coach)
except PersonalOnlineCourse.DoesNotExist: except CustomCourseForEdX.DoesNotExist:
return None return None
def get_poc_schedule(course, poc): def get_ccx_schedule(course, ccx):
""" """
Generate a JSON serializable POC schedule. Generate a JSON serializable CCX schedule.
""" """
def visit(node, depth=1): def visit(node, depth=1):
""" """
Recursive generator function which yields POC schedule nodes. Recursive generator function which yields CCX schedule nodes.
""" """
for child in node.get_children(): for child in node.get_children():
start = get_override_for_poc(poc, child, 'start', None) start = get_override_for_ccx(ccx, child, 'start', None)
if start: if start:
start = str(start)[:-9] start = str(start)[:-9]
due = get_override_for_poc(poc, child, 'due', None) due = get_override_for_ccx(ccx, child, 'due', None)
if due: if due:
due = str(due)[:-9] due = str(due)[:-9]
hidden = get_override_for_poc( hidden = get_override_for_ccx(
poc, child, 'visible_to_staff_only', ccx, child, 'visible_to_staff_only',
child.visible_to_staff_only) child.visible_to_staff_only)
visited = { visited = {
'location': str(child.location), 'location': str(child.location),
...@@ -317,9 +317,9 @@ def get_poc_schedule(course, poc): ...@@ -317,9 +317,9 @@ def get_poc_schedule(course, poc):
@ensure_csrf_cookie @ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True) @cache_control(no_cache=True, no_store=True, must_revalidate=True)
@coach_dashboard @coach_dashboard
def poc_schedule(request, course): def ccx_schedule(request, course):
poc = get_poc_for_coach(course, request.user) ccx = get_ccx_for_coach(course, request.user)
schedule = get_poc_schedule(course, poc) schedule = get_ccx_schedule(course, ccx)
json_schedule = json.dumps(schedule, indent=4) json_schedule = json.dumps(schedule, indent=4)
return HttpResponse(json_schedule, mimetype='application/json') return HttpResponse(json_schedule, mimetype='application/json')
...@@ -327,11 +327,11 @@ def poc_schedule(request, course): ...@@ -327,11 +327,11 @@ def poc_schedule(request, course):
@ensure_csrf_cookie @ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True) @cache_control(no_cache=True, no_store=True, must_revalidate=True)
@coach_dashboard @coach_dashboard
def poc_invite(request, course): def ccx_invite(request, course):
""" """
Invite users to new poc Invite users to new ccx
""" """
poc = get_poc_for_coach(course, request.user) ccx = get_ccx_for_coach(course, request.user)
action = request.POST.get('enrollment-button') action = request.POST.get('enrollment-button')
identifiers_raw = request.POST.get('student-ids') identifiers_raw = request.POST.get('student-ids')
identifiers = _split_input_list(identifiers_raw) identifiers = _split_input_list(identifiers_raw)
...@@ -350,26 +350,26 @@ def poc_invite(request, course): ...@@ -350,26 +350,26 @@ def poc_invite(request, course):
validate_email(email) validate_email(email)
if action == 'Enroll': if action == 'Enroll':
enroll_email( enroll_email(
poc, ccx,
email, email,
auto_enroll=auto_enroll, auto_enroll=auto_enroll,
email_students=email_students email_students=email_students
) )
if action == "Unenroll": if action == "Unenroll":
unenroll_email(poc, email, email_students=email_students) unenroll_email(ccx, email, email_students=email_students)
except ValidationError: except ValidationError:
pass # maybe log this? pass # maybe log this?
url = reverse('poc_coach_dashboard', kwargs={'course_id': course.id}) url = reverse('ccx_coach_dashboard', kwargs={'course_id': course.id})
return redirect(url) return redirect(url)
@ensure_csrf_cookie @ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True) @cache_control(no_cache=True, no_store=True, must_revalidate=True)
@coach_dashboard @coach_dashboard
def poc_student_management(request, course): def ccx_student_management(request, course):
"""Manage the enrollment of individual students in a POC """Manage the enrollment of individual students in a CCX
""" """
poc = get_poc_for_coach(course, request.user) ccx = get_ccx_for_coach(course, request.user)
action = request.POST.get('student-action', None) action = request.POST.get('student-action', None)
student_id = request.POST.get('student-id', '') student_id = request.POST.get('student-id', '')
user = email = None user = email = None
...@@ -385,21 +385,21 @@ def poc_student_management(request, course): ...@@ -385,21 +385,21 @@ def poc_student_management(request, course):
if action == 'add': if action == 'add':
# by decree, no emails sent to students added this way # by decree, no emails sent to students added this way
# by decree, any students added this way are auto_enrolled # by decree, any students added this way are auto_enrolled
enroll_email(poc, email, auto_enroll=True, email_students=False) enroll_email(ccx, email, auto_enroll=True, email_students=False)
elif action == 'revoke': elif action == 'revoke':
unenroll_email(poc, email, email_students=False) unenroll_email(ccx, email, email_students=False)
except ValidationError: except ValidationError:
pass # XXX: log, report? pass # XXX: log, report?
url = reverse('poc_coach_dashboard', kwargs={'course_id': course.id}) url = reverse('ccx_coach_dashboard', kwargs={'course_id': course.id})
return redirect(url) return redirect(url)
@cache_control(no_cache=True, no_store=True, must_revalidate=True) @cache_control(no_cache=True, no_store=True, must_revalidate=True)
@coach_dashboard @coach_dashboard
def poc_gradebook(request, course): def ccx_gradebook(request, course):
""" """
Show the gradebook for this POC. Show the gradebook for this CCX.
""" """
# Need course module for overrides to function properly # Need course module for overrides to function properly
field_data_cache = FieldDataCache.cache_for_descriptor_descendents( field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
...@@ -407,16 +407,16 @@ def poc_gradebook(request, course): ...@@ -407,16 +407,16 @@ def poc_gradebook(request, course):
course = get_module_for_descriptor( course = get_module_for_descriptor(
request.user, request, course, field_data_cache, course.id) request.user, request, course, field_data_cache, course.id)
poc = get_poc_for_coach(course, request.user) ccx = get_ccx_for_coach(course, request.user)
with poc_context(poc): with ccx_context(ccx):
# The grading policy for the MOOC is probably already cached. We need # The grading policy for the MOOC is probably already cached. We need
# to make sure we have the POC grading policy loaded. # to make sure we have the CCX grading policy loaded.
course._field_data_cache = {} # pylint: disable=protected-access course._field_data_cache = {} # pylint: disable=protected-access
course.set_grading_policy(course.grading_policy) course.set_grading_policy(course.grading_policy)
enrolled_students = User.objects.filter( enrolled_students = User.objects.filter(
pocmembership__poc=poc, ccxmembership__ccx=ccx,
pocmembership__active=1 ccxmembership__active=1
).order_by('username').select_related("profile") ).order_by('username').select_related("profile")
student_info = [ student_info = [
...@@ -442,7 +442,7 @@ def poc_gradebook(request, course): ...@@ -442,7 +442,7 @@ def poc_gradebook(request, course):
@cache_control(no_cache=True, no_store=True, must_revalidate=True) @cache_control(no_cache=True, no_store=True, must_revalidate=True)
@coach_dashboard @coach_dashboard
def poc_grades_csv(request, course): def ccx_grades_csv(request, course):
""" """
Download grades as CSV. Download grades as CSV.
""" """
...@@ -451,16 +451,16 @@ def poc_grades_csv(request, course): ...@@ -451,16 +451,16 @@ def poc_grades_csv(request, course):
course.id, request.user, course, depth=2) course.id, request.user, course, depth=2)
course = get_module_for_descriptor( course = get_module_for_descriptor(
request.user, request, course, field_data_cache, course.id) request.user, request, course, field_data_cache, course.id)
poc = get_poc_for_coach(course, request.user) ccx = get_ccx_for_coach(course, request.user)
with poc_context(poc): with ccx_context(ccx):
# The grading policy for the MOOC is probably already cached. We need # The grading policy for the MOOC is probably already cached. We need
# to make sure we have the POC grading policy loaded. # to make sure we have the CCX grading policy loaded.
course._field_data_cache = {} # pylint: disable=protected-access course._field_data_cache = {} # pylint: disable=protected-access
course.set_grading_policy(course.grading_policy) course.set_grading_policy(course.grading_policy)
enrolled_students = User.objects.filter( enrolled_students = User.objects.filter(
pocmembership__poc=poc, ccxmembership__ccx=ccx,
pocmembership__active=1 ccxmembership__active=1
).order_by('username').select_related("profile") ).order_by('username').select_related("profile")
grades = iterate_grades_for(course, enrolled_students) grades = iterate_grades_for(course, enrolled_students)
...@@ -496,8 +496,8 @@ def poc_grades_csv(request, course): ...@@ -496,8 +496,8 @@ def poc_grades_csv(request, course):
@login_required @login_required
def swich_active_poc(request, course_id, poc_id=None): def switch_active_ccx(request, course_id, ccx_id=None):
"""set the active POC for the logged-in user """set the active CCX for the logged-in user
""" """
user = request.user user = request.user
course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
...@@ -506,21 +506,21 @@ def swich_active_poc(request, course_id, poc_id=None): ...@@ -506,21 +506,21 @@ def swich_active_poc(request, course_id, poc_id=None):
course_url = reverse( course_url = reverse(
'course_root', args=[course.id.to_deprecated_string()] 'course_root', args=[course.id.to_deprecated_string()]
) )
if poc_id is not None: if ccx_id is not None:
try: try:
requested_poc = PersonalOnlineCourse.objects.get(pk=poc_id) requested_ccx = CustomCourseForEdX.objects.get(pk=ccx_id)
assert requested_poc.course_id.to_deprecated_string() == course_id assert requested_ccx.course_id.to_deprecated_string() == course_id
if not PocMembership.objects.filter( if not CcxMembership.objects.filter(
poc=requested_poc, student=request.user, active=True ccx=requested_ccx, student=request.user, active=True
).exists(): ).exists():
poc_id = None ccx_id = None
except PersonalOnlineCourse.DoesNotExist: except CustomCourseForEdX.DoesNotExist:
# what to do here? Log the failure? Do we care? # what to do here? Log the failure? Do we care?
poc_id = None ccx_id = None
except AssertionError: except AssertionError:
# what to do here? Log the failure? Do we care? # what to do here? Log the failure? Do we care?
poc_id = None ccx_id = None
request.session[ACTIVE_POC_KEY] = poc_id request.session[ACTIVE_CCX_KEY] = ccx_id
return HttpResponseRedirect(course_url) return HttpResponseRedirect(course_url)
...@@ -248,7 +248,7 @@ def _grade(student, request, course, keep_raw_scores): ...@@ -248,7 +248,7 @@ def _grade(student, request, course, keep_raw_scores):
totaled_scores[section_format] = format_scores totaled_scores[section_format] = format_scores
# Grading policy might be overriden by a POC, need to reset it # Grading policy might be overriden by a CCX, need to reset it
course.set_grading_policy(course.grading_policy) course.set_grading_policy(course.grading_policy)
grade_summary = course.grader.grade(totaled_scores, generate_random_scores=settings.GENERATE_PROFILE_SCORES) grade_summary = course.grader.grade(totaled_scores, generate_random_scores=settings.GENERATE_PROFILE_SCORES)
......
...@@ -15,7 +15,7 @@ from django_comment_common.models import Role ...@@ -15,7 +15,7 @@ from django_comment_common.models import Role
from student.roles import ( from student.roles import (
CourseBetaTesterRole, CourseBetaTesterRole,
CourseInstructorRole, CourseInstructorRole,
CoursePocCoachRole, CourseCcxCoachRole,
CourseStaffRole, CourseStaffRole,
) )
...@@ -26,7 +26,7 @@ ROLES = { ...@@ -26,7 +26,7 @@ ROLES = {
'beta': CourseBetaTesterRole, 'beta': CourseBetaTesterRole,
'instructor': CourseInstructorRole, 'instructor': CourseInstructorRole,
'staff': CourseStaffRole, 'staff': CourseStaffRole,
'poc_coach': CoursePocCoachRole, 'ccx_coach': CourseCcxCoachRole,
} }
......
...@@ -679,7 +679,7 @@ def bulk_beta_modify_access(request, course_id): ...@@ -679,7 +679,7 @@ def bulk_beta_modify_access(request, course_id):
@common_exceptions_400 @common_exceptions_400
@require_query_params( @require_query_params(
unique_student_identifier="email or username of user to change access", unique_student_identifier="email or username of user to change access",
rolename="'instructor', 'staff', 'beta', or 'poc_coach'", rolename="'instructor', 'staff', 'beta', or 'ccx_coach'",
action="'allow' or 'revoke'" action="'allow' or 'revoke'"
) )
def modify_access(request, course_id): def modify_access(request, course_id):
...@@ -691,7 +691,7 @@ def modify_access(request, course_id): ...@@ -691,7 +691,7 @@ def modify_access(request, course_id):
Query parameters: Query parameters:
unique_student_identifer is the target user's username or email unique_student_identifer is the target user's username or email
rolename is one of ['instructor', 'staff', 'beta', 'poc_coach'] rolename is one of ['instructor', 'staff', 'beta', 'ccx_coach']
action is one of ['allow', 'revoke'] action is one of ['allow', 'revoke']
""" """
course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id) course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
...@@ -762,7 +762,7 @@ def list_course_role_members(request, course_id): ...@@ -762,7 +762,7 @@ def list_course_role_members(request, course_id):
List instructors and staff. List instructors and staff.
Requires instructor access. Requires instructor access.
rolename is one of ['instructor', 'staff', 'beta', 'poc_coach'] rolename is one of ['instructor', 'staff', 'beta', 'ccx_coach']
Returns JSON of the form { Returns JSON of the form {
"course_id": "some/course/id", "course_id": "some/course/id",
......
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'PocFutureMembership'
db.create_table('pocs_pocfuturemembership', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('poc', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['pocs.PersonalOnlineCourse'])),
('email', self.gf('django.db.models.fields.CharField')(max_length=255)),
))
db.send_create_signal('pocs', ['PocFutureMembership'])
# Adding field 'PocMembership.active'
db.add_column('pocs_pocmembership', 'active',
self.gf('django.db.models.fields.BooleanField')(default=False),
keep_default=False)
def backwards(self, orm):
# Deleting model 'PocFutureMembership'
db.delete_table('pocs_pocfuturemembership')
# Deleting field 'PocMembership.active'
db.delete_column('pocs_pocmembership', 'active')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'pocs.personalonlinecourse': {
'Meta': {'object_name': 'PersonalOnlineCourse'},
'coach': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
'display_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'pocs.pocfieldoverride': {
'Meta': {'unique_together': "(('poc', 'location', 'field'),)", 'object_name': 'PocFieldOverride'},
'field': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'location': ('xmodule_django.models.LocationKeyField', [], {'max_length': '255', 'db_index': 'True'}),
'poc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['pocs.PersonalOnlineCourse']"}),
'value': ('django.db.models.fields.TextField', [], {'default': "'null'"})
},
'pocs.pocfuturemembership': {
'Meta': {'object_name': 'PocFutureMembership'},
'email': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'poc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['pocs.PersonalOnlineCourse']"})
},
'pocs.pocmembership': {
'Meta': {'object_name': 'PocMembership'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'poc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['pocs.PersonalOnlineCourse']"}),
'student': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
}
}
complete_apps = ['pocs']
\ No newline at end of file
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'PocFutureMembership.auto_enroll'
db.add_column('pocs_pocfuturemembership', 'auto_enroll',
self.gf('django.db.models.fields.BooleanField')(default=False),
keep_default=False)
def backwards(self, orm):
# Deleting field 'PocFutureMembership.auto_enroll'
db.delete_column('pocs_pocfuturemembership', 'auto_enroll')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'pocs.personalonlinecourse': {
'Meta': {'object_name': 'PersonalOnlineCourse'},
'coach': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
'display_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'pocs.pocfieldoverride': {
'Meta': {'unique_together': "(('poc', 'location', 'field'),)", 'object_name': 'PocFieldOverride'},
'field': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'location': ('xmodule_django.models.LocationKeyField', [], {'max_length': '255', 'db_index': 'True'}),
'poc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['pocs.PersonalOnlineCourse']"}),
'value': ('django.db.models.fields.TextField', [], {'default': "'null'"})
},
'pocs.pocfuturemembership': {
'Meta': {'object_name': 'PocFutureMembership'},
'auto_enroll': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'email': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'poc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['pocs.PersonalOnlineCourse']"})
},
'pocs.pocmembership': {
'Meta': {'object_name': 'PocMembership'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'poc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['pocs.PersonalOnlineCourse']"}),
'student': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
}
}
complete_apps = ['pocs']
\ No newline at end of file
from factory.django import DjangoModelFactory
from pocs.models import PersonalOnlineCourse
from pocs.models import PocMembership
from pocs.models import PocFutureMembership
class PocFactory(DjangoModelFactory):
FACTORY_FOR = PersonalOnlineCourse
display_name = "Test POC"
class PocMembershipFactory(DjangoModelFactory):
FACTORY_FOR = PocMembership
active = False
class PocFutureMembershipFactory(DjangoModelFactory):
FACTORY_FOR = PocFutureMembership
...@@ -577,12 +577,12 @@ ECOMMERCE_API_URL = ENV_TOKENS.get('ECOMMERCE_API_URL', ECOMMERCE_API_URL) ...@@ -577,12 +577,12 @@ ECOMMERCE_API_URL = ENV_TOKENS.get('ECOMMERCE_API_URL', ECOMMERCE_API_URL)
ECOMMERCE_API_SIGNING_KEY = AUTH_TOKENS.get('ECOMMERCE_API_SIGNING_KEY', ECOMMERCE_API_SIGNING_KEY) ECOMMERCE_API_SIGNING_KEY = AUTH_TOKENS.get('ECOMMERCE_API_SIGNING_KEY', ECOMMERCE_API_SIGNING_KEY)
ECOMMERCE_API_TIMEOUT = ENV_TOKENS.get('ECOMMERCE_API_TIMEOUT', ECOMMERCE_API_TIMEOUT) ECOMMERCE_API_TIMEOUT = ENV_TOKENS.get('ECOMMERCE_API_TIMEOUT', ECOMMERCE_API_TIMEOUT)
##### Personal Online Courses ##### ##### Custom Courses for EdX #####
if FEATURES.get('PERSONAL_ONLINE_COURSES'): if FEATURES.get('CUSTOM_COURSES_EDX'):
INSTALLED_APPS += ('pocs',) INSTALLED_APPS += ('ccx',)
MIDDLEWARE_CLASSES += ('pocs.overrides.PocMiddleware',) MIDDLEWARE_CLASSES += ('ccx.overrides.CcxMiddleware',)
FIELD_OVERRIDE_PROVIDERS += ( FIELD_OVERRIDE_PROVIDERS += (
'pocs.overrides.PersonalOnlineCoursesOverrideProvider', 'ccx.overrides.CustomCoursesForEdxOverrideProvider',
) )
##### Individual Due Date Extensions ##### ##### Individual Due Date Extensions #####
......
...@@ -214,8 +214,8 @@ FEATURES = { ...@@ -214,8 +214,8 @@ FEATURES = {
# True. # True.
'INDIVIDUAL_DUE_DATES': False, 'INDIVIDUAL_DUE_DATES': False,
# Enable Personal Online Courses # Enable Custom Courses for EdX
'PERSONAL_ONLINE_COURSES': False, 'CUSTOM_COURSES_EDX': False,
# Enable legacy instructor dashboard # Enable legacy instructor dashboard
'ENABLE_INSTRUCTOR_LEGACY_DASHBOARD': True, 'ENABLE_INSTRUCTOR_LEGACY_DASHBOARD': True,
...@@ -1203,7 +1203,8 @@ reverify_js = [ ...@@ -1203,7 +1203,8 @@ reverify_js = [
'js/verify_student/incourse_reverify.js', 'js/verify_student/incourse_reverify.js',
] ]
pocs_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'js/pocs/**/*.js')) ccx_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'js/ccx/**/*.js'))
PIPELINE_CSS = { PIPELINE_CSS = {
'style-vendor': { 'style-vendor': {
...@@ -1399,9 +1400,9 @@ PIPELINE_JS = { ...@@ -1399,9 +1400,9 @@ PIPELINE_JS = {
'source_filenames': reverify_js, 'source_filenames': reverify_js,
'output_filename': 'js/reverify.js' 'output_filename': 'js/reverify.js'
}, },
'pocs': { 'ccx': {
'source_filenames': pocs_js, 'source_filenames': ccx_js,
'output_filename': 'js/pocs.js' 'output_filename': 'js/ccx.js'
} }
} }
......
...@@ -469,6 +469,6 @@ FACEBOOK_API_VERSION = "v2.2" ...@@ -469,6 +469,6 @@ FACEBOOK_API_VERSION = "v2.2"
# Certificates Views # Certificates Views
FEATURES['CERTIFICATES_HTML_VIEW'] = True FEATURES['CERTIFICATES_HTML_VIEW'] = True
######### personal online courses ######### ######### custom courses #########
INSTALLED_APPS += ('pocs',) INSTALLED_APPS += ('ccx',)
MIDDLEWARE_CLASSES += ('pocs.overrides.PocMiddleware',) MIDDLEWARE_CLASSES += ('ccx.overrides.CcxMiddleware',)
...@@ -3,18 +3,18 @@ var edx = edx || {}; ...@@ -3,18 +3,18 @@ var edx = edx || {};
(function($, _, Backbone, gettext) { (function($, _, Backbone, gettext) {
'use strict'; 'use strict';
edx.pocs = edx.pocs || {}; edx.ccx = edx.ccx || {};
edx.pocs.schedule = edx.pocs.schedule || {}; edx.ccx.schedule = edx.ccx.schedule || {};
var syncErrorMessage = gettext("The data could not be saved."); var syncErrorMessage = gettext("The data could not be saved.");
var self; var self;
edx.pocs.schedule.reloadPage = function() { edx.ccx.schedule.reloadPage = function() {
location.reload(); location.reload();
}; };
edx.pocs.schedule.UnitModel = Backbone.Model.extend({ edx.ccx.schedule.UnitModel = Backbone.Model.extend({
defaults: { defaults: {
location: '', location: '',
display_name: '', display_name: '',
...@@ -27,18 +27,18 @@ var edx = edx || {}; ...@@ -27,18 +27,18 @@ var edx = edx || {};
}); });
edx.pocs.schedule.Schedule = Backbone.Collection.extend({ edx.ccx.schedule.Schedule = Backbone.Collection.extend({
model: edx.pocs.schedule.UnitModel, model: edx.ccx.schedule.UnitModel,
url: 'poc_schedule' url: 'ccx_schedule'
}); });
edx.pocs.schedule.ScheduleView = Backbone.View.extend({ edx.ccx.schedule.ScheduleView = Backbone.View.extend({
initialize: function() { initialize: function() {
_.bindAll(this, 'render'); _.bindAll(this, 'render');
this.schedule_collection = new edx.pocs.schedule.Schedule(); this.schedule_collection = new edx.ccx.schedule.Schedule();
this.schedule = {}; this.schedule = {};
this.schedule_collection.bind('reset', this.render); this.schedule_collection.bind('reset', this.render);
this.schedule_collection.fetch({reset: true}); this.schedule_collection.fetch({reset: true});
...@@ -63,23 +63,23 @@ var edx = edx || {}; ...@@ -63,23 +63,23 @@ var edx = edx || {};
this.showing = this.pruned(self.schedule, function(node) { this.showing = this.pruned(self.schedule, function(node) {
return !node.hidden}); return !node.hidden});
this.$el.html(schedule_template({chapters: this.showing})); this.$el.html(schedule_template({chapters: this.showing}));
$('table.poc-schedule .sequential,.vertical').hide(); $('table.ccx-schedule .sequential,.vertical').hide();
$('table.poc-schedule .toggle-collapse').on('click', this.toggle_collapse); $('table.ccx-schedule .toggle-collapse').on('click', this.toggle_collapse);
// //
// Hidden hover fields for empty date fields // Hidden hover fields for empty date fields
$('table.poc-schedule .date a').each(function() { $('table.ccx-schedule .date a').each(function() {
if (! $(this).text()) { if (! $(this).text()) {
$(this).text('Set date').addClass('empty'); $(this).text('Set date').addClass('empty');
} }
}); });
// Handle date edit clicks // Handle date edit clicks
$('table.poc-schedule .date a').attr('href', '#enter-date-modal') $('table.ccx-schedule .date a').attr('href', '#enter-date-modal')
.leanModal({closeButton: '.close-modal'}); .leanModal({closeButton: '.close-modal'});
$('table.poc-schedule .due-date a').on('click', this.enterNewDate('due')); $('table.ccx-schedule .due-date a').on('click', this.enterNewDate('due'));
$('table.poc-schedule .start-date a').on('click', this.enterNewDate('start')); $('table.ccx-schedule .start-date a').on('click', this.enterNewDate('start'));
// Click handler for remove all // Click handler for remove all
$('table.poc-schedule a#remove-all').on('click', function(event) { $('table.ccx-schedule a#remove-all').on('click', function(event) {
event.preventDefault(); event.preventDefault();
self.schedule_apply(self.schedule, self.hide); self.schedule_apply(self.schedule, self.hide);
self.dirty = true; self.dirty = true;
...@@ -175,7 +175,7 @@ var edx = edx || {}; ...@@ -175,7 +175,7 @@ var edx = edx || {};
}); });
// Remove unit handler // Remove unit handler
$('table.poc-schedule a.remove-unit').on('click', function(event) { $('table.ccx-schedule a.remove-unit').on('click', function(event) {
var row = $(this).closest('tr'), var row = $(this).closest('tr'),
path = row.data('location').split(' '), path = row.data('location').split(' '),
unit = self.find_unit(self.schedule, path[0], path[1], path[2]); unit = self.find_unit(self.schedule, path[0], path[1], path[2]);
......
...@@ -77,8 +77,8 @@ ...@@ -77,8 +77,8 @@
@import "course/instructor/email"; @import "course/instructor/email";
@import "xmodule/descriptors/css/module-styles.scss"; @import "xmodule/descriptors/css/module-styles.scss";
// course - poc_coach // course - ccx_coach
@import "course/poc_coach/dashboard"; @import "course/ccx_coach/dashboard";
// discussion // discussion
@import "course/discussion/form-wmd-toolbar"; @import "course/discussion/form-wmd-toolbar";
.poc-schedule-container { .ccx-schedule-container {
float: left; float: left;
width: 750px; width: 750px;
} }
table.poc-schedule { table.ccx-schedule {
width: 100%; width: 100%;
thead { thead {
...@@ -34,19 +34,19 @@ table.poc-schedule { ...@@ -34,19 +34,19 @@ table.poc-schedule {
} }
} }
.poc-schedule-sidebar { .ccx-schedule-sidebar {
float: left; float: left;
width: 295px; width: 295px;
margin-left: 20px; margin-left: 20px;
} }
.poc-sidebar-panel { .ccx-sidebar-panel {
border: 1px solid #cbcbcb; border: 1px solid #cbcbcb;
padding: 15px; padding: 15px;
margin-bottom: 20px; margin-bottom: 20px;
} }
form.poc-form { form.ccx-form {
line-height: 1.5; line-height: 1.5;
select { select {
width: 100%; width: 100%;
......
<%page args="poc, membership, course" /> <%page args="ccx, membership, course" />
<%! from django.utils.translation import ugettext as _ %> <%! from django.utils.translation import ugettext as _ %>
<%! <%!
...@@ -6,24 +6,24 @@ ...@@ -6,24 +6,24 @@
from courseware.courses import course_image_url, get_course_about_section from courseware.courses import course_image_url, get_course_about_section
%> %>
<% <%
poc_switch_target = reverse('switch_active_poc', args=[course.id.to_deprecated_string(), poc.id]) ccx_switch_target = reverse('switch_active_ccx', args=[course.id.to_deprecated_string(), ccx.id])
%> %>
<li class="course-item"> <li class="course-item">
<article class="course"> <article class="course">
<a href="${poc_switch_target}" class="cover"> <a href="${ccx_switch_target}" class="cover">
<img src="${course_image_url(course)}" alt="${_('{course_number} {poc_name} Cover Image').format(course_number=course.number, poc_name=poc.display_name) |h}" /> <img src="${course_image_url(course)}" alt="${_('{course_number} {ccx_name} Cover Image').format(course_number=course.number, ccx_name=ccx.display_name) |h}" />
</a> </a>
<section class="info"> <section class="info">
<hgroup> <hgroup>
<p class="date-block"> <p class="date-block">
Personal Online Course Custom Course
</p> </p>
<h2 class="university">${get_course_about_section(course, 'university')}</h2> <h2 class="university">${get_course_about_section(course, 'university')}</h2>
<h3> <h3>
<a href="${poc_switch_target}">${course.display_number_with_default | h} ${poc.display_name}</a> <a href="${ccx_switch_target}">${course.display_number_with_default | h} ${ccx.display_name}</a>
</h3> </h3>
</hgroup> </hgroup>
<a href="${poc_switch_target}" class="enter-course">${_('View Course')}</a> <a href="${ccx_switch_target}" class="enter-course">${_('View Course')}</a>
</section> </section>
</article> </article>
</li> </li>
...@@ -4,8 +4,8 @@ ...@@ -4,8 +4,8 @@
<%inherit file="/main.html" /> <%inherit file="/main.html" />
<%namespace name='static' file='/static_content.html'/> <%namespace name='static' file='/static_content.html'/>
<%block name="pagetitle">${_("POC Coach Dashboard")}</%block> <%block name="pagetitle">${_("CCX Coach Dashboard")}</%block>
<%block name="nav_skip">#poc-coach-dashboard-content</%block> <%block name="nav_skip">#ccx-coach-dashboard-content</%block>
<%block name="headextra"> <%block name="headextra">
<%static:css group='style-course-vendor'/> <%static:css group='style-course-vendor'/>
...@@ -14,24 +14,24 @@ ...@@ -14,24 +14,24 @@
<%static:css group='style-course'/> <%static:css group='style-course'/>
</%block> </%block>
<%include file="/courseware/course_navigation.html" args="active_page='poc_coach'" /> <%include file="/courseware/course_navigation.html" args="active_page='ccx_coach'" />
<section class="container"> <section class="container">
<div class="instructor-dashboard-wrapper-2"> <div class="instructor-dashboard-wrapper-2">
<section class="instructor-dashboard-content-2" id="poc-coach-dashboard-content"> <section class="instructor-dashboard-content-2" id="ccx-coach-dashboard-content">
<h1>${_("POC Coach Dashboard")}</h1> <h1>${_("CCX Coach Dashboard")}</h1>
%if not poc: %if not ccx:
<section> <section>
<form action="${create_poc_url}" method="POST"> <form action="${create_ccx_url}" method="POST">
<input type="hidden" name="csrfmiddlewaretoken" value="${csrf_token}"/> <input type="hidden" name="csrfmiddlewaretoken" value="${csrf_token}"/>
<input name="name" placeholder="Name your POC"/><br/> <input name="name" placeholder="Name your CCX"/><br/>
<button id="create-poc">Coach a new Personal Online Course</button> <button id="create-ccx">Coach a new Custom Course for EdX</button>
</form> </form>
</section> </section>
%endif %endif
%if poc: %if ccx:
<ul class="instructor-nav"> <ul class="instructor-nav">
<li class="nav-item"> <li class="nav-item">
<a href="#" data-section="membership">${_("Enrollment")}</a> <a href="#" data-section="membership">${_("Enrollment")}</a>
......
<%! from django.utils.translation import ugettext as _ %> <%! from django.utils.translation import ugettext as _ %>
<div class="batch-enrollment" style="float:left;width:50%"> <div class="batch-enrollment" style="float:left;width:50%">
<form method="POST" action="poc_invite"> <form method="POST" action="ccx_invite">
<input type="hidden" name="csrfmiddlewaretoken" value="${ csrf_token }"> <input type="hidden" name="csrfmiddlewaretoken" value="${ csrf_token }">
<h2> ${_("Batch Enrollment")} </h2> <h2> ${_("Batch Enrollment")} </h2>
<p> <p>
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
</div> </div>
<div class="member-lists-management" style="float:left;width:50%"> <div class="member-lists-management" style="float:left;width:50%">
<form method="POST" action="poc_manage_student"> <form method="POST" action="ccx_manage_student">
<input type="hidden" name="csrfmiddlewaretoken" value="${ csrf_token }"> <input type="hidden" name="csrfmiddlewaretoken" value="${ csrf_token }">
<div class="auth-list-container active"> <div class="auth-list-container active">
<div class="member-list-widget"> <div class="member-list-widget">
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
%for member in poc_members: %for member in ccx_members:
<tr> <tr>
<td>${member.student}</td> <td>${member.student}</td>
<td>${member.student.email}</td> <td>${member.student.email}</td>
......
...@@ -15,18 +15,18 @@ ...@@ -15,18 +15,18 @@
.ui-datepicker { z-index: 100000 !important; } .ui-datepicker { z-index: 100000 !important; }
input.date, input.time { width: auto !important; display: inline !important; } input.date, input.time { width: auto !important; display: inline !important; }
</style> </style>
<%static:js group='pocs'/> <%static:js group='ccx'/>
</%block> </%block>
%for template_name in ["schedule"]: %for template_name in ["schedule"]:
<script type="text/template" id="poc-${template_name}-template"> <script type="text/template" id="ccx-${template_name}-template">
<%static:include path="pocs/${template_name}.underscore" /> <%static:include path="ccx/${template_name}.underscore" />
</script> </script>
%endfor %endfor
<div class="poc-schedule-container"> <div class="ccx-schedule-container">
<div id="poc-schedule"></div> <div id="ccx-schedule"></div>
<div id="new-poc-schedule"></div> <div id="new-ccx-schedule"></div>
</div> </div>
<section id="enter-date-modal" class="modal" aria-hidden="true"> <section id="enter-date-modal" class="modal" aria-hidden="true">
...@@ -53,8 +53,8 @@ ...@@ -53,8 +53,8 @@
</div> </div>
</section> </section>
<div class="poc-schedule-sidebar"> <div class="ccx-schedule-sidebar">
<div class="poc-sidebar-panel" id="dirty-schedule"> <div class="ccx-sidebar-panel" id="dirty-schedule">
<h2>${_('Save changes')}</h2> <h2>${_('Save changes')}</h2>
<form role="form"> <form role="form">
<p>${_("You have unsaved changes.")}</p> <p>${_("You have unsaved changes.")}</p>
...@@ -64,13 +64,13 @@ ...@@ -64,13 +64,13 @@
</div> </div>
</form> </form>
</div> </div>
<div class="poc-sidebar-panel" id="ajax-error"> <div class="ccx-sidebar-panel" id="ajax-error">
<h2>${_('Error')}</h2> <h2>${_('Error')}</h2>
<p>${_("There was an error saving changes.")}</p> <p>${_("There was an error saving changes.")}</p>
</div> </div>
<div class="poc-sidebar-panel"> <div class="ccx-sidebar-panel">
<h2>${_('Schedule a Unit')}</h2> <h2>${_('Schedule a Unit')}</h2>
<form role="form" id="add-unit" name="add-unit" class="poc-form"> <form role="form" id="add-unit" name="add-unit" class="ccx-form">
<div class="field"> <div class="field">
<b>${_('Section')}</b><br/> <b>${_('Section')}</b><br/>
<select name="chapter"></select> <select name="chapter"></select>
...@@ -110,12 +110,12 @@ ...@@ -110,12 +110,12 @@
<script> <script>
$(function() { $(function() {
schedule_template = _.template($('#poc-schedule-template').html()); schedule_template = _.template($('#ccx-schedule-template').html());
var view = new edx.pocs.schedule.ScheduleView({ var view = new edx.ccx.schedule.ScheduleView({
el: $('#new-poc-schedule') el: $('#new-ccx-schedule')
}); });
view.render(); view.render();
//poc_schedule.render(); //ccx_schedule.render();
$('.datepair .time').timepicker({ $('.datepair .time').timepicker({
'showDuration': true, 'showDuration': true,
'timeFormat': 'G:i' 'timeFormat': 'G:i'
......
<table class="poc-schedule"> <table class="ccx-schedule">
<thead> <thead>
<tr> <tr>
<th><%- gettext('Unit') %></th> <th><%- gettext('Unit') %></th>
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
<% _.each(chapters, function(chapter) { %> <% _.each(chapters, function(chapter) { %>
<tr class="chapter collapsed" data-location="<%= chapter.location %>" data-depth="1"> <tr class="chapter collapsed" data-location="<%= chapter.location %>" data-depth="1">
<td class="unit"> <td class="unit">
<a href="#"><i class="icon-caret-right icon toggle-collapse"></i></a> <a href="#"><i class="icon-caret-right icon toggle-collapse"></i></a>
<%= chapter.display_name %> <%= chapter.display_name %>
</td> </td>
<td class="date start-date"><a><%= chapter.start %></a></td> <td class="date start-date"><a><%= chapter.start %></a></td>
...@@ -23,10 +23,10 @@ ...@@ -23,10 +23,10 @@
</a></td> </a></td>
</tr> </tr>
<% _.each(chapter.children, function(child) { %> <% _.each(chapter.children, function(child) { %>
<tr class="sequential collapsed" data-depth="2" <tr class="sequential collapsed" data-depth="2"
data-location="<%= chapter.location %> <%= child.location %>"> data-location="<%= chapter.location %> <%= child.location %>">
<td class="unit"> <td class="unit">
<a href="#"><i class="icon-caret-right icon toggle-collapse"></i></a> <a href="#"><i class="icon-caret-right icon toggle-collapse"></i></a>
<%= child.display_name %> <%= child.display_name %>
</td> </td>
<td class="date start-date"><a><%= child.start %></a></td> <td class="date start-date"><a><%= child.start %></a></td>
......
...@@ -243,9 +243,9 @@ ...@@ -243,9 +243,9 @@
<%include file='dashboard/_dashboard_course_listing.html' args="course=course, enrollment=enrollment, show_courseware_link=show_courseware_link, cert_status=cert_status, show_email_settings=show_email_settings, course_mode_info=course_mode_info, show_refund_option = show_refund_option, is_paid_course = is_paid_course, is_course_blocked = is_course_blocked, verification_status=course_verification_status, course_requirements=course_requirements" /> <%include file='dashboard/_dashboard_course_listing.html' args="course=course, enrollment=enrollment, show_courseware_link=show_courseware_link, cert_status=cert_status, show_email_settings=show_email_settings, course_mode_info=course_mode_info, show_refund_option = show_refund_option, is_paid_course = is_paid_course, is_course_blocked = is_course_blocked, verification_status=course_verification_status, course_requirements=course_requirements" />
% endfor % endfor
% if settings.FEATURES.get('PERSONAL_ONLINE_COURSES', False): % if settings.FEATURES.get('CUSTOM_COURSES_EDX', False):
% for poc, membership, course in poc_membership_triplets: % for ccx, membership, course in ccx_membership_triplets:
<%include file='pocs/_dashboard_poc_listing.html' args="poc=poc, membership=membership, course=course" /> <%include file='ccx/_dashboard_ccx_listing.html' args="ccx=ccx, membership=membership, course=course" />
% endfor % endfor
% endif % endif
......
...@@ -244,17 +244,17 @@ ...@@ -244,17 +244,17 @@
></div> ></div>
%endif %endif
%if section_data['access']['instructor'] and settings.FEATURES.get('PERSONAL_ONLINE_COURSES', False): %if section_data['access']['instructor'] and settings.FEATURES.get('CUSTOM_COURSES_EDX', False):
<div class="auth-list-container" <div class="auth-list-container"
data-rolename="poc_coach" data-rolename="ccx_coach"
data-display-name="${_("POC Coaches")}" data-display-name="${_("CCX Coaches")}"
data-info-text=" data-info-text="
${_("POC Coaches are able to create their own Personal Online Courses " ${_("CCX Coaches are able to create their own Custom Courses "
"based on this course, which they can use to provide personalized " "based on this course, which they can use to provide personalized "
"instruction to their own students based in this course material.")}" "instruction to their own students based in this course material.")}"
data-list-endpoint="${section_data['list_course_role_members_url']}" data-list-endpoint="${section_data['list_course_role_members_url']}"
data-modify-endpoint="${section_data['modify_access_url']}" data-modify-endpoint="${section_data['modify_access_url']}"
data-add-button-label="${_("Add POC Coach")}" data-add-button-label="${_("Add CCX Coach")}"
></div> ></div>
%endif %endif
</div> </div>
...@@ -13,7 +13,7 @@ from status.status import get_site_status_msg ...@@ -13,7 +13,7 @@ from status.status import get_site_status_msg
<%! from microsite_configuration import microsite %> <%! from microsite_configuration import microsite %>
<%! from microsite_configuration.templatetags.microsite import platform_name %> <%! from microsite_configuration.templatetags.microsite import platform_name %>
<%! from pocs.overrides import get_current_poc %> <%! from ccx.overrides import get_current_ccx %>
## Provide a hook for themes to inject branding on top. ## Provide a hook for themes to inject branding on top.
<%block name="navigation_top" /> <%block name="navigation_top" />
...@@ -52,10 +52,10 @@ site_status_msg = get_site_status_msg(course_id) ...@@ -52,10 +52,10 @@ site_status_msg = get_site_status_msg(course_id)
${course.display_number_with_default | h} ${course.display_number_with_default | h}
<% <%
display_name = course.display_name_with_default display_name = course.display_name_with_default
if settings.FEATURES.get('PERSONAL_ONLINE_COURSES', False): if settings.FEATURES.get('CUSTOM_COURSES_EDX', False):
poc = get_current_poc() ccx = get_current_ccx()
if poc: if ccx:
display_name = poc.display_name display_name = ccx.display_name
%> %>
${display_name}</h2> ${display_name}</h2>
% endif % endif
......
...@@ -343,26 +343,26 @@ if settings.COURSEWARE_ENABLED: ...@@ -343,26 +343,26 @@ if settings.COURSEWARE_ENABLED:
# For the instructor # For the instructor
url(r'^courses/{}/instructor$'.format(settings.COURSE_ID_PATTERN), url(r'^courses/{}/instructor$'.format(settings.COURSE_ID_PATTERN),
'instructor.views.instructor_dashboard.instructor_dashboard_2', name="instructor_dashboard"), 'instructor.views.instructor_dashboard.instructor_dashboard_2', name="instructor_dashboard"),
url(r'^courses/{}/poc_coach$'.format(settings.COURSE_ID_PATTERN), url(r'^courses/{}/ccx_coach$'.format(settings.COURSE_ID_PATTERN),
'pocs.views.dashboard', name='poc_coach_dashboard'), 'ccx.views.dashboard', name='ccx_coach_dashboard'),
url(r'^courses/{}/create_poc$'.format(settings.COURSE_ID_PATTERN), url(r'^courses/{}/create_ccx$'.format(settings.COURSE_ID_PATTERN),
'pocs.views.create_poc', name='create_poc'), 'ccx.views.create_ccx', name='create_ccx'),
url(r'^courses/{}/save_poc$'.format(settings.COURSE_ID_PATTERN), url(r'^courses/{}/save_ccx$'.format(settings.COURSE_ID_PATTERN),
'pocs.views.save_poc', name='save_poc'), 'ccx.views.save_ccx', name='save_ccx'),
url(r'^courses/{}/poc_invite$'.format(settings.COURSE_ID_PATTERN), url(r'^courses/{}/ccx_invite$'.format(settings.COURSE_ID_PATTERN),
'pocs.views.poc_invite', name='poc_invite'), 'ccx.views.ccx_invite', name='ccx_invite'),
url(r'^courses/{}/poc_schedule$'.format(settings.COURSE_ID_PATTERN), url(r'^courses/{}/ccx_schedule$'.format(settings.COURSE_ID_PATTERN),
'pocs.views.poc_schedule', name='poc_schedule'), 'ccx.views.ccx_schedule', name='ccx_schedule'),
url(r'^courses/{}/poc_manage_student$'.format(settings.COURSE_ID_PATTERN), url(r'^courses/{}/ccx_manage_student$'.format(settings.COURSE_ID_PATTERN),
'pocs.views.poc_student_management', name='poc_manage_student'), 'ccx.views.ccx_student_management', name='ccx_manage_student'),
url(r'^courses/{}/poc_gradebook$'.format(settings.COURSE_ID_PATTERN), url(r'^courses/{}/ccx_gradebook$'.format(settings.COURSE_ID_PATTERN),
'pocs.views.poc_gradebook', name='poc_gradebook'), 'ccx.views.ccx_gradebook', name='ccx_gradebook'),
url(r'^courses/{}/poc_grades.csv$'.format(settings.COURSE_ID_PATTERN), url(r'^courses/{}/ccx_grades.csv$'.format(settings.COURSE_ID_PATTERN),
'pocs.views.poc_grades_csv', name='poc_grades_csv'), 'ccx.views.ccx_grades_csv', name='ccx_grades_csv'),
url(r'^courses/{}/poc_set_grading_policy$'.format(settings.COURSE_ID_PATTERN), url(r'^courses/{}/ccx_set_grading_policy$'.format(settings.COURSE_ID_PATTERN),
'pocs.views.set_grading_policy', name='poc_set_grading_policy'), 'ccx.views.set_grading_policy', name='ccx_set_grading_policy'),
url(r'^courses/{}/swich_poc(?:/(?P<poc_id>[\d]+))?$'.format(settings.COURSE_ID_PATTERN), url(r'^courses/{}/switch_ccx(?:/(?P<ccx_id>[\d]+))?$'.format(settings.COURSE_ID_PATTERN),
'pocs.views.swich_active_poc', name='switch_active_poc'), 'ccx.views.switch_active_ccx', name='switch_active_ccx'),
url(r'^courses/{}/set_course_mode_price$'.format(settings.COURSE_ID_PATTERN), url(r'^courses/{}/set_course_mode_price$'.format(settings.COURSE_ID_PATTERN),
'instructor.views.instructor_dashboard.set_course_mode_price', name="set_course_mode_price"), 'instructor.views.instructor_dashboard.set_course_mode_price', name="set_course_mode_price"),
url(r'^courses/{}/instructor/api/'.format(settings.COURSE_ID_PATTERN), url(r'^courses/{}/instructor/api/'.format(settings.COURSE_ID_PATTERN),
......
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