diff --git a/.gitignore b/.gitignore index 69d98d7db8d56de01a8556131bad2b563df4bd8b..b166d2719fc708eb8787fe2fcf43c6f011a84a3c 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,8 @@ jscover.log jscover.log.* .tddium* common/test/data/test_unicode/static/ +django-pyfs +test_root/uploads/*.txt ### Installation artifacts *.egg-info diff --git a/cms/djangoapps/contentstore/tests/test_course_settings.py b/cms/djangoapps/contentstore/tests/test_course_settings.py index 584a4820c086bb8a6740e173689470c6bbc1af6a..c041f72f5b9af474ae229d6fe82d7640980f7eb2 100644 --- a/cms/djangoapps/contentstore/tests/test_course_settings.py +++ b/cms/djangoapps/contentstore/tests/test_course_settings.py @@ -139,6 +139,100 @@ class CourseDetailsTestCase(CourseTestCase): self.assertNotContains(response, "Course Introduction Video") self.assertNotContains(response, "Requirements") + def _seed_milestone_relationship_types(self): + """ + Helper method to prepopulate MRTs so the tests can run + Note the settings check -- exams feature must be enabled for the tests to run correctly + """ + if settings.FEATURES.get('ENTRANCE_EXAMS', False): + from milestones.models import MilestoneRelationshipType + MilestoneRelationshipType.objects.create(name='requires') + MilestoneRelationshipType.objects.create(name='fulfills') + + @patch.dict(settings.FEATURES, {'ENTRANCE_EXAMS': True}) + def test_entrance_exam_created_and_deleted_successfully(self): + self._seed_milestone_relationship_types() + settings_details_url = get_url(self.course.id) + data = { + 'entrance_exam_enabled': 'true', + 'entrance_exam_minimum_score_pct': '60', + 'syllabus': 'none', + 'short_description': 'empty', + 'overview': '', + 'effort': '', + 'intro_video': '' + } + response = self.client.post(settings_details_url, data=json.dumps(data), content_type='application/json', + HTTP_ACCEPT='application/json') + self.assertEquals(response.status_code, 200) + course = modulestore().get_course(self.course.id) + self.assertTrue(course.entrance_exam_enabled) + self.assertEquals(course.entrance_exam_minimum_score_pct, .60) + + # Delete the entrance exam + data['entrance_exam_enabled'] = "false" + response = self.client.post( + settings_details_url, + data=json.dumps(data), + content_type='application/json', + HTTP_ACCEPT='application/json' + ) + course = modulestore().get_course(self.course.id) + self.assertEquals(response.status_code, 200) + self.assertFalse(course.entrance_exam_enabled) + self.assertEquals(course.entrance_exam_minimum_score_pct, None) + + @patch.dict(settings.FEATURES, {'ENTRANCE_EXAMS': True}) + def test_entrance_exam_store_default_min_score(self): + """ + test that creating an entrance exam should store the default value, if key missing in json request + or entrance_exam_minimum_score_pct is an empty string + """ + self._seed_milestone_relationship_types() + settings_details_url = get_url(self.course.id) + test_data_1 = { + 'entrance_exam_enabled': 'true', + 'syllabus': 'none', + 'short_description': 'empty', + 'overview': '', + 'effort': '', + 'intro_video': '' + } + response = self.client.post( + settings_details_url, + data=json.dumps(test_data_1), + content_type='application/json', + HTTP_ACCEPT='application/json' + ) + self.assertEquals(response.status_code, 200) + course = modulestore().get_course(self.course.id) + self.assertTrue(course.entrance_exam_enabled) + + # entrance_exam_minimum_score_pct is not present in the request so default value should be saved. + self.assertEquals(course.entrance_exam_minimum_score_pct, .5) + + #add entrance_exam_minimum_score_pct with empty value in json request. + test_data_2 = { + 'entrance_exam_enabled': 'true', + 'entrance_exam_minimum_score_pct': '', + 'syllabus': 'none', + 'short_description': 'empty', + 'overview': '', + 'effort': '', + 'intro_video': '' + } + + response = self.client.post( + settings_details_url, + data=json.dumps(test_data_2), + content_type='application/json', + HTTP_ACCEPT='application/json' + ) + self.assertEquals(response.status_code, 200) + course = modulestore().get_course(self.course.id) + self.assertTrue(course.entrance_exam_enabled) + self.assertEquals(course.entrance_exam_minimum_score_pct, .5) + def test_editable_short_description_fetch(self): settings_details_url = get_url(self.course.id) diff --git a/cms/djangoapps/contentstore/views/__init__.py b/cms/djangoapps/contentstore/views/__init__.py index 9cceccd6e64f27e19c42162e7b1e23e4d3087f9a..2f582ef49808aab5604e553bc7100028ccfaac9c 100644 --- a/cms/djangoapps/contentstore/views/__init__.py +++ b/cms/djangoapps/contentstore/views/__init__.py @@ -8,6 +8,7 @@ from .assets import * from .checklist import * from .component import * from .course import * +from .entrance_exam import * from .error import * from .helpers import * from .item import * diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py index e13f1f1a8708900d0b1635057bd3f5855d4ac4cb..ecf18c2f64ca659827894476a9988ba2f71d8cb9 100644 --- a/cms/djangoapps/contentstore/views/course.py +++ b/cms/djangoapps/contentstore/views/course.py @@ -60,6 +60,8 @@ from .component import ( ADVANCED_COMPONENT_TYPES, ) from contentstore.tasks import rerun_course +from contentstore.views.entrance_exam import create_entrance_exam, delete_entrance_exam + from .library import LIBRARIES_ENABLED from .item import create_xblock_info from course_creators.views import get_course_creator_status, add_user_with_status_unrequested @@ -824,7 +826,8 @@ def settings_handler(request, course_key_string): 'details_url': reverse_course_url('settings_handler', course_key), 'about_page_editable': about_page_editable, 'short_description_editable': short_description_editable, - 'upload_asset_url': upload_asset_url + 'upload_asset_url': upload_asset_url, + 'course_handler_url': reverse_course_url('course_handler', course_key), } if prerequisite_course_enabled: courses, in_process_course_actions = get_courses_accessible_to_user(request) @@ -843,13 +846,40 @@ def settings_handler(request, course_key_string): # encoder serializes dates, old locations, and instances encoder=CourseSettingsEncoder ) - else: # post or put, doesn't matter. + # For every other possible method type submitted by the caller... + else: # if pre-requisite course feature is enabled set pre-requisite course if prerequisite_course_enabled: prerequisite_course_keys = request.json.get('pre_requisite_courses', []) if not all(is_valid_course_key(course_key) for course_key in prerequisite_course_keys): return JsonResponseBadRequest({"error": _("Invalid prerequisite course key")}) set_prerequisite_courses(course_key, prerequisite_course_keys) + + # If the entrance exams feature has been enabled, we'll need to check for some + # feature-specific settings and handle them accordingly + # We have to be careful that we're only executing the following logic if we actually + # need to create or delete an entrance exam from the specified course + if settings.FEATURES.get('ENTRANCE_EXAMS', False): + course_entrance_exam_present = course_module.entrance_exam_enabled + entrance_exam_enabled = request.json.get('entrance_exam_enabled', '') == 'true' + ee_min_score_pct = request.json.get('entrance_exam_minimum_score_pct', None) + + # If the entrance exam box on the settings screen has been checked, + # and the course does not already have an entrance exam attached... + if entrance_exam_enabled and not course_entrance_exam_present: + # Load the default minimum score threshold from settings, then try to override it + entrance_exam_minimum_score_pct = float(settings.ENTRANCE_EXAM_MIN_SCORE_PCT) + if ee_min_score_pct and ee_min_score_pct != '': + entrance_exam_minimum_score_pct = float(ee_min_score_pct) + # Create the entrance exam + create_entrance_exam(request, course_key, entrance_exam_minimum_score_pct) + + # If the entrance exam box on the settings screen has been unchecked, + # and the course has an entrance exam attached... + elif not entrance_exam_enabled and course_entrance_exam_present: + delete_entrance_exam(request, course_key) + + # Perform the normal update workflow for the CourseDetails model return JsonResponse( CourseDetails.update_from_json(course_key, request.json, request.user), encoder=CourseSettingsEncoder diff --git a/cms/djangoapps/contentstore/views/entrance_exam.py b/cms/djangoapps/contentstore/views/entrance_exam.py new file mode 100644 index 0000000000000000000000000000000000000000..caa94a2cc41eb68338f03383ac84d41c0d976e3d --- /dev/null +++ b/cms/djangoapps/contentstore/views/entrance_exam.py @@ -0,0 +1,224 @@ +""" +Entrance Exams view module -- handles all requests related to entrance exam management via Studio +Intended to be utilized as an AJAX callback handler, versus a proper view/screen +""" +import json +import logging + +from django.contrib.auth.decorators import login_required +from django_future.csrf import ensure_csrf_cookie +from django.http import HttpResponse +from django.test import RequestFactory + +from contentstore.views.item import create_item, delete_item +from milestones import api as milestones_api +from models.settings.course_metadata import CourseMetadata +from opaque_keys.edx.keys import CourseKey, UsageKey +from opaque_keys import InvalidKeyError +from student.auth import has_course_author_access +from util.milestones_helpers import generate_milestone_namespace, NAMESPACE_CHOICES +from xmodule.modulestore.django import modulestore +from xmodule.modulestore.exceptions import ItemNotFoundError +from django.conf import settings + +__all__ = ['entrance_exam', ] + +log = logging.getLogger(__name__) + + +@login_required +@ensure_csrf_cookie +def entrance_exam(request, course_key_string): + """ + The restful handler for entrance exams. + It allows retrieval of all the assets (as an HTML page), as well as uploading new assets, + deleting assets, and changing the "locked" state of an asset. + + GET + Retrieves the entrance exam module (metadata) for the specified course + POST + Adds an entrance exam module to the specified course. + DELETE + Removes the entrance exam from the course + """ + course_key = CourseKey.from_string(course_key_string) + + # Deny access if the user is valid, but they lack the proper object access privileges + if not has_course_author_access(request.user, course_key): + return HttpResponse(status=403) + + # Retrieve the entrance exam module for the specified course (returns 404 if none found) + if request.method == 'GET': + return _get_entrance_exam(request, course_key) + + # Create a new entrance exam for the specified course (returns 201 if created) + elif request.method == 'POST': + response_format = request.REQUEST.get('format', 'html') + http_accept = request.META.get('http_accept') + if response_format == 'json' or 'application/json' in http_accept: + ee_min_score = request.POST.get('entrance_exam_minimum_score_pct', None) + + # if request contains empty value or none then save the default one. + entrance_exam_minimum_score_pct = float(settings.ENTRANCE_EXAM_MIN_SCORE_PCT) + if ee_min_score != '' and ee_min_score is not None: + entrance_exam_minimum_score_pct = float(ee_min_score) + return create_entrance_exam(request, course_key, entrance_exam_minimum_score_pct) + return HttpResponse(status=400) + + # Remove the entrance exam module for the specified course (returns 204 regardless of existence) + elif request.method == 'DELETE': + return delete_entrance_exam(request, course_key) + + # No other HTTP verbs/methods are supported at this time + else: + return HttpResponse(status=405) + + +def create_entrance_exam(request, course_key, entrance_exam_minimum_score_pct): + """ + api method to create an entrance exam. + First clean out any old entrance exams. + """ + _delete_entrance_exam(request, course_key) + return _create_entrance_exam( + request=request, + course_key=course_key, + entrance_exam_minimum_score_pct=entrance_exam_minimum_score_pct + ) + + +def _create_entrance_exam(request, course_key, entrance_exam_minimum_score_pct=None): + """ + Internal workflow operation to create an entrance exam + """ + # Provide a default value for the minimum score percent if nothing specified + if entrance_exam_minimum_score_pct is None: + entrance_exam_minimum_score_pct = float(settings.ENTRANCE_EXAM_MIN_SCORE_PCT) + + # Confirm the course exists + course = modulestore().get_course(course_key) + if course is None: + return HttpResponse(status=400) + + # Create the entrance exam item (currently it's just a chapter) + payload = { + 'category': "chapter", + 'display_name': "Entrance Exam", + 'parent_locator': unicode(course.location), + 'is_entrance_exam': True, + 'in_entrance_exam': True, + } + factory = RequestFactory() + internal_request = factory.post('/', json.dumps(payload), content_type="application/json") + internal_request.user = request.user + created_item = json.loads(create_item(internal_request).content) + + # Set the entrance exam metadata flags for this course + # Reload the course so we don't overwrite the new child reference + course = modulestore().get_course(course_key) + metadata = { + 'entrance_exam_enabled': True, + 'entrance_exam_minimum_score_pct': entrance_exam_minimum_score_pct / 100, + 'entrance_exam_id': created_item['locator'], + } + CourseMetadata.update_from_dict(metadata, course, request.user) + + # Add an entrance exam milestone if one does not already exist + milestone_namespace = generate_milestone_namespace( + NAMESPACE_CHOICES['ENTRANCE_EXAM'], + course_key + ) + milestones = milestones_api.get_milestones(milestone_namespace) + if len(milestones): + milestone = milestones[0] + else: + description = 'Autogenerated during {} entrance exam creation.'.format(unicode(course.id)) + milestone = milestones_api.add_milestone({ + 'name': 'Completed Course Entrance Exam', + 'namespace': milestone_namespace, + 'description': description + }) + relationship_types = milestones_api.get_milestone_relationship_types() + milestones_api.add_course_milestone( + unicode(course.id), + relationship_types['REQUIRES'], + milestone + ) + milestones_api.add_course_content_milestone( + unicode(course.id), + created_item['locator'], + relationship_types['FULFILLS'], + milestone + ) + + return HttpResponse(status=201) + + +def _get_entrance_exam(request, course_key): # pylint: disable=W0613 + """ + Internal workflow operation to retrieve an entrance exam + """ + course = modulestore().get_course(course_key) + if course is None: + return HttpResponse(status=400) + if not getattr(course, 'entrance_exam_id'): + return HttpResponse(status=404) + try: + exam_key = UsageKey.from_string(course.entrance_exam_id) + except InvalidKeyError: + return HttpResponse(status=404) + try: + exam_descriptor = modulestore().get_item(exam_key) + return HttpResponse( + _serialize_entrance_exam(exam_descriptor), + status=200, mimetype='application/json') + except ItemNotFoundError: + return HttpResponse(status=404) + + +def delete_entrance_exam(request, course_key): + """ + api method to delete an entrance exam + """ + return _delete_entrance_exam(request=request, course_key=course_key) + + +def _delete_entrance_exam(request, course_key): + """ + Internal workflow operation to remove an entrance exam + """ + store = modulestore() + course = store.get_course(course_key) + if course is None: + return HttpResponse(status=400) + + course_children = store.get_items( + course_key, + qualifiers={'category': 'chapter'} + ) + for course_child in course_children: + if course_child.is_entrance_exam: + delete_item(request, course_child.scope_ids.usage_id) + milestones_api.remove_content_references(unicode(course_child.scope_ids.usage_id)) + + # Reset the entrance exam flags on the course + # Reload the course so we have the latest state + course = store.get_course(course_key) + if getattr(course, 'entrance_exam_id'): + metadata = { + 'entrance_exam_enabled': False, + 'entrance_exam_minimum_score_pct': None, + 'entrance_exam_id': None, + } + CourseMetadata.update_from_dict(metadata, course, request.user) + + return HttpResponse(status=204) + + +def _serialize_entrance_exam(entrance_exam_module): + """ + Internal helper to convert an entrance exam module/object into JSON + """ + return json.dumps({ + 'locator': unicode(entrance_exam_module.location) + }) diff --git a/cms/djangoapps/contentstore/views/item.py b/cms/djangoapps/contentstore/views/item.py index d93ac2c42e3a0aba7e72a6a4b1fbd91c1741e725..8610559f1f308420ed856aa3171d5cf41b07dad1 100644 --- a/cms/djangoapps/contentstore/views/item.py +++ b/cms/djangoapps/contentstore/views/item.py @@ -13,6 +13,7 @@ from functools import partial from static_replace import replace_static_urls from xmodule_modifiers import wrap_xblock, request_token +from django.conf import settings from django.core.exceptions import PermissionDenied from django.contrib.auth.decorators import login_required from django.http import HttpResponseBadRequest, HttpResponse, Http404 @@ -87,6 +88,17 @@ def usage_key_with_run(usage_key_string): return usage_key +def _filter_entrance_exam_grader(graders): + """ + If the entrance exams feature is enabled we need to hide away the grader from + views/controls like the 'Grade as' dropdown that allows a course author to select + the grader type for a given section of a course + """ + if settings.FEATURES.get('ENTRANCE_EXAMS', False): + graders = [grader for grader in graders if grader.get('type') != u'Entrance Exam'] + return graders + + # pylint: disable=unused-argument @require_http_methods(("DELETE", "GET", "PUT", "POST", "PATCH")) @login_required @@ -511,6 +523,15 @@ def _save_xblock(user, xblock, data=None, children_strings=None, metadata=None, return JsonResponse(result, encoder=EdxJSONEncoder) +@login_required +@expect_json +def create_item(request): + """ + Exposes internal helper method without breaking existing bindings/dependencies + """ + return _create_item(request) + + @login_required @expect_json def _create_item(request): @@ -549,6 +570,15 @@ def _create_item(request): if display_name is not None: metadata['display_name'] = display_name + # Entrance Exams: Chapter module positioning + child_position = None + if settings.FEATURES.get('ENTRANCE_EXAMS', False): + is_entrance_exam = request.json.get('is_entrance_exam', False) + if category == 'chapter' and is_entrance_exam: + metadata['is_entrance_exam'] = is_entrance_exam + metadata['in_entrance_exam'] = True # Inherited metadata, all children will have it + child_position = 0 + # TODO need to fix components that are sending definition_data as strings, instead of as dicts # For now, migrate them into dicts here. if isinstance(data, basestring): @@ -562,8 +592,32 @@ def _create_item(request): definition_data=data, metadata=metadata, runtime=parent.runtime, + position=child_position ) + # Entrance Exams: Grader assignment + if settings.FEATURES.get('ENTRANCE_EXAMS', False): + course = store.get_course(usage_key.course_key) + if hasattr(course, 'entrance_exam_enabled') and course.entrance_exam_enabled: + if category == 'sequential' and request.json.get('parent_locator') == course.entrance_exam_id: + grader = { + "type": "Entrance Exam", + "min_count": 0, + "drop_count": 0, + "short_label": "Entrance", + "weight": 0 + } + grading_model = CourseGradingModel.update_grader_from_json( + course.id, + grader, + request.user + ) + CourseGradingModel.update_section_grader_type( + created_block, + grading_model['type'], + request.user + ) + # VS[compat] cdodge: This is a hack because static_tabs also have references from the course module, so # if we add one then we need to also add it to the policy information (i.e. metadata) # we should remove this once we can break this reference from the course to static tabs @@ -643,6 +697,15 @@ def _duplicate_item(parent_usage_key, duplicate_source_usage_key, user, display_ return dest_module.location +@login_required +@expect_json +def delete_item(request, usage_key): + """ + Exposes internal helper method without breaking existing bindings/dependencies + """ + _delete_item(usage_key, request.user) + + def _delete_item(usage_key, user): """ Deletes an existing xblock with the given usage_key. @@ -781,6 +844,9 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F else: graders = [] + # Filter the graders data as needed + graders = _filter_entrance_exam_grader(graders) + # Compute the child info first so it can be included in aggregate information for the parent should_visit_children = include_child_info and (course_outline and not is_xblock_unit or not course_outline) if should_visit_children and xblock.has_children: @@ -799,6 +865,11 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F visibility_state = None published = modulestore().has_published_version(xblock) if not is_library_block else None + #instead of adding a new feature directly into xblock-info, we should add them into override_type. + override_type = {} + if getattr(xblock, "is_entrance_exam", None): + override_type['is_entrance_exam'] = xblock.is_entrance_exam + xblock_info = { "id": unicode(xblock.location), "display_name": xblock.display_name_with_default, @@ -818,6 +889,7 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F "format": xblock.format, "course_graders": json.dumps([grader.get('type') for grader in graders]), "has_changes": has_changes, + "override_type": override_type, } if data is not None: xblock_info["data"] = data diff --git a/cms/djangoapps/contentstore/views/tests/test_entrance_exam.py b/cms/djangoapps/contentstore/views/tests/test_entrance_exam.py new file mode 100644 index 0000000000000000000000000000000000000000..a2cf5c70439731424d61d93bce5c96050251a7ea --- /dev/null +++ b/cms/djangoapps/contentstore/views/tests/test_entrance_exam.py @@ -0,0 +1,252 @@ +""" +Test module for Entrance Exams AJAX callback handler workflows +""" +import json + +from django.conf import settings +from django.contrib.auth.models import User +from django.test.client import RequestFactory + +from contentstore.tests.utils import AjaxEnabledTestClient, CourseTestCase +from contentstore.utils import reverse_url +from contentstore.views.entrance_exam import create_entrance_exam +from models.settings.course_grading import CourseGradingModel +from models.settings.course_metadata import CourseMetadata +from opaque_keys.edx.keys import UsageKey +from student.tests.factories import UserFactory +from xmodule.modulestore.django import modulestore + +if settings.FEATURES.get('MILESTONES_APP', False): + from milestones import api as milestones_api + from milestones.models import MilestoneRelationshipType + from util.milestones_helpers import serialize_user + + +class EntranceExamHandlerTests(CourseTestCase): + """ + Base test class for create, save, and delete + """ + if settings.FEATURES.get('ENTRANCE_EXAMS', False): + def setUp(self): + """ + Shared scaffolding for individual test runs + """ + super(EntranceExamHandlerTests, self).setUp() + self.course_key = self.course.id + self.usage_key = self.course.location + self.course_url = '/course/{}'.format(unicode(self.course.id)) + self.exam_url = '/course/{}/entrance_exam/'.format(unicode(self.course.id)) + MilestoneRelationshipType.objects.create(name='requires', active=True) + MilestoneRelationshipType.objects.create(name='fulfills', active=True) + self.milestone_relationship_types = milestones_api.get_milestone_relationship_types() + + def test_contentstore_views_entrance_exam_post(self): + """ + Unit Test: test_contentstore_views_entrance_exam_post + """ + resp = self.client.post(self.exam_url, {}, http_accept='application/json') + self.assertEqual(resp.status_code, 201) + resp = self.client.get(self.exam_url) + self.assertEqual(resp.status_code, 200) + + # Reload the test course now that the exam module has been added + self.course = modulestore().get_course(self.course.id) + metadata = CourseMetadata.fetch_all(self.course) + self.assertTrue(metadata['entrance_exam_enabled']) + self.assertIsNotNone(metadata['entrance_exam_minimum_score_pct']) + self.assertIsNotNone(metadata['entrance_exam_id']['value']) + self.assertTrue(len(milestones_api.get_course_milestones(unicode(self.course.id)))) + content_milestones = milestones_api.get_course_content_milestones( + unicode(self.course.id), + metadata['entrance_exam_id']['value'], + self.milestone_relationship_types['FULFILLS'] + ) + self.assertTrue(len(content_milestones)) + + def test_contentstore_views_entrance_exam_post_new_sequential_confirm_grader(self): + """ + Unit Test: test_contentstore_views_entrance_exam_post + """ + resp = self.client.post(self.exam_url, {}, http_accept='application/json') + self.assertEqual(resp.status_code, 201) + resp = self.client.get(self.exam_url) + self.assertEqual(resp.status_code, 200) + + # Reload the test course now that the exam module has been added + self.course = modulestore().get_course(self.course.id) + + # Add a new child sequential to the exam module + # Confirm that the grader type is 'Entrance Exam' + chapter_locator_string = json.loads(resp.content).get('locator') + # chapter_locator = UsageKey.from_string(chapter_locator_string) + seq_data = { + 'category': "sequential", + 'display_name': "Entrance Exam Subsection", + 'parent_locator': chapter_locator_string, + } + resp = self.client.ajax_post(reverse_url('xblock_handler'), seq_data) + seq_locator_string = json.loads(resp.content).get('locator') + seq_locator = UsageKey.from_string(seq_locator_string) + section_grader_type = CourseGradingModel.get_section_grader_type(seq_locator) + self.assertEqual('Entrance Exam', section_grader_type['graderType']) + + def test_contentstore_views_entrance_exam_get(self): + """ + Unit Test: test_contentstore_views_entrance_exam_get + """ + resp = self.client.post( + self.exam_url, + {'entrance_exam_minimum_score_pct': settings.ENTRANCE_EXAM_MIN_SCORE_PCT}, + http_accept='application/json' + ) + self.assertEqual(resp.status_code, 201) + resp = self.client.get(self.exam_url) + self.assertEqual(resp.status_code, 200) + + def test_contentstore_views_entrance_exam_delete(self): + """ + Unit Test: test_contentstore_views_entrance_exam_delete + """ + resp = self.client.post(self.exam_url, {}, http_accept='application/json') + self.assertEqual(resp.status_code, 201) + resp = self.client.get(self.exam_url) + self.assertEqual(resp.status_code, 200) + resp = self.client.delete(self.exam_url) + self.assertEqual(resp.status_code, 204) + resp = self.client.get(self.exam_url) + self.assertEqual(resp.status_code, 404) + + user = User.objects.create( + username='test_user', + email='test_user@edx.org', + is_active=True, + ) + user.set_password('test') + user.save() + milestones = milestones_api.get_course_milestones(unicode(self.course_key)) + self.assertEqual(len(milestones), 1) + milestone_key = '{}.{}'.format(milestones[0]['namespace'], milestones[0]['name']) + paths = milestones_api.get_course_milestones_fulfillment_paths( + unicode(self.course_key), + serialize_user(user) + ) + + # What we have now is a course milestone requirement and no valid fulfillment + # paths for the specified user. The LMS is going to have to ignore this situation, + # because we can't confidently prevent it from occuring at some point in the future. + # milestone_key_1 = + self.assertEqual(len(paths[milestone_key]), 0) + + # Re-adding an entrance exam to the course should fix the missing link + # It wipes out any old entrance exam artifacts and inserts a new exam course chapter/module + resp = self.client.post(self.exam_url, {}, http_accept='application/json') + self.assertEqual(resp.status_code, 201) + resp = self.client.get(self.exam_url) + self.assertEqual(resp.status_code, 200) + + def test_contentstore_views_entrance_exam_delete_bogus_course(self): + """ + Unit Test: test_contentstore_views_entrance_exam_delete_bogus_course + """ + resp = self.client.delete('/course/bad/course/key/entrance_exam') + self.assertEqual(resp.status_code, 400) + + def test_contentstore_views_entrance_exam_get_bogus_course(self): + """ + Unit Test: test_contentstore_views_entrance_exam_get_bogus_course + """ + resp = self.client.get('/course/bad/course/key/entrance_exam') + self.assertEqual(resp.status_code, 400) + + def test_contentstore_views_entrance_exam_get_bogus_exam(self): + """ + Unit Test: test_contentstore_views_entrance_exam_get_bogus_exam + """ + resp = self.client.post( + self.exam_url, + {'entrance_exam_minimum_score_pct': '50'}, + http_accept='application/json' + ) + self.assertEqual(resp.status_code, 201) + resp = self.client.get(self.exam_url) + self.assertEqual(resp.status_code, 200) + self.course = modulestore().get_course(self.course.id) + + # Should raise an ItemNotFoundError and return a 404 + updated_metadata = {'entrance_exam_id': 'i4x://org.4/course_4/chapter/ed7c4c6a4d68409998e2c8554c4629d1'} + CourseMetadata.update_from_dict( + updated_metadata, + self.course, + self.user, + ) + self.course = modulestore().get_course(self.course.id) + resp = self.client.get(self.exam_url) + self.assertEqual(resp.status_code, 404) + + # Should raise an InvalidKeyError and return a 404 + updated_metadata = {'entrance_exam_id': '123afsdfsad90f87'} + CourseMetadata.update_from_dict( + updated_metadata, + self.course, + self.user, + ) + self.course = modulestore().get_course(self.course.id) + resp = self.client.get(self.exam_url) + self.assertEqual(resp.status_code, 404) + + def test_contentstore_views_entrance_exam_post_bogus_course(self): + """ + Unit Test: test_contentstore_views_entrance_exam_post_bogus_course + """ + resp = self.client.post( + '/course/bad/course/key/entrance_exam', + {}, + http_accept='application/json' + ) + self.assertEqual(resp.status_code, 400) + + def test_contentstore_views_entrance_exam_post_invalid_http_accept(self): + """ + Unit Test: test_contentstore_views_entrance_exam_post_invalid_http_accept + """ + resp = self.client.post( + '/course/bad/course/key/entrance_exam', + {}, + http_accept='text/html' + ) + self.assertEqual(resp.status_code, 400) + + def test_contentstore_views_entrance_exam_get_invalid_user(self): + """ + Unit Test: test_contentstore_views_entrance_exam_get_invalid_user + """ + user = User.objects.create( + username='test_user', + email='test_user@edx.org', + is_active=True, + ) + user.set_password('test') + user.save() + self.client = AjaxEnabledTestClient() + self.client.login(username='test_user', password='test') + resp = self.client.get(self.exam_url) + self.assertEqual(resp.status_code, 403) + + def test_contentstore_views_entrance_exam_unsupported_method(self): + """ + Unit Test: test_contentstore_views_entrance_exam_unsupported_method + """ + resp = self.client.put(self.exam_url) + self.assertEqual(resp.status_code, 405) + + def test_entrance_exam_view_direct_missing_score_setting(self): + """ + Unit Test: test_entrance_exam_view_direct_missing_score_setting + """ + user = UserFactory() + user.is_staff = True + request = RequestFactory() + request.user = user + + resp = create_entrance_exam(request, self.course.id, None) + self.assertEqual(resp.status_code, 201) diff --git a/cms/djangoapps/models/settings/course_details.py b/cms/djangoapps/models/settings/course_details.py index 509c2df6a26e51699a7b0556dc7d0a21c08fabce..afb215e0186a2e477a4506e55a5cd639cb56cec8 100644 --- a/cms/djangoapps/models/settings/course_details.py +++ b/cms/djangoapps/models/settings/course_details.py @@ -4,6 +4,8 @@ import datetime import json from json.encoder import JSONEncoder +from django.conf import settings + from opaque_keys.edx.locations import Location from xmodule.modulestore.exceptions import ItemNotFoundError from contentstore.utils import course_image_url @@ -19,6 +21,9 @@ ABOUT_ATTRIBUTES = [ 'short_description', 'overview', 'effort', + 'entrance_exam_enabled', + 'entrance_exam_id', + 'entrance_exam_minimum_score_pct', ] @@ -40,6 +45,12 @@ class CourseDetails(object): self.course_image_name = "" self.course_image_asset_path = "" # URL of the course image self.pre_requisite_courses = [] # pre-requisite courses + self.entrance_exam_enabled = "" # is entrance exam enabled + self.entrance_exam_id = "" # the content location for the entrance exam + self.entrance_exam_minimum_score_pct = settings.FEATURES.get( + 'ENTRANCE_EXAM_MIN_SCORE_PCT', + '50' + ) # minimum passing score for entrance exam content module/tree @classmethod def _fetch_about_attribute(cls, course_key, attribute): @@ -168,7 +179,8 @@ class CourseDetails(object): # NOTE: below auto writes to the db w/o verifying that any of the fields actually changed # to make faster, could compare against db or could have client send over a list of which fields changed. for attribute in ABOUT_ATTRIBUTES: - cls.update_about_item(course_key, attribute, jsondict[attribute], descriptor, user) + if attribute in jsondict: + cls.update_about_item(course_key, attribute, jsondict[attribute], descriptor, user) recomposed_video_tag = CourseDetails.recompose_video_tag(jsondict['intro_video']) cls.update_about_item(course_key, 'video', recomposed_video_tag, descriptor, user) diff --git a/cms/djangoapps/models/settings/course_metadata.py b/cms/djangoapps/models/settings/course_metadata.py index f7b63570afa1b651b67f3d095799dd95d964b6ea..5a7b97915460abeb0d70b2b31a057cf8887fff35 100644 --- a/cms/djangoapps/models/settings/course_metadata.py +++ b/cms/djangoapps/models/settings/course_metadata.py @@ -1,3 +1,6 @@ +""" +Django module for Course Metadata class -- manages advanced settings and related parameters +""" from xblock.fields import Scope from xmodule.modulestore.django import modulestore from django.utils.translation import ugettext as _ @@ -33,7 +36,10 @@ class CourseMetadata(object): 'tags', # from xblock 'visible_to_staff_only', 'group_access', - 'pre_requisite_courses' + 'pre_requisite_courses', + 'entrance_exam_enabled', + 'entrance_exam_minimum_score_pct', + 'entrance_exam_id', ] @classmethod @@ -61,21 +67,28 @@ class CourseMetadata(object): persistence and return a CourseMetadata model. """ result = {} + metadata = cls.fetch_all(descriptor) + for key, value in metadata.iteritems(): + if key in cls.filtered_list(): + continue + result[key] = value + return result + @classmethod + def fetch_all(cls, descriptor): + """ + Fetches all key:value pairs from persistence and returns a CourseMetadata model. + """ + result = {} for field in descriptor.fields.values(): if field.scope != Scope.settings: continue - - if field.name in cls.filtered_list(): - continue - result[field.name] = { 'value': field.read_json(descriptor), 'display_name': _(field.display_name), 'help': _(field.help), 'deprecated': field.runtime_options.get('deprecated', False) } - return result @classmethod diff --git a/cms/envs/bok_choy.env.json b/cms/envs/bok_choy.env.json index 685d2f7b630a4c9d118ba4e857bd7c8acdb9e03c..c24495433de57625074554a46e5499847513f1a1 100644 --- a/cms/envs/bok_choy.env.json +++ b/cms/envs/bok_choy.env.json @@ -68,6 +68,8 @@ "ENABLE_DISCUSSION_SERVICE": true, "ENABLE_INSTRUCTOR_ANALYTICS": true, "ENABLE_S3_GRADE_DOWNLOADS": true, + "ENTRANCE_EXAMS": true, + "MILESTONES_APP": true, "PREVIEW_LMS_BASE": "localhost:8003", "SUBDOMAIN_BRANDING": false, "SUBDOMAIN_COURSE_LISTINGS": false, diff --git a/cms/envs/bok_choy.py b/cms/envs/bok_choy.py index 6b6470e78b1c3b3466012ad8fbef63e77b879dc6..37bb2e2185170090c97194eb8dc708ba4515f195 100644 --- a/cms/envs/bok_choy.py +++ b/cms/envs/bok_choy.py @@ -60,6 +60,9 @@ FEATURES['MILESTONES_APP'] = True # Enable pre-requisite course FEATURES['ENABLE_PREREQUISITE_COURSES'] = True +########################### Entrance Exams ################################# +FEATURES['ENTRANCE_EXAMS'] = True + # Unfortunately, we need to use debug mode to serve staticfiles DEBUG = True diff --git a/cms/envs/common.py b/cms/envs/common.py index 2f5a676e410669efa21c21637ed505bdca8bd051..f0818b2db38312e036cb5562847f9828fc48fc95 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -113,6 +113,7 @@ FEATURES = { # Turn off Video Upload Pipeline through Studio, by default 'ENABLE_VIDEO_UPLOAD_PIPELINE': False, + # Is this an edX-owned domain? (edx.org) # for consistency in user-experience, keep the value of this feature flag # in sync with the one in lms/envs/common.py @@ -134,7 +135,14 @@ FEATURES = { # Prerequisite courses feature flag 'ENABLE_PREREQUISITE_COURSES': False, + + # Toggle course milestones app/feature + 'MILESTONES_APP': False, + + # Toggle course entrance exams feature + 'ENTRANCE_EXAMS': False, } + ENABLE_JASMINE = False @@ -751,7 +759,9 @@ OPTIONAL_APPS = ( # edxval 'edxval', - 'milestones' + + # milestones + 'milestones', ) @@ -786,6 +796,9 @@ MAX_ASSET_UPLOAD_FILE_SIZE_IN_MB = 10 # a file that exceeds the above size MAX_ASSET_UPLOAD_FILE_SIZE_URL = "" +### Default value for entrance exam minimum score +ENTRANCE_EXAM_MIN_SCORE_PCT = 50 + ################ ADVANCED_COMPONENT_TYPES ############### ADVANCED_COMPONENT_TYPES = [ diff --git a/cms/envs/devstack.py b/cms/envs/devstack.py index 50fc0a1b37e2cdaed5252b67781f022a244697d6..f714172955441595e718ca30df3f8a5822e2487f 100644 --- a/cms/envs/devstack.py +++ b/cms/envs/devstack.py @@ -75,6 +75,15 @@ DEBUG_TOOLBAR_CONFIG = { # Stacktraces slow down page loads drastically (for pages with lots of queries). DEBUG_TOOLBAR_MONGO_STACKTRACES = False + +################################ MILESTONES ################################ +FEATURES['MILESTONES_APP'] = True + + +################################ ENTRANCE EXAMS ################################ +FEATURES['ENTRANCE_EXAMS'] = True + + ############################################################################### # See if the developer has any local overrides. try: diff --git a/cms/envs/test.py b/cms/envs/test.py index e3a329436030689f03a8f820b1d176e8beb052c0..63cc896d9d4b85ec6bccc71d201d61cddf5bdbf3 100644 --- a/cms/envs/test.py +++ b/cms/envs/test.py @@ -232,7 +232,15 @@ FEATURES['USE_MICROSITES'] = True # the one in lms/envs/test.py FEATURES['ENABLE_DISCUSSION_SERVICE'] = False + # Enable content libraries code for the tests FEATURES['ENABLE_CONTENT_LIBRARIES'] = True FEATURES['ENABLE_EDXNOTES'] = True + +# MILESTONES +FEATURES['MILESTONES_APP'] = True + +# ENTRANCE EXAMS +FEATURES['ENTRANCE_EXAMS'] = True +ENTRANCE_EXAM_MIN_SCORE_PCT = 50 diff --git a/cms/static/images/spinner-on-grey.gif b/cms/static/images/spinner-on-grey.gif new file mode 100644 index 0000000000000000000000000000000000000000..f43d52e4f4d8311e6530b1f2b84c12d4a5c36e97 Binary files /dev/null and b/cms/static/images/spinner-on-grey.gif differ diff --git a/cms/static/js/models/settings/course_details.js b/cms/static/js/models/settings/course_details.js index 58b58fb7af6f4d144c8083ce762e37ad38be9e51..0b2124975a5305da851c6560a3d0b4411cb1b326 100644 --- a/cms/static/js/models/settings/course_details.js +++ b/cms/static/js/models/settings/course_details.js @@ -1,4 +1,5 @@ -define(["backbone", "underscore", "gettext"], function(Backbone, _, gettext) { +define(["backbone", "underscore", "gettext", "js/models/validation_helpers"], + function(Backbone, _, gettext, ValidationHelpers) { var CourseDetails = Backbone.Model.extend({ defaults: { @@ -16,7 +17,9 @@ var CourseDetails = Backbone.Model.extend({ effort: null, // an int or null, course_image_name: '', // the filename course_image_asset_path: '', // the full URL (/c4x/org/course/num/asset/filename) - pre_requisite_courses: [] + pre_requisite_courses: [], + entrance_exam_enabled : '', + entrance_exam_minimum_score_pct: '50' }, validate: function(newattrs) { @@ -44,6 +47,16 @@ var CourseDetails = Backbone.Model.extend({ } // TODO check if key points to a real video using google's youtube api } + if(_.has(newattrs, 'entrance_exam_minimum_score_pct')){ + var range = { + min: 1, + max: 100 + }; + if(!ValidationHelpers.validateIntegerRange(newattrs.entrance_exam_minimum_score_pct, range)){ + errors.entrance_exam_minimum_score_pct = gettext("Please enter an integer between " + + range.min +" and "+ range.max +"."); + } + } if (!_.isEmpty(errors)) return errors; // NOTE don't return empty errors as that will be interpreted as an error state }, diff --git a/cms/static/js/models/validation_helpers.js b/cms/static/js/models/validation_helpers.js new file mode 100644 index 0000000000000000000000000000000000000000..5a008fc79862beab1c250cca3844bd908acb9867 --- /dev/null +++ b/cms/static/js/models/validation_helpers.js @@ -0,0 +1,20 @@ +/** + * Provide helper methods for modal validation. +*/ +define(["jquery"], + function($) { + + var validateIntegerRange = function(attributeVal, range) { + //Validating attribute should have an integer value and should be under the given range. + var isIntegerUnderRange = true; + var value = Math.round(attributeVal); // see if this ensures value saved is int + if (!isFinite(value) || /\D+/.test(attributeVal) || value < range.min || value > range.max) { + isIntegerUnderRange = false; + } + return isIntegerUnderRange; + } + + return { + 'validateIntegerRange': validateIntegerRange + } + }); diff --git a/cms/static/js/models/xblock_info.js b/cms/static/js/models/xblock_info.js index 4e643f7d5fadf9f216e23abede167f147a898b50..34d82ebc1fc28d016b2b62b4cf586512fab172b7 100644 --- a/cms/static/js/models/xblock_info.js +++ b/cms/static/js/models/xblock_info.js @@ -131,7 +131,11 @@ function(Backbone, _, str, ModuleUtils) { * content groups. Note that this is not a recursive property. Will only be present if * publishing info was explicitly requested. */ - 'has_content_group_components': null + 'has_content_group_components': null, + /** + * Indicate the type of xblock + */ + 'override_type': null }, initialize: function () { @@ -168,6 +172,19 @@ function(Backbone, _, str, ModuleUtils) { return !this.get('published') || this.get('has_changes'); }, + canBeDeleted: function(){ + //get the type of xblock + if(this.get('override_type') != null) { + var type = this.get('override_type'); + + //hide/remove the delete trash icon if type is entrance exam. + if (_.has(type, 'is_entrance_exam') && type['is_entrance_exam']) { + return false; + } + } + return true; + }, + /** * Return a list of convenience methods to check affiliation to the category. * @return {Array} diff --git a/cms/static/js/spec/views/settings/main_spec.js b/cms/static/js/spec/views/settings/main_spec.js index 7fea35e84839ceefd4745b43c4916eab892c90cb..81c10613feab32428b7eec9f16663a22e5545b90 100644 --- a/cms/static/js/spec/views/settings/main_spec.js +++ b/cms/static/js/spec/views/settings/main_spec.js @@ -20,7 +20,9 @@ define([ effort : null, course_image_name : '', course_image_asset_path : '', - pre_requisite_courses : [] + pre_requisite_courses : [], + entrance_exam_enabled : '', + entrance_exam_minimum_score_pct: '50' }, mockSettingsPage = readFixtures('mock/mock-settings-page.underscore'); @@ -76,5 +78,45 @@ define([ ); AjaxHelpers.respondWithJson(requests, expectedJson); }); + + it('should save entrance exam course details information correctly', function () { + var entrance_exam_minimum_score_pct = '60'; + var entrance_exam_enabled = 'true'; + + var entrance_exam_min_score = this.view.$('#entrance-exam-minimum-score-pct'); + var entrance_exam_enabled_field = this.view.$('#entrance-exam-enabled'); + + var requests = AjaxHelpers.requests(this), + expectedJson = $.extend(true, {}, modelData, { + entrance_exam_enabled: entrance_exam_enabled, + entrance_exam_minimum_score_pct: entrance_exam_minimum_score_pct + }); + + expect(this.view.$('.div-grade-requirements div')).toBeHidden(); + + // select the entrance-exam-enabled checkbox. grade requirement section should be visible + entrance_exam_enabled_field + .attr('checked', entrance_exam_enabled) + .trigger('change'); + expect(this.view.$('.div-grade-requirements div')).toBeVisible(); + + //input some invalid values. + expect(entrance_exam_min_score.val('101').trigger('input')).toHaveClass("error"); + expect(entrance_exam_min_score.val('invalidVal').trigger('input')).toHaveClass("error"); + + //if input an empty value, model should be populated with the default value. + entrance_exam_min_score.val('').trigger('input'); + expect(this.model.get('entrance_exam_minimum_score_pct')) + .toEqual(this.model.defaults.entrance_exam_minimum_score_pct); + + // input a valid value for entrance exam minimum score. + entrance_exam_min_score.val(entrance_exam_minimum_score_pct).trigger('input'); + + this.view.saveView(); + AjaxHelpers.expectJsonRequest( + requests, 'POST', urlRoot, expectedJson + ); + AjaxHelpers.respondWithJson(requests, expectedJson); + }); }); }); diff --git a/cms/static/js/views/settings/main.js b/cms/static/js/views/settings/main.js index 8e10e49221ba21c50d9c1c89d96c1815c420507b..d6978987fe00ebf4df4ed872956edacac41a8c7b 100644 --- a/cms/static/js/views/settings/main.js +++ b/cms/static/js/views/settings/main.js @@ -64,10 +64,21 @@ var DetailsView = ValidatingView.extend({ var imageURL = this.model.get('course_image_asset_path'); this.$el.find('#course-image-url').val(imageURL); this.$el.find('#course-image').attr('src', imageURL); + var pre_requisite_courses = this.model.get('pre_requisite_courses'); pre_requisite_courses = pre_requisite_courses.length > 0 ? pre_requisite_courses : ''; this.$el.find('#' + this.fieldToSelectorMap['pre_requisite_courses']).val(pre_requisite_courses); + if (this.model.get('entrance_exam_enabled') == 'true') { + this.$('#' + this.fieldToSelectorMap['entrance_exam_enabled']).attr('checked', this.model.get('entrance_exam_enabled')); + this.$('.div-grade-requirements').show(); + } + else { + this.$('#' + this.fieldToSelectorMap['entrance_exam_enabled']).removeAttr('checked'); + this.$('.div-grade-requirements').hide(); + } + this.$('#' + this.fieldToSelectorMap['entrance_exam_minimum_score_pct']).val(this.model.get('entrance_exam_minimum_score_pct')); + return this; }, fieldToSelectorMap : { @@ -80,7 +91,9 @@ var DetailsView = ValidatingView.extend({ 'intro_video' : 'course-introduction-video', 'effort' : "course-effort", 'course_image_asset_path': 'course-image-url', - 'pre_requisite_courses': 'pre-requisite-course' + 'pre_requisite_courses': 'pre-requisite-course', + 'entrance_exam_enabled': 'entrance-exam-enabled', + 'entrance_exam_minimum_score_pct': 'entrance-exam-minimum-score-pct' }, updateTime : function(e) { @@ -156,6 +169,23 @@ var DetailsView = ValidatingView.extend({ case 'course-effort': this.setField(event); break; + case 'entrance-exam-enabled': + if($(event.currentTarget).is(":checked")){ + this.$('.div-grade-requirements').show(); + }else{ + this.$('.div-grade-requirements').hide(); + } + this.setField(event); + break; + case 'entrance-exam-minimum-score-pct': + // If the val is an empty string then update model with default value. + if ($(event.currentTarget).val() === '') { + this.model.set('entrance_exam_minimum_score_pct', this.model.defaults.entrance_exam_minimum_score_pct); + } + else { + this.setField(event); + } + break; case 'course-short-description': this.setField(event); break; diff --git a/cms/static/js/views/validation.js b/cms/static/js/views/validation.js index bbca2e67a07292d4c278ea51c0c6b650f026602f..435274b9ce7fa02c41129f0bbefa6e121311654c 100644 --- a/cms/static/js/views/validation.js +++ b/cms/static/js/views/validation.js @@ -60,7 +60,12 @@ var ValidatingView = BaseView.extend({ // Set model field and return the new value. this.clearValidationErrors(); var field = this.selectorToField[event.currentTarget.id]; - var newVal = $(event.currentTarget).val(); + var newVal = '' + if(event.currentTarget.type == 'checkbox'){ + newVal = $(event.currentTarget).is(":checked").toString(); + }else{ + newVal = $(event.currentTarget).val(); + } this.model.set(field, newVal); this.model.isValid(); return newVal; diff --git a/cms/static/sass/views/_settings.scss b/cms/static/sass/views/_settings.scss index 4ce762a91ca38fcca65d14e8c9eca2a978a9f88b..273db8d2e163781ae73e47bfa36abe0e1c92b01e 100644 --- a/cms/static/sass/views/_settings.scss +++ b/cms/static/sass/views/_settings.scss @@ -100,8 +100,12 @@ @include transition(color $tmg-f2 ease-in-out 0s); display: block; margin-top: ($baseline/4); - color: $gray-l3; + color: $gray-d1; } + .tip-inline{ + display: inline; + margin-left: 5px; + } .message-error { @extend %t-copy-sub1; @@ -126,6 +130,30 @@ .list-input { @extend %cont-no-list; + .show-data{ + .heading{ + border: 1px solid #E0E0E0; + padding: 5px 15px; + margin-top: 5px; + } + .div-grade-requirements{ + border: 1px solid #E0E0E0; + border-top: none; + padding: 10px 15px; + label{font-weight: 600;} + input#entrance-exam-minimum-score-pct{ + height: 40px; + font-size: 18px; + } + } + } + #heading-entrance-exam{ + font-weight: 600; + } + + label[for="entrance-exam-enabled"] { + font-size: 14px; + } .field { margin: 0 0 ($baseline*2) 0; diff --git a/cms/templates/js/course-outline.underscore b/cms/templates/js/course-outline.underscore index 6bb9311a9b2299510596a24a237096447f47799e..711b21e6ba1d7123d956189f9de415e47e4a22f1 100644 --- a/cms/templates/js/course-outline.underscore +++ b/cms/templates/js/course-outline.underscore @@ -78,12 +78,14 @@ if (xblockInfo.get('graded')) { </a> </li> <% } %> - <li class="action-item action-delete"> - <a href="#" data-tooltip="<%= gettext('Delete') %>" class="delete-button action-button"> - <i class="icon fa fa-trash-o"></i> - <span class="sr action-button-text"><%= gettext('Delete') %></span> - </a> - </li> + <% if (xblockInfo.canBeDeleted()) { %> + <li class="action-item action-delete"> + <a href="#" data-tooltip="<%= gettext('Delete') %>" class="delete-button action-button"> + <i class="icon fa fa-trash-o" aria-hidden="true"></i> + <span class="sr action-button-text"><%= gettext('Delete') %></span> + </a> + </li> + <% } %> <li class="action-item action-drag"> <span data-tooltip="<%= gettext('Drag to reorder') %>" class="drag-handle <%= xblockType %>-drag-handle action"> diff --git a/cms/templates/js/mock/mock-settings-page.underscore b/cms/templates/js/mock/mock-settings-page.underscore index be45253da1f228b28203842c91d9448697219fcd..1dd28b53b925084994818b2c73fd943813ca0677 100644 --- a/cms/templates/js/mock/mock-settings-page.underscore +++ b/cms/templates/js/mock/mock-settings-page.underscore @@ -74,6 +74,19 @@ <span class="tip tip-inline">Course that students must complete before beginning this course</span> <button type="submit" class="sr" name="submit" value="submit">set pre-requisite course</button> </li> + <h3 id="heading-entrance-exam">${_("Entrance Exam")}</h3> + <div class="show-data"> + <div class="heading"> + <input type="checkbox" id="entrance-exam-enabled" /> + <label for="entrance-exam-enabled">${_("Require students to pass an exam before beginning the course.")}</label> + </div> + <div class="div-grade-requirements"> + <p><span class="tip tip-inline">${_("To create your course entrance exam, go to the ")}<a href='${course_handler_url}'>${_("Course Outline")}</a>${_(". An Entrance Exam section will be created automatically.")}</span></p> + <p><label for="entrance-exam-minimum-score-pct">${_("Minimum Passing Score")}</label></p> + <p><div><input type="text" id="entrance-exam-minimum-score-pct" aria-describedby="min-score-format min-score-tip"><span id="min-score-format" class="tip tip-inline">${_(" %")}</span></div></p> + <p><span class="tip tip-inline" id="min-score-tip">${_("The minimum score a student must receive to pass the entrance exam.")}</span></p> + </div> + </div> </li> </ol> </section> diff --git a/cms/templates/settings.html b/cms/templates/settings.html index 280a71b7bd866f0acce947f901f19297db49a962..06cdd5d7e8b68f87b37e147cea6a84c41cf47c09 100644 --- a/cms/templates/settings.html +++ b/cms/templates/settings.html @@ -322,6 +322,23 @@ CMS.URL.UPLOAD_ASSET = '${upload_asset_url}'; </form> </li> % endif + % if settings.FEATURES.get('ENTRANCE_EXAMS'): + <li> + <h3 id="heading-entrance-exam">${_("Entrance Exam")}</h3> + <div class="show-data"> + <div class="heading"> + <input type="checkbox" id="entrance-exam-enabled" /> + <label for="entrance-exam-enabled">${_("Require students to pass an exam before beginning the course.")}</label> + </div> + <div class="div-grade-requirements" hidden="hidden"> + <p><span class="tip tip-inline">${_("You can now view and author your course entrance exam from the ")}<a href='${course_handler_url}'>${_("Course Outline")}</a></span></p> + <p><h3>${_("Grade Requirements")}</h3></p> + <p><div><input type="text" id="entrance-exam-minimum-score-pct" aria-describedby="min-score-format"><span id="min-score-format" class="tip tip-inline">${_(" %")}</span></div></p> + <p><span class="tip tip-inline">${_("The score student must meet in order to successfully complete the entrance exam. ")}</span></p> + </div> + </div> + </li> + % endif </ol> </section> % endif diff --git a/cms/urls.py b/cms/urls.py index ff5d95f991706f622b852de8f572ada386c92071..4a216e1883c17b363c5f23dec8da2415571dcd00 100644 --- a/cms/urls.py +++ b/cms/urls.py @@ -158,6 +158,12 @@ if settings.FEATURES.get('AUTOMATIC_AUTH_FOR_TESTING'): url(r'^auto_auth$', 'student.views.auto_auth'), ) +# enable entrance exams +if settings.FEATURES.get('ENTRANCE_EXAMS'): + urlpatterns += ( + url(r'^course/{}/entrance_exam/?$'.format(settings.COURSE_KEY_PATTERN), 'contentstore.views.entrance_exam'), + ) + if settings.DEBUG: try: from .urls_dev import urlpatterns as dev_urlpatterns diff --git a/common/djangoapps/util/milestones_helpers.py b/common/djangoapps/util/milestones_helpers.py index 8668c472cedce38d4668c95bf70c8cd56c467d1b..9b8048a18a0a84269bee27c65e159a11af882aaa 100644 --- a/common/djangoapps/util/milestones_helpers.py +++ b/common/djangoapps/util/milestones_helpers.py @@ -1,6 +1,6 @@ # pylint: disable=invalid-name """ -Helper methods for milestones api calls. +Utility library for working with the edx-milestones app """ from django.conf import settings @@ -20,6 +20,10 @@ from milestones.api import ( ) from milestones.models import MilestoneRelationshipType +NAMESPACE_CHOICES = { + 'ENTRANCE_EXAM': 'entrance_exams' +} + def add_prerequisite_course(course_key, prerequisite_course_key): """ @@ -165,3 +169,21 @@ def seed_milestone_relationship_types(): if settings.FEATURES.get('MILESTONES_APP', False): MilestoneRelationshipType.objects.create(name='requires') MilestoneRelationshipType.objects.create(name='fulfills') + + +def generate_milestone_namespace(namespace, course_key=None): + """ + Returns a specifically-formatted namespace string for the specified type + """ + if namespace in NAMESPACE_CHOICES.values(): + if namespace == 'entrance_exams': + return '{}.{}'.format(unicode(course_key), NAMESPACE_CHOICES['ENTRANCE_EXAM']) + + +def serialize_user(user): + """ + Returns a milestones-friendly representation of a user object + """ + return { + 'id': user.id, + } diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py index cb445883e108008e177b576511ad0174ebedeb9c..2633f514e3dc725e346b32245b9160f9b47314aa 100644 --- a/common/lib/xmodule/xmodule/course_module.py +++ b/common/lib/xmodule/xmodule/course_module.py @@ -1,3 +1,6 @@ +""" +Django module container for classes and operations related to the "Course Module" content type +""" import logging from cStringIO import StringIO from math import exp @@ -8,12 +11,13 @@ from datetime import datetime import dateutil.parser from lazy import lazy + from xmodule.seq_module import SequenceDescriptor, SequenceModule from xmodule.graders import grader_from_conf from xmodule.tabs import CourseTabList import json -from xblock.fields import Scope, List, String, Dict, Boolean, Integer +from xblock.fields import Scope, List, String, Dict, Boolean, Integer, Float from .fields import Date from django.utils.timezone import UTC @@ -657,6 +661,31 @@ class CourseFields(object): {"display_name": _("None"), "value": CATALOG_VISIBILITY_NONE}] ) + entrance_exam_enabled = Boolean( + display_name=_("Entrance Exam Enabled"), + help=_( + "Specify whether students must complete an entrance exam before they can view your course content." + + "Note, you must enable Entrance Exams for this course setting to take effect."), + default=False, + scope=Scope.settings, + ) + + entrance_exam_minimum_score_pct = Float( + display_name=_("Entrance Exam Minimum Score (%)"), + help=_( + "Specify a minimum percentage score for an entrance exam before students can view your course content." + + "Note, you must enable Entrance Exams for this course setting to take effect."), + default=65, + scope=Scope.settings, + ) + + entrance_exam_id = String( + display_name=_("Entrance Exam ID"), + help=_("Content module identifier (location) of entrance exam."), + default=None, + scope=Scope.settings, + ) + class CourseDescriptor(CourseFields, SequenceDescriptor): module_class = SequenceModule diff --git a/common/lib/xmodule/xmodule/modulestore/inheritance.py b/common/lib/xmodule/xmodule/modulestore/inheritance.py index b8cd3445102bd4c68c44265594527ce95b908db7..022eb92b584a229414ec8ecf3cb3566d241dd05a 100644 --- a/common/lib/xmodule/xmodule/modulestore/inheritance.py +++ b/common/lib/xmodule/xmodule/modulestore/inheritance.py @@ -177,6 +177,14 @@ class InheritanceMixin(XBlockMixin): scope=Scope.user_info ) + in_entrance_exam = Boolean( + display_name=_("Tag this module as part of an Entrance Exam section"), + help=_("Enter true or false. If true, answer submissions for problem modules will be " + "considered in the Entrance Exam scoring/gating algorithm."), + scope=Scope.settings, + default=False + ) + def compute_inherited_metadata(descriptor): """Given a descriptor, traverse all of its descendants and do metadata diff --git a/common/lib/xmodule/xmodule/modulestore/mongo/base.py b/common/lib/xmodule/xmodule/modulestore/mongo/base.py index 85564417b156de1d2fe3851eacda6b9a04ab3a2c..80e6d5cf804c5d38be40447edfa259ea19f3d3b4 100644 --- a/common/lib/xmodule/xmodule/modulestore/mongo/base.py +++ b/common/lib/xmodule/xmodule/modulestore/mongo/base.py @@ -1225,7 +1225,13 @@ class MongoModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase, Mongo # attach to parent if given if 'detached' not in xblock._class_tags: parent = self.get_item(parent_usage_key) - parent.children.append(xblock.location) + + # Originally added to support entrance exams (settings.FEATURES.get('ENTRANCE_EXAMS')) + if kwargs.get('position') is None: + parent.children.append(xblock.location) + else: + parent.children.insert(kwargs.get('position'), xblock.location) + self.update_item(parent, user_id) return xblock diff --git a/common/lib/xmodule/xmodule/modulestore/split_mongo/split.py b/common/lib/xmodule/xmodule/modulestore/split_mongo/split.py index 9e9b09ebd209b4002c00b0900703181befab99c7..093e90c038ddf6ca7619a5598b481e8478f0bb65 100644 --- a/common/lib/xmodule/xmodule/modulestore/split_mongo/split.py +++ b/common/lib/xmodule/xmodule/modulestore/split_mongo/split.py @@ -1510,7 +1510,16 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase): raise ItemNotFoundError(parent_usage_key) parent = new_structure['blocks'][block_id] - parent['fields'].setdefault('children', []).append(BlockKey.from_usage_key(xblock.location)) + + # Originally added to support entrance exams (settings.FEATURES.get('ENTRANCE_EXAMS')) + if kwargs.get('position') is None: + parent['fields'].setdefault('children', []).append(BlockKey.from_usage_key(xblock.location)) + else: + parent['fields'].setdefault('children', []).insert( + kwargs.get('position'), + BlockKey.from_usage_key(xblock.location) + ) + if parent['edit_info']['update_version'] != new_structure['_id']: # if the parent hadn't been previously changed in this bulk transaction, indicate that it's # part of the bulk transaction diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py b/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py index 737e0c8b7a6648332321ed5e0a277ef1c4669c3e..38e6e30e2c72212e07d85d4206befbf35a5610ca 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py @@ -676,6 +676,35 @@ class TestMongoModuleStore(TestMongoModuleStoreBase): finally: shutil.rmtree(root_dir) + def test_draft_modulestore_create_child_with_position(self): + """ + This test is designed to hit a specific set of use cases having to do with + the child positioning logic found in mongo/base.py:create_child() + """ + # Set up the draft module store + course = self.draft_store.create_course("TestX", "ChildTest", "1234_A1", 1) + first_child = self.draft_store.create_child( + self.dummy_user, + course.location, + "chapter", + block_id=course.location.block_id + ) + second_child = self.draft_store.create_child( + self.dummy_user, + course.location, + "chapter", + block_id=course.location.block_id, + position=0 + ) + + # First child should have been moved to second position, and better child takes the lead + course = self.draft_store.get_course(course.id) + self.assertEqual(unicode(course.children[1]), unicode(first_child.location)) + self.assertEqual(unicode(course.children[0]), unicode(second_child.location)) + + # Clean up the data so we don't break other tests which apparently expect a particular state + self.draft_store.delete_course(course.id, self.dummy_user) + class TestMongoModuleStoreWithNoAssetCollection(TestMongoModuleStore): ''' diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py b/common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py index 27493d91809a6f1949e5bf6c9e82fb29b7cd6aea..6edf6c6d4e23798db442392ceda333929b5a4761 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py @@ -1396,6 +1396,41 @@ class TestItemCrud(SplitModuleTest): for _ in range(4): self.create_subtree_for_deletion(node_loc, category_queue[1:]) + def test_split_modulestore_create_child_with_position(self): + """ + This test is designed to hit a specific set of use cases having to do with + the child positioning logic found in split_mongo/split.py:create_child() + """ + # Set up the split module store + store = modulestore() + user = random.getrandbits(32) + course_key = CourseLocator('test_org', 'test_transaction', 'test_run') + with store.bulk_operations(course_key): + new_course = store.create_course('test_org', 'test_transaction', 'test_run', user, BRANCH_NAME_DRAFT) + new_course_locator = new_course.id + versionless_course_locator = new_course_locator.version_agnostic() + first_child = store.create_child( + self.user_id, + new_course.location, + "chapter" + ) + refetch_course = store.get_course(versionless_course_locator) + second_child = store.create_child( + self.user_id, + refetch_course.location, + "chapter", + position=0 + ) + + # First child should have been moved to second position, and better child takes the lead + refetch_course = store.get_course(versionless_course_locator) + children = refetch_course.get_children() + self.assertEqual(unicode(children[1].location), unicode(first_child.location)) + self.assertEqual(unicode(children[0].location), unicode(second_child.location)) + + # Clean up the data so we don't break other tests which apparently expect a particular state + store.delete_course(refetch_course.id, user) + class TestCourseCreation(SplitModuleTest): """ diff --git a/common/lib/xmodule/xmodule/seq_module.py b/common/lib/xmodule/xmodule/seq_module.py index d07447aab05bfd727ee143ada4264469b9b289e6..2156f0d18f70ab4f87b5627e61f721cbc155f65e 100644 --- a/common/lib/xmodule/xmodule/seq_module.py +++ b/common/lib/xmodule/xmodule/seq_module.py @@ -4,7 +4,7 @@ import warnings from lxml import etree -from xblock.fields import Integer, Scope +from xblock.fields import Integer, Scope, Boolean from xblock.fragment import Fragment from pkg_resources import resource_string @@ -45,6 +45,16 @@ class SequenceFields(object): scope=Scope.user_state, ) + # Entrance Exam flag -- see cms/contentstore/views/entrance_exam.py for usage + is_entrance_exam = Boolean( + display_name=_("Is Entrance Exam"), + help=_( + "Tag this course module as an Entrance Exam. " + + "Note, you must enable Entrance Exams for this course setting to take effect." + ), + scope=Scope.settings, + ) + class SequenceModule(SequenceFields, XModule): ''' Layout module which lays out content in a temporal sequence diff --git a/common/test/acceptance/pages/studio/settings.py b/common/test/acceptance/pages/studio/settings.py index 96d5bd23016dcb0343ae6bbe1ea3b2b457110c30..432246f4cebdbec26d20aa63b4e2dbf0a0b4486a 100644 --- a/common/test/acceptance/pages/studio/settings.py +++ b/common/test/acceptance/pages/studio/settings.py @@ -1,6 +1,7 @@ """ Course Schedule and Details Settings page. """ +from bok_choy.promise import EmptyPromise from .course_page import CoursePage from .utils import press_the_notification_button @@ -23,11 +24,42 @@ class SettingsPage(CoursePage): """ return self.q(css='#pre-requisite-course') - def save_changes(self): + @property + def entrance_exam_field(self): + """ + Returns the enable entrance exam checkbox. + """ + return self.q(css='#entrance-exam-enabled').execute() + + def require_entrance_exam(self, required=True): + """ + Set the entrance exam requirement via the checkbox. + """ + checkbox = self.entrance_exam_field[0] + selected = checkbox.is_selected() + if required and not selected: + checkbox.click() + self.wait_for_element_visibility( + '#entrance-exam-minimum-score-pct', + 'Entrance exam minimum score percent is visible' + ) + if not required and selected: + checkbox.click() + self.wait_for_element_invisibility( + '#entrance-exam-minimum-score-pct', + 'Entrance exam minimum score percent is visible' + ) + + def save_changes(self, wait_for_confirmation=True): """ - Clicks save button. + Clicks save button, waits for confirmation unless otherwise specified """ press_the_notification_button(self, "save") + if wait_for_confirmation: + EmptyPromise( + lambda: self.q(css='#alert-confirmation-title').present, + 'Waiting for save confirmation...' + ).fulfill() def refresh_page(self): """ diff --git a/common/test/acceptance/tests/helpers.py b/common/test/acceptance/tests/helpers.py index b0851c4d3e8fe5c4960a0382a75544e9d071d843..19da396f13299c97f5259fdb41668c4733ee194b 100644 --- a/common/test/acceptance/tests/helpers.py +++ b/common/test/acceptance/tests/helpers.py @@ -221,6 +221,19 @@ def is_option_value_selected(browser_query, value): return ddl_selected_value == value +def element_has_text(page, css_selector, text): + """ + Return true if the given text is present in the list. + """ + text_present = False + text_list = page.q(css=css_selector).text + + if len(text_list) > 0 and (text in text_list): + text_present = True + + return text_present + + class UniqueCourseTest(WebAppTest): """ Test that provides a unique course ID. diff --git a/common/test/acceptance/tests/lms/test_lms.py b/common/test/acceptance/tests/lms/test_lms.py index 307d973d6403aff5ee180f355a6ebe6c1f2e53d4..55e62219b02cbd4716b6d826632f2982d2ababe5 100644 --- a/common/test/acceptance/tests/lms/test_lms.py +++ b/common/test/acceptance/tests/lms/test_lms.py @@ -7,13 +7,14 @@ from textwrap import dedent from unittest import skip from nose.plugins.attrib import attr -from bok_choy.web_app_test import WebAppTest from bok_choy.promise import EmptyPromise +from bok_choy.web_app_test import WebAppTest from ..helpers import ( UniqueCourseTest, load_data_str, generate_course_key, select_option_by_value, + element_has_text ) from ...pages.lms.auto_auth import AutoAuthPage from ...pages.common.logout import LogoutPage @@ -27,6 +28,7 @@ from ...pages.lms.dashboard import DashboardPage from ...pages.lms.problem import ProblemPage from ...pages.lms.video.video import VideoPage from ...pages.lms.courseware import CoursewarePage +from ...pages.studio.settings import SettingsPage from ...pages.lms.login_and_register import CombinedLoginAndRegisterPage from ...pages.studio.settings import SettingsPage from ...fixtures.course import CourseFixture, XBlockFixtureDesc, CourseUpdateDesc @@ -771,3 +773,73 @@ class ProblemExecutionTest(UniqueCourseTest): problem_page.fill_answer("4") problem_page.click_check() self.assertFalse(problem_page.is_correct()) + + +class EntranceExamTest(UniqueCourseTest): + """ + Tests that course has an entrance exam. + """ + + def setUp(self): + """ + Initialize pages and install a course fixture. + """ + super(EntranceExamTest, self).setUp() + + CourseFixture( + self.course_info['org'], self.course_info['number'], + self.course_info['run'], self.course_info['display_name'] + ).install() + + self.course_info_page = CourseInfoPage(self.browser, self.course_id) + self.settings_page = SettingsPage( + self.browser, + self.course_info['org'], + self.course_info['number'], + self.course_info['run'] + ) + + # Auto-auth register for the course + AutoAuthPage(self.browser, course_id=self.course_id).visit() + + def test_entrance_exam_section(self): + """ + Scenario: Any course that is enabled for an entrance exam, should have entrance exam section at course info + page. + Given that I am on the course info page + When I view the course info that has an entrance exam + Then there should be an "Entrance Exam" section.' + """ + + # visit course info page and make sure there is not entrance exam section. + self.course_info_page.visit() + self.course_info_page.wait_for_page() + self.assertFalse(element_has_text( + page=self.course_info_page, + css_selector='div ol li a', + text='Entrance Exam' + )) + + # Logout and login as a staff. + LogoutPage(self.browser).visit() + AutoAuthPage(self.browser, course_id=self.course_id, staff=True).visit() + + # visit course settings page and set/enabled entrance exam for that course. + self.settings_page.visit() + self.settings_page.wait_for_page() + self.assertTrue(self.settings_page.is_browser_on_page()) + self.settings_page.entrance_exam_field[0].click() + self.settings_page.save_changes() + + # Logout and login as a student. + LogoutPage(self.browser).visit() + AutoAuthPage(self.browser, course_id=self.course_id, staff=False).visit() + + # visit course info page and make sure there is an "Entrance Exam" section. + self.course_info_page.visit() + self.course_info_page.wait_for_page() + self.assertTrue(element_has_text( + page=self.course_info_page, + css_selector='div ol li a', + text='Entrance Exam' + )) diff --git a/common/test/acceptance/tests/studio/test_studio_settings_details.py b/common/test/acceptance/tests/studio/test_studio_settings_details.py index 6fd0225ca62f448703b1f37892cfc600f784c3b1..bbec1d875c121ac25a16f4c00ea268eb069d2eec 100644 --- a/common/test/acceptance/tests/studio/test_studio_settings_details.py +++ b/common/test/acceptance/tests/studio/test_studio_settings_details.py @@ -1,16 +1,20 @@ """ Acceptance tests for Studio's Settings Details pages """ +from unittest import skip + from acceptance.tests.studio.base_studio_test import StudioCourseTest from ...fixtures.course import CourseFixture +from ...pages.studio.settings import SettingsPage +from ...pages.studio.overview import CourseOutlinePage +from ...tests.studio.base_studio_test import StudioCourseTest from ..helpers import ( generate_course_key, select_option_by_value, - is_option_value_selected + is_option_value_selected, + element_has_text, ) -from ...pages.studio.settings import SettingsPage - class SettingsMilestonesTest(StudioCourseTest): """ @@ -82,3 +86,43 @@ class SettingsMilestonesTest(StudioCourseTest): self.settings_detail.save_changes() self.assertTrue('Your changes have been saved.' in self.settings_detail.browser.page_source) self.assertTrue(is_option_value_selected(browser_query=self.settings_detail.pre_requisite_course, value='')) + + def test_page_has_enable_entrance_exam_field(self): + """ + Test to make sure page has 'enable entrance exam' field. + """ + self.assertTrue(self.settings_detail.entrance_exam_field) + + @skip('Passes in devstack, passes individually in Jenkins, fails in suite in Jenkins.') + def test_enable_entrance_exam_for_course(self): + """ + Test that entrance exam should be created after checking the 'enable entrance exam' checkbox. + And also that the entrance exam is destroyed after deselecting the checkbox. + """ + self.settings_detail.require_entrance_exam(required=True) + self.settings_detail.save_changes() + + # getting the course outline page. + course_outline_page = CourseOutlinePage( + self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run'] + ) + course_outline_page.visit() + + # title with text 'Entrance Exam' should be present on page. + self.assertTrue(element_has_text( + page=course_outline_page, + css_selector='span.section-title', + text='Entrance Exam' + )) + + # Delete the currently created entrance exam. + self.settings_detail.visit() + self.settings_detail.require_entrance_exam(required=False) + self.settings_detail.save_changes() + + course_outline_page.visit() + self.assertFalse(element_has_text( + page=course_outline_page, + css_selector='span.section-title', + text='Entrance Exam' + )) diff --git a/common/test/db_cache/bok_choy_data.json b/common/test/db_cache/bok_choy_data.json index 091f4ca99d90c76f62284e4251553830b6e5e0ed..c112ae95e6e7125e3ddc7aaf59de8ba321eae891 100644 --- a/common/test/db_cache/bok_choy_data.json +++ b/common/test/db_cache/bok_choy_data.json @@ -1 +1 @@ -[{"pk": 62, "model": "contenttypes.contenttype", "fields": {"model": "accesstoken", "name": "access token", "app_label": "oauth2"}}, {"pk": 131, "model": "contenttypes.contenttype", "fields": {"model": "aiclassifier", "name": "ai classifier", "app_label": "assessment"}}, {"pk": 130, "model": "contenttypes.contenttype", "fields": {"model": "aiclassifierset", "name": "ai classifier set", "app_label": "assessment"}}, {"pk": 133, "model": "contenttypes.contenttype", "fields": {"model": "aigradingworkflow", "name": "ai grading workflow", "app_label": "assessment"}}, {"pk": 132, "model": "contenttypes.contenttype", "fields": {"model": "aitrainingworkflow", "name": "ai training workflow", "app_label": "assessment"}}, {"pk": 33, "model": "contenttypes.contenttype", "fields": {"model": "anonymoususerid", "name": "anonymous user id", "app_label": "student"}}, {"pk": 112, "model": "contenttypes.contenttype", "fields": {"model": "answer", "name": "answer", "app_label": "mentoring"}}, {"pk": 65, "model": "contenttypes.contenttype", "fields": {"model": "article", "name": "article", "app_label": "wiki"}}, {"pk": 66, "model": "contenttypes.contenttype", "fields": {"model": "articleforobject", "name": "Article for object", "app_label": "wiki"}}, {"pk": 69, "model": "contenttypes.contenttype", "fields": {"model": "articleplugin", "name": "article plugin", "app_label": "wiki"}}, {"pk": 67, "model": "contenttypes.contenttype", "fields": {"model": "articlerevision", "name": "article revision", "app_label": "wiki"}}, {"pk": 74, "model": "contenttypes.contenttype", "fields": {"model": "articlesubscription", "name": "article subscription", "app_label": "wiki"}}, {"pk": 121, "model": "contenttypes.contenttype", "fields": {"model": "assessment", "name": "assessment", "app_label": "assessment"}}, {"pk": 124, "model": "contenttypes.contenttype", "fields": {"model": "assessmentfeedback", "name": "assessment feedback", "app_label": "assessment"}}, {"pk": 123, "model": "contenttypes.contenttype", "fields": {"model": "assessmentfeedbackoption", "name": "assessment feedback option", "app_label": "assessment"}}, {"pk": 122, "model": "contenttypes.contenttype", "fields": {"model": "assessmentpart", "name": "assessment part", "app_label": "assessment"}}, {"pk": 134, "model": "contenttypes.contenttype", "fields": {"model": "assessmentworkflow", "name": "assessment workflow", "app_label": "workflow"}}, {"pk": 135, "model": "contenttypes.contenttype", "fields": {"model": "assessmentworkflowstep", "name": "assessment workflow step", "app_label": "workflow"}}, {"pk": 19, "model": "contenttypes.contenttype", "fields": {"model": "association", "name": "association", "app_label": "django_openid_auth"}}, {"pk": 24, "model": "contenttypes.contenttype", "fields": {"model": "association", "name": "association", "app_label": "default"}}, {"pk": 97, "model": "contenttypes.contenttype", "fields": {"model": "certificateitem", "name": "certificate item", "app_label": "shoppingcart"}}, {"pk": 48, "model": "contenttypes.contenttype", "fields": {"model": "certificatewhitelist", "name": "certificate whitelist", "app_label": "certificates"}}, {"pk": 60, "model": "contenttypes.contenttype", "fields": {"model": "client", "name": "client", "app_label": "oauth2"}}, {"pk": 25, "model": "contenttypes.contenttype", "fields": {"model": "code", "name": "code", "app_label": "default"}}, {"pk": 4, "model": "contenttypes.contenttype", "fields": {"model": "contenttype", "name": "content type", "app_label": "contenttypes"}}, {"pk": 91, "model": "contenttypes.contenttype", "fields": {"model": "coupon", "name": "coupon", "app_label": "shoppingcart"}}, {"pk": 92, "model": "contenttypes.contenttype", "fields": {"model": "couponredemption", "name": "coupon redemption", "app_label": "shoppingcart"}}, {"pk": 45, "model": "contenttypes.contenttype", "fields": {"model": "courseaccessrole", "name": "course access role", "app_label": "student"}}, {"pk": 58, "model": "contenttypes.contenttype", "fields": {"model": "courseauthorization", "name": "course authorization", "app_label": "bulk_email"}}, {"pk": 144, "model": "contenttypes.contenttype", "fields": {"model": "coursecontentmilestone", "name": "course content milestone", "app_label": "milestones"}}, {"pk": 147, "model": "contenttypes.contenttype", "fields": {"model": "coursecreator", "name": "course creator", "app_label": "course_creators"}}, {"pk": 55, "model": "contenttypes.contenttype", "fields": {"model": "courseemail", "name": "course email", "app_label": "bulk_email"}}, {"pk": 57, "model": "contenttypes.contenttype", "fields": {"model": "courseemailtemplate", "name": "course email template", "app_label": "bulk_email"}}, {"pk": 43, "model": "contenttypes.contenttype", "fields": {"model": "courseenrollment", "name": "course enrollment", "app_label": "student"}}, {"pk": 44, "model": "contenttypes.contenttype", "fields": {"model": "courseenrollmentallowed", "name": "course enrollment allowed", "app_label": "student"}}, {"pk": 143, "model": "contenttypes.contenttype", "fields": {"model": "coursemilestone", "name": "course milestone", "app_label": "milestones"}}, {"pk": 100, "model": "contenttypes.contenttype", "fields": {"model": "coursemode", "name": "course mode", "app_label": "course_modes"}}, {"pk": 101, "model": "contenttypes.contenttype", "fields": {"model": "coursemodesarchive", "name": "course modes archive", "app_label": "course_modes"}}, {"pk": 94, "model": "contenttypes.contenttype", "fields": {"model": "courseregcodeitem", "name": "course reg code item", "app_label": "shoppingcart"}}, {"pk": 95, "model": "contenttypes.contenttype", "fields": {"model": "courseregcodeitemannotation", "name": "course reg code item annotation", "app_label": "shoppingcart"}}, {"pk": 89, "model": "contenttypes.contenttype", "fields": {"model": "courseregistrationcode", "name": "course registration code", "app_label": "shoppingcart"}}, {"pk": 108, "model": "contenttypes.contenttype", "fields": {"model": "coursererunstate", "name": "course rerun state", "app_label": "course_action_state"}}, {"pk": 51, "model": "contenttypes.contenttype", "fields": {"model": "coursesoftware", "name": "course software", "app_label": "licenses"}}, {"pk": 53, "model": "contenttypes.contenttype", "fields": {"model": "courseusergroup", "name": "course user group", "app_label": "course_groups"}}, {"pk": 54, "model": "contenttypes.contenttype", "fields": {"model": "courseusergrouppartitiongroup", "name": "course user group partition group", "app_label": "course_groups"}}, {"pk": 138, "model": "contenttypes.contenttype", "fields": {"model": "coursevideo", "name": "course video", "app_label": "edxval"}}, {"pk": 119, "model": "contenttypes.contenttype", "fields": {"model": "criterion", "name": "criterion", "app_label": "assessment"}}, {"pk": 120, "model": "contenttypes.contenttype", "fields": {"model": "criterionoption", "name": "criterion option", "app_label": "assessment"}}, {"pk": 10, "model": "contenttypes.contenttype", "fields": {"model": "crontabschedule", "name": "crontab", "app_label": "djcelery"}}, {"pk": 103, "model": "contenttypes.contenttype", "fields": {"model": "darklangconfig", "name": "dark lang config", "app_label": "dark_lang"}}, {"pk": 46, "model": "contenttypes.contenttype", "fields": {"model": "dashboardconfiguration", "name": "dashboard configuration", "app_label": "student"}}, {"pk": 99, "model": "contenttypes.contenttype", "fields": {"model": "donation", "name": "donation", "app_label": "shoppingcart"}}, {"pk": 98, "model": "contenttypes.contenttype", "fields": {"model": "donationconfiguration", "name": "donation configuration", "app_label": "shoppingcart"}}, {"pk": 105, "model": "contenttypes.contenttype", "fields": {"model": "embargoedcourse", "name": "embargoed course", "app_label": "embargo"}}, {"pk": 106, "model": "contenttypes.contenttype", "fields": {"model": "embargoedstate", "name": "embargoed state", "app_label": "embargo"}}, {"pk": 139, "model": "contenttypes.contenttype", "fields": {"model": "encodedvideo", "name": "encoded video", "app_label": "edxval"}}, {"pk": 59, "model": "contenttypes.contenttype", "fields": {"model": "externalauthmap", "name": "external auth map", "app_label": "external_auth"}}, {"pk": 49, "model": "contenttypes.contenttype", "fields": {"model": "generatedcertificate", "name": "generated certificate", "app_label": "certificates"}}, {"pk": 61, "model": "contenttypes.contenttype", "fields": {"model": "grant", "name": "grant", "app_label": "oauth2"}}, {"pk": 2, "model": "contenttypes.contenttype", "fields": {"model": "group", "name": "group", "app_label": "auth"}}, {"pk": 50, "model": "contenttypes.contenttype", "fields": {"model": "instructortask", "name": "instructor task", "app_label": "instructor_task"}}, {"pk": 9, "model": "contenttypes.contenttype", "fields": {"model": "intervalschedule", "name": "interval", "app_label": "djcelery"}}, {"pk": 88, "model": "contenttypes.contenttype", "fields": {"model": "invoice", "name": "invoice", "app_label": "shoppingcart"}}, {"pk": 107, "model": "contenttypes.contenttype", "fields": {"model": "ipfilter", "name": "ip filter", "app_label": "embargo"}}, {"pk": 113, "model": "contenttypes.contenttype", "fields": {"model": "lightchild", "name": "light child", "app_label": "mentoring"}}, {"pk": 21, "model": "contenttypes.contenttype", "fields": {"model": "logentry", "name": "log entry", "app_label": "admin"}}, {"pk": 42, "model": "contenttypes.contenttype", "fields": {"model": "loginfailures", "name": "login failures", "app_label": "student"}}, {"pk": 104, "model": "contenttypes.contenttype", "fields": {"model": "midcoursereverificationwindow", "name": "midcourse reverification window", "app_label": "reverification"}}, {"pk": 15, "model": "contenttypes.contenttype", "fields": {"model": "migrationhistory", "name": "migration history", "app_label": "south"}}, {"pk": 141, "model": "contenttypes.contenttype", "fields": {"model": "milestone", "name": "milestone", "app_label": "milestones"}}, {"pk": 142, "model": "contenttypes.contenttype", "fields": {"model": "milestonerelationshiptype", "name": "milestone relationship type", "app_label": "milestones"}}, {"pk": 18, "model": "contenttypes.contenttype", "fields": {"model": "nonce", "name": "nonce", "app_label": "django_openid_auth"}}, {"pk": 23, "model": "contenttypes.contenttype", "fields": {"model": "nonce", "name": "nonce", "app_label": "default"}}, {"pk": 81, "model": "contenttypes.contenttype", "fields": {"model": "note", "name": "note", "app_label": "notes"}}, {"pk": 78, "model": "contenttypes.contenttype", "fields": {"model": "notification", "name": "notification", "app_label": "django_notify"}}, {"pk": 31, "model": "contenttypes.contenttype", "fields": {"model": "offlinecomputedgrade", "name": "offline computed grade", "app_label": "courseware"}}, {"pk": 32, "model": "contenttypes.contenttype", "fields": {"model": "offlinecomputedgradelog", "name": "offline computed grade log", "app_label": "courseware"}}, {"pk": 56, "model": "contenttypes.contenttype", "fields": {"model": "optout", "name": "optout", "app_label": "bulk_email"}}, {"pk": 86, "model": "contenttypes.contenttype", "fields": {"model": "order", "name": "order", "app_label": "shoppingcart"}}, {"pk": 87, "model": "contenttypes.contenttype", "fields": {"model": "orderitem", "name": "order item", "app_label": "shoppingcart"}}, {"pk": 93, "model": "contenttypes.contenttype", "fields": {"model": "paidcourseregistration", "name": "paid course registration", "app_label": "shoppingcart"}}, {"pk": 96, "model": "contenttypes.contenttype", "fields": {"model": "paidcourseregistrationannotation", "name": "paid course registration annotation", "app_label": "shoppingcart"}}, {"pk": 41, "model": "contenttypes.contenttype", "fields": {"model": "passwordhistory", "name": "password history", "app_label": "student"}}, {"pk": 125, "model": "contenttypes.contenttype", "fields": {"model": "peerworkflow", "name": "peer workflow", "app_label": "assessment"}}, {"pk": 126, "model": "contenttypes.contenttype", "fields": {"model": "peerworkflowitem", "name": "peer workflow item", "app_label": "assessment"}}, {"pk": 40, "model": "contenttypes.contenttype", "fields": {"model": "pendingemailchange", "name": "pending email change", "app_label": "student"}}, {"pk": 39, "model": "contenttypes.contenttype", "fields": {"model": "pendingnamechange", "name": "pending name change", "app_label": "student"}}, {"pk": 12, "model": "contenttypes.contenttype", "fields": {"model": "periodictask", "name": "periodic task", "app_label": "djcelery"}}, {"pk": 11, "model": "contenttypes.contenttype", "fields": {"model": "periodictasks", "name": "periodic tasks", "app_label": "djcelery"}}, {"pk": 1, "model": "contenttypes.contenttype", "fields": {"model": "permission", "name": "permission", "app_label": "auth"}}, {"pk": 136, "model": "contenttypes.contenttype", "fields": {"model": "profile", "name": "profile", "app_label": "edxval"}}, {"pk": 17, "model": "contenttypes.contenttype", "fields": {"model": "psychometricdata", "name": "psychometric data", "app_label": "psychometrics"}}, {"pk": 80, "model": "contenttypes.contenttype", "fields": {"model": "puzzlecomplete", "name": "puzzle complete", "app_label": "foldit"}}, {"pk": 63, "model": "contenttypes.contenttype", "fields": {"model": "refreshtoken", "name": "refresh token", "app_label": "oauth2"}}, {"pk": 38, "model": "contenttypes.contenttype", "fields": {"model": "registration", "name": "registration", "app_label": "student"}}, {"pk": 90, "model": "contenttypes.contenttype", "fields": {"model": "registrationcoderedemption", "name": "registration code redemption", "app_label": "shoppingcart"}}, {"pk": 70, "model": "contenttypes.contenttype", "fields": {"model": "reusableplugin", "name": "reusable plugin", "app_label": "wiki"}}, {"pk": 72, "model": "contenttypes.contenttype", "fields": {"model": "revisionplugin", "name": "revision plugin", "app_label": "wiki"}}, {"pk": 73, "model": "contenttypes.contenttype", "fields": {"model": "revisionpluginrevision", "name": "revision plugin revision", "app_label": "wiki"}}, {"pk": 118, "model": "contenttypes.contenttype", "fields": {"model": "rubric", "name": "rubric", "app_label": "assessment"}}, {"pk": 8, "model": "contenttypes.contenttype", "fields": {"model": "tasksetmeta", "name": "saved group result", "app_label": "djcelery"}}, {"pk": 79, "model": "contenttypes.contenttype", "fields": {"model": "score", "name": "score", "app_label": "foldit"}}, {"pk": 116, "model": "contenttypes.contenttype", "fields": {"model": "score", "name": "score", "app_label": "submissions"}}, {"pk": 117, "model": "contenttypes.contenttype", "fields": {"model": "scoresummary", "name": "score summary", "app_label": "submissions"}}, {"pk": 16, "model": "contenttypes.contenttype", "fields": {"model": "servercircuit", "name": "server circuit", "app_label": "circuit"}}, {"pk": 5, "model": "contenttypes.contenttype", "fields": {"model": "session", "name": "session", "app_label": "sessions"}}, {"pk": 76, "model": "contenttypes.contenttype", "fields": {"model": "settings", "name": "settings", "app_label": "django_notify"}}, {"pk": 71, "model": "contenttypes.contenttype", "fields": {"model": "simpleplugin", "name": "simple plugin", "app_label": "wiki"}}, {"pk": 6, "model": "contenttypes.contenttype", "fields": {"model": "site", "name": "site", "app_label": "sites"}}, {"pk": 102, "model": "contenttypes.contenttype", "fields": {"model": "softwaresecurephotoverification", "name": "software secure photo verification", "app_label": "verify_student"}}, {"pk": 82, "model": "contenttypes.contenttype", "fields": {"model": "splashconfig", "name": "splash config", "app_label": "splash"}}, {"pk": 114, "model": "contenttypes.contenttype", "fields": {"model": "studentitem", "name": "student item", "app_label": "submissions"}}, {"pk": 26, "model": "contenttypes.contenttype", "fields": {"model": "studentmodule", "name": "student module", "app_label": "courseware"}}, {"pk": 27, "model": "contenttypes.contenttype", "fields": {"model": "studentmodulehistory", "name": "student module history", "app_label": "courseware"}}, {"pk": 128, "model": "contenttypes.contenttype", "fields": {"model": "studenttrainingworkflow", "name": "student training workflow", "app_label": "assessment"}}, {"pk": 129, "model": "contenttypes.contenttype", "fields": {"model": "studenttrainingworkflowitem", "name": "student training workflow item", "app_label": "assessment"}}, {"pk": 148, "model": "contenttypes.contenttype", "fields": {"model": "studioconfig", "name": "studio config", "app_label": "xblock_config"}}, {"pk": 115, "model": "contenttypes.contenttype", "fields": {"model": "submission", "name": "submission", "app_label": "submissions"}}, {"pk": 77, "model": "contenttypes.contenttype", "fields": {"model": "subscription", "name": "subscription", "app_label": "django_notify"}}, {"pk": 140, "model": "contenttypes.contenttype", "fields": {"model": "subtitle", "name": "subtitle", "app_label": "edxval"}}, {"pk": 110, "model": "contenttypes.contenttype", "fields": {"model": "surveyanswer", "name": "survey answer", "app_label": "survey"}}, {"pk": 109, "model": "contenttypes.contenttype", "fields": {"model": "surveyform", "name": "survey form", "app_label": "survey"}}, {"pk": 14, "model": "contenttypes.contenttype", "fields": {"model": "taskstate", "name": "task", "app_label": "djcelery"}}, {"pk": 7, "model": "contenttypes.contenttype", "fields": {"model": "taskmeta", "name": "task state", "app_label": "djcelery"}}, {"pk": 47, "model": "contenttypes.contenttype", "fields": {"model": "trackinglog", "name": "tracking log", "app_label": "track"}}, {"pk": 127, "model": "contenttypes.contenttype", "fields": {"model": "trainingexample", "name": "training example", "app_label": "assessment"}}, {"pk": 64, "model": "contenttypes.contenttype", "fields": {"model": "trustedclient", "name": "trusted client", "app_label": "oauth2_provider"}}, {"pk": 75, "model": "contenttypes.contenttype", "fields": {"model": "notificationtype", "name": "type", "app_label": "django_notify"}}, {"pk": 68, "model": "contenttypes.contenttype", "fields": {"model": "urlpath", "name": "URL path", "app_label": "wiki"}}, {"pk": 3, "model": "contenttypes.contenttype", "fields": {"model": "user", "name": "user", "app_label": "auth"}}, {"pk": 84, "model": "contenttypes.contenttype", "fields": {"model": "usercoursetag", "name": "user course tag", "app_label": "user_api"}}, {"pk": 52, "model": "contenttypes.contenttype", "fields": {"model": "userlicense", "name": "user license", "app_label": "licenses"}}, {"pk": 145, "model": "contenttypes.contenttype", "fields": {"model": "usermilestone", "name": "user milestone", "app_label": "milestones"}}, {"pk": 20, "model": "contenttypes.contenttype", "fields": {"model": "useropenid", "name": "user open id", "app_label": "django_openid_auth"}}, {"pk": 85, "model": "contenttypes.contenttype", "fields": {"model": "userorgtag", "name": "user org tag", "app_label": "user_api"}}, {"pk": 83, "model": "contenttypes.contenttype", "fields": {"model": "userpreference", "name": "user preference", "app_label": "user_api"}}, {"pk": 35, "model": "contenttypes.contenttype", "fields": {"model": "userprofile", "name": "user profile", "app_label": "student"}}, {"pk": 36, "model": "contenttypes.contenttype", "fields": {"model": "usersignupsource", "name": "user signup source", "app_label": "student"}}, {"pk": 22, "model": "contenttypes.contenttype", "fields": {"model": "usersocialauth", "name": "user social auth", "app_label": "default"}}, {"pk": 34, "model": "contenttypes.contenttype", "fields": {"model": "userstanding", "name": "user standing", "app_label": "student"}}, {"pk": 37, "model": "contenttypes.contenttype", "fields": {"model": "usertestgroup", "name": "user test group", "app_label": "student"}}, {"pk": 137, "model": "contenttypes.contenttype", "fields": {"model": "video", "name": "video", "app_label": "edxval"}}, {"pk": 146, "model": "contenttypes.contenttype", "fields": {"model": "videouploadconfig", "name": "video upload config", "app_label": "contentstore"}}, {"pk": 13, "model": "contenttypes.contenttype", "fields": {"model": "workerstate", "name": "worker", "app_label": "djcelery"}}, {"pk": 111, "model": "contenttypes.contenttype", "fields": {"model": "xblockasidesconfig", "name": "x block asides config", "app_label": "lms_xblock"}}, {"pk": 30, "model": "contenttypes.contenttype", "fields": {"model": "xmodulestudentinfofield", "name": "x module student info field", "app_label": "courseware"}}, {"pk": 29, "model": "contenttypes.contenttype", "fields": {"model": "xmodulestudentprefsfield", "name": "x module student prefs field", "app_label": "courseware"}}, {"pk": 28, "model": "contenttypes.contenttype", "fields": {"model": "xmoduleuserstatesummaryfield", "name": "x module user state summary field", "app_label": "courseware"}}, {"pk": 1, "model": "sites.site", "fields": {"domain": "example.com", "name": "example.com"}}, {"pk": 1, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:15Z", "app_name": "courseware", "migration": "0001_initial"}}, {"pk": 2, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:15Z", "app_name": "courseware", "migration": "0002_add_indexes"}}, {"pk": 3, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:15Z", "app_name": "courseware", "migration": "0003_done_grade_cache"}}, {"pk": 4, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:15Z", "app_name": "courseware", "migration": "0004_add_field_studentmodule_course_id"}}, {"pk": 5, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:15Z", "app_name": "courseware", "migration": "0005_auto__add_offlinecomputedgrade__add_unique_offlinecomputedgrade_user_c"}}, {"pk": 6, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:15Z", "app_name": "courseware", "migration": "0006_create_student_module_history"}}, {"pk": 7, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:15Z", "app_name": "courseware", "migration": "0007_allow_null_version_in_history"}}, {"pk": 8, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:16Z", "app_name": "courseware", "migration": "0008_add_xmodule_storage"}}, {"pk": 9, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:16Z", "app_name": "courseware", "migration": "0009_add_field_default"}}, {"pk": 10, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:16Z", "app_name": "courseware", "migration": "0010_rename_xblock_field_content_to_user_state_summary"}}, {"pk": 11, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:16Z", "app_name": "student", "migration": "0001_initial"}}, {"pk": 12, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:16Z", "app_name": "student", "migration": "0002_text_to_varchar_and_indexes"}}, {"pk": 13, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0003_auto__add_usertestgroup"}}, {"pk": 14, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0004_add_email_index"}}, {"pk": 15, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0005_name_change"}}, {"pk": 16, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0006_expand_meta_field"}}, {"pk": 17, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0007_convert_to_utf8"}}, {"pk": 18, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0008__auto__add_courseregistration"}}, {"pk": 19, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0009_auto__del_courseregistration__add_courseenrollment"}}, {"pk": 20, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0010_auto__chg_field_courseenrollment_course_id"}}, {"pk": 21, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0011_auto__chg_field_courseenrollment_user__del_unique_courseenrollment_use"}}, {"pk": 22, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0012_auto__add_field_userprofile_gender__add_field_userprofile_date_of_birt"}}, {"pk": 23, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0013_auto__chg_field_userprofile_meta"}}, {"pk": 24, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0014_auto__del_courseenrollment"}}, {"pk": 25, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0015_auto__add_courseenrollment__add_unique_courseenrollment_user_course_id"}}, {"pk": 26, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0016_auto__add_field_courseenrollment_date__chg_field_userprofile_country"}}, {"pk": 27, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0017_rename_date_to_created"}}, {"pk": 28, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0018_auto"}}, {"pk": 29, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0019_create_approved_demographic_fields_fall_2012"}}, {"pk": 30, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:18Z", "app_name": "student", "migration": "0020_add_test_center_user"}}, {"pk": 31, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:18Z", "app_name": "student", "migration": "0021_remove_askbot"}}, {"pk": 32, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:18Z", "app_name": "student", "migration": "0022_auto__add_courseenrollmentallowed__add_unique_courseenrollmentallowed_"}}, {"pk": 33, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:18Z", "app_name": "student", "migration": "0023_add_test_center_registration"}}, {"pk": 34, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:18Z", "app_name": "student", "migration": "0024_add_allow_certificate"}}, {"pk": 35, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:18Z", "app_name": "student", "migration": "0025_auto__add_field_courseenrollmentallowed_auto_enroll"}}, {"pk": 36, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:18Z", "app_name": "student", "migration": "0026_auto__remove_index_student_testcenterregistration_accommodation_request"}}, {"pk": 37, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:18Z", "app_name": "student", "migration": "0027_add_active_flag_and_mode_to_courseware_enrollment"}}, {"pk": 38, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:19Z", "app_name": "student", "migration": "0028_auto__add_userstanding"}}, {"pk": 39, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:19Z", "app_name": "student", "migration": "0029_add_lookup_table_between_user_and_anonymous_student_id"}}, {"pk": 40, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:19Z", "app_name": "student", "migration": "0029_remove_pearson"}}, {"pk": 41, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:19Z", "app_name": "student", "migration": "0030_auto__chg_field_anonymoususerid_anonymous_user_id"}}, {"pk": 42, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:19Z", "app_name": "student", "migration": "0031_drop_student_anonymoususerid_temp_archive"}}, {"pk": 43, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:19Z", "app_name": "student", "migration": "0032_add_field_UserProfile_country_add_field_UserProfile_city"}}, {"pk": 44, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:19Z", "app_name": "student", "migration": "0032_auto__add_loginfailures"}}, {"pk": 45, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:19Z", "app_name": "student", "migration": "0033_auto__add_passwordhistory"}}, {"pk": 46, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:19Z", "app_name": "student", "migration": "0034_auto__add_courseaccessrole"}}, {"pk": 47, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "student", "migration": "0035_access_roles"}}, {"pk": 48, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "student", "migration": "0036_access_roles_orgless"}}, {"pk": 49, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "student", "migration": "0037_auto__add_courseregistrationcode"}}, {"pk": 50, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "student", "migration": "0038_auto__add_usersignupsource"}}, {"pk": 51, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "student", "migration": "0039_auto__del_courseregistrationcode"}}, {"pk": 52, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "student", "migration": "0040_auto__del_field_usersignupsource_user_id__add_field_usersignupsource_u"}}, {"pk": 53, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "student", "migration": "0041_add_dashboard_config"}}, {"pk": 54, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "student", "migration": "0042_grant_sales_admin_roles"}}, {"pk": 55, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "track", "migration": "0001_initial"}}, {"pk": 56, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "track", "migration": "0002_auto__add_field_trackinglog_host__chg_field_trackinglog_event_type__ch"}}, {"pk": 57, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0001_added_generatedcertificates"}}, {"pk": 58, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0002_auto__add_field_generatedcertificate_download_url"}}, {"pk": 59, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0003_auto__add_field_generatedcertificate_enabled"}}, {"pk": 60, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0004_auto__add_field_generatedcertificate_graded_certificate_id__add_field_"}}, {"pk": 61, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0005_auto__add_field_generatedcertificate_name"}}, {"pk": 62, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0006_auto__chg_field_generatedcertificate_certificate_id"}}, {"pk": 63, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0007_auto__add_revokedcertificate"}}, {"pk": 64, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0008_auto__del_revokedcertificate__del_field_generatedcertificate_name__add"}}, {"pk": 65, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0009_auto__del_field_generatedcertificate_graded_download_url__del_field_ge"}}, {"pk": 66, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0010_auto__del_field_generatedcertificate_enabled__add_field_generatedcerti"}}, {"pk": 67, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0011_auto__del_field_generatedcertificate_certificate_id__add_field_generat"}}, {"pk": 68, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0012_auto__add_field_generatedcertificate_name__add_field_generatedcertific"}}, {"pk": 69, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0013_auto__add_field_generatedcertificate_error_reason"}}, {"pk": 70, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0014_adding_whitelist"}}, {"pk": 71, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0015_adding_mode_for_verified_certs"}}, {"pk": 72, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:22Z", "app_name": "instructor_task", "migration": "0001_initial"}}, {"pk": 73, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:22Z", "app_name": "instructor_task", "migration": "0002_add_subtask_field"}}, {"pk": 74, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:22Z", "app_name": "licenses", "migration": "0001_initial"}}, {"pk": 75, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:22Z", "app_name": "course_groups", "migration": "0001_initial"}}, {"pk": 76, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:22Z", "app_name": "course_groups", "migration": "0002_add_model_CourseUserGroupPartitionGroup"}}, {"pk": 77, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0001_initial"}}, {"pk": 78, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0002_change_field_names"}}, {"pk": 79, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0003_add_optout_user"}}, {"pk": 80, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0004_migrate_optout_user"}}, {"pk": 81, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0005_remove_optout_email"}}, {"pk": 82, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0006_add_course_email_template"}}, {"pk": 83, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0007_load_course_email_template"}}, {"pk": 84, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0008_add_course_authorizations"}}, {"pk": 85, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0009_force_unique_course_ids"}}, {"pk": 86, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0010_auto__chg_field_optout_course_id__add_field_courseemail_template_name_"}}, {"pk": 87, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "external_auth", "migration": "0001_initial"}}, {"pk": 88, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:24Z", "app_name": "oauth2", "migration": "0001_initial"}}, {"pk": 89, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:24Z", "app_name": "oauth2", "migration": "0002_auto__chg_field_client_user"}}, {"pk": 90, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:24Z", "app_name": "oauth2", "migration": "0003_auto__add_field_client_name"}}, {"pk": 91, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:24Z", "app_name": "oauth2", "migration": "0004_auto__add_index_accesstoken_token"}}, {"pk": 92, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:24Z", "app_name": "oauth2_provider", "migration": "0001_initial"}}, {"pk": 93, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:25Z", "app_name": "wiki", "migration": "0001_initial"}}, {"pk": 94, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:25Z", "app_name": "wiki", "migration": "0002_auto__add_field_articleplugin_created"}}, {"pk": 95, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:25Z", "app_name": "wiki", "migration": "0003_auto__add_field_urlpath_article"}}, {"pk": 96, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:25Z", "app_name": "wiki", "migration": "0004_populate_urlpath__article"}}, {"pk": 97, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:25Z", "app_name": "wiki", "migration": "0005_auto__chg_field_urlpath_article"}}, {"pk": 98, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:26Z", "app_name": "wiki", "migration": "0006_auto__add_attachmentrevision__add_image__add_attachment"}}, {"pk": 99, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:26Z", "app_name": "wiki", "migration": "0007_auto__add_articlesubscription"}}, {"pk": 100, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:26Z", "app_name": "wiki", "migration": "0008_auto__add_simpleplugin__add_revisionpluginrevision__add_imagerevision_"}}, {"pk": 101, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:26Z", "app_name": "wiki", "migration": "0009_auto__add_field_imagerevision_width__add_field_imagerevision_height"}}, {"pk": 102, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:26Z", "app_name": "wiki", "migration": "0010_auto__chg_field_imagerevision_image"}}, {"pk": 103, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:26Z", "app_name": "wiki", "migration": "0011_auto__chg_field_imagerevision_width__chg_field_imagerevision_height"}}, {"pk": 104, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:27Z", "app_name": "django_notify", "migration": "0001_initial"}}, {"pk": 105, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:27Z", "app_name": "notifications", "migration": "0001_initial"}}, {"pk": 106, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:27Z", "app_name": "foldit", "migration": "0001_initial"}}, {"pk": 107, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:28Z", "app_name": "django_comment_client", "migration": "0001_initial"}}, {"pk": 108, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:28Z", "app_name": "django_comment_common", "migration": "0001_initial"}}, {"pk": 109, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:29Z", "app_name": "notes", "migration": "0001_initial"}}, {"pk": 110, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:29Z", "app_name": "splash", "migration": "0001_initial"}}, {"pk": 111, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:29Z", "app_name": "splash", "migration": "0002_auto__add_field_splashconfig_unaffected_url_paths"}}, {"pk": 112, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:29Z", "app_name": "user_api", "migration": "0001_initial"}}, {"pk": 113, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "user_api", "migration": "0002_auto__add_usercoursetags__add_unique_usercoursetags_user_course_id_key"}}, {"pk": 114, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "user_api", "migration": "0003_rename_usercoursetags"}}, {"pk": 115, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "user_api", "migration": "0004_auto__add_userorgtag__add_unique_userorgtag_user_org_key__chg_field_us"}}, {"pk": 116, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "shoppingcart", "migration": "0001_initial"}}, {"pk": 117, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "shoppingcart", "migration": "0002_auto__add_field_paidcourseregistration_mode"}}, {"pk": 118, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "shoppingcart", "migration": "0003_auto__del_field_orderitem_line_cost"}}, {"pk": 119, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "shoppingcart", "migration": "0004_auto__add_field_orderitem_fulfilled_time"}}, {"pk": 120, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "shoppingcart", "migration": "0005_auto__add_paidcourseregistrationannotation__add_field_orderitem_report"}}, {"pk": 121, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "shoppingcart", "migration": "0006_auto__add_field_order_refunded_time__add_field_orderitem_refund_reques"}}, {"pk": 122, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "shoppingcart", "migration": "0007_auto__add_field_orderitem_service_fee"}}, {"pk": 123, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:31Z", "app_name": "shoppingcart", "migration": "0008_auto__add_coupons__add_couponredemption__chg_field_certificateitem_cou"}}, {"pk": 124, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:31Z", "app_name": "shoppingcart", "migration": "0009_auto__del_coupons__add_courseregistrationcode__add_coupon__chg_field_c"}}, {"pk": 125, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:31Z", "app_name": "shoppingcart", "migration": "0010_auto__add_registrationcoderedemption__del_field_courseregistrationcode"}}, {"pk": 126, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:31Z", "app_name": "shoppingcart", "migration": "0011_auto__add_invoice__add_field_courseregistrationcode_invoice"}}, {"pk": 127, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:31Z", "app_name": "shoppingcart", "migration": "0012_auto__del_field_courseregistrationcode_transaction_group_name__del_fie"}}, {"pk": 128, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:32Z", "app_name": "shoppingcart", "migration": "0013_auto__add_field_invoice_is_valid"}}, {"pk": 129, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:32Z", "app_name": "shoppingcart", "migration": "0014_auto__del_field_invoice_tax_id__add_field_invoice_address_line_1__add_"}}, {"pk": 130, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:32Z", "app_name": "shoppingcart", "migration": "0015_auto__del_field_invoice_purchase_order_number__del_field_invoice_compa"}}, {"pk": 131, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:32Z", "app_name": "shoppingcart", "migration": "0016_auto__del_field_invoice_company_email__del_field_invoice_company_refer"}}, {"pk": 132, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:32Z", "app_name": "shoppingcart", "migration": "0017_auto__add_field_courseregistrationcode_order__chg_field_registrationco"}}, {"pk": 133, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:32Z", "app_name": "shoppingcart", "migration": "0018_auto__add_donation"}}, {"pk": 134, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:32Z", "app_name": "shoppingcart", "migration": "0019_auto__add_donationconfiguration"}}, {"pk": 135, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:33Z", "app_name": "shoppingcart", "migration": "0020_auto__add_courseregcodeitem__add_courseregcodeitemannotation__add_fiel"}}, {"pk": 136, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:33Z", "app_name": "shoppingcart", "migration": "0021_auto__add_field_orderitem_created__add_field_orderitem_modified"}}, {"pk": 137, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:33Z", "app_name": "shoppingcart", "migration": "0022_auto__add_field_registrationcoderedemption_course_enrollment__add_fiel"}}, {"pk": 138, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:33Z", "app_name": "shoppingcart", "migration": "0023_auto__add_field_coupon_expiration_date"}}, {"pk": 139, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:33Z", "app_name": "shoppingcart", "migration": "0024_auto__add_field_courseregistrationcode_mode_slug"}}, {"pk": 140, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:33Z", "app_name": "course_modes", "migration": "0001_initial"}}, {"pk": 141, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:33Z", "app_name": "course_modes", "migration": "0002_auto__add_field_coursemode_currency"}}, {"pk": 142, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:33Z", "app_name": "course_modes", "migration": "0003_auto__add_unique_coursemode_course_id_currency_mode_slug"}}, {"pk": 143, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:34Z", "app_name": "course_modes", "migration": "0004_auto__add_field_coursemode_expiration_date"}}, {"pk": 144, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:34Z", "app_name": "course_modes", "migration": "0005_auto__add_field_coursemode_expiration_datetime"}}, {"pk": 145, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:34Z", "app_name": "course_modes", "migration": "0006_expiration_date_to_datetime"}}, {"pk": 146, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:34Z", "app_name": "course_modes", "migration": "0007_add_description"}}, {"pk": 147, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:34Z", "app_name": "course_modes", "migration": "0007_auto__add_coursemodesarchive__chg_field_coursemode_course_id"}}, {"pk": 148, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:34Z", "app_name": "verify_student", "migration": "0001_initial"}}, {"pk": 149, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:34Z", "app_name": "verify_student", "migration": "0002_auto__add_field_softwaresecurephotoverification_window"}}, {"pk": 150, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:34Z", "app_name": "verify_student", "migration": "0003_auto__add_field_softwaresecurephotoverification_display"}}, {"pk": 151, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:35Z", "app_name": "dark_lang", "migration": "0001_initial"}}, {"pk": 152, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:35Z", "app_name": "dark_lang", "migration": "0002_enable_on_install"}}, {"pk": 153, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:35Z", "app_name": "reverification", "migration": "0001_initial"}}, {"pk": 154, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:35Z", "app_name": "embargo", "migration": "0001_initial"}}, {"pk": 155, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:36Z", "app_name": "course_action_state", "migration": "0001_initial"}}, {"pk": 156, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:36Z", "app_name": "course_action_state", "migration": "0002_add_rerun_display_name"}}, {"pk": 157, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:36Z", "app_name": "survey", "migration": "0001_initial"}}, {"pk": 158, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:37Z", "app_name": "lms_xblock", "migration": "0001_initial"}}, {"pk": 159, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:37Z", "app_name": "mentoring", "migration": "0001_initial"}}, {"pk": 160, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:37Z", "app_name": "mentoring", "migration": "0002_auto__add_field_answer_course_id__chg_field_answer_student_id"}}, {"pk": 161, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:37Z", "app_name": "mentoring", "migration": "0003_auto__del_unique_answer_student_id_name__add_unique_answer_course_id_s"}}, {"pk": 162, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:37Z", "app_name": "mentoring", "migration": "0004_auto__add_lightchild__add_unique_lightchild_student_id_course_id_name"}}, {"pk": 163, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:37Z", "app_name": "mentoring", "migration": "0005_auto__chg_field_lightchild_name"}}, {"pk": 164, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:38Z", "app_name": "submissions", "migration": "0001_initial"}}, {"pk": 165, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:38Z", "app_name": "submissions", "migration": "0002_auto__add_scoresummary"}}, {"pk": 166, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:38Z", "app_name": "submissions", "migration": "0003_auto__del_field_submission_answer__add_field_submission_raw_answer"}}, {"pk": 167, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:38Z", "app_name": "submissions", "migration": "0004_auto__add_field_score_reset"}}, {"pk": 168, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:39Z", "app_name": "assessment", "migration": "0001_initial"}}, {"pk": 169, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:39Z", "app_name": "assessment", "migration": "0002_auto__add_assessmentfeedbackoption__del_field_assessmentfeedback_feedb"}}, {"pk": 170, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:39Z", "app_name": "assessment", "migration": "0003_add_index_pw_course_item_student"}}, {"pk": 171, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:39Z", "app_name": "assessment", "migration": "0004_auto__add_field_peerworkflow_graded_count"}}, {"pk": 172, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:39Z", "app_name": "assessment", "migration": "0005_auto__del_field_peerworkflow_graded_count__add_field_peerworkflow_grad"}}, {"pk": 173, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:39Z", "app_name": "assessment", "migration": "0006_auto__add_field_assessmentpart_feedback"}}, {"pk": 174, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:39Z", "app_name": "assessment", "migration": "0007_auto__chg_field_assessmentpart_feedback"}}, {"pk": 175, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:40Z", "app_name": "assessment", "migration": "0008_student_training"}}, {"pk": 176, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:40Z", "app_name": "assessment", "migration": "0009_auto__add_unique_studenttrainingworkflowitem_order_num_workflow"}}, {"pk": 177, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:40Z", "app_name": "assessment", "migration": "0010_auto__add_unique_studenttrainingworkflow_submission_uuid"}}, {"pk": 178, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:40Z", "app_name": "assessment", "migration": "0011_ai_training"}}, {"pk": 179, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:40Z", "app_name": "assessment", "migration": "0012_move_algorithm_id_to_classifier_set"}}, {"pk": 180, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:40Z", "app_name": "assessment", "migration": "0013_auto__add_field_aigradingworkflow_essay_text"}}, {"pk": 181, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:40Z", "app_name": "assessment", "migration": "0014_auto__add_field_aitrainingworkflow_item_id__add_field_aitrainingworkfl"}}, {"pk": 182, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:40Z", "app_name": "assessment", "migration": "0015_auto__add_unique_aitrainingworkflow_uuid__add_unique_aigradingworkflow"}}, {"pk": 183, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:41Z", "app_name": "assessment", "migration": "0016_auto__add_field_aiclassifierset_course_id__add_field_aiclassifierset_i"}}, {"pk": 184, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:41Z", "app_name": "assessment", "migration": "0016_auto__add_field_rubric_structure_hash"}}, {"pk": 185, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:41Z", "app_name": "assessment", "migration": "0017_rubric_structure_hash"}}, {"pk": 186, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:41Z", "app_name": "assessment", "migration": "0018_auto__add_field_assessmentpart_criterion"}}, {"pk": 187, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:41Z", "app_name": "assessment", "migration": "0019_assessmentpart_criterion_field"}}, {"pk": 188, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:41Z", "app_name": "assessment", "migration": "0020_assessmentpart_criterion_not_null"}}, {"pk": 189, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:41Z", "app_name": "assessment", "migration": "0021_assessmentpart_option_nullable"}}, {"pk": 190, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:41Z", "app_name": "assessment", "migration": "0022__add_label_fields"}}, {"pk": 191, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:41Z", "app_name": "assessment", "migration": "0023_assign_criteria_and_option_labels"}}, {"pk": 192, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:42Z", "app_name": "assessment", "migration": "0024_auto__chg_field_assessmentpart_criterion"}}, {"pk": 193, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:42Z", "app_name": "workflow", "migration": "0001_initial"}}, {"pk": 194, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:42Z", "app_name": "workflow", "migration": "0002_auto__add_field_assessmentworkflow_course_id__add_field_assessmentwork"}}, {"pk": 195, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:42Z", "app_name": "workflow", "migration": "0003_auto__add_assessmentworkflowstep"}}, {"pk": 196, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:42Z", "app_name": "edxval", "migration": "0001_initial"}}, {"pk": 197, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:43Z", "app_name": "edxval", "migration": "0002_default_profiles"}}, {"pk": 198, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:43Z", "app_name": "edxval", "migration": "0003_status_and_created_fields"}}, {"pk": 199, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:43Z", "app_name": "milestones", "migration": "0001_initial"}}, {"pk": 200, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:43Z", "app_name": "milestones", "migration": "0002_seed_relationship_types"}}, {"pk": 201, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:43Z", "app_name": "django_extensions", "migration": "0001_empty"}}, {"pk": 202, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:46Z", "app_name": "contentstore", "migration": "0001_initial"}}, {"pk": 203, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:46Z", "app_name": "course_creators", "migration": "0001_initial"}}, {"pk": 204, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:46Z", "app_name": "xblock_config", "migration": "0001_initial"}}, {"pk": 1, "model": "edxval.profile", "fields": {"width": 1280, "profile_name": "desktop_mp4", "extension": "mp4", "height": 720}}, {"pk": 2, "model": "edxval.profile", "fields": {"width": 1280, "profile_name": "desktop_webm", "extension": "webm", "height": 720}}, {"pk": 3, "model": "edxval.profile", "fields": {"width": 960, "profile_name": "mobile_high", "extension": "mp4", "height": 540}}, {"pk": 4, "model": "edxval.profile", "fields": {"width": 640, "profile_name": "mobile_low", "extension": "mp4", "height": 360}}, {"pk": 5, "model": "edxval.profile", "fields": {"width": 1920, "profile_name": "youtube", "extension": "mp4", "height": 1080}}, {"pk": 1, "model": "milestones.milestonerelationshiptype", "fields": {"active": true, "description": "Autogenerated milestone relationship type \"fulfills\"", "modified": "2015-01-15T03:15:43Z", "name": "fulfills", "created": "2015-01-15T03:15:43Z"}}, {"pk": 2, "model": "milestones.milestonerelationshiptype", "fields": {"active": true, "description": "Autogenerated milestone relationship type \"requires\"", "modified": "2015-01-15T03:15:43Z", "name": "requires", "created": "2015-01-15T03:15:43Z"}}, {"pk": 61, "model": "auth.permission", "fields": {"codename": "add_logentry", "name": "Can add log entry", "content_type": 21}}, {"pk": 62, "model": "auth.permission", "fields": {"codename": "change_logentry", "name": "Can change log entry", "content_type": 21}}, {"pk": 63, "model": "auth.permission", "fields": {"codename": "delete_logentry", "name": "Can delete log entry", "content_type": 21}}, {"pk": 394, "model": "auth.permission", "fields": {"codename": "add_aiclassifier", "name": "Can add ai classifier", "content_type": 131}}, {"pk": 395, "model": "auth.permission", "fields": {"codename": "change_aiclassifier", "name": "Can change ai classifier", "content_type": 131}}, {"pk": 396, "model": "auth.permission", "fields": {"codename": "delete_aiclassifier", "name": "Can delete ai classifier", "content_type": 131}}, {"pk": 391, "model": "auth.permission", "fields": {"codename": "add_aiclassifierset", "name": "Can add ai classifier set", "content_type": 130}}, {"pk": 392, "model": "auth.permission", "fields": {"codename": "change_aiclassifierset", "name": "Can change ai classifier set", "content_type": 130}}, {"pk": 393, "model": "auth.permission", "fields": {"codename": "delete_aiclassifierset", "name": "Can delete ai classifier set", "content_type": 130}}, {"pk": 400, "model": "auth.permission", "fields": {"codename": "add_aigradingworkflow", "name": "Can add ai grading workflow", "content_type": 133}}, {"pk": 401, "model": "auth.permission", "fields": {"codename": "change_aigradingworkflow", "name": "Can change ai grading workflow", "content_type": 133}}, {"pk": 402, "model": "auth.permission", "fields": {"codename": "delete_aigradingworkflow", "name": "Can delete ai grading workflow", "content_type": 133}}, {"pk": 397, "model": "auth.permission", "fields": {"codename": "add_aitrainingworkflow", "name": "Can add ai training workflow", "content_type": 132}}, {"pk": 398, "model": "auth.permission", "fields": {"codename": "change_aitrainingworkflow", "name": "Can change ai training workflow", "content_type": 132}}, {"pk": 399, "model": "auth.permission", "fields": {"codename": "delete_aitrainingworkflow", "name": "Can delete ai training workflow", "content_type": 132}}, {"pk": 364, "model": "auth.permission", "fields": {"codename": "add_assessment", "name": "Can add assessment", "content_type": 121}}, {"pk": 365, "model": "auth.permission", "fields": {"codename": "change_assessment", "name": "Can change assessment", "content_type": 121}}, {"pk": 366, "model": "auth.permission", "fields": {"codename": "delete_assessment", "name": "Can delete assessment", "content_type": 121}}, {"pk": 373, "model": "auth.permission", "fields": {"codename": "add_assessmentfeedback", "name": "Can add assessment feedback", "content_type": 124}}, {"pk": 374, "model": "auth.permission", "fields": {"codename": "change_assessmentfeedback", "name": "Can change assessment feedback", "content_type": 124}}, {"pk": 375, "model": "auth.permission", "fields": {"codename": "delete_assessmentfeedback", "name": "Can delete assessment feedback", "content_type": 124}}, {"pk": 370, "model": "auth.permission", "fields": {"codename": "add_assessmentfeedbackoption", "name": "Can add assessment feedback option", "content_type": 123}}, {"pk": 371, "model": "auth.permission", "fields": {"codename": "change_assessmentfeedbackoption", "name": "Can change assessment feedback option", "content_type": 123}}, {"pk": 372, "model": "auth.permission", "fields": {"codename": "delete_assessmentfeedbackoption", "name": "Can delete assessment feedback option", "content_type": 123}}, {"pk": 367, "model": "auth.permission", "fields": {"codename": "add_assessmentpart", "name": "Can add assessment part", "content_type": 122}}, {"pk": 368, "model": "auth.permission", "fields": {"codename": "change_assessmentpart", "name": "Can change assessment part", "content_type": 122}}, {"pk": 369, "model": "auth.permission", "fields": {"codename": "delete_assessmentpart", "name": "Can delete assessment part", "content_type": 122}}, {"pk": 358, "model": "auth.permission", "fields": {"codename": "add_criterion", "name": "Can add criterion", "content_type": 119}}, {"pk": 359, "model": "auth.permission", "fields": {"codename": "change_criterion", "name": "Can change criterion", "content_type": 119}}, {"pk": 360, "model": "auth.permission", "fields": {"codename": "delete_criterion", "name": "Can delete criterion", "content_type": 119}}, {"pk": 361, "model": "auth.permission", "fields": {"codename": "add_criterionoption", "name": "Can add criterion option", "content_type": 120}}, {"pk": 362, "model": "auth.permission", "fields": {"codename": "change_criterionoption", "name": "Can change criterion option", "content_type": 120}}, {"pk": 363, "model": "auth.permission", "fields": {"codename": "delete_criterionoption", "name": "Can delete criterion option", "content_type": 120}}, {"pk": 376, "model": "auth.permission", "fields": {"codename": "add_peerworkflow", "name": "Can add peer workflow", "content_type": 125}}, {"pk": 377, "model": "auth.permission", "fields": {"codename": "change_peerworkflow", "name": "Can change peer workflow", "content_type": 125}}, {"pk": 378, "model": "auth.permission", "fields": {"codename": "delete_peerworkflow", "name": "Can delete peer workflow", "content_type": 125}}, {"pk": 379, "model": "auth.permission", "fields": {"codename": "add_peerworkflowitem", "name": "Can add peer workflow item", "content_type": 126}}, {"pk": 380, "model": "auth.permission", "fields": {"codename": "change_peerworkflowitem", "name": "Can change peer workflow item", "content_type": 126}}, {"pk": 381, "model": "auth.permission", "fields": {"codename": "delete_peerworkflowitem", "name": "Can delete peer workflow item", "content_type": 126}}, {"pk": 355, "model": "auth.permission", "fields": {"codename": "add_rubric", "name": "Can add rubric", "content_type": 118}}, {"pk": 356, "model": "auth.permission", "fields": {"codename": "change_rubric", "name": "Can change rubric", "content_type": 118}}, {"pk": 357, "model": "auth.permission", "fields": {"codename": "delete_rubric", "name": "Can delete rubric", "content_type": 118}}, {"pk": 385, "model": "auth.permission", "fields": {"codename": "add_studenttrainingworkflow", "name": "Can add student training workflow", "content_type": 128}}, {"pk": 386, "model": "auth.permission", "fields": {"codename": "change_studenttrainingworkflow", "name": "Can change student training workflow", "content_type": 128}}, {"pk": 387, "model": "auth.permission", "fields": {"codename": "delete_studenttrainingworkflow", "name": "Can delete student training workflow", "content_type": 128}}, {"pk": 388, "model": "auth.permission", "fields": {"codename": "add_studenttrainingworkflowitem", "name": "Can add student training workflow item", "content_type": 129}}, {"pk": 389, "model": "auth.permission", "fields": {"codename": "change_studenttrainingworkflowitem", "name": "Can change student training workflow item", "content_type": 129}}, {"pk": 390, "model": "auth.permission", "fields": {"codename": "delete_studenttrainingworkflowitem", "name": "Can delete student training workflow item", "content_type": 129}}, {"pk": 382, "model": "auth.permission", "fields": {"codename": "add_trainingexample", "name": "Can add training example", "content_type": 127}}, {"pk": 383, "model": "auth.permission", "fields": {"codename": "change_trainingexample", "name": "Can change training example", "content_type": 127}}, {"pk": 384, "model": "auth.permission", "fields": {"codename": "delete_trainingexample", "name": "Can delete training example", "content_type": 127}}, {"pk": 4, "model": "auth.permission", "fields": {"codename": "add_group", "name": "Can add group", "content_type": 2}}, {"pk": 5, "model": "auth.permission", "fields": {"codename": "change_group", "name": "Can change group", "content_type": 2}}, {"pk": 6, "model": "auth.permission", "fields": {"codename": "delete_group", "name": "Can delete group", "content_type": 2}}, {"pk": 1, "model": "auth.permission", "fields": {"codename": "add_permission", "name": "Can add permission", "content_type": 1}}, {"pk": 2, "model": "auth.permission", "fields": {"codename": "change_permission", "name": "Can change permission", "content_type": 1}}, {"pk": 3, "model": "auth.permission", "fields": {"codename": "delete_permission", "name": "Can delete permission", "content_type": 1}}, {"pk": 7, "model": "auth.permission", "fields": {"codename": "add_user", "name": "Can add user", "content_type": 3}}, {"pk": 8, "model": "auth.permission", "fields": {"codename": "change_user", "name": "Can change user", "content_type": 3}}, {"pk": 9, "model": "auth.permission", "fields": {"codename": "delete_user", "name": "Can delete user", "content_type": 3}}, {"pk": 172, "model": "auth.permission", "fields": {"codename": "add_courseauthorization", "name": "Can add course authorization", "content_type": 58}}, {"pk": 173, "model": "auth.permission", "fields": {"codename": "change_courseauthorization", "name": "Can change course authorization", "content_type": 58}}, {"pk": 174, "model": "auth.permission", "fields": {"codename": "delete_courseauthorization", "name": "Can delete course authorization", "content_type": 58}}, {"pk": 163, "model": "auth.permission", "fields": {"codename": "add_courseemail", "name": "Can add course email", "content_type": 55}}, {"pk": 164, "model": "auth.permission", "fields": {"codename": "change_courseemail", "name": "Can change course email", "content_type": 55}}, {"pk": 165, "model": "auth.permission", "fields": {"codename": "delete_courseemail", "name": "Can delete course email", "content_type": 55}}, {"pk": 169, "model": "auth.permission", "fields": {"codename": "add_courseemailtemplate", "name": "Can add course email template", "content_type": 57}}, {"pk": 170, "model": "auth.permission", "fields": {"codename": "change_courseemailtemplate", "name": "Can change course email template", "content_type": 57}}, {"pk": 171, "model": "auth.permission", "fields": {"codename": "delete_courseemailtemplate", "name": "Can delete course email template", "content_type": 57}}, {"pk": 166, "model": "auth.permission", "fields": {"codename": "add_optout", "name": "Can add optout", "content_type": 56}}, {"pk": 167, "model": "auth.permission", "fields": {"codename": "change_optout", "name": "Can change optout", "content_type": 56}}, {"pk": 168, "model": "auth.permission", "fields": {"codename": "delete_optout", "name": "Can delete optout", "content_type": 56}}, {"pk": 142, "model": "auth.permission", "fields": {"codename": "add_certificatewhitelist", "name": "Can add certificate whitelist", "content_type": 48}}, {"pk": 143, "model": "auth.permission", "fields": {"codename": "change_certificatewhitelist", "name": "Can change certificate whitelist", "content_type": 48}}, {"pk": 144, "model": "auth.permission", "fields": {"codename": "delete_certificatewhitelist", "name": "Can delete certificate whitelist", "content_type": 48}}, {"pk": 145, "model": "auth.permission", "fields": {"codename": "add_generatedcertificate", "name": "Can add generated certificate", "content_type": 49}}, {"pk": 146, "model": "auth.permission", "fields": {"codename": "change_generatedcertificate", "name": "Can change generated certificate", "content_type": 49}}, {"pk": 147, "model": "auth.permission", "fields": {"codename": "delete_generatedcertificate", "name": "Can delete generated certificate", "content_type": 49}}, {"pk": 46, "model": "auth.permission", "fields": {"codename": "add_servercircuit", "name": "Can add server circuit", "content_type": 16}}, {"pk": 47, "model": "auth.permission", "fields": {"codename": "change_servercircuit", "name": "Can change server circuit", "content_type": 16}}, {"pk": 48, "model": "auth.permission", "fields": {"codename": "delete_servercircuit", "name": "Can delete server circuit", "content_type": 16}}, {"pk": 439, "model": "auth.permission", "fields": {"codename": "add_videouploadconfig", "name": "Can add video upload config", "content_type": 146}}, {"pk": 440, "model": "auth.permission", "fields": {"codename": "change_videouploadconfig", "name": "Can change video upload config", "content_type": 146}}, {"pk": 441, "model": "auth.permission", "fields": {"codename": "delete_videouploadconfig", "name": "Can delete video upload config", "content_type": 146}}, {"pk": 10, "model": "auth.permission", "fields": {"codename": "add_contenttype", "name": "Can add content type", "content_type": 4}}, {"pk": 11, "model": "auth.permission", "fields": {"codename": "change_contenttype", "name": "Can change content type", "content_type": 4}}, {"pk": 12, "model": "auth.permission", "fields": {"codename": "delete_contenttype", "name": "Can delete content type", "content_type": 4}}, {"pk": 91, "model": "auth.permission", "fields": {"codename": "add_offlinecomputedgrade", "name": "Can add offline computed grade", "content_type": 31}}, {"pk": 92, "model": "auth.permission", "fields": {"codename": "change_offlinecomputedgrade", "name": "Can change offline computed grade", "content_type": 31}}, {"pk": 93, "model": "auth.permission", "fields": {"codename": "delete_offlinecomputedgrade", "name": "Can delete offline computed grade", "content_type": 31}}, {"pk": 94, "model": "auth.permission", "fields": {"codename": "add_offlinecomputedgradelog", "name": "Can add offline computed grade log", "content_type": 32}}, {"pk": 95, "model": "auth.permission", "fields": {"codename": "change_offlinecomputedgradelog", "name": "Can change offline computed grade log", "content_type": 32}}, {"pk": 96, "model": "auth.permission", "fields": {"codename": "delete_offlinecomputedgradelog", "name": "Can delete offline computed grade log", "content_type": 32}}, {"pk": 76, "model": "auth.permission", "fields": {"codename": "add_studentmodule", "name": "Can add student module", "content_type": 26}}, {"pk": 77, "model": "auth.permission", "fields": {"codename": "change_studentmodule", "name": "Can change student module", "content_type": 26}}, {"pk": 78, "model": "auth.permission", "fields": {"codename": "delete_studentmodule", "name": "Can delete student module", "content_type": 26}}, {"pk": 79, "model": "auth.permission", "fields": {"codename": "add_studentmodulehistory", "name": "Can add student module history", "content_type": 27}}, {"pk": 80, "model": "auth.permission", "fields": {"codename": "change_studentmodulehistory", "name": "Can change student module history", "content_type": 27}}, {"pk": 81, "model": "auth.permission", "fields": {"codename": "delete_studentmodulehistory", "name": "Can delete student module history", "content_type": 27}}, {"pk": 88, "model": "auth.permission", "fields": {"codename": "add_xmodulestudentinfofield", "name": "Can add x module student info field", "content_type": 30}}, {"pk": 89, "model": "auth.permission", "fields": {"codename": "change_xmodulestudentinfofield", "name": "Can change x module student info field", "content_type": 30}}, {"pk": 90, "model": "auth.permission", "fields": {"codename": "delete_xmodulestudentinfofield", "name": "Can delete x module student info field", "content_type": 30}}, {"pk": 85, "model": "auth.permission", "fields": {"codename": "add_xmodulestudentprefsfield", "name": "Can add x module student prefs field", "content_type": 29}}, {"pk": 86, "model": "auth.permission", "fields": {"codename": "change_xmodulestudentprefsfield", "name": "Can change x module student prefs field", "content_type": 29}}, {"pk": 87, "model": "auth.permission", "fields": {"codename": "delete_xmodulestudentprefsfield", "name": "Can delete x module student prefs field", "content_type": 29}}, {"pk": 82, "model": "auth.permission", "fields": {"codename": "add_xmoduleuserstatesummaryfield", "name": "Can add x module user state summary field", "content_type": 28}}, {"pk": 83, "model": "auth.permission", "fields": {"codename": "change_xmoduleuserstatesummaryfield", "name": "Can change x module user state summary field", "content_type": 28}}, {"pk": 84, "model": "auth.permission", "fields": {"codename": "delete_xmoduleuserstatesummaryfield", "name": "Can delete x module user state summary field", "content_type": 28}}, {"pk": 325, "model": "auth.permission", "fields": {"codename": "add_coursererunstate", "name": "Can add course rerun state", "content_type": 108}}, {"pk": 326, "model": "auth.permission", "fields": {"codename": "change_coursererunstate", "name": "Can change course rerun state", "content_type": 108}}, {"pk": 327, "model": "auth.permission", "fields": {"codename": "delete_coursererunstate", "name": "Can delete course rerun state", "content_type": 108}}, {"pk": 442, "model": "auth.permission", "fields": {"codename": "add_coursecreator", "name": "Can add course creator", "content_type": 147}}, {"pk": 443, "model": "auth.permission", "fields": {"codename": "change_coursecreator", "name": "Can change course creator", "content_type": 147}}, {"pk": 444, "model": "auth.permission", "fields": {"codename": "delete_coursecreator", "name": "Can delete course creator", "content_type": 147}}, {"pk": 157, "model": "auth.permission", "fields": {"codename": "add_courseusergroup", "name": "Can add course user group", "content_type": 53}}, {"pk": 158, "model": "auth.permission", "fields": {"codename": "change_courseusergroup", "name": "Can change course user group", "content_type": 53}}, {"pk": 159, "model": "auth.permission", "fields": {"codename": "delete_courseusergroup", "name": "Can delete course user group", "content_type": 53}}, {"pk": 160, "model": "auth.permission", "fields": {"codename": "add_courseusergrouppartitiongroup", "name": "Can add course user group partition group", "content_type": 54}}, {"pk": 161, "model": "auth.permission", "fields": {"codename": "change_courseusergrouppartitiongroup", "name": "Can change course user group partition group", "content_type": 54}}, {"pk": 162, "model": "auth.permission", "fields": {"codename": "delete_courseusergrouppartitiongroup", "name": "Can delete course user group partition group", "content_type": 54}}, {"pk": 301, "model": "auth.permission", "fields": {"codename": "add_coursemode", "name": "Can add course mode", "content_type": 100}}, {"pk": 302, "model": "auth.permission", "fields": {"codename": "change_coursemode", "name": "Can change course mode", "content_type": 100}}, {"pk": 303, "model": "auth.permission", "fields": {"codename": "delete_coursemode", "name": "Can delete course mode", "content_type": 100}}, {"pk": 304, "model": "auth.permission", "fields": {"codename": "add_coursemodesarchive", "name": "Can add course modes archive", "content_type": 101}}, {"pk": 305, "model": "auth.permission", "fields": {"codename": "change_coursemodesarchive", "name": "Can change course modes archive", "content_type": 101}}, {"pk": 306, "model": "auth.permission", "fields": {"codename": "delete_coursemodesarchive", "name": "Can delete course modes archive", "content_type": 101}}, {"pk": 310, "model": "auth.permission", "fields": {"codename": "add_darklangconfig", "name": "Can add dark lang config", "content_type": 103}}, {"pk": 311, "model": "auth.permission", "fields": {"codename": "change_darklangconfig", "name": "Can change dark lang config", "content_type": 103}}, {"pk": 312, "model": "auth.permission", "fields": {"codename": "delete_darklangconfig", "name": "Can delete dark lang config", "content_type": 103}}, {"pk": 70, "model": "auth.permission", "fields": {"codename": "add_association", "name": "Can add association", "content_type": 24}}, {"pk": 71, "model": "auth.permission", "fields": {"codename": "change_association", "name": "Can change association", "content_type": 24}}, {"pk": 72, "model": "auth.permission", "fields": {"codename": "delete_association", "name": "Can delete association", "content_type": 24}}, {"pk": 73, "model": "auth.permission", "fields": {"codename": "add_code", "name": "Can add code", "content_type": 25}}, {"pk": 74, "model": "auth.permission", "fields": {"codename": "change_code", "name": "Can change code", "content_type": 25}}, {"pk": 75, "model": "auth.permission", "fields": {"codename": "delete_code", "name": "Can delete code", "content_type": 25}}, {"pk": 67, "model": "auth.permission", "fields": {"codename": "add_nonce", "name": "Can add nonce", "content_type": 23}}, {"pk": 68, "model": "auth.permission", "fields": {"codename": "change_nonce", "name": "Can change nonce", "content_type": 23}}, {"pk": 69, "model": "auth.permission", "fields": {"codename": "delete_nonce", "name": "Can delete nonce", "content_type": 23}}, {"pk": 64, "model": "auth.permission", "fields": {"codename": "add_usersocialauth", "name": "Can add user social auth", "content_type": 22}}, {"pk": 65, "model": "auth.permission", "fields": {"codename": "change_usersocialauth", "name": "Can change user social auth", "content_type": 22}}, {"pk": 66, "model": "auth.permission", "fields": {"codename": "delete_usersocialauth", "name": "Can delete user social auth", "content_type": 22}}, {"pk": 235, "model": "auth.permission", "fields": {"codename": "add_notification", "name": "Can add notification", "content_type": 78}}, {"pk": 236, "model": "auth.permission", "fields": {"codename": "change_notification", "name": "Can change notification", "content_type": 78}}, {"pk": 237, "model": "auth.permission", "fields": {"codename": "delete_notification", "name": "Can delete notification", "content_type": 78}}, {"pk": 226, "model": "auth.permission", "fields": {"codename": "add_notificationtype", "name": "Can add type", "content_type": 75}}, {"pk": 227, "model": "auth.permission", "fields": {"codename": "change_notificationtype", "name": "Can change type", "content_type": 75}}, {"pk": 228, "model": "auth.permission", "fields": {"codename": "delete_notificationtype", "name": "Can delete type", "content_type": 75}}, {"pk": 229, "model": "auth.permission", "fields": {"codename": "add_settings", "name": "Can add settings", "content_type": 76}}, {"pk": 230, "model": "auth.permission", "fields": {"codename": "change_settings", "name": "Can change settings", "content_type": 76}}, {"pk": 231, "model": "auth.permission", "fields": {"codename": "delete_settings", "name": "Can delete settings", "content_type": 76}}, {"pk": 232, "model": "auth.permission", "fields": {"codename": "add_subscription", "name": "Can add subscription", "content_type": 77}}, {"pk": 233, "model": "auth.permission", "fields": {"codename": "change_subscription", "name": "Can change subscription", "content_type": 77}}, {"pk": 234, "model": "auth.permission", "fields": {"codename": "delete_subscription", "name": "Can delete subscription", "content_type": 77}}, {"pk": 55, "model": "auth.permission", "fields": {"codename": "add_association", "name": "Can add association", "content_type": 19}}, {"pk": 56, "model": "auth.permission", "fields": {"codename": "change_association", "name": "Can change association", "content_type": 19}}, {"pk": 57, "model": "auth.permission", "fields": {"codename": "delete_association", "name": "Can delete association", "content_type": 19}}, {"pk": 52, "model": "auth.permission", "fields": {"codename": "add_nonce", "name": "Can add nonce", "content_type": 18}}, {"pk": 53, "model": "auth.permission", "fields": {"codename": "change_nonce", "name": "Can change nonce", "content_type": 18}}, {"pk": 54, "model": "auth.permission", "fields": {"codename": "delete_nonce", "name": "Can delete nonce", "content_type": 18}}, {"pk": 58, "model": "auth.permission", "fields": {"codename": "add_useropenid", "name": "Can add user open id", "content_type": 20}}, {"pk": 59, "model": "auth.permission", "fields": {"codename": "change_useropenid", "name": "Can change user open id", "content_type": 20}}, {"pk": 60, "model": "auth.permission", "fields": {"codename": "delete_useropenid", "name": "Can delete user open id", "content_type": 20}}, {"pk": 28, "model": "auth.permission", "fields": {"codename": "add_crontabschedule", "name": "Can add crontab", "content_type": 10}}, {"pk": 29, "model": "auth.permission", "fields": {"codename": "change_crontabschedule", "name": "Can change crontab", "content_type": 10}}, {"pk": 30, "model": "auth.permission", "fields": {"codename": "delete_crontabschedule", "name": "Can delete crontab", "content_type": 10}}, {"pk": 25, "model": "auth.permission", "fields": {"codename": "add_intervalschedule", "name": "Can add interval", "content_type": 9}}, {"pk": 26, "model": "auth.permission", "fields": {"codename": "change_intervalschedule", "name": "Can change interval", "content_type": 9}}, {"pk": 27, "model": "auth.permission", "fields": {"codename": "delete_intervalschedule", "name": "Can delete interval", "content_type": 9}}, {"pk": 34, "model": "auth.permission", "fields": {"codename": "add_periodictask", "name": "Can add periodic task", "content_type": 12}}, {"pk": 35, "model": "auth.permission", "fields": {"codename": "change_periodictask", "name": "Can change periodic task", "content_type": 12}}, {"pk": 36, "model": "auth.permission", "fields": {"codename": "delete_periodictask", "name": "Can delete periodic task", "content_type": 12}}, {"pk": 31, "model": "auth.permission", "fields": {"codename": "add_periodictasks", "name": "Can add periodic tasks", "content_type": 11}}, {"pk": 32, "model": "auth.permission", "fields": {"codename": "change_periodictasks", "name": "Can change periodic tasks", "content_type": 11}}, {"pk": 33, "model": "auth.permission", "fields": {"codename": "delete_periodictasks", "name": "Can delete periodic tasks", "content_type": 11}}, {"pk": 19, "model": "auth.permission", "fields": {"codename": "add_taskmeta", "name": "Can add task state", "content_type": 7}}, {"pk": 20, "model": "auth.permission", "fields": {"codename": "change_taskmeta", "name": "Can change task state", "content_type": 7}}, {"pk": 21, "model": "auth.permission", "fields": {"codename": "delete_taskmeta", "name": "Can delete task state", "content_type": 7}}, {"pk": 22, "model": "auth.permission", "fields": {"codename": "add_tasksetmeta", "name": "Can add saved group result", "content_type": 8}}, {"pk": 23, "model": "auth.permission", "fields": {"codename": "change_tasksetmeta", "name": "Can change saved group result", "content_type": 8}}, {"pk": 24, "model": "auth.permission", "fields": {"codename": "delete_tasksetmeta", "name": "Can delete saved group result", "content_type": 8}}, {"pk": 40, "model": "auth.permission", "fields": {"codename": "add_taskstate", "name": "Can add task", "content_type": 14}}, {"pk": 41, "model": "auth.permission", "fields": {"codename": "change_taskstate", "name": "Can change task", "content_type": 14}}, {"pk": 42, "model": "auth.permission", "fields": {"codename": "delete_taskstate", "name": "Can delete task", "content_type": 14}}, {"pk": 37, "model": "auth.permission", "fields": {"codename": "add_workerstate", "name": "Can add worker", "content_type": 13}}, {"pk": 38, "model": "auth.permission", "fields": {"codename": "change_workerstate", "name": "Can change worker", "content_type": 13}}, {"pk": 39, "model": "auth.permission", "fields": {"codename": "delete_workerstate", "name": "Can delete worker", "content_type": 13}}, {"pk": 415, "model": "auth.permission", "fields": {"codename": "add_coursevideo", "name": "Can add course video", "content_type": 138}}, {"pk": 416, "model": "auth.permission", "fields": {"codename": "change_coursevideo", "name": "Can change course video", "content_type": 138}}, {"pk": 417, "model": "auth.permission", "fields": {"codename": "delete_coursevideo", "name": "Can delete course video", "content_type": 138}}, {"pk": 418, "model": "auth.permission", "fields": {"codename": "add_encodedvideo", "name": "Can add encoded video", "content_type": 139}}, {"pk": 419, "model": "auth.permission", "fields": {"codename": "change_encodedvideo", "name": "Can change encoded video", "content_type": 139}}, {"pk": 420, "model": "auth.permission", "fields": {"codename": "delete_encodedvideo", "name": "Can delete encoded video", "content_type": 139}}, {"pk": 409, "model": "auth.permission", "fields": {"codename": "add_profile", "name": "Can add profile", "content_type": 136}}, {"pk": 410, "model": "auth.permission", "fields": {"codename": "change_profile", "name": "Can change profile", "content_type": 136}}, {"pk": 411, "model": "auth.permission", "fields": {"codename": "delete_profile", "name": "Can delete profile", "content_type": 136}}, {"pk": 421, "model": "auth.permission", "fields": {"codename": "add_subtitle", "name": "Can add subtitle", "content_type": 140}}, {"pk": 422, "model": "auth.permission", "fields": {"codename": "change_subtitle", "name": "Can change subtitle", "content_type": 140}}, {"pk": 423, "model": "auth.permission", "fields": {"codename": "delete_subtitle", "name": "Can delete subtitle", "content_type": 140}}, {"pk": 412, "model": "auth.permission", "fields": {"codename": "add_video", "name": "Can add video", "content_type": 137}}, {"pk": 413, "model": "auth.permission", "fields": {"codename": "change_video", "name": "Can change video", "content_type": 137}}, {"pk": 414, "model": "auth.permission", "fields": {"codename": "delete_video", "name": "Can delete video", "content_type": 137}}, {"pk": 316, "model": "auth.permission", "fields": {"codename": "add_embargoedcourse", "name": "Can add embargoed course", "content_type": 105}}, {"pk": 317, "model": "auth.permission", "fields": {"codename": "change_embargoedcourse", "name": "Can change embargoed course", "content_type": 105}}, {"pk": 318, "model": "auth.permission", "fields": {"codename": "delete_embargoedcourse", "name": "Can delete embargoed course", "content_type": 105}}, {"pk": 319, "model": "auth.permission", "fields": {"codename": "add_embargoedstate", "name": "Can add embargoed state", "content_type": 106}}, {"pk": 320, "model": "auth.permission", "fields": {"codename": "change_embargoedstate", "name": "Can change embargoed state", "content_type": 106}}, {"pk": 321, "model": "auth.permission", "fields": {"codename": "delete_embargoedstate", "name": "Can delete embargoed state", "content_type": 106}}, {"pk": 322, "model": "auth.permission", "fields": {"codename": "add_ipfilter", "name": "Can add ip filter", "content_type": 107}}, {"pk": 323, "model": "auth.permission", "fields": {"codename": "change_ipfilter", "name": "Can change ip filter", "content_type": 107}}, {"pk": 324, "model": "auth.permission", "fields": {"codename": "delete_ipfilter", "name": "Can delete ip filter", "content_type": 107}}, {"pk": 175, "model": "auth.permission", "fields": {"codename": "add_externalauthmap", "name": "Can add external auth map", "content_type": 59}}, {"pk": 176, "model": "auth.permission", "fields": {"codename": "change_externalauthmap", "name": "Can change external auth map", "content_type": 59}}, {"pk": 177, "model": "auth.permission", "fields": {"codename": "delete_externalauthmap", "name": "Can delete external auth map", "content_type": 59}}, {"pk": 241, "model": "auth.permission", "fields": {"codename": "add_puzzlecomplete", "name": "Can add puzzle complete", "content_type": 80}}, {"pk": 242, "model": "auth.permission", "fields": {"codename": "change_puzzlecomplete", "name": "Can change puzzle complete", "content_type": 80}}, {"pk": 243, "model": "auth.permission", "fields": {"codename": "delete_puzzlecomplete", "name": "Can delete puzzle complete", "content_type": 80}}, {"pk": 238, "model": "auth.permission", "fields": {"codename": "add_score", "name": "Can add score", "content_type": 79}}, {"pk": 239, "model": "auth.permission", "fields": {"codename": "change_score", "name": "Can change score", "content_type": 79}}, {"pk": 240, "model": "auth.permission", "fields": {"codename": "delete_score", "name": "Can delete score", "content_type": 79}}, {"pk": 148, "model": "auth.permission", "fields": {"codename": "add_instructortask", "name": "Can add instructor task", "content_type": 50}}, {"pk": 149, "model": "auth.permission", "fields": {"codename": "change_instructortask", "name": "Can change instructor task", "content_type": 50}}, {"pk": 150, "model": "auth.permission", "fields": {"codename": "delete_instructortask", "name": "Can delete instructor task", "content_type": 50}}, {"pk": 151, "model": "auth.permission", "fields": {"codename": "add_coursesoftware", "name": "Can add course software", "content_type": 51}}, {"pk": 152, "model": "auth.permission", "fields": {"codename": "change_coursesoftware", "name": "Can change course software", "content_type": 51}}, {"pk": 153, "model": "auth.permission", "fields": {"codename": "delete_coursesoftware", "name": "Can delete course software", "content_type": 51}}, {"pk": 154, "model": "auth.permission", "fields": {"codename": "add_userlicense", "name": "Can add user license", "content_type": 52}}, {"pk": 155, "model": "auth.permission", "fields": {"codename": "change_userlicense", "name": "Can change user license", "content_type": 52}}, {"pk": 156, "model": "auth.permission", "fields": {"codename": "delete_userlicense", "name": "Can delete user license", "content_type": 52}}, {"pk": 334, "model": "auth.permission", "fields": {"codename": "add_xblockasidesconfig", "name": "Can add x block asides config", "content_type": 111}}, {"pk": 335, "model": "auth.permission", "fields": {"codename": "change_xblockasidesconfig", "name": "Can change x block asides config", "content_type": 111}}, {"pk": 336, "model": "auth.permission", "fields": {"codename": "delete_xblockasidesconfig", "name": "Can delete x block asides config", "content_type": 111}}, {"pk": 337, "model": "auth.permission", "fields": {"codename": "add_answer", "name": "Can add answer", "content_type": 112}}, {"pk": 338, "model": "auth.permission", "fields": {"codename": "change_answer", "name": "Can change answer", "content_type": 112}}, {"pk": 339, "model": "auth.permission", "fields": {"codename": "delete_answer", "name": "Can delete answer", "content_type": 112}}, {"pk": 340, "model": "auth.permission", "fields": {"codename": "add_lightchild", "name": "Can add light child", "content_type": 113}}, {"pk": 341, "model": "auth.permission", "fields": {"codename": "change_lightchild", "name": "Can change light child", "content_type": 113}}, {"pk": 342, "model": "auth.permission", "fields": {"codename": "delete_lightchild", "name": "Can delete light child", "content_type": 113}}, {"pk": 433, "model": "auth.permission", "fields": {"codename": "add_coursecontentmilestone", "name": "Can add course content milestone", "content_type": 144}}, {"pk": 434, "model": "auth.permission", "fields": {"codename": "change_coursecontentmilestone", "name": "Can change course content milestone", "content_type": 144}}, {"pk": 435, "model": "auth.permission", "fields": {"codename": "delete_coursecontentmilestone", "name": "Can delete course content milestone", "content_type": 144}}, {"pk": 430, "model": "auth.permission", "fields": {"codename": "add_coursemilestone", "name": "Can add course milestone", "content_type": 143}}, {"pk": 431, "model": "auth.permission", "fields": {"codename": "change_coursemilestone", "name": "Can change course milestone", "content_type": 143}}, {"pk": 432, "model": "auth.permission", "fields": {"codename": "delete_coursemilestone", "name": "Can delete course milestone", "content_type": 143}}, {"pk": 424, "model": "auth.permission", "fields": {"codename": "add_milestone", "name": "Can add milestone", "content_type": 141}}, {"pk": 425, "model": "auth.permission", "fields": {"codename": "change_milestone", "name": "Can change milestone", "content_type": 141}}, {"pk": 426, "model": "auth.permission", "fields": {"codename": "delete_milestone", "name": "Can delete milestone", "content_type": 141}}, {"pk": 427, "model": "auth.permission", "fields": {"codename": "add_milestonerelationshiptype", "name": "Can add milestone relationship type", "content_type": 142}}, {"pk": 428, "model": "auth.permission", "fields": {"codename": "change_milestonerelationshiptype", "name": "Can change milestone relationship type", "content_type": 142}}, {"pk": 429, "model": "auth.permission", "fields": {"codename": "delete_milestonerelationshiptype", "name": "Can delete milestone relationship type", "content_type": 142}}, {"pk": 436, "model": "auth.permission", "fields": {"codename": "add_usermilestone", "name": "Can add user milestone", "content_type": 145}}, {"pk": 437, "model": "auth.permission", "fields": {"codename": "change_usermilestone", "name": "Can change user milestone", "content_type": 145}}, {"pk": 438, "model": "auth.permission", "fields": {"codename": "delete_usermilestone", "name": "Can delete user milestone", "content_type": 145}}, {"pk": 244, "model": "auth.permission", "fields": {"codename": "add_note", "name": "Can add note", "content_type": 81}}, {"pk": 245, "model": "auth.permission", "fields": {"codename": "change_note", "name": "Can change note", "content_type": 81}}, {"pk": 246, "model": "auth.permission", "fields": {"codename": "delete_note", "name": "Can delete note", "content_type": 81}}, {"pk": 184, "model": "auth.permission", "fields": {"codename": "add_accesstoken", "name": "Can add access token", "content_type": 62}}, {"pk": 185, "model": "auth.permission", "fields": {"codename": "change_accesstoken", "name": "Can change access token", "content_type": 62}}, {"pk": 186, "model": "auth.permission", "fields": {"codename": "delete_accesstoken", "name": "Can delete access token", "content_type": 62}}, {"pk": 178, "model": "auth.permission", "fields": {"codename": "add_client", "name": "Can add client", "content_type": 60}}, {"pk": 179, "model": "auth.permission", "fields": {"codename": "change_client", "name": "Can change client", "content_type": 60}}, {"pk": 180, "model": "auth.permission", "fields": {"codename": "delete_client", "name": "Can delete client", "content_type": 60}}, {"pk": 181, "model": "auth.permission", "fields": {"codename": "add_grant", "name": "Can add grant", "content_type": 61}}, {"pk": 182, "model": "auth.permission", "fields": {"codename": "change_grant", "name": "Can change grant", "content_type": 61}}, {"pk": 183, "model": "auth.permission", "fields": {"codename": "delete_grant", "name": "Can delete grant", "content_type": 61}}, {"pk": 187, "model": "auth.permission", "fields": {"codename": "add_refreshtoken", "name": "Can add refresh token", "content_type": 63}}, {"pk": 188, "model": "auth.permission", "fields": {"codename": "change_refreshtoken", "name": "Can change refresh token", "content_type": 63}}, {"pk": 189, "model": "auth.permission", "fields": {"codename": "delete_refreshtoken", "name": "Can delete refresh token", "content_type": 63}}, {"pk": 190, "model": "auth.permission", "fields": {"codename": "add_trustedclient", "name": "Can add trusted client", "content_type": 64}}, {"pk": 191, "model": "auth.permission", "fields": {"codename": "change_trustedclient", "name": "Can change trusted client", "content_type": 64}}, {"pk": 192, "model": "auth.permission", "fields": {"codename": "delete_trustedclient", "name": "Can delete trusted client", "content_type": 64}}, {"pk": 49, "model": "auth.permission", "fields": {"codename": "add_psychometricdata", "name": "Can add psychometric data", "content_type": 17}}, {"pk": 50, "model": "auth.permission", "fields": {"codename": "change_psychometricdata", "name": "Can change psychometric data", "content_type": 17}}, {"pk": 51, "model": "auth.permission", "fields": {"codename": "delete_psychometricdata", "name": "Can delete psychometric data", "content_type": 17}}, {"pk": 313, "model": "auth.permission", "fields": {"codename": "add_midcoursereverificationwindow", "name": "Can add midcourse reverification window", "content_type": 104}}, {"pk": 314, "model": "auth.permission", "fields": {"codename": "change_midcoursereverificationwindow", "name": "Can change midcourse reverification window", "content_type": 104}}, {"pk": 315, "model": "auth.permission", "fields": {"codename": "delete_midcoursereverificationwindow", "name": "Can delete midcourse reverification window", "content_type": 104}}, {"pk": 13, "model": "auth.permission", "fields": {"codename": "add_session", "name": "Can add session", "content_type": 5}}, {"pk": 14, "model": "auth.permission", "fields": {"codename": "change_session", "name": "Can change session", "content_type": 5}}, {"pk": 15, "model": "auth.permission", "fields": {"codename": "delete_session", "name": "Can delete session", "content_type": 5}}, {"pk": 292, "model": "auth.permission", "fields": {"codename": "add_certificateitem", "name": "Can add certificate item", "content_type": 97}}, {"pk": 293, "model": "auth.permission", "fields": {"codename": "change_certificateitem", "name": "Can change certificate item", "content_type": 97}}, {"pk": 294, "model": "auth.permission", "fields": {"codename": "delete_certificateitem", "name": "Can delete certificate item", "content_type": 97}}, {"pk": 274, "model": "auth.permission", "fields": {"codename": "add_coupon", "name": "Can add coupon", "content_type": 91}}, {"pk": 275, "model": "auth.permission", "fields": {"codename": "change_coupon", "name": "Can change coupon", "content_type": 91}}, {"pk": 276, "model": "auth.permission", "fields": {"codename": "delete_coupon", "name": "Can delete coupon", "content_type": 91}}, {"pk": 277, "model": "auth.permission", "fields": {"codename": "add_couponredemption", "name": "Can add coupon redemption", "content_type": 92}}, {"pk": 278, "model": "auth.permission", "fields": {"codename": "change_couponredemption", "name": "Can change coupon redemption", "content_type": 92}}, {"pk": 279, "model": "auth.permission", "fields": {"codename": "delete_couponredemption", "name": "Can delete coupon redemption", "content_type": 92}}, {"pk": 283, "model": "auth.permission", "fields": {"codename": "add_courseregcodeitem", "name": "Can add course reg code item", "content_type": 94}}, {"pk": 284, "model": "auth.permission", "fields": {"codename": "change_courseregcodeitem", "name": "Can change course reg code item", "content_type": 94}}, {"pk": 285, "model": "auth.permission", "fields": {"codename": "delete_courseregcodeitem", "name": "Can delete course reg code item", "content_type": 94}}, {"pk": 286, "model": "auth.permission", "fields": {"codename": "add_courseregcodeitemannotation", "name": "Can add course reg code item annotation", "content_type": 95}}, {"pk": 287, "model": "auth.permission", "fields": {"codename": "change_courseregcodeitemannotation", "name": "Can change course reg code item annotation", "content_type": 95}}, {"pk": 288, "model": "auth.permission", "fields": {"codename": "delete_courseregcodeitemannotation", "name": "Can delete course reg code item annotation", "content_type": 95}}, {"pk": 268, "model": "auth.permission", "fields": {"codename": "add_courseregistrationcode", "name": "Can add course registration code", "content_type": 89}}, {"pk": 269, "model": "auth.permission", "fields": {"codename": "change_courseregistrationcode", "name": "Can change course registration code", "content_type": 89}}, {"pk": 270, "model": "auth.permission", "fields": {"codename": "delete_courseregistrationcode", "name": "Can delete course registration code", "content_type": 89}}, {"pk": 298, "model": "auth.permission", "fields": {"codename": "add_donation", "name": "Can add donation", "content_type": 99}}, {"pk": 299, "model": "auth.permission", "fields": {"codename": "change_donation", "name": "Can change donation", "content_type": 99}}, {"pk": 300, "model": "auth.permission", "fields": {"codename": "delete_donation", "name": "Can delete donation", "content_type": 99}}, {"pk": 295, "model": "auth.permission", "fields": {"codename": "add_donationconfiguration", "name": "Can add donation configuration", "content_type": 98}}, {"pk": 296, "model": "auth.permission", "fields": {"codename": "change_donationconfiguration", "name": "Can change donation configuration", "content_type": 98}}, {"pk": 297, "model": "auth.permission", "fields": {"codename": "delete_donationconfiguration", "name": "Can delete donation configuration", "content_type": 98}}, {"pk": 265, "model": "auth.permission", "fields": {"codename": "add_invoice", "name": "Can add invoice", "content_type": 88}}, {"pk": 266, "model": "auth.permission", "fields": {"codename": "change_invoice", "name": "Can change invoice", "content_type": 88}}, {"pk": 267, "model": "auth.permission", "fields": {"codename": "delete_invoice", "name": "Can delete invoice", "content_type": 88}}, {"pk": 259, "model": "auth.permission", "fields": {"codename": "add_order", "name": "Can add order", "content_type": 86}}, {"pk": 260, "model": "auth.permission", "fields": {"codename": "change_order", "name": "Can change order", "content_type": 86}}, {"pk": 261, "model": "auth.permission", "fields": {"codename": "delete_order", "name": "Can delete order", "content_type": 86}}, {"pk": 262, "model": "auth.permission", "fields": {"codename": "add_orderitem", "name": "Can add order item", "content_type": 87}}, {"pk": 263, "model": "auth.permission", "fields": {"codename": "change_orderitem", "name": "Can change order item", "content_type": 87}}, {"pk": 264, "model": "auth.permission", "fields": {"codename": "delete_orderitem", "name": "Can delete order item", "content_type": 87}}, {"pk": 280, "model": "auth.permission", "fields": {"codename": "add_paidcourseregistration", "name": "Can add paid course registration", "content_type": 93}}, {"pk": 281, "model": "auth.permission", "fields": {"codename": "change_paidcourseregistration", "name": "Can change paid course registration", "content_type": 93}}, {"pk": 282, "model": "auth.permission", "fields": {"codename": "delete_paidcourseregistration", "name": "Can delete paid course registration", "content_type": 93}}, {"pk": 289, "model": "auth.permission", "fields": {"codename": "add_paidcourseregistrationannotation", "name": "Can add paid course registration annotation", "content_type": 96}}, {"pk": 290, "model": "auth.permission", "fields": {"codename": "change_paidcourseregistrationannotation", "name": "Can change paid course registration annotation", "content_type": 96}}, {"pk": 291, "model": "auth.permission", "fields": {"codename": "delete_paidcourseregistrationannotation", "name": "Can delete paid course registration annotation", "content_type": 96}}, {"pk": 271, "model": "auth.permission", "fields": {"codename": "add_registrationcoderedemption", "name": "Can add registration code redemption", "content_type": 90}}, {"pk": 272, "model": "auth.permission", "fields": {"codename": "change_registrationcoderedemption", "name": "Can change registration code redemption", "content_type": 90}}, {"pk": 273, "model": "auth.permission", "fields": {"codename": "delete_registrationcoderedemption", "name": "Can delete registration code redemption", "content_type": 90}}, {"pk": 16, "model": "auth.permission", "fields": {"codename": "add_site", "name": "Can add site", "content_type": 6}}, {"pk": 17, "model": "auth.permission", "fields": {"codename": "change_site", "name": "Can change site", "content_type": 6}}, {"pk": 18, "model": "auth.permission", "fields": {"codename": "delete_site", "name": "Can delete site", "content_type": 6}}, {"pk": 43, "model": "auth.permission", "fields": {"codename": "add_migrationhistory", "name": "Can add migration history", "content_type": 15}}, {"pk": 44, "model": "auth.permission", "fields": {"codename": "change_migrationhistory", "name": "Can change migration history", "content_type": 15}}, {"pk": 45, "model": "auth.permission", "fields": {"codename": "delete_migrationhistory", "name": "Can delete migration history", "content_type": 15}}, {"pk": 247, "model": "auth.permission", "fields": {"codename": "add_splashconfig", "name": "Can add splash config", "content_type": 82}}, {"pk": 248, "model": "auth.permission", "fields": {"codename": "change_splashconfig", "name": "Can change splash config", "content_type": 82}}, {"pk": 249, "model": "auth.permission", "fields": {"codename": "delete_splashconfig", "name": "Can delete splash config", "content_type": 82}}, {"pk": 97, "model": "auth.permission", "fields": {"codename": "add_anonymoususerid", "name": "Can add anonymous user id", "content_type": 33}}, {"pk": 98, "model": "auth.permission", "fields": {"codename": "change_anonymoususerid", "name": "Can change anonymous user id", "content_type": 33}}, {"pk": 99, "model": "auth.permission", "fields": {"codename": "delete_anonymoususerid", "name": "Can delete anonymous user id", "content_type": 33}}, {"pk": 133, "model": "auth.permission", "fields": {"codename": "add_courseaccessrole", "name": "Can add course access role", "content_type": 45}}, {"pk": 134, "model": "auth.permission", "fields": {"codename": "change_courseaccessrole", "name": "Can change course access role", "content_type": 45}}, {"pk": 135, "model": "auth.permission", "fields": {"codename": "delete_courseaccessrole", "name": "Can delete course access role", "content_type": 45}}, {"pk": 127, "model": "auth.permission", "fields": {"codename": "add_courseenrollment", "name": "Can add course enrollment", "content_type": 43}}, {"pk": 128, "model": "auth.permission", "fields": {"codename": "change_courseenrollment", "name": "Can change course enrollment", "content_type": 43}}, {"pk": 129, "model": "auth.permission", "fields": {"codename": "delete_courseenrollment", "name": "Can delete course enrollment", "content_type": 43}}, {"pk": 130, "model": "auth.permission", "fields": {"codename": "add_courseenrollmentallowed", "name": "Can add course enrollment allowed", "content_type": 44}}, {"pk": 131, "model": "auth.permission", "fields": {"codename": "change_courseenrollmentallowed", "name": "Can change course enrollment allowed", "content_type": 44}}, {"pk": 132, "model": "auth.permission", "fields": {"codename": "delete_courseenrollmentallowed", "name": "Can delete course enrollment allowed", "content_type": 44}}, {"pk": 136, "model": "auth.permission", "fields": {"codename": "add_dashboardconfiguration", "name": "Can add dashboard configuration", "content_type": 46}}, {"pk": 137, "model": "auth.permission", "fields": {"codename": "change_dashboardconfiguration", "name": "Can change dashboard configuration", "content_type": 46}}, {"pk": 138, "model": "auth.permission", "fields": {"codename": "delete_dashboardconfiguration", "name": "Can delete dashboard configuration", "content_type": 46}}, {"pk": 124, "model": "auth.permission", "fields": {"codename": "add_loginfailures", "name": "Can add login failures", "content_type": 42}}, {"pk": 125, "model": "auth.permission", "fields": {"codename": "change_loginfailures", "name": "Can change login failures", "content_type": 42}}, {"pk": 126, "model": "auth.permission", "fields": {"codename": "delete_loginfailures", "name": "Can delete login failures", "content_type": 42}}, {"pk": 121, "model": "auth.permission", "fields": {"codename": "add_passwordhistory", "name": "Can add password history", "content_type": 41}}, {"pk": 122, "model": "auth.permission", "fields": {"codename": "change_passwordhistory", "name": "Can change password history", "content_type": 41}}, {"pk": 123, "model": "auth.permission", "fields": {"codename": "delete_passwordhistory", "name": "Can delete password history", "content_type": 41}}, {"pk": 118, "model": "auth.permission", "fields": {"codename": "add_pendingemailchange", "name": "Can add pending email change", "content_type": 40}}, {"pk": 119, "model": "auth.permission", "fields": {"codename": "change_pendingemailchange", "name": "Can change pending email change", "content_type": 40}}, {"pk": 120, "model": "auth.permission", "fields": {"codename": "delete_pendingemailchange", "name": "Can delete pending email change", "content_type": 40}}, {"pk": 115, "model": "auth.permission", "fields": {"codename": "add_pendingnamechange", "name": "Can add pending name change", "content_type": 39}}, {"pk": 116, "model": "auth.permission", "fields": {"codename": "change_pendingnamechange", "name": "Can change pending name change", "content_type": 39}}, {"pk": 117, "model": "auth.permission", "fields": {"codename": "delete_pendingnamechange", "name": "Can delete pending name change", "content_type": 39}}, {"pk": 112, "model": "auth.permission", "fields": {"codename": "add_registration", "name": "Can add registration", "content_type": 38}}, {"pk": 113, "model": "auth.permission", "fields": {"codename": "change_registration", "name": "Can change registration", "content_type": 38}}, {"pk": 114, "model": "auth.permission", "fields": {"codename": "delete_registration", "name": "Can delete registration", "content_type": 38}}, {"pk": 103, "model": "auth.permission", "fields": {"codename": "add_userprofile", "name": "Can add user profile", "content_type": 35}}, {"pk": 104, "model": "auth.permission", "fields": {"codename": "change_userprofile", "name": "Can change user profile", "content_type": 35}}, {"pk": 105, "model": "auth.permission", "fields": {"codename": "delete_userprofile", "name": "Can delete user profile", "content_type": 35}}, {"pk": 106, "model": "auth.permission", "fields": {"codename": "add_usersignupsource", "name": "Can add user signup source", "content_type": 36}}, {"pk": 107, "model": "auth.permission", "fields": {"codename": "change_usersignupsource", "name": "Can change user signup source", "content_type": 36}}, {"pk": 108, "model": "auth.permission", "fields": {"codename": "delete_usersignupsource", "name": "Can delete user signup source", "content_type": 36}}, {"pk": 100, "model": "auth.permission", "fields": {"codename": "add_userstanding", "name": "Can add user standing", "content_type": 34}}, {"pk": 101, "model": "auth.permission", "fields": {"codename": "change_userstanding", "name": "Can change user standing", "content_type": 34}}, {"pk": 102, "model": "auth.permission", "fields": {"codename": "delete_userstanding", "name": "Can delete user standing", "content_type": 34}}, {"pk": 109, "model": "auth.permission", "fields": {"codename": "add_usertestgroup", "name": "Can add user test group", "content_type": 37}}, {"pk": 110, "model": "auth.permission", "fields": {"codename": "change_usertestgroup", "name": "Can change user test group", "content_type": 37}}, {"pk": 111, "model": "auth.permission", "fields": {"codename": "delete_usertestgroup", "name": "Can delete user test group", "content_type": 37}}, {"pk": 349, "model": "auth.permission", "fields": {"codename": "add_score", "name": "Can add score", "content_type": 116}}, {"pk": 350, "model": "auth.permission", "fields": {"codename": "change_score", "name": "Can change score", "content_type": 116}}, {"pk": 351, "model": "auth.permission", "fields": {"codename": "delete_score", "name": "Can delete score", "content_type": 116}}, {"pk": 352, "model": "auth.permission", "fields": {"codename": "add_scoresummary", "name": "Can add score summary", "content_type": 117}}, {"pk": 353, "model": "auth.permission", "fields": {"codename": "change_scoresummary", "name": "Can change score summary", "content_type": 117}}, {"pk": 354, "model": "auth.permission", "fields": {"codename": "delete_scoresummary", "name": "Can delete score summary", "content_type": 117}}, {"pk": 343, "model": "auth.permission", "fields": {"codename": "add_studentitem", "name": "Can add student item", "content_type": 114}}, {"pk": 344, "model": "auth.permission", "fields": {"codename": "change_studentitem", "name": "Can change student item", "content_type": 114}}, {"pk": 345, "model": "auth.permission", "fields": {"codename": "delete_studentitem", "name": "Can delete student item", "content_type": 114}}, {"pk": 346, "model": "auth.permission", "fields": {"codename": "add_submission", "name": "Can add submission", "content_type": 115}}, {"pk": 347, "model": "auth.permission", "fields": {"codename": "change_submission", "name": "Can change submission", "content_type": 115}}, {"pk": 348, "model": "auth.permission", "fields": {"codename": "delete_submission", "name": "Can delete submission", "content_type": 115}}, {"pk": 331, "model": "auth.permission", "fields": {"codename": "add_surveyanswer", "name": "Can add survey answer", "content_type": 110}}, {"pk": 332, "model": "auth.permission", "fields": {"codename": "change_surveyanswer", "name": "Can change survey answer", "content_type": 110}}, {"pk": 333, "model": "auth.permission", "fields": {"codename": "delete_surveyanswer", "name": "Can delete survey answer", "content_type": 110}}, {"pk": 328, "model": "auth.permission", "fields": {"codename": "add_surveyform", "name": "Can add survey form", "content_type": 109}}, {"pk": 329, "model": "auth.permission", "fields": {"codename": "change_surveyform", "name": "Can change survey form", "content_type": 109}}, {"pk": 330, "model": "auth.permission", "fields": {"codename": "delete_surveyform", "name": "Can delete survey form", "content_type": 109}}, {"pk": 139, "model": "auth.permission", "fields": {"codename": "add_trackinglog", "name": "Can add tracking log", "content_type": 47}}, {"pk": 140, "model": "auth.permission", "fields": {"codename": "change_trackinglog", "name": "Can change tracking log", "content_type": 47}}, {"pk": 141, "model": "auth.permission", "fields": {"codename": "delete_trackinglog", "name": "Can delete tracking log", "content_type": 47}}, {"pk": 253, "model": "auth.permission", "fields": {"codename": "add_usercoursetag", "name": "Can add user course tag", "content_type": 84}}, {"pk": 254, "model": "auth.permission", "fields": {"codename": "change_usercoursetag", "name": "Can change user course tag", "content_type": 84}}, {"pk": 255, "model": "auth.permission", "fields": {"codename": "delete_usercoursetag", "name": "Can delete user course tag", "content_type": 84}}, {"pk": 256, "model": "auth.permission", "fields": {"codename": "add_userorgtag", "name": "Can add user org tag", "content_type": 85}}, {"pk": 257, "model": "auth.permission", "fields": {"codename": "change_userorgtag", "name": "Can change user org tag", "content_type": 85}}, {"pk": 258, "model": "auth.permission", "fields": {"codename": "delete_userorgtag", "name": "Can delete user org tag", "content_type": 85}}, {"pk": 250, "model": "auth.permission", "fields": {"codename": "add_userpreference", "name": "Can add user preference", "content_type": 83}}, {"pk": 251, "model": "auth.permission", "fields": {"codename": "change_userpreference", "name": "Can change user preference", "content_type": 83}}, {"pk": 252, "model": "auth.permission", "fields": {"codename": "delete_userpreference", "name": "Can delete user preference", "content_type": 83}}, {"pk": 307, "model": "auth.permission", "fields": {"codename": "add_softwaresecurephotoverification", "name": "Can add software secure photo verification", "content_type": 102}}, {"pk": 308, "model": "auth.permission", "fields": {"codename": "change_softwaresecurephotoverification", "name": "Can change software secure photo verification", "content_type": 102}}, {"pk": 309, "model": "auth.permission", "fields": {"codename": "delete_softwaresecurephotoverification", "name": "Can delete software secure photo verification", "content_type": 102}}, {"pk": 193, "model": "auth.permission", "fields": {"codename": "add_article", "name": "Can add article", "content_type": 65}}, {"pk": 197, "model": "auth.permission", "fields": {"codename": "assign", "name": "Can change ownership of any article", "content_type": 65}}, {"pk": 194, "model": "auth.permission", "fields": {"codename": "change_article", "name": "Can change article", "content_type": 65}}, {"pk": 195, "model": "auth.permission", "fields": {"codename": "delete_article", "name": "Can delete article", "content_type": 65}}, {"pk": 198, "model": "auth.permission", "fields": {"codename": "grant", "name": "Can assign permissions to other users", "content_type": 65}}, {"pk": 196, "model": "auth.permission", "fields": {"codename": "moderate", "name": "Can edit all articles and lock/unlock/restore", "content_type": 65}}, {"pk": 199, "model": "auth.permission", "fields": {"codename": "add_articleforobject", "name": "Can add Article for object", "content_type": 66}}, {"pk": 200, "model": "auth.permission", "fields": {"codename": "change_articleforobject", "name": "Can change Article for object", "content_type": 66}}, {"pk": 201, "model": "auth.permission", "fields": {"codename": "delete_articleforobject", "name": "Can delete Article for object", "content_type": 66}}, {"pk": 208, "model": "auth.permission", "fields": {"codename": "add_articleplugin", "name": "Can add article plugin", "content_type": 69}}, {"pk": 209, "model": "auth.permission", "fields": {"codename": "change_articleplugin", "name": "Can change article plugin", "content_type": 69}}, {"pk": 210, "model": "auth.permission", "fields": {"codename": "delete_articleplugin", "name": "Can delete article plugin", "content_type": 69}}, {"pk": 202, "model": "auth.permission", "fields": {"codename": "add_articlerevision", "name": "Can add article revision", "content_type": 67}}, {"pk": 203, "model": "auth.permission", "fields": {"codename": "change_articlerevision", "name": "Can change article revision", "content_type": 67}}, {"pk": 204, "model": "auth.permission", "fields": {"codename": "delete_articlerevision", "name": "Can delete article revision", "content_type": 67}}, {"pk": 223, "model": "auth.permission", "fields": {"codename": "add_articlesubscription", "name": "Can add article subscription", "content_type": 74}}, {"pk": 224, "model": "auth.permission", "fields": {"codename": "change_articlesubscription", "name": "Can change article subscription", "content_type": 74}}, {"pk": 225, "model": "auth.permission", "fields": {"codename": "delete_articlesubscription", "name": "Can delete article subscription", "content_type": 74}}, {"pk": 211, "model": "auth.permission", "fields": {"codename": "add_reusableplugin", "name": "Can add reusable plugin", "content_type": 70}}, {"pk": 212, "model": "auth.permission", "fields": {"codename": "change_reusableplugin", "name": "Can change reusable plugin", "content_type": 70}}, {"pk": 213, "model": "auth.permission", "fields": {"codename": "delete_reusableplugin", "name": "Can delete reusable plugin", "content_type": 70}}, {"pk": 217, "model": "auth.permission", "fields": {"codename": "add_revisionplugin", "name": "Can add revision plugin", "content_type": 72}}, {"pk": 218, "model": "auth.permission", "fields": {"codename": "change_revisionplugin", "name": "Can change revision plugin", "content_type": 72}}, {"pk": 219, "model": "auth.permission", "fields": {"codename": "delete_revisionplugin", "name": "Can delete revision plugin", "content_type": 72}}, {"pk": 220, "model": "auth.permission", "fields": {"codename": "add_revisionpluginrevision", "name": "Can add revision plugin revision", "content_type": 73}}, {"pk": 221, "model": "auth.permission", "fields": {"codename": "change_revisionpluginrevision", "name": "Can change revision plugin revision", "content_type": 73}}, {"pk": 222, "model": "auth.permission", "fields": {"codename": "delete_revisionpluginrevision", "name": "Can delete revision plugin revision", "content_type": 73}}, {"pk": 214, "model": "auth.permission", "fields": {"codename": "add_simpleplugin", "name": "Can add simple plugin", "content_type": 71}}, {"pk": 215, "model": "auth.permission", "fields": {"codename": "change_simpleplugin", "name": "Can change simple plugin", "content_type": 71}}, {"pk": 216, "model": "auth.permission", "fields": {"codename": "delete_simpleplugin", "name": "Can delete simple plugin", "content_type": 71}}, {"pk": 205, "model": "auth.permission", "fields": {"codename": "add_urlpath", "name": "Can add URL path", "content_type": 68}}, {"pk": 206, "model": "auth.permission", "fields": {"codename": "change_urlpath", "name": "Can change URL path", "content_type": 68}}, {"pk": 207, "model": "auth.permission", "fields": {"codename": "delete_urlpath", "name": "Can delete URL path", "content_type": 68}}, {"pk": 403, "model": "auth.permission", "fields": {"codename": "add_assessmentworkflow", "name": "Can add assessment workflow", "content_type": 134}}, {"pk": 404, "model": "auth.permission", "fields": {"codename": "change_assessmentworkflow", "name": "Can change assessment workflow", "content_type": 134}}, {"pk": 405, "model": "auth.permission", "fields": {"codename": "delete_assessmentworkflow", "name": "Can delete assessment workflow", "content_type": 134}}, {"pk": 406, "model": "auth.permission", "fields": {"codename": "add_assessmentworkflowstep", "name": "Can add assessment workflow step", "content_type": 135}}, {"pk": 407, "model": "auth.permission", "fields": {"codename": "change_assessmentworkflowstep", "name": "Can change assessment workflow step", "content_type": 135}}, {"pk": 408, "model": "auth.permission", "fields": {"codename": "delete_assessmentworkflowstep", "name": "Can delete assessment workflow step", "content_type": 135}}, {"pk": 445, "model": "auth.permission", "fields": {"codename": "add_studioconfig", "name": "Can add studio config", "content_type": 148}}, {"pk": 446, "model": "auth.permission", "fields": {"codename": "change_studioconfig", "name": "Can change studio config", "content_type": 148}}, {"pk": 447, "model": "auth.permission", "fields": {"codename": "delete_studioconfig", "name": "Can delete studio config", "content_type": 148}}, {"pk": 1, "model": "dark_lang.darklangconfig", "fields": {"change_date": "2015-01-15T03:15:35Z", "changed_by": null, "enabled": true, "released_languages": ""}}] \ No newline at end of file +[{"pk": 62, "model": "contenttypes.contenttype", "fields": {"model": "accesstoken", "name": "access token", "app_label": "oauth2"}}, {"pk": 131, "model": "contenttypes.contenttype", "fields": {"model": "aiclassifier", "name": "ai classifier", "app_label": "assessment"}}, {"pk": 130, "model": "contenttypes.contenttype", "fields": {"model": "aiclassifierset", "name": "ai classifier set", "app_label": "assessment"}}, {"pk": 133, "model": "contenttypes.contenttype", "fields": {"model": "aigradingworkflow", "name": "ai grading workflow", "app_label": "assessment"}}, {"pk": 132, "model": "contenttypes.contenttype", "fields": {"model": "aitrainingworkflow", "name": "ai training workflow", "app_label": "assessment"}}, {"pk": 33, "model": "contenttypes.contenttype", "fields": {"model": "anonymoususerid", "name": "anonymous user id", "app_label": "student"}}, {"pk": 112, "model": "contenttypes.contenttype", "fields": {"model": "answer", "name": "answer", "app_label": "mentoring"}}, {"pk": 65, "model": "contenttypes.contenttype", "fields": {"model": "article", "name": "article", "app_label": "wiki"}}, {"pk": 66, "model": "contenttypes.contenttype", "fields": {"model": "articleforobject", "name": "Article for object", "app_label": "wiki"}}, {"pk": 69, "model": "contenttypes.contenttype", "fields": {"model": "articleplugin", "name": "article plugin", "app_label": "wiki"}}, {"pk": 67, "model": "contenttypes.contenttype", "fields": {"model": "articlerevision", "name": "article revision", "app_label": "wiki"}}, {"pk": 74, "model": "contenttypes.contenttype", "fields": {"model": "articlesubscription", "name": "article subscription", "app_label": "wiki"}}, {"pk": 121, "model": "contenttypes.contenttype", "fields": {"model": "assessment", "name": "assessment", "app_label": "assessment"}}, {"pk": 124, "model": "contenttypes.contenttype", "fields": {"model": "assessmentfeedback", "name": "assessment feedback", "app_label": "assessment"}}, {"pk": 123, "model": "contenttypes.contenttype", "fields": {"model": "assessmentfeedbackoption", "name": "assessment feedback option", "app_label": "assessment"}}, {"pk": 122, "model": "contenttypes.contenttype", "fields": {"model": "assessmentpart", "name": "assessment part", "app_label": "assessment"}}, {"pk": 134, "model": "contenttypes.contenttype", "fields": {"model": "assessmentworkflow", "name": "assessment workflow", "app_label": "workflow"}}, {"pk": 135, "model": "contenttypes.contenttype", "fields": {"model": "assessmentworkflowstep", "name": "assessment workflow step", "app_label": "workflow"}}, {"pk": 19, "model": "contenttypes.contenttype", "fields": {"model": "association", "name": "association", "app_label": "django_openid_auth"}}, {"pk": 24, "model": "contenttypes.contenttype", "fields": {"model": "association", "name": "association", "app_label": "default"}}, {"pk": 97, "model": "contenttypes.contenttype", "fields": {"model": "certificateitem", "name": "certificate item", "app_label": "shoppingcart"}}, {"pk": 48, "model": "contenttypes.contenttype", "fields": {"model": "certificatewhitelist", "name": "certificate whitelist", "app_label": "certificates"}}, {"pk": 60, "model": "contenttypes.contenttype", "fields": {"model": "client", "name": "client", "app_label": "oauth2"}}, {"pk": 25, "model": "contenttypes.contenttype", "fields": {"model": "code", "name": "code", "app_label": "default"}}, {"pk": 4, "model": "contenttypes.contenttype", "fields": {"model": "contenttype", "name": "content type", "app_label": "contenttypes"}}, {"pk": 91, "model": "contenttypes.contenttype", "fields": {"model": "coupon", "name": "coupon", "app_label": "shoppingcart"}}, {"pk": 92, "model": "contenttypes.contenttype", "fields": {"model": "couponredemption", "name": "coupon redemption", "app_label": "shoppingcart"}}, {"pk": 45, "model": "contenttypes.contenttype", "fields": {"model": "courseaccessrole", "name": "course access role", "app_label": "student"}}, {"pk": 58, "model": "contenttypes.contenttype", "fields": {"model": "courseauthorization", "name": "course authorization", "app_label": "bulk_email"}}, {"pk": 144, "model": "contenttypes.contenttype", "fields": {"model": "coursecontentmilestone", "name": "course content milestone", "app_label": "milestones"}}, {"pk": 147, "model": "contenttypes.contenttype", "fields": {"model": "coursecreator", "name": "course creator", "app_label": "course_creators"}}, {"pk": 55, "model": "contenttypes.contenttype", "fields": {"model": "courseemail", "name": "course email", "app_label": "bulk_email"}}, {"pk": 57, "model": "contenttypes.contenttype", "fields": {"model": "courseemailtemplate", "name": "course email template", "app_label": "bulk_email"}}, {"pk": 43, "model": "contenttypes.contenttype", "fields": {"model": "courseenrollment", "name": "course enrollment", "app_label": "student"}}, {"pk": 44, "model": "contenttypes.contenttype", "fields": {"model": "courseenrollmentallowed", "name": "course enrollment allowed", "app_label": "student"}}, {"pk": 143, "model": "contenttypes.contenttype", "fields": {"model": "coursemilestone", "name": "course milestone", "app_label": "milestones"}}, {"pk": 100, "model": "contenttypes.contenttype", "fields": {"model": "coursemode", "name": "course mode", "app_label": "course_modes"}}, {"pk": 101, "model": "contenttypes.contenttype", "fields": {"model": "coursemodesarchive", "name": "course modes archive", "app_label": "course_modes"}}, {"pk": 94, "model": "contenttypes.contenttype", "fields": {"model": "courseregcodeitem", "name": "course reg code item", "app_label": "shoppingcart"}}, {"pk": 95, "model": "contenttypes.contenttype", "fields": {"model": "courseregcodeitemannotation", "name": "course reg code item annotation", "app_label": "shoppingcart"}}, {"pk": 89, "model": "contenttypes.contenttype", "fields": {"model": "courseregistrationcode", "name": "course registration code", "app_label": "shoppingcart"}}, {"pk": 108, "model": "contenttypes.contenttype", "fields": {"model": "coursererunstate", "name": "course rerun state", "app_label": "course_action_state"}}, {"pk": 51, "model": "contenttypes.contenttype", "fields": {"model": "coursesoftware", "name": "course software", "app_label": "licenses"}}, {"pk": 53, "model": "contenttypes.contenttype", "fields": {"model": "courseusergroup", "name": "course user group", "app_label": "course_groups"}}, {"pk": 54, "model": "contenttypes.contenttype", "fields": {"model": "courseusergrouppartitiongroup", "name": "course user group partition group", "app_label": "course_groups"}}, {"pk": 138, "model": "contenttypes.contenttype", "fields": {"model": "coursevideo", "name": "course video", "app_label": "edxval"}}, {"pk": 119, "model": "contenttypes.contenttype", "fields": {"model": "criterion", "name": "criterion", "app_label": "assessment"}}, {"pk": 120, "model": "contenttypes.contenttype", "fields": {"model": "criterionoption", "name": "criterion option", "app_label": "assessment"}}, {"pk": 10, "model": "contenttypes.contenttype", "fields": {"model": "crontabschedule", "name": "crontab", "app_label": "djcelery"}}, {"pk": 103, "model": "contenttypes.contenttype", "fields": {"model": "darklangconfig", "name": "dark lang config", "app_label": "dark_lang"}}, {"pk": 46, "model": "contenttypes.contenttype", "fields": {"model": "dashboardconfiguration", "name": "dashboard configuration", "app_label": "student"}}, {"pk": 99, "model": "contenttypes.contenttype", "fields": {"model": "donation", "name": "donation", "app_label": "shoppingcart"}}, {"pk": 98, "model": "contenttypes.contenttype", "fields": {"model": "donationconfiguration", "name": "donation configuration", "app_label": "shoppingcart"}}, {"pk": 105, "model": "contenttypes.contenttype", "fields": {"model": "embargoedcourse", "name": "embargoed course", "app_label": "embargo"}}, {"pk": 106, "model": "contenttypes.contenttype", "fields": {"model": "embargoedstate", "name": "embargoed state", "app_label": "embargo"}}, {"pk": 139, "model": "contenttypes.contenttype", "fields": {"model": "encodedvideo", "name": "encoded video", "app_label": "edxval"}}, {"pk": 59, "model": "contenttypes.contenttype", "fields": {"model": "externalauthmap", "name": "external auth map", "app_label": "external_auth"}}, {"pk": 49, "model": "contenttypes.contenttype", "fields": {"model": "generatedcertificate", "name": "generated certificate", "app_label": "certificates"}}, {"pk": 61, "model": "contenttypes.contenttype", "fields": {"model": "grant", "name": "grant", "app_label": "oauth2"}}, {"pk": 2, "model": "contenttypes.contenttype", "fields": {"model": "group", "name": "group", "app_label": "auth"}}, {"pk": 50, "model": "contenttypes.contenttype", "fields": {"model": "instructortask", "name": "instructor task", "app_label": "instructor_task"}}, {"pk": 9, "model": "contenttypes.contenttype", "fields": {"model": "intervalschedule", "name": "interval", "app_label": "djcelery"}}, {"pk": 88, "model": "contenttypes.contenttype", "fields": {"model": "invoice", "name": "invoice", "app_label": "shoppingcart"}}, {"pk": 107, "model": "contenttypes.contenttype", "fields": {"model": "ipfilter", "name": "ip filter", "app_label": "embargo"}}, {"pk": 113, "model": "contenttypes.contenttype", "fields": {"model": "lightchild", "name": "light child", "app_label": "mentoring"}}, {"pk": 21, "model": "contenttypes.contenttype", "fields": {"model": "logentry", "name": "log entry", "app_label": "admin"}}, {"pk": 42, "model": "contenttypes.contenttype", "fields": {"model": "loginfailures", "name": "login failures", "app_label": "student"}}, {"pk": 104, "model": "contenttypes.contenttype", "fields": {"model": "midcoursereverificationwindow", "name": "midcourse reverification window", "app_label": "reverification"}}, {"pk": 15, "model": "contenttypes.contenttype", "fields": {"model": "migrationhistory", "name": "migration history", "app_label": "south"}}, {"pk": 141, "model": "contenttypes.contenttype", "fields": {"model": "milestone", "name": "milestone", "app_label": "milestones"}}, {"pk": 142, "model": "contenttypes.contenttype", "fields": {"model": "milestonerelationshiptype", "name": "milestone relationship type", "app_label": "milestones"}}, {"pk": 18, "model": "contenttypes.contenttype", "fields": {"model": "nonce", "name": "nonce", "app_label": "django_openid_auth"}}, {"pk": 23, "model": "contenttypes.contenttype", "fields": {"model": "nonce", "name": "nonce", "app_label": "default"}}, {"pk": 81, "model": "contenttypes.contenttype", "fields": {"model": "note", "name": "note", "app_label": "notes"}}, {"pk": 78, "model": "contenttypes.contenttype", "fields": {"model": "notification", "name": "notification", "app_label": "django_notify"}}, {"pk": 31, "model": "contenttypes.contenttype", "fields": {"model": "offlinecomputedgrade", "name": "offline computed grade", "app_label": "courseware"}}, {"pk": 32, "model": "contenttypes.contenttype", "fields": {"model": "offlinecomputedgradelog", "name": "offline computed grade log", "app_label": "courseware"}}, {"pk": 56, "model": "contenttypes.contenttype", "fields": {"model": "optout", "name": "optout", "app_label": "bulk_email"}}, {"pk": 86, "model": "contenttypes.contenttype", "fields": {"model": "order", "name": "order", "app_label": "shoppingcart"}}, {"pk": 87, "model": "contenttypes.contenttype", "fields": {"model": "orderitem", "name": "order item", "app_label": "shoppingcart"}}, {"pk": 93, "model": "contenttypes.contenttype", "fields": {"model": "paidcourseregistration", "name": "paid course registration", "app_label": "shoppingcart"}}, {"pk": 96, "model": "contenttypes.contenttype", "fields": {"model": "paidcourseregistrationannotation", "name": "paid course registration annotation", "app_label": "shoppingcart"}}, {"pk": 41, "model": "contenttypes.contenttype", "fields": {"model": "passwordhistory", "name": "password history", "app_label": "student"}}, {"pk": 125, "model": "contenttypes.contenttype", "fields": {"model": "peerworkflow", "name": "peer workflow", "app_label": "assessment"}}, {"pk": 126, "model": "contenttypes.contenttype", "fields": {"model": "peerworkflowitem", "name": "peer workflow item", "app_label": "assessment"}}, {"pk": 40, "model": "contenttypes.contenttype", "fields": {"model": "pendingemailchange", "name": "pending email change", "app_label": "student"}}, {"pk": 39, "model": "contenttypes.contenttype", "fields": {"model": "pendingnamechange", "name": "pending name change", "app_label": "student"}}, {"pk": 12, "model": "contenttypes.contenttype", "fields": {"model": "periodictask", "name": "periodic task", "app_label": "djcelery"}}, {"pk": 11, "model": "contenttypes.contenttype", "fields": {"model": "periodictasks", "name": "periodic tasks", "app_label": "djcelery"}}, {"pk": 1, "model": "contenttypes.contenttype", "fields": {"model": "permission", "name": "permission", "app_label": "auth"}}, {"pk": 136, "model": "contenttypes.contenttype", "fields": {"model": "profile", "name": "profile", "app_label": "edxval"}}, {"pk": 17, "model": "contenttypes.contenttype", "fields": {"model": "psychometricdata", "name": "psychometric data", "app_label": "psychometrics"}}, {"pk": 80, "model": "contenttypes.contenttype", "fields": {"model": "puzzlecomplete", "name": "puzzle complete", "app_label": "foldit"}}, {"pk": 63, "model": "contenttypes.contenttype", "fields": {"model": "refreshtoken", "name": "refresh token", "app_label": "oauth2"}}, {"pk": 38, "model": "contenttypes.contenttype", "fields": {"model": "registration", "name": "registration", "app_label": "student"}}, {"pk": 90, "model": "contenttypes.contenttype", "fields": {"model": "registrationcoderedemption", "name": "registration code redemption", "app_label": "shoppingcart"}}, {"pk": 70, "model": "contenttypes.contenttype", "fields": {"model": "reusableplugin", "name": "reusable plugin", "app_label": "wiki"}}, {"pk": 72, "model": "contenttypes.contenttype", "fields": {"model": "revisionplugin", "name": "revision plugin", "app_label": "wiki"}}, {"pk": 73, "model": "contenttypes.contenttype", "fields": {"model": "revisionpluginrevision", "name": "revision plugin revision", "app_label": "wiki"}}, {"pk": 118, "model": "contenttypes.contenttype", "fields": {"model": "rubric", "name": "rubric", "app_label": "assessment"}}, {"pk": 8, "model": "contenttypes.contenttype", "fields": {"model": "tasksetmeta", "name": "saved group result", "app_label": "djcelery"}}, {"pk": 79, "model": "contenttypes.contenttype", "fields": {"model": "score", "name": "score", "app_label": "foldit"}}, {"pk": 116, "model": "contenttypes.contenttype", "fields": {"model": "score", "name": "score", "app_label": "submissions"}}, {"pk": 117, "model": "contenttypes.contenttype", "fields": {"model": "scoresummary", "name": "score summary", "app_label": "submissions"}}, {"pk": 16, "model": "contenttypes.contenttype", "fields": {"model": "servercircuit", "name": "server circuit", "app_label": "circuit"}}, {"pk": 5, "model": "contenttypes.contenttype", "fields": {"model": "session", "name": "session", "app_label": "sessions"}}, {"pk": 76, "model": "contenttypes.contenttype", "fields": {"model": "settings", "name": "settings", "app_label": "django_notify"}}, {"pk": 71, "model": "contenttypes.contenttype", "fields": {"model": "simpleplugin", "name": "simple plugin", "app_label": "wiki"}}, {"pk": 6, "model": "contenttypes.contenttype", "fields": {"model": "site", "name": "site", "app_label": "sites"}}, {"pk": 102, "model": "contenttypes.contenttype", "fields": {"model": "softwaresecurephotoverification", "name": "software secure photo verification", "app_label": "verify_student"}}, {"pk": 82, "model": "contenttypes.contenttype", "fields": {"model": "splashconfig", "name": "splash config", "app_label": "splash"}}, {"pk": 114, "model": "contenttypes.contenttype", "fields": {"model": "studentitem", "name": "student item", "app_label": "submissions"}}, {"pk": 26, "model": "contenttypes.contenttype", "fields": {"model": "studentmodule", "name": "student module", "app_label": "courseware"}}, {"pk": 27, "model": "contenttypes.contenttype", "fields": {"model": "studentmodulehistory", "name": "student module history", "app_label": "courseware"}}, {"pk": 128, "model": "contenttypes.contenttype", "fields": {"model": "studenttrainingworkflow", "name": "student training workflow", "app_label": "assessment"}}, {"pk": 129, "model": "contenttypes.contenttype", "fields": {"model": "studenttrainingworkflowitem", "name": "student training workflow item", "app_label": "assessment"}}, {"pk": 148, "model": "contenttypes.contenttype", "fields": {"model": "studioconfig", "name": "studio config", "app_label": "xblock_config"}}, {"pk": 115, "model": "contenttypes.contenttype", "fields": {"model": "submission", "name": "submission", "app_label": "submissions"}}, {"pk": 77, "model": "contenttypes.contenttype", "fields": {"model": "subscription", "name": "subscription", "app_label": "django_notify"}}, {"pk": 140, "model": "contenttypes.contenttype", "fields": {"model": "subtitle", "name": "subtitle", "app_label": "edxval"}}, {"pk": 110, "model": "contenttypes.contenttype", "fields": {"model": "surveyanswer", "name": "survey answer", "app_label": "survey"}}, {"pk": 109, "model": "contenttypes.contenttype", "fields": {"model": "surveyform", "name": "survey form", "app_label": "survey"}}, {"pk": 14, "model": "contenttypes.contenttype", "fields": {"model": "taskstate", "name": "task", "app_label": "djcelery"}}, {"pk": 7, "model": "contenttypes.contenttype", "fields": {"model": "taskmeta", "name": "task state", "app_label": "djcelery"}}, {"pk": 47, "model": "contenttypes.contenttype", "fields": {"model": "trackinglog", "name": "tracking log", "app_label": "track"}}, {"pk": 127, "model": "contenttypes.contenttype", "fields": {"model": "trainingexample", "name": "training example", "app_label": "assessment"}}, {"pk": 64, "model": "contenttypes.contenttype", "fields": {"model": "trustedclient", "name": "trusted client", "app_label": "oauth2_provider"}}, {"pk": 75, "model": "contenttypes.contenttype", "fields": {"model": "notificationtype", "name": "type", "app_label": "django_notify"}}, {"pk": 68, "model": "contenttypes.contenttype", "fields": {"model": "urlpath", "name": "URL path", "app_label": "wiki"}}, {"pk": 3, "model": "contenttypes.contenttype", "fields": {"model": "user", "name": "user", "app_label": "auth"}}, {"pk": 84, "model": "contenttypes.contenttype", "fields": {"model": "usercoursetag", "name": "user course tag", "app_label": "user_api"}}, {"pk": 52, "model": "contenttypes.contenttype", "fields": {"model": "userlicense", "name": "user license", "app_label": "licenses"}}, {"pk": 145, "model": "contenttypes.contenttype", "fields": {"model": "usermilestone", "name": "user milestone", "app_label": "milestones"}}, {"pk": 20, "model": "contenttypes.contenttype", "fields": {"model": "useropenid", "name": "user open id", "app_label": "django_openid_auth"}}, {"pk": 85, "model": "contenttypes.contenttype", "fields": {"model": "userorgtag", "name": "user org tag", "app_label": "user_api"}}, {"pk": 83, "model": "contenttypes.contenttype", "fields": {"model": "userpreference", "name": "user preference", "app_label": "user_api"}}, {"pk": 35, "model": "contenttypes.contenttype", "fields": {"model": "userprofile", "name": "user profile", "app_label": "student"}}, {"pk": 36, "model": "contenttypes.contenttype", "fields": {"model": "usersignupsource", "name": "user signup source", "app_label": "student"}}, {"pk": 22, "model": "contenttypes.contenttype", "fields": {"model": "usersocialauth", "name": "user social auth", "app_label": "default"}}, {"pk": 34, "model": "contenttypes.contenttype", "fields": {"model": "userstanding", "name": "user standing", "app_label": "student"}}, {"pk": 37, "model": "contenttypes.contenttype", "fields": {"model": "usertestgroup", "name": "user test group", "app_label": "student"}}, {"pk": 137, "model": "contenttypes.contenttype", "fields": {"model": "video", "name": "video", "app_label": "edxval"}}, {"pk": 146, "model": "contenttypes.contenttype", "fields": {"model": "videouploadconfig", "name": "video upload config", "app_label": "contentstore"}}, {"pk": 13, "model": "contenttypes.contenttype", "fields": {"model": "workerstate", "name": "worker", "app_label": "djcelery"}}, {"pk": 111, "model": "contenttypes.contenttype", "fields": {"model": "xblockasidesconfig", "name": "x block asides config", "app_label": "lms_xblock"}}, {"pk": 30, "model": "contenttypes.contenttype", "fields": {"model": "xmodulestudentinfofield", "name": "x module student info field", "app_label": "courseware"}}, {"pk": 29, "model": "contenttypes.contenttype", "fields": {"model": "xmodulestudentprefsfield", "name": "x module student prefs field", "app_label": "courseware"}}, {"pk": 28, "model": "contenttypes.contenttype", "fields": {"model": "xmoduleuserstatesummaryfield", "name": "x module user state summary field", "app_label": "courseware"}}, {"pk": 1, "model": "sites.site", "fields": {"domain": "example.com", "name": "example.com"}}, {"pk": 1, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:15Z", "app_name": "courseware", "migration": "0001_initial"}}, {"pk": 2, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:15Z", "app_name": "courseware", "migration": "0002_add_indexes"}}, {"pk": 3, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:15Z", "app_name": "courseware", "migration": "0003_done_grade_cache"}}, {"pk": 4, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:15Z", "app_name": "courseware", "migration": "0004_add_field_studentmodule_course_id"}}, {"pk": 5, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:15Z", "app_name": "courseware", "migration": "0005_auto__add_offlinecomputedgrade__add_unique_offlinecomputedgrade_user_c"}}, {"pk": 6, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:15Z", "app_name": "courseware", "migration": "0006_create_student_module_history"}}, {"pk": 7, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:15Z", "app_name": "courseware", "migration": "0007_allow_null_version_in_history"}}, {"pk": 8, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:16Z", "app_name": "courseware", "migration": "0008_add_xmodule_storage"}}, {"pk": 9, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:16Z", "app_name": "courseware", "migration": "0009_add_field_default"}}, {"pk": 10, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:16Z", "app_name": "courseware", "migration": "0010_rename_xblock_field_content_to_user_state_summary"}}, {"pk": 11, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:16Z", "app_name": "student", "migration": "0001_initial"}}, {"pk": 12, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:16Z", "app_name": "student", "migration": "0002_text_to_varchar_and_indexes"}}, {"pk": 13, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0003_auto__add_usertestgroup"}}, {"pk": 14, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0004_add_email_index"}}, {"pk": 15, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0005_name_change"}}, {"pk": 16, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0006_expand_meta_field"}}, {"pk": 17, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0007_convert_to_utf8"}}, {"pk": 18, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0008__auto__add_courseregistration"}}, {"pk": 19, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0009_auto__del_courseregistration__add_courseenrollment"}}, {"pk": 20, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0010_auto__chg_field_courseenrollment_course_id"}}, {"pk": 21, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0011_auto__chg_field_courseenrollment_user__del_unique_courseenrollment_use"}}, {"pk": 22, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0012_auto__add_field_userprofile_gender__add_field_userprofile_date_of_birt"}}, {"pk": 23, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0013_auto__chg_field_userprofile_meta"}}, {"pk": 24, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0014_auto__del_courseenrollment"}}, {"pk": 25, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0015_auto__add_courseenrollment__add_unique_courseenrollment_user_course_id"}}, {"pk": 26, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0016_auto__add_field_courseenrollment_date__chg_field_userprofile_country"}}, {"pk": 27, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0017_rename_date_to_created"}}, {"pk": 28, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0018_auto"}}, {"pk": 29, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:17Z", "app_name": "student", "migration": "0019_create_approved_demographic_fields_fall_2012"}}, {"pk": 30, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:18Z", "app_name": "student", "migration": "0020_add_test_center_user"}}, {"pk": 31, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:18Z", "app_name": "student", "migration": "0021_remove_askbot"}}, {"pk": 32, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:18Z", "app_name": "student", "migration": "0022_auto__add_courseenrollmentallowed__add_unique_courseenrollmentallowed_"}}, {"pk": 33, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:18Z", "app_name": "student", "migration": "0023_add_test_center_registration"}}, {"pk": 34, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:18Z", "app_name": "student", "migration": "0024_add_allow_certificate"}}, {"pk": 35, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:18Z", "app_name": "student", "migration": "0025_auto__add_field_courseenrollmentallowed_auto_enroll"}}, {"pk": 36, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:18Z", "app_name": "student", "migration": "0026_auto__remove_index_student_testcenterregistration_accommodation_request"}}, {"pk": 37, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:18Z", "app_name": "student", "migration": "0027_add_active_flag_and_mode_to_courseware_enrollment"}}, {"pk": 38, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:19Z", "app_name": "student", "migration": "0028_auto__add_userstanding"}}, {"pk": 39, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:19Z", "app_name": "student", "migration": "0029_add_lookup_table_between_user_and_anonymous_student_id"}}, {"pk": 40, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:19Z", "app_name": "student", "migration": "0029_remove_pearson"}}, {"pk": 41, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:19Z", "app_name": "student", "migration": "0030_auto__chg_field_anonymoususerid_anonymous_user_id"}}, {"pk": 42, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:19Z", "app_name": "student", "migration": "0031_drop_student_anonymoususerid_temp_archive"}}, {"pk": 43, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:19Z", "app_name": "student", "migration": "0032_add_field_UserProfile_country_add_field_UserProfile_city"}}, {"pk": 44, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:19Z", "app_name": "student", "migration": "0032_auto__add_loginfailures"}}, {"pk": 45, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:19Z", "app_name": "student", "migration": "0033_auto__add_passwordhistory"}}, {"pk": 46, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:19Z", "app_name": "student", "migration": "0034_auto__add_courseaccessrole"}}, {"pk": 47, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "student", "migration": "0035_access_roles"}}, {"pk": 48, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "student", "migration": "0036_access_roles_orgless"}}, {"pk": 49, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "student", "migration": "0037_auto__add_courseregistrationcode"}}, {"pk": 50, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "student", "migration": "0038_auto__add_usersignupsource"}}, {"pk": 51, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "student", "migration": "0039_auto__del_courseregistrationcode"}}, {"pk": 52, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "student", "migration": "0040_auto__del_field_usersignupsource_user_id__add_field_usersignupsource_u"}}, {"pk": 53, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "student", "migration": "0041_add_dashboard_config"}}, {"pk": 54, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "student", "migration": "0042_grant_sales_admin_roles"}}, {"pk": 55, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "track", "migration": "0001_initial"}}, {"pk": 56, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:20Z", "app_name": "track", "migration": "0002_auto__add_field_trackinglog_host__chg_field_trackinglog_event_type__ch"}}, {"pk": 57, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0001_added_generatedcertificates"}}, {"pk": 58, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0002_auto__add_field_generatedcertificate_download_url"}}, {"pk": 59, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0003_auto__add_field_generatedcertificate_enabled"}}, {"pk": 60, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0004_auto__add_field_generatedcertificate_graded_certificate_id__add_field_"}}, {"pk": 61, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0005_auto__add_field_generatedcertificate_name"}}, {"pk": 62, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0006_auto__chg_field_generatedcertificate_certificate_id"}}, {"pk": 63, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0007_auto__add_revokedcertificate"}}, {"pk": 64, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0008_auto__del_revokedcertificate__del_field_generatedcertificate_name__add"}}, {"pk": 65, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0009_auto__del_field_generatedcertificate_graded_download_url__del_field_ge"}}, {"pk": 66, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0010_auto__del_field_generatedcertificate_enabled__add_field_generatedcerti"}}, {"pk": 67, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0011_auto__del_field_generatedcertificate_certificate_id__add_field_generat"}}, {"pk": 68, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0012_auto__add_field_generatedcertificate_name__add_field_generatedcertific"}}, {"pk": 69, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0013_auto__add_field_generatedcertificate_error_reason"}}, {"pk": 70, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0014_adding_whitelist"}}, {"pk": 71, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:21Z", "app_name": "certificates", "migration": "0015_adding_mode_for_verified_certs"}}, {"pk": 72, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:22Z", "app_name": "instructor_task", "migration": "0001_initial"}}, {"pk": 73, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:22Z", "app_name": "instructor_task", "migration": "0002_add_subtask_field"}}, {"pk": 74, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:22Z", "app_name": "licenses", "migration": "0001_initial"}}, {"pk": 75, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:22Z", "app_name": "course_groups", "migration": "0001_initial"}}, {"pk": 76, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:22Z", "app_name": "course_groups", "migration": "0002_add_model_CourseUserGroupPartitionGroup"}}, {"pk": 77, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0001_initial"}}, {"pk": 78, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0002_change_field_names"}}, {"pk": 79, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0003_add_optout_user"}}, {"pk": 80, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0004_migrate_optout_user"}}, {"pk": 81, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0005_remove_optout_email"}}, {"pk": 82, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0006_add_course_email_template"}}, {"pk": 83, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0007_load_course_email_template"}}, {"pk": 84, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0008_add_course_authorizations"}}, {"pk": 85, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0009_force_unique_course_ids"}}, {"pk": 86, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "bulk_email", "migration": "0010_auto__chg_field_optout_course_id__add_field_courseemail_template_name_"}}, {"pk": 87, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:23Z", "app_name": "external_auth", "migration": "0001_initial"}}, {"pk": 88, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:24Z", "app_name": "oauth2", "migration": "0001_initial"}}, {"pk": 89, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:24Z", "app_name": "oauth2", "migration": "0002_auto__chg_field_client_user"}}, {"pk": 90, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:24Z", "app_name": "oauth2", "migration": "0003_auto__add_field_client_name"}}, {"pk": 91, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:24Z", "app_name": "oauth2", "migration": "0004_auto__add_index_accesstoken_token"}}, {"pk": 92, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:24Z", "app_name": "oauth2_provider", "migration": "0001_initial"}}, {"pk": 93, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:25Z", "app_name": "wiki", "migration": "0001_initial"}}, {"pk": 94, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:25Z", "app_name": "wiki", "migration": "0002_auto__add_field_articleplugin_created"}}, {"pk": 95, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:25Z", "app_name": "wiki", "migration": "0003_auto__add_field_urlpath_article"}}, {"pk": 96, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:25Z", "app_name": "wiki", "migration": "0004_populate_urlpath__article"}}, {"pk": 97, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:25Z", "app_name": "wiki", "migration": "0005_auto__chg_field_urlpath_article"}}, {"pk": 98, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:26Z", "app_name": "wiki", "migration": "0006_auto__add_attachmentrevision__add_image__add_attachment"}}, {"pk": 99, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:26Z", "app_name": "wiki", "migration": "0007_auto__add_articlesubscription"}}, {"pk": 100, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:26Z", "app_name": "wiki", "migration": "0008_auto__add_simpleplugin__add_revisionpluginrevision__add_imagerevision_"}}, {"pk": 101, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:26Z", "app_name": "wiki", "migration": "0009_auto__add_field_imagerevision_width__add_field_imagerevision_height"}}, {"pk": 102, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:26Z", "app_name": "wiki", "migration": "0010_auto__chg_field_imagerevision_image"}}, {"pk": 103, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:26Z", "app_name": "wiki", "migration": "0011_auto__chg_field_imagerevision_width__chg_field_imagerevision_height"}}, {"pk": 104, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:27Z", "app_name": "django_notify", "migration": "0001_initial"}}, {"pk": 105, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:27Z", "app_name": "notifications", "migration": "0001_initial"}}, {"pk": 106, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:27Z", "app_name": "foldit", "migration": "0001_initial"}}, {"pk": 107, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:28Z", "app_name": "django_comment_client", "migration": "0001_initial"}}, {"pk": 108, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:28Z", "app_name": "django_comment_common", "migration": "0001_initial"}}, {"pk": 109, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:29Z", "app_name": "notes", "migration": "0001_initial"}}, {"pk": 110, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:29Z", "app_name": "splash", "migration": "0001_initial"}}, {"pk": 111, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:29Z", "app_name": "splash", "migration": "0002_auto__add_field_splashconfig_unaffected_url_paths"}}, {"pk": 112, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:29Z", "app_name": "user_api", "migration": "0001_initial"}}, {"pk": 113, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "user_api", "migration": "0002_auto__add_usercoursetags__add_unique_usercoursetags_user_course_id_key"}}, {"pk": 114, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "user_api", "migration": "0003_rename_usercoursetags"}}, {"pk": 115, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "user_api", "migration": "0004_auto__add_userorgtag__add_unique_userorgtag_user_org_key__chg_field_us"}}, {"pk": 116, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "shoppingcart", "migration": "0001_initial"}}, {"pk": 117, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "shoppingcart", "migration": "0002_auto__add_field_paidcourseregistration_mode"}}, {"pk": 118, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "shoppingcart", "migration": "0003_auto__del_field_orderitem_line_cost"}}, {"pk": 119, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "shoppingcart", "migration": "0004_auto__add_field_orderitem_fulfilled_time"}}, {"pk": 120, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "shoppingcart", "migration": "0005_auto__add_paidcourseregistrationannotation__add_field_orderitem_report"}}, {"pk": 121, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "shoppingcart", "migration": "0006_auto__add_field_order_refunded_time__add_field_orderitem_refund_reques"}}, {"pk": 122, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:30Z", "app_name": "shoppingcart", "migration": "0007_auto__add_field_orderitem_service_fee"}}, {"pk": 123, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:31Z", "app_name": "shoppingcart", "migration": "0008_auto__add_coupons__add_couponredemption__chg_field_certificateitem_cou"}}, {"pk": 124, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:31Z", "app_name": "shoppingcart", "migration": "0009_auto__del_coupons__add_courseregistrationcode__add_coupon__chg_field_c"}}, {"pk": 125, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:31Z", "app_name": "shoppingcart", "migration": "0010_auto__add_registrationcoderedemption__del_field_courseregistrationcode"}}, {"pk": 126, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:31Z", "app_name": "shoppingcart", "migration": "0011_auto__add_invoice__add_field_courseregistrationcode_invoice"}}, {"pk": 127, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:31Z", "app_name": "shoppingcart", "migration": "0012_auto__del_field_courseregistrationcode_transaction_group_name__del_fie"}}, {"pk": 128, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:32Z", "app_name": "shoppingcart", "migration": "0013_auto__add_field_invoice_is_valid"}}, {"pk": 129, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:32Z", "app_name": "shoppingcart", "migration": "0014_auto__del_field_invoice_tax_id__add_field_invoice_address_line_1__add_"}}, {"pk": 130, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:32Z", "app_name": "shoppingcart", "migration": "0015_auto__del_field_invoice_purchase_order_number__del_field_invoice_compa"}}, {"pk": 131, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:32Z", "app_name": "shoppingcart", "migration": "0016_auto__del_field_invoice_company_email__del_field_invoice_company_refer"}}, {"pk": 132, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:32Z", "app_name": "shoppingcart", "migration": "0017_auto__add_field_courseregistrationcode_order__chg_field_registrationco"}}, {"pk": 133, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:32Z", "app_name": "shoppingcart", "migration": "0018_auto__add_donation"}}, {"pk": 134, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:32Z", "app_name": "shoppingcart", "migration": "0019_auto__add_donationconfiguration"}}, {"pk": 135, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:33Z", "app_name": "shoppingcart", "migration": "0020_auto__add_courseregcodeitem__add_courseregcodeitemannotation__add_fiel"}}, {"pk": 136, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:33Z", "app_name": "shoppingcart", "migration": "0021_auto__add_field_orderitem_created__add_field_orderitem_modified"}}, {"pk": 137, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:33Z", "app_name": "shoppingcart", "migration": "0022_auto__add_field_registrationcoderedemption_course_enrollment__add_fiel"}}, {"pk": 138, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:33Z", "app_name": "shoppingcart", "migration": "0023_auto__add_field_coupon_expiration_date"}}, {"pk": 139, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:33Z", "app_name": "shoppingcart", "migration": "0024_auto__add_field_courseregistrationcode_mode_slug"}}, {"pk": 140, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:33Z", "app_name": "course_modes", "migration": "0001_initial"}}, {"pk": 141, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:33Z", "app_name": "course_modes", "migration": "0002_auto__add_field_coursemode_currency"}}, {"pk": 142, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:33Z", "app_name": "course_modes", "migration": "0003_auto__add_unique_coursemode_course_id_currency_mode_slug"}}, {"pk": 143, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:34Z", "app_name": "course_modes", "migration": "0004_auto__add_field_coursemode_expiration_date"}}, {"pk": 144, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:34Z", "app_name": "course_modes", "migration": "0005_auto__add_field_coursemode_expiration_datetime"}}, {"pk": 145, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:34Z", "app_name": "course_modes", "migration": "0006_expiration_date_to_datetime"}}, {"pk": 146, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:34Z", "app_name": "course_modes", "migration": "0007_add_description"}}, {"pk": 147, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:34Z", "app_name": "course_modes", "migration": "0007_auto__add_coursemodesarchive__chg_field_coursemode_course_id"}}, {"pk": 148, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:34Z", "app_name": "verify_student", "migration": "0001_initial"}}, {"pk": 149, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:34Z", "app_name": "verify_student", "migration": "0002_auto__add_field_softwaresecurephotoverification_window"}}, {"pk": 150, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:34Z", "app_name": "verify_student", "migration": "0003_auto__add_field_softwaresecurephotoverification_display"}}, {"pk": 151, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:35Z", "app_name": "dark_lang", "migration": "0001_initial"}}, {"pk": 152, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:35Z", "app_name": "dark_lang", "migration": "0002_enable_on_install"}}, {"pk": 153, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:35Z", "app_name": "reverification", "migration": "0001_initial"}}, {"pk": 154, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:35Z", "app_name": "embargo", "migration": "0001_initial"}}, {"pk": 155, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:36Z", "app_name": "course_action_state", "migration": "0001_initial"}}, {"pk": 156, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:36Z", "app_name": "course_action_state", "migration": "0002_add_rerun_display_name"}}, {"pk": 157, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:36Z", "app_name": "survey", "migration": "0001_initial"}}, {"pk": 158, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:37Z", "app_name": "lms_xblock", "migration": "0001_initial"}}, {"pk": 159, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:37Z", "app_name": "mentoring", "migration": "0001_initial"}}, {"pk": 160, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:37Z", "app_name": "mentoring", "migration": "0002_auto__add_field_answer_course_id__chg_field_answer_student_id"}}, {"pk": 161, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:37Z", "app_name": "mentoring", "migration": "0003_auto__del_unique_answer_student_id_name__add_unique_answer_course_id_s"}}, {"pk": 162, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:37Z", "app_name": "mentoring", "migration": "0004_auto__add_lightchild__add_unique_lightchild_student_id_course_id_name"}}, {"pk": 163, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:37Z", "app_name": "mentoring", "migration": "0005_auto__chg_field_lightchild_name"}}, {"pk": 164, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:38Z", "app_name": "submissions", "migration": "0001_initial"}}, {"pk": 165, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:38Z", "app_name": "submissions", "migration": "0002_auto__add_scoresummary"}}, {"pk": 166, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:38Z", "app_name": "submissions", "migration": "0003_auto__del_field_submission_answer__add_field_submission_raw_answer"}}, {"pk": 167, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:38Z", "app_name": "submissions", "migration": "0004_auto__add_field_score_reset"}}, {"pk": 168, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:39Z", "app_name": "assessment", "migration": "0001_initial"}}, {"pk": 169, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:39Z", "app_name": "assessment", "migration": "0002_auto__add_assessmentfeedbackoption__del_field_assessmentfeedback_feedb"}}, {"pk": 170, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:39Z", "app_name": "assessment", "migration": "0003_add_index_pw_course_item_student"}}, {"pk": 171, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:39Z", "app_name": "assessment", "migration": "0004_auto__add_field_peerworkflow_graded_count"}}, {"pk": 172, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:39Z", "app_name": "assessment", "migration": "0005_auto__del_field_peerworkflow_graded_count__add_field_peerworkflow_grad"}}, {"pk": 173, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:39Z", "app_name": "assessment", "migration": "0006_auto__add_field_assessmentpart_feedback"}}, {"pk": 174, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:39Z", "app_name": "assessment", "migration": "0007_auto__chg_field_assessmentpart_feedback"}}, {"pk": 175, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:40Z", "app_name": "assessment", "migration": "0008_student_training"}}, {"pk": 176, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:40Z", "app_name": "assessment", "migration": "0009_auto__add_unique_studenttrainingworkflowitem_order_num_workflow"}}, {"pk": 177, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:40Z", "app_name": "assessment", "migration": "0010_auto__add_unique_studenttrainingworkflow_submission_uuid"}}, {"pk": 178, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:40Z", "app_name": "assessment", "migration": "0011_ai_training"}}, {"pk": 179, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:40Z", "app_name": "assessment", "migration": "0012_move_algorithm_id_to_classifier_set"}}, {"pk": 180, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:40Z", "app_name": "assessment", "migration": "0013_auto__add_field_aigradingworkflow_essay_text"}}, {"pk": 181, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:40Z", "app_name": "assessment", "migration": "0014_auto__add_field_aitrainingworkflow_item_id__add_field_aitrainingworkfl"}}, {"pk": 182, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:40Z", "app_name": "assessment", "migration": "0015_auto__add_unique_aitrainingworkflow_uuid__add_unique_aigradingworkflow"}}, {"pk": 183, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:41Z", "app_name": "assessment", "migration": "0016_auto__add_field_aiclassifierset_course_id__add_field_aiclassifierset_i"}}, {"pk": 184, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:41Z", "app_name": "assessment", "migration": "0016_auto__add_field_rubric_structure_hash"}}, {"pk": 185, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:41Z", "app_name": "assessment", "migration": "0017_rubric_structure_hash"}}, {"pk": 186, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:41Z", "app_name": "assessment", "migration": "0018_auto__add_field_assessmentpart_criterion"}}, {"pk": 187, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:41Z", "app_name": "assessment", "migration": "0019_assessmentpart_criterion_field"}}, {"pk": 188, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:41Z", "app_name": "assessment", "migration": "0020_assessmentpart_criterion_not_null"}}, {"pk": 189, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:41Z", "app_name": "assessment", "migration": "0021_assessmentpart_option_nullable"}}, {"pk": 190, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:41Z", "app_name": "assessment", "migration": "0022__add_label_fields"}}, {"pk": 191, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:41Z", "app_name": "assessment", "migration": "0023_assign_criteria_and_option_labels"}}, {"pk": 192, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:42Z", "app_name": "assessment", "migration": "0024_auto__chg_field_assessmentpart_criterion"}}, {"pk": 193, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:42Z", "app_name": "workflow", "migration": "0001_initial"}}, {"pk": 194, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:42Z", "app_name": "workflow", "migration": "0002_auto__add_field_assessmentworkflow_course_id__add_field_assessmentwork"}}, {"pk": 195, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:42Z", "app_name": "workflow", "migration": "0003_auto__add_assessmentworkflowstep"}}, {"pk": 196, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:42Z", "app_name": "edxval", "migration": "0001_initial"}}, {"pk": 197, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:43Z", "app_name": "edxval", "migration": "0002_default_profiles"}}, {"pk": 198, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:43Z", "app_name": "edxval", "migration": "0003_status_and_created_fields"}}, {"pk": 199, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:43Z", "app_name": "milestones", "migration": "0001_initial"}}, {"pk": 200, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:43Z", "app_name": "milestones", "migration": "0002_seed_relationship_types"}}, {"pk": 201, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:43Z", "app_name": "django_extensions", "migration": "0001_empty"}}, {"pk": 202, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:46Z", "app_name": "contentstore", "migration": "0001_initial"}}, {"pk": 203, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:46Z", "app_name": "course_creators", "migration": "0001_initial"}}, {"pk": 204, "model": "south.migrationhistory", "fields": {"applied": "2015-01-15T03:15:46Z", "app_name": "xblock_config", "migration": "0001_initial"}}, {"pk": 1, "model": "edxval.profile", "fields": {"width": 1280, "profile_name": "desktop_mp4", "extension": "mp4", "height": 720}}, {"pk": 2, "model": "edxval.profile", "fields": {"width": 1280, "profile_name": "desktop_webm", "extension": "webm", "height": 720}}, {"pk": 3, "model": "edxval.profile", "fields": {"width": 960, "profile_name": "mobile_high", "extension": "mp4", "height": 540}}, {"pk": 4, "model": "edxval.profile", "fields": {"width": 640, "profile_name": "mobile_low", "extension": "mp4", "height": 360}}, {"pk": 5, "model": "edxval.profile", "fields": {"width": 1920, "profile_name": "youtube", "extension": "mp4", "height": 1080}}, {"pk": 1, "model": "milestones.milestonerelationshiptype", "fields": {"active": true, "description": "Autogenerated milestone relationship type \"fulfills\"", "modified": "2015-01-15T03:15:43Z", "name": "fulfills", "created": "2015-01-15T03:15:43Z"}}, {"pk": 2, "model": "milestones.milestonerelationshiptype", "fields": {"active": true, "description": "Autogenerated milestone relationship type \"requires\"", "modified": "2015-01-15T03:15:43Z", "name": "requires", "created": "2015-01-15T03:15:43Z"}}, {"pk": 61, "model": "auth.permission", "fields": {"codename": "add_logentry", "name": "Can add log entry", "content_type": 21}}, {"pk": 62, "model": "auth.permission", "fields": {"codename": "change_logentry", "name": "Can change log entry", "content_type": 21}}, {"pk": 63, "model": "auth.permission", "fields": {"codename": "delete_logentry", "name": "Can delete log entry", "content_type": 21}}, {"pk": 394, "model": "auth.permission", "fields": {"codename": "add_aiclassifier", "name": "Can add ai classifier", "content_type": 131}}, {"pk": 395, "model": "auth.permission", "fields": {"codename": "change_aiclassifier", "name": "Can change ai classifier", "content_type": 131}}, {"pk": 396, "model": "auth.permission", "fields": {"codename": "delete_aiclassifier", "name": "Can delete ai classifier", "content_type": 131}}, {"pk": 391, "model": "auth.permission", "fields": {"codename": "add_aiclassifierset", "name": "Can add ai classifier set", "content_type": 130}}, {"pk": 392, "model": "auth.permission", "fields": {"codename": "change_aiclassifierset", "name": "Can change ai classifier set", "content_type": 130}}, {"pk": 393, "model": "auth.permission", "fields": {"codename": "delete_aiclassifierset", "name": "Can delete ai classifier set", "content_type": 130}}, {"pk": 400, "model": "auth.permission", "fields": {"codename": "add_aigradingworkflow", "name": "Can add ai grading workflow", "content_type": 133}}, {"pk": 401, "model": "auth.permission", "fields": {"codename": "change_aigradingworkflow", "name": "Can change ai grading workflow", "content_type": 133}}, {"pk": 402, "model": "auth.permission", "fields": {"codename": "delete_aigradingworkflow", "name": "Can delete ai grading workflow", "content_type": 133}}, {"pk": 397, "model": "auth.permission", "fields": {"codename": "add_aitrainingworkflow", "name": "Can add ai training workflow", "content_type": 132}}, {"pk": 398, "model": "auth.permission", "fields": {"codename": "change_aitrainingworkflow", "name": "Can change ai training workflow", "content_type": 132}}, {"pk": 399, "model": "auth.permission", "fields": {"codename": "delete_aitrainingworkflow", "name": "Can delete ai training workflow", "content_type": 132}}, {"pk": 364, "model": "auth.permission", "fields": {"codename": "add_assessment", "name": "Can add assessment", "content_type": 121}}, {"pk": 365, "model": "auth.permission", "fields": {"codename": "change_assessment", "name": "Can change assessment", "content_type": 121}}, {"pk": 366, "model": "auth.permission", "fields": {"codename": "delete_assessment", "name": "Can delete assessment", "content_type": 121}}, {"pk": 373, "model": "auth.permission", "fields": {"codename": "add_assessmentfeedback", "name": "Can add assessment feedback", "content_type": 124}}, {"pk": 374, "model": "auth.permission", "fields": {"codename": "change_assessmentfeedback", "name": "Can change assessment feedback", "content_type": 124}}, {"pk": 375, "model": "auth.permission", "fields": {"codename": "delete_assessmentfeedback", "name": "Can delete assessment feedback", "content_type": 124}}, {"pk": 370, "model": "auth.permission", "fields": {"codename": "add_assessmentfeedbackoption", "name": "Can add assessment feedback option", "content_type": 123}}, {"pk": 371, "model": "auth.permission", "fields": {"codename": "change_assessmentfeedbackoption", "name": "Can change assessment feedback option", "content_type": 123}}, {"pk": 372, "model": "auth.permission", "fields": {"codename": "delete_assessmentfeedbackoption", "name": "Can delete assessment feedback option", "content_type": 123}}, {"pk": 367, "model": "auth.permission", "fields": {"codename": "add_assessmentpart", "name": "Can add assessment part", "content_type": 122}}, {"pk": 368, "model": "auth.permission", "fields": {"codename": "change_assessmentpart", "name": "Can change assessment part", "content_type": 122}}, {"pk": 369, "model": "auth.permission", "fields": {"codename": "delete_assessmentpart", "name": "Can delete assessment part", "content_type": 122}}, {"pk": 358, "model": "auth.permission", "fields": {"codename": "add_criterion", "name": "Can add criterion", "content_type": 119}}, {"pk": 359, "model": "auth.permission", "fields": {"codename": "change_criterion", "name": "Can change criterion", "content_type": 119}}, {"pk": 360, "model": "auth.permission", "fields": {"codename": "delete_criterion", "name": "Can delete criterion", "content_type": 119}}, {"pk": 361, "model": "auth.permission", "fields": {"codename": "add_criterionoption", "name": "Can add criterion option", "content_type": 120}}, {"pk": 362, "model": "auth.permission", "fields": {"codename": "change_criterionoption", "name": "Can change criterion option", "content_type": 120}}, {"pk": 363, "model": "auth.permission", "fields": {"codename": "delete_criterionoption", "name": "Can delete criterion option", "content_type": 120}}, {"pk": 376, "model": "auth.permission", "fields": {"codename": "add_peerworkflow", "name": "Can add peer workflow", "content_type": 125}}, {"pk": 377, "model": "auth.permission", "fields": {"codename": "change_peerworkflow", "name": "Can change peer workflow", "content_type": 125}}, {"pk": 378, "model": "auth.permission", "fields": {"codename": "delete_peerworkflow", "name": "Can delete peer workflow", "content_type": 125}}, {"pk": 379, "model": "auth.permission", "fields": {"codename": "add_peerworkflowitem", "name": "Can add peer workflow item", "content_type": 126}}, {"pk": 380, "model": "auth.permission", "fields": {"codename": "change_peerworkflowitem", "name": "Can change peer workflow item", "content_type": 126}}, {"pk": 381, "model": "auth.permission", "fields": {"codename": "delete_peerworkflowitem", "name": "Can delete peer workflow item", "content_type": 126}}, {"pk": 355, "model": "auth.permission", "fields": {"codename": "add_rubric", "name": "Can add rubric", "content_type": 118}}, {"pk": 356, "model": "auth.permission", "fields": {"codename": "change_rubric", "name": "Can change rubric", "content_type": 118}}, {"pk": 357, "model": "auth.permission", "fields": {"codename": "delete_rubric", "name": "Can delete rubric", "content_type": 118}}, {"pk": 385, "model": "auth.permission", "fields": {"codename": "add_studenttrainingworkflow", "name": "Can add student training workflow", "content_type": 128}}, {"pk": 386, "model": "auth.permission", "fields": {"codename": "change_studenttrainingworkflow", "name": "Can change student training workflow", "content_type": 128}}, {"pk": 387, "model": "auth.permission", "fields": {"codename": "delete_studenttrainingworkflow", "name": "Can delete student training workflow", "content_type": 128}}, {"pk": 388, "model": "auth.permission", "fields": {"codename": "add_studenttrainingworkflowitem", "name": "Can add student training workflow item", "content_type": 129}}, {"pk": 389, "model": "auth.permission", "fields": {"codename": "change_studenttrainingworkflowitem", "name": "Can change student training workflow item", "content_type": 129}}, {"pk": 390, "model": "auth.permission", "fields": {"codename": "delete_studenttrainingworkflowitem", "name": "Can delete student training workflow item", "content_type": 129}}, {"pk": 382, "model": "auth.permission", "fields": {"codename": "add_trainingexample", "name": "Can add training example", "content_type": 127}}, {"pk": 383, "model": "auth.permission", "fields": {"codename": "change_trainingexample", "name": "Can change training example", "content_type": 127}}, {"pk": 384, "model": "auth.permission", "fields": {"codename": "delete_trainingexample", "name": "Can delete training example", "content_type": 127}}, {"pk": 4, "model": "auth.permission", "fields": {"codename": "add_group", "name": "Can add group", "content_type": 2}}, {"pk": 5, "model": "auth.permission", "fields": {"codename": "change_group", "name": "Can change group", "content_type": 2}}, {"pk": 6, "model": "auth.permission", "fields": {"codename": "delete_group", "name": "Can delete group", "content_type": 2}}, {"pk": 1, "model": "auth.permission", "fields": {"codename": "add_permission", "name": "Can add permission", "content_type": 1}}, {"pk": 2, "model": "auth.permission", "fields": {"codename": "change_permission", "name": "Can change permission", "content_type": 1}}, {"pk": 3, "model": "auth.permission", "fields": {"codename": "delete_permission", "name": "Can delete permission", "content_type": 1}}, {"pk": 7, "model": "auth.permission", "fields": {"codename": "add_user", "name": "Can add user", "content_type": 3}}, {"pk": 8, "model": "auth.permission", "fields": {"codename": "change_user", "name": "Can change user", "content_type": 3}}, {"pk": 9, "model": "auth.permission", "fields": {"codename": "delete_user", "name": "Can delete user", "content_type": 3}}, {"pk": 172, "model": "auth.permission", "fields": {"codename": "add_courseauthorization", "name": "Can add course authorization", "content_type": 58}}, {"pk": 173, "model": "auth.permission", "fields": {"codename": "change_courseauthorization", "name": "Can change course authorization", "content_type": 58}}, {"pk": 174, "model": "auth.permission", "fields": {"codename": "delete_courseauthorization", "name": "Can delete course authorization", "content_type": 58}}, {"pk": 163, "model": "auth.permission", "fields": {"codename": "add_courseemail", "name": "Can add course email", "content_type": 55}}, {"pk": 164, "model": "auth.permission", "fields": {"codename": "change_courseemail", "name": "Can change course email", "content_type": 55}}, {"pk": 165, "model": "auth.permission", "fields": {"codename": "delete_courseemail", "name": "Can delete course email", "content_type": 55}}, {"pk": 169, "model": "auth.permission", "fields": {"codename": "add_courseemailtemplate", "name": "Can add course email template", "content_type": 57}}, {"pk": 170, "model": "auth.permission", "fields": {"codename": "change_courseemailtemplate", "name": "Can change course email template", "content_type": 57}}, {"pk": 171, "model": "auth.permission", "fields": {"codename": "delete_courseemailtemplate", "name": "Can delete course email template", "content_type": 57}}, {"pk": 166, "model": "auth.permission", "fields": {"codename": "add_optout", "name": "Can add optout", "content_type": 56}}, {"pk": 167, "model": "auth.permission", "fields": {"codename": "change_optout", "name": "Can change optout", "content_type": 56}}, {"pk": 168, "model": "auth.permission", "fields": {"codename": "delete_optout", "name": "Can delete optout", "content_type": 56}}, {"pk": 142, "model": "auth.permission", "fields": {"codename": "add_certificatewhitelist", "name": "Can add certificate whitelist", "content_type": 48}}, {"pk": 143, "model": "auth.permission", "fields": {"codename": "change_certificatewhitelist", "name": "Can change certificate whitelist", "content_type": 48}}, {"pk": 144, "model": "auth.permission", "fields": {"codename": "delete_certificatewhitelist", "name": "Can delete certificate whitelist", "content_type": 48}}, {"pk": 145, "model": "auth.permission", "fields": {"codename": "add_generatedcertificate", "name": "Can add generated certificate", "content_type": 49}}, {"pk": 146, "model": "auth.permission", "fields": {"codename": "change_generatedcertificate", "name": "Can change generated certificate", "content_type": 49}}, {"pk": 147, "model": "auth.permission", "fields": {"codename": "delete_generatedcertificate", "name": "Can delete generated certificate", "content_type": 49}}, {"pk": 46, "model": "auth.permission", "fields": {"codename": "add_servercircuit", "name": "Can add server circuit", "content_type": 16}}, {"pk": 47, "model": "auth.permission", "fields": {"codename": "change_servercircuit", "name": "Can change server circuit", "content_type": 16}}, {"pk": 48, "model": "auth.permission", "fields": {"codename": "delete_servercircuit", "name": "Can delete server circuit", "content_type": 16}}, {"pk": 439, "model": "auth.permission", "fields": {"codename": "add_videouploadconfig", "name": "Can add video upload config", "content_type": 146}}, {"pk": 440, "model": "auth.permission", "fields": {"codename": "change_videouploadconfig", "name": "Can change video upload config", "content_type": 146}}, {"pk": 441, "model": "auth.permission", "fields": {"codename": "delete_videouploadconfig", "name": "Can delete video upload config", "content_type": 146}}, {"pk": 10, "model": "auth.permission", "fields": {"codename": "add_contenttype", "name": "Can add content type", "content_type": 4}}, {"pk": 11, "model": "auth.permission", "fields": {"codename": "change_contenttype", "name": "Can change content type", "content_type": 4}}, {"pk": 12, "model": "auth.permission", "fields": {"codename": "delete_contenttype", "name": "Can delete content type", "content_type": 4}}, {"pk": 91, "model": "auth.permission", "fields": {"codename": "add_offlinecomputedgrade", "name": "Can add offline computed grade", "content_type": 31}}, {"pk": 92, "model": "auth.permission", "fields": {"codename": "change_offlinecomputedgrade", "name": "Can change offline computed grade", "content_type": 31}}, {"pk": 93, "model": "auth.permission", "fields": {"codename": "delete_offlinecomputedgrade", "name": "Can delete offline computed grade", "content_type": 31}}, {"pk": 94, "model": "auth.permission", "fields": {"codename": "add_offlinecomputedgradelog", "name": "Can add offline computed grade log", "content_type": 32}}, {"pk": 95, "model": "auth.permission", "fields": {"codename": "change_offlinecomputedgradelog", "name": "Can change offline computed grade log", "content_type": 32}}, {"pk": 96, "model": "auth.permission", "fields": {"codename": "delete_offlinecomputedgradelog", "name": "Can delete offline computed grade log", "content_type": 32}}, {"pk": 76, "model": "auth.permission", "fields": {"codename": "add_studentmodule", "name": "Can add student module", "content_type": 26}}, {"pk": 77, "model": "auth.permission", "fields": {"codename": "change_studentmodule", "name": "Can change student module", "content_type": 26}}, {"pk": 78, "model": "auth.permission", "fields": {"codename": "delete_studentmodule", "name": "Can delete student module", "content_type": 26}}, {"pk": 79, "model": "auth.permission", "fields": {"codename": "add_studentmodulehistory", "name": "Can add student module history", "content_type": 27}}, {"pk": 80, "model": "auth.permission", "fields": {"codename": "change_studentmodulehistory", "name": "Can change student module history", "content_type": 27}}, {"pk": 81, "model": "auth.permission", "fields": {"codename": "delete_studentmodulehistory", "name": "Can delete student module history", "content_type": 27}}, {"pk": 88, "model": "auth.permission", "fields": {"codename": "add_xmodulestudentinfofield", "name": "Can add x module student info field", "content_type": 30}}, {"pk": 89, "model": "auth.permission", "fields": {"codename": "change_xmodulestudentinfofield", "name": "Can change x module student info field", "content_type": 30}}, {"pk": 90, "model": "auth.permission", "fields": {"codename": "delete_xmodulestudentinfofield", "name": "Can delete x module student info field", "content_type": 30}}, {"pk": 85, "model": "auth.permission", "fields": {"codename": "add_xmodulestudentprefsfield", "name": "Can add x module student prefs field", "content_type": 29}}, {"pk": 86, "model": "auth.permission", "fields": {"codename": "change_xmodulestudentprefsfield", "name": "Can change x module student prefs field", "content_type": 29}}, {"pk": 87, "model": "auth.permission", "fields": {"codename": "delete_xmodulestudentprefsfield", "name": "Can delete x module student prefs field", "content_type": 29}}, {"pk": 82, "model": "auth.permission", "fields": {"codename": "add_xmoduleuserstatesummaryfield", "name": "Can add x module user state summary field", "content_type": 28}}, {"pk": 83, "model": "auth.permission", "fields": {"codename": "change_xmoduleuserstatesummaryfield", "name": "Can change x module user state summary field", "content_type": 28}}, {"pk": 84, "model": "auth.permission", "fields": {"codename": "delete_xmoduleuserstatesummaryfield", "name": "Can delete x module user state summary field", "content_type": 28}}, {"pk": 325, "model": "auth.permission", "fields": {"codename": "add_coursererunstate", "name": "Can add course rerun state", "content_type": 108}}, {"pk": 326, "model": "auth.permission", "fields": {"codename": "change_coursererunstate", "name": "Can change course rerun state", "content_type": 108}}, {"pk": 327, "model": "auth.permission", "fields": {"codename": "delete_coursererunstate", "name": "Can delete course rerun state", "content_type": 108}}, {"pk": 442, "model": "auth.permission", "fields": {"codename": "add_coursecreator", "name": "Can add course creator", "content_type": 147}}, {"pk": 443, "model": "auth.permission", "fields": {"codename": "change_coursecreator", "name": "Can change course creator", "content_type": 147}}, {"pk": 444, "model": "auth.permission", "fields": {"codename": "delete_coursecreator", "name": "Can delete course creator", "content_type": 147}}, {"pk": 157, "model": "auth.permission", "fields": {"codename": "add_courseusergroup", "name": "Can add course user group", "content_type": 53}}, {"pk": 158, "model": "auth.permission", "fields": {"codename": "change_courseusergroup", "name": "Can change course user group", "content_type": 53}}, {"pk": 159, "model": "auth.permission", "fields": {"codename": "delete_courseusergroup", "name": "Can delete course user group", "content_type": 53}}, {"pk": 160, "model": "auth.permission", "fields": {"codename": "add_courseusergrouppartitiongroup", "name": "Can add course user group partition group", "content_type": 54}}, {"pk": 161, "model": "auth.permission", "fields": {"codename": "change_courseusergrouppartitiongroup", "name": "Can change course user group partition group", "content_type": 54}}, {"pk": 162, "model": "auth.permission", "fields": {"codename": "delete_courseusergrouppartitiongroup", "name": "Can delete course user group partition group", "content_type": 54}}, {"pk": 301, "model": "auth.permission", "fields": {"codename": "add_coursemode", "name": "Can add course mode", "content_type": 100}}, {"pk": 302, "model": "auth.permission", "fields": {"codename": "change_coursemode", "name": "Can change course mode", "content_type": 100}}, {"pk": 303, "model": "auth.permission", "fields": {"codename": "delete_coursemode", "name": "Can delete course mode", "content_type": 100}}, {"pk": 304, "model": "auth.permission", "fields": {"codename": "add_coursemodesarchive", "name": "Can add course modes archive", "content_type": 101}}, {"pk": 305, "model": "auth.permission", "fields": {"codename": "change_coursemodesarchive", "name": "Can change course modes archive", "content_type": 101}}, {"pk": 306, "model": "auth.permission", "fields": {"codename": "delete_coursemodesarchive", "name": "Can delete course modes archive", "content_type": 101}}, {"pk": 310, "model": "auth.permission", "fields": {"codename": "add_darklangconfig", "name": "Can add dark lang config", "content_type": 103}}, {"pk": 311, "model": "auth.permission", "fields": {"codename": "change_darklangconfig", "name": "Can change dark lang config", "content_type": 103}}, {"pk": 312, "model": "auth.permission", "fields": {"codename": "delete_darklangconfig", "name": "Can delete dark lang config", "content_type": 103}}, {"pk": 70, "model": "auth.permission", "fields": {"codename": "add_association", "name": "Can add association", "content_type": 24}}, {"pk": 71, "model": "auth.permission", "fields": {"codename": "change_association", "name": "Can change association", "content_type": 24}}, {"pk": 72, "model": "auth.permission", "fields": {"codename": "delete_association", "name": "Can delete association", "content_type": 24}}, {"pk": 73, "model": "auth.permission", "fields": {"codename": "add_code", "name": "Can add code", "content_type": 25}}, {"pk": 74, "model": "auth.permission", "fields": {"codename": "change_code", "name": "Can change code", "content_type": 25}}, {"pk": 75, "model": "auth.permission", "fields": {"codename": "delete_code", "name": "Can delete code", "content_type": 25}}, {"pk": 67, "model": "auth.permission", "fields": {"codename": "add_nonce", "name": "Can add nonce", "content_type": 23}}, {"pk": 68, "model": "auth.permission", "fields": {"codename": "change_nonce", "name": "Can change nonce", "content_type": 23}}, {"pk": 69, "model": "auth.permission", "fields": {"codename": "delete_nonce", "name": "Can delete nonce", "content_type": 23}}, {"pk": 64, "model": "auth.permission", "fields": {"codename": "add_usersocialauth", "name": "Can add user social auth", "content_type": 22}}, {"pk": 65, "model": "auth.permission", "fields": {"codename": "change_usersocialauth", "name": "Can change user social auth", "content_type": 22}}, {"pk": 66, "model": "auth.permission", "fields": {"codename": "delete_usersocialauth", "name": "Can delete user social auth", "content_type": 22}}, {"pk": 235, "model": "auth.permission", "fields": {"codename": "add_notification", "name": "Can add notification", "content_type": 78}}, {"pk": 236, "model": "auth.permission", "fields": {"codename": "change_notification", "name": "Can change notification", "content_type": 78}}, {"pk": 237, "model": "auth.permission", "fields": {"codename": "delete_notification", "name": "Can delete notification", "content_type": 78}}, {"pk": 226, "model": "auth.permission", "fields": {"codename": "add_notificationtype", "name": "Can add type", "content_type": 75}}, {"pk": 227, "model": "auth.permission", "fields": {"codename": "change_notificationtype", "name": "Can change type", "content_type": 75}}, {"pk": 228, "model": "auth.permission", "fields": {"codename": "delete_notificationtype", "name": "Can delete type", "content_type": 75}}, {"pk": 229, "model": "auth.permission", "fields": {"codename": "add_settings", "name": "Can add settings", "content_type": 76}}, {"pk": 230, "model": "auth.permission", "fields": {"codename": "change_settings", "name": "Can change settings", "content_type": 76}}, {"pk": 231, "model": "auth.permission", "fields": {"codename": "delete_settings", "name": "Can delete settings", "content_type": 76}}, {"pk": 232, "model": "auth.permission", "fields": {"codename": "add_subscription", "name": "Can add subscription", "content_type": 77}}, {"pk": 233, "model": "auth.permission", "fields": {"codename": "change_subscription", "name": "Can change subscription", "content_type": 77}}, {"pk": 234, "model": "auth.permission", "fields": {"codename": "delete_subscription", "name": "Can delete subscription", "content_type": 77}}, {"pk": 55, "model": "auth.permission", "fields": {"codename": "add_association", "name": "Can add association", "content_type": 19}}, {"pk": 56, "model": "auth.permission", "fields": {"codename": "change_association", "name": "Can change association", "content_type": 19}}, {"pk": 57, "model": "auth.permission", "fields": {"codename": "delete_association", "name": "Can delete association", "content_type": 19}}, {"pk": 52, "model": "auth.permission", "fields": {"codename": "add_nonce", "name": "Can add nonce", "content_type": 18}}, {"pk": 53, "model": "auth.permission", "fields": {"codename": "change_nonce", "name": "Can change nonce", "content_type": 18}}, {"pk": 54, "model": "auth.permission", "fields": {"codename": "delete_nonce", "name": "Can delete nonce", "content_type": 18}}, {"pk": 58, "model": "auth.permission", "fields": {"codename": "add_useropenid", "name": "Can add user open id", "content_type": 20}}, {"pk": 59, "model": "auth.permission", "fields": {"codename": "change_useropenid", "name": "Can change user open id", "content_type": 20}}, {"pk": 60, "model": "auth.permission", "fields": {"codename": "delete_useropenid", "name": "Can delete user open id", "content_type": 20}}, {"pk": 28, "model": "auth.permission", "fields": {"codename": "add_crontabschedule", "name": "Can add crontab", "content_type": 10}}, {"pk": 29, "model": "auth.permission", "fields": {"codename": "change_crontabschedule", "name": "Can change crontab", "content_type": 10}}, {"pk": 30, "model": "auth.permission", "fields": {"codename": "delete_crontabschedule", "name": "Can delete crontab", "content_type": 10}}, {"pk": 25, "model": "auth.permission", "fields": {"codename": "add_intervalschedule", "name": "Can add interval", "content_type": 9}}, {"pk": 26, "model": "auth.permission", "fields": {"codename": "change_intervalschedule", "name": "Can change interval", "content_type": 9}}, {"pk": 27, "model": "auth.permission", "fields": {"codename": "delete_intervalschedule", "name": "Can delete interval", "content_type": 9}}, {"pk": 34, "model": "auth.permission", "fields": {"codename": "add_periodictask", "name": "Can add periodic task", "content_type": 12}}, {"pk": 35, "model": "auth.permission", "fields": {"codename": "change_periodictask", "name": "Can change periodic task", "content_type": 12}}, {"pk": 36, "model": "auth.permission", "fields": {"codename": "delete_periodictask", "name": "Can delete periodic task", "content_type": 12}}, {"pk": 31, "model": "auth.permission", "fields": {"codename": "add_periodictasks", "name": "Can add periodic tasks", "content_type": 11}}, {"pk": 32, "model": "auth.permission", "fields": {"codename": "change_periodictasks", "name": "Can change periodic tasks", "content_type": 11}}, {"pk": 33, "model": "auth.permission", "fields": {"codename": "delete_periodictasks", "name": "Can delete periodic tasks", "content_type": 11}}, {"pk": 19, "model": "auth.permission", "fields": {"codename": "add_taskmeta", "name": "Can add task state", "content_type": 7}}, {"pk": 20, "model": "auth.permission", "fields": {"codename": "change_taskmeta", "name": "Can change task state", "content_type": 7}}, {"pk": 21, "model": "auth.permission", "fields": {"codename": "delete_taskmeta", "name": "Can delete task state", "content_type": 7}}, {"pk": 22, "model": "auth.permission", "fields": {"codename": "add_tasksetmeta", "name": "Can add saved group result", "content_type": 8}}, {"pk": 23, "model": "auth.permission", "fields": {"codename": "change_tasksetmeta", "name": "Can change saved group result", "content_type": 8}}, {"pk": 24, "model": "auth.permission", "fields": {"codename": "delete_tasksetmeta", "name": "Can delete saved group result", "content_type": 8}}, {"pk": 40, "model": "auth.permission", "fields": {"codename": "add_taskstate", "name": "Can add task", "content_type": 14}}, {"pk": 41, "model": "auth.permission", "fields": {"codename": "change_taskstate", "name": "Can change task", "content_type": 14}}, {"pk": 42, "model": "auth.permission", "fields": {"codename": "delete_taskstate", "name": "Can delete task", "content_type": 14}}, {"pk": 37, "model": "auth.permission", "fields": {"codename": "add_workerstate", "name": "Can add worker", "content_type": 13}}, {"pk": 38, "model": "auth.permission", "fields": {"codename": "change_workerstate", "name": "Can change worker", "content_type": 13}}, {"pk": 39, "model": "auth.permission", "fields": {"codename": "delete_workerstate", "name": "Can delete worker", "content_type": 13}}, {"pk": 415, "model": "auth.permission", "fields": {"codename": "add_coursevideo", "name": "Can add course video", "content_type": 138}}, {"pk": 416, "model": "auth.permission", "fields": {"codename": "change_coursevideo", "name": "Can change course video", "content_type": 138}}, {"pk": 417, "model": "auth.permission", "fields": {"codename": "delete_coursevideo", "name": "Can delete course video", "content_type": 138}}, {"pk": 418, "model": "auth.permission", "fields": {"codename": "add_encodedvideo", "name": "Can add encoded video", "content_type": 139}}, {"pk": 419, "model": "auth.permission", "fields": {"codename": "change_encodedvideo", "name": "Can change encoded video", "content_type": 139}}, {"pk": 420, "model": "auth.permission", "fields": {"codename": "delete_encodedvideo", "name": "Can delete encoded video", "content_type": 139}}, {"pk": 409, "model": "auth.permission", "fields": {"codename": "add_profile", "name": "Can add profile", "content_type": 136}}, {"pk": 410, "model": "auth.permission", "fields": {"codename": "change_profile", "name": "Can change profile", "content_type": 136}}, {"pk": 411, "model": "auth.permission", "fields": {"codename": "delete_profile", "name": "Can delete profile", "content_type": 136}}, {"pk": 421, "model": "auth.permission", "fields": {"codename": "add_subtitle", "name": "Can add subtitle", "content_type": 140}}, {"pk": 422, "model": "auth.permission", "fields": {"codename": "change_subtitle", "name": "Can change subtitle", "content_type": 140}}, {"pk": 423, "model": "auth.permission", "fields": {"codename": "delete_subtitle", "name": "Can delete subtitle", "content_type": 140}}, {"pk": 412, "model": "auth.permission", "fields": {"codename": "add_video", "name": "Can add video", "content_type": 137}}, {"pk": 413, "model": "auth.permission", "fields": {"codename": "change_video", "name": "Can change video", "content_type": 137}}, {"pk": 414, "model": "auth.permission", "fields": {"codename": "delete_video", "name": "Can delete video", "content_type": 137}}, {"pk": 316, "model": "auth.permission", "fields": {"codename": "add_embargoedcourse", "name": "Can add embargoed course", "content_type": 105}}, {"pk": 317, "model": "auth.permission", "fields": {"codename": "change_embargoedcourse", "name": "Can change embargoed course", "content_type": 105}}, {"pk": 318, "model": "auth.permission", "fields": {"codename": "delete_embargoedcourse", "name": "Can delete embargoed course", "content_type": 105}}, {"pk": 319, "model": "auth.permission", "fields": {"codename": "add_embargoedstate", "name": "Can add embargoed state", "content_type": 106}}, {"pk": 320, "model": "auth.permission", "fields": {"codename": "change_embargoedstate", "name": "Can change embargoed state", "content_type": 106}}, {"pk": 321, "model": "auth.permission", "fields": {"codename": "delete_embargoedstate", "name": "Can delete embargoed state", "content_type": 106}}, {"pk": 322, "model": "auth.permission", "fields": {"codename": "add_ipfilter", "name": "Can add ip filter", "content_type": 107}}, {"pk": 323, "model": "auth.permission", "fields": {"codename": "change_ipfilter", "name": "Can change ip filter", "content_type": 107}}, {"pk": 324, "model": "auth.permission", "fields": {"codename": "delete_ipfilter", "name": "Can delete ip filter", "content_type": 107}}, {"pk": 175, "model": "auth.permission", "fields": {"codename": "add_externalauthmap", "name": "Can add external auth map", "content_type": 59}}, {"pk": 176, "model": "auth.permission", "fields": {"codename": "change_externalauthmap", "name": "Can change external auth map", "content_type": 59}}, {"pk": 177, "model": "auth.permission", "fields": {"codename": "delete_externalauthmap", "name": "Can delete external auth map", "content_type": 59}}, {"pk": 241, "model": "auth.permission", "fields": {"codename": "add_puzzlecomplete", "name": "Can add puzzle complete", "content_type": 80}}, {"pk": 242, "model": "auth.permission", "fields": {"codename": "change_puzzlecomplete", "name": "Can change puzzle complete", "content_type": 80}}, {"pk": 243, "model": "auth.permission", "fields": {"codename": "delete_puzzlecomplete", "name": "Can delete puzzle complete", "content_type": 80}}, {"pk": 238, "model": "auth.permission", "fields": {"codename": "add_score", "name": "Can add score", "content_type": 79}}, {"pk": 239, "model": "auth.permission", "fields": {"codename": "change_score", "name": "Can change score", "content_type": 79}}, {"pk": 240, "model": "auth.permission", "fields": {"codename": "delete_score", "name": "Can delete score", "content_type": 79}}, {"pk": 148, "model": "auth.permission", "fields": {"codename": "add_instructortask", "name": "Can add instructor task", "content_type": 50}}, {"pk": 149, "model": "auth.permission", "fields": {"codename": "change_instructortask", "name": "Can change instructor task", "content_type": 50}}, {"pk": 150, "model": "auth.permission", "fields": {"codename": "delete_instructortask", "name": "Can delete instructor task", "content_type": 50}}, {"pk": 151, "model": "auth.permission", "fields": {"codename": "add_coursesoftware", "name": "Can add course software", "content_type": 51}}, {"pk": 152, "model": "auth.permission", "fields": {"codename": "change_coursesoftware", "name": "Can change course software", "content_type": 51}}, {"pk": 153, "model": "auth.permission", "fields": {"codename": "delete_coursesoftware", "name": "Can delete course software", "content_type": 51}}, {"pk": 154, "model": "auth.permission", "fields": {"codename": "add_userlicense", "name": "Can add user license", "content_type": 52}}, {"pk": 155, "model": "auth.permission", "fields": {"codename": "change_userlicense", "name": "Can change user license", "content_type": 52}}, {"pk": 156, "model": "auth.permission", "fields": {"codename": "delete_userlicense", "name": "Can delete user license", "content_type": 52}}, {"pk": 334, "model": "auth.permission", "fields": {"codename": "add_xblockasidesconfig", "name": "Can add x block asides config", "content_type": 111}}, {"pk": 335, "model": "auth.permission", "fields": {"codename": "change_xblockasidesconfig", "name": "Can change x block asides config", "content_type": 111}}, {"pk": 336, "model": "auth.permission", "fields": {"codename": "delete_xblockasidesconfig", "name": "Can delete x block asides config", "content_type": 111}}, {"pk": 337, "model": "auth.permission", "fields": {"codename": "add_answer", "name": "Can add answer", "content_type": 112}}, {"pk": 338, "model": "auth.permission", "fields": {"codename": "change_answer", "name": "Can change answer", "content_type": 112}}, {"pk": 339, "model": "auth.permission", "fields": {"codename": "delete_answer", "name": "Can delete answer", "content_type": 112}}, {"pk": 340, "model": "auth.permission", "fields": {"codename": "add_lightchild", "name": "Can add light child", "content_type": 113}}, {"pk": 341, "model": "auth.permission", "fields": {"codename": "change_lightchild", "name": "Can change light child", "content_type": 113}}, {"pk": 342, "model": "auth.permission", "fields": {"codename": "delete_lightchild", "name": "Can delete light child", "content_type": 113}}, {"pk": 433, "model": "auth.permission", "fields": {"codename": "add_coursecontentmilestone", "name": "Can add course content milestone", "content_type": 144}}, {"pk": 434, "model": "auth.permission", "fields": {"codename": "change_coursecontentmilestone", "name": "Can change course content milestone", "content_type": 144}}, {"pk": 435, "model": "auth.permission", "fields": {"codename": "delete_coursecontentmilestone", "name": "Can delete course content milestone", "content_type": 144}}, {"pk": 430, "model": "auth.permission", "fields": {"codename": "add_coursemilestone", "name": "Can add course milestone", "content_type": 143}}, {"pk": 431, "model": "auth.permission", "fields": {"codename": "change_coursemilestone", "name": "Can change course milestone", "content_type": 143}}, {"pk": 432, "model": "auth.permission", "fields": {"codename": "delete_coursemilestone", "name": "Can delete course milestone", "content_type": 143}}, {"pk": 424, "model": "auth.permission", "fields": {"codename": "add_milestone", "name": "Can add milestone", "content_type": 141}}, {"pk": 425, "model": "auth.permission", "fields": {"codename": "change_milestone", "name": "Can change milestone", "content_type": 141}}, {"pk": 426, "model": "auth.permission", "fields": {"codename": "delete_milestone", "name": "Can delete milestone", "content_type": 141}}, {"pk": 427, "model": "auth.permission", "fields": {"codename": "add_milestonerelationshiptype", "name": "Can add milestone relationship type", "content_type": 142}}, {"pk": 428, "model": "auth.permission", "fields": {"codename": "change_milestonerelationshiptype", "name": "Can change milestone relationship type", "content_type": 142}}, {"pk": 429, "model": "auth.permission", "fields": {"codename": "delete_milestonerelationshiptype", "name": "Can delete milestone relationship type", "content_type": 142}}, {"pk": 436, "model": "auth.permission", "fields": {"codename": "add_usermilestone", "name": "Can add user milestone", "content_type": 145}}, {"pk": 437, "model": "auth.permission", "fields": {"codename": "change_usermilestone", "name": "Can change user milestone", "content_type": 145}}, {"pk": 438, "model": "auth.permission", "fields": {"codename": "delete_usermilestone", "name": "Can delete user milestone", "content_type": 145}}, {"pk": 244, "model": "auth.permission", "fields": {"codename": "add_note", "name": "Can add note", "content_type": 81}}, {"pk": 245, "model": "auth.permission", "fields": {"codename": "change_note", "name": "Can change note", "content_type": 81}}, {"pk": 246, "model": "auth.permission", "fields": {"codename": "delete_note", "name": "Can delete note", "content_type": 81}}, {"pk": 184, "model": "auth.permission", "fields": {"codename": "add_accesstoken", "name": "Can add access token", "content_type": 62}}, {"pk": 185, "model": "auth.permission", "fields": {"codename": "change_accesstoken", "name": "Can change access token", "content_type": 62}}, {"pk": 186, "model": "auth.permission", "fields": {"codename": "delete_accesstoken", "name": "Can delete access token", "content_type": 62}}, {"pk": 178, "model": "auth.permission", "fields": {"codename": "add_client", "name": "Can add client", "content_type": 60}}, {"pk": 179, "model": "auth.permission", "fields": {"codename": "change_client", "name": "Can change client", "content_type": 60}}, {"pk": 180, "model": "auth.permission", "fields": {"codename": "delete_client", "name": "Can delete client", "content_type": 60}}, {"pk": 181, "model": "auth.permission", "fields": {"codename": "add_grant", "name": "Can add grant", "content_type": 61}}, {"pk": 182, "model": "auth.permission", "fields": {"codename": "change_grant", "name": "Can change grant", "content_type": 61}}, {"pk": 183, "model": "auth.permission", "fields": {"codename": "delete_grant", "name": "Can delete grant", "content_type": 61}}, {"pk": 187, "model": "auth.permission", "fields": {"codename": "add_refreshtoken", "name": "Can add refresh token", "content_type": 63}}, {"pk": 188, "model": "auth.permission", "fields": {"codename": "change_refreshtoken", "name": "Can change refresh token", "content_type": 63}}, {"pk": 189, "model": "auth.permission", "fields": {"codename": "delete_refreshtoken", "name": "Can delete refresh token", "content_type": 63}}, {"pk": 190, "model": "auth.permission", "fields": {"codename": "add_trustedclient", "name": "Can add trusted client", "content_type": 64}}, {"pk": 191, "model": "auth.permission", "fields": {"codename": "change_trustedclient", "name": "Can change trusted client", "content_type": 64}}, {"pk": 192, "model": "auth.permission", "fields": {"codename": "delete_trustedclient", "name": "Can delete trusted client", "content_type": 64}}, {"pk": 49, "model": "auth.permission", "fields": {"codename": "add_psychometricdata", "name": "Can add psychometric data", "content_type": 17}}, {"pk": 50, "model": "auth.permission", "fields": {"codename": "change_psychometricdata", "name": "Can change psychometric data", "content_type": 17}}, {"pk": 51, "model": "auth.permission", "fields": {"codename": "delete_psychometricdata", "name": "Can delete psychometric data", "content_type": 17}}, {"pk": 313, "model": "auth.permission", "fields": {"codename": "add_midcoursereverificationwindow", "name": "Can add midcourse reverification window", "content_type": 104}}, {"pk": 314, "model": "auth.permission", "fields": {"codename": "change_midcoursereverificationwindow", "name": "Can change midcourse reverification window", "content_type": 104}}, {"pk": 315, "model": "auth.permission", "fields": {"codename": "delete_midcoursereverificationwindow", "name": "Can delete midcourse reverification window", "content_type": 104}}, {"pk": 13, "model": "auth.permission", "fields": {"codename": "add_session", "name": "Can add session", "content_type": 5}}, {"pk": 14, "model": "auth.permission", "fields": {"codename": "change_session", "name": "Can change session", "content_type": 5}}, {"pk": 15, "model": "auth.permission", "fields": {"codename": "delete_session", "name": "Can delete session", "content_type": 5}}, {"pk": 292, "model": "auth.permission", "fields": {"codename": "add_certificateitem", "name": "Can add certificate item", "content_type": 97}}, {"pk": 293, "model": "auth.permission", "fields": {"codename": "change_certificateitem", "name": "Can change certificate item", "content_type": 97}}, {"pk": 294, "model": "auth.permission", "fields": {"codename": "delete_certificateitem", "name": "Can delete certificate item", "content_type": 97}}, {"pk": 274, "model": "auth.permission", "fields": {"codename": "add_coupon", "name": "Can add coupon", "content_type": 91}}, {"pk": 275, "model": "auth.permission", "fields": {"codename": "change_coupon", "name": "Can change coupon", "content_type": 91}}, {"pk": 276, "model": "auth.permission", "fields": {"codename": "delete_coupon", "name": "Can delete coupon", "content_type": 91}}, {"pk": 277, "model": "auth.permission", "fields": {"codename": "add_couponredemption", "name": "Can add coupon redemption", "content_type": 92}}, {"pk": 278, "model": "auth.permission", "fields": {"codename": "change_couponredemption", "name": "Can change coupon redemption", "content_type": 92}}, {"pk": 279, "model": "auth.permission", "fields": {"codename": "delete_couponredemption", "name": "Can delete coupon redemption", "content_type": 92}}, {"pk": 283, "model": "auth.permission", "fields": {"codename": "add_courseregcodeitem", "name": "Can add course reg code item", "content_type": 94}}, {"pk": 284, "model": "auth.permission", "fields": {"codename": "change_courseregcodeitem", "name": "Can change course reg code item", "content_type": 94}}, {"pk": 285, "model": "auth.permission", "fields": {"codename": "delete_courseregcodeitem", "name": "Can delete course reg code item", "content_type": 94}}, {"pk": 286, "model": "auth.permission", "fields": {"codename": "add_courseregcodeitemannotation", "name": "Can add course reg code item annotation", "content_type": 95}}, {"pk": 287, "model": "auth.permission", "fields": {"codename": "change_courseregcodeitemannotation", "name": "Can change course reg code item annotation", "content_type": 95}}, {"pk": 288, "model": "auth.permission", "fields": {"codename": "delete_courseregcodeitemannotation", "name": "Can delete course reg code item annotation", "content_type": 95}}, {"pk": 268, "model": "auth.permission", "fields": {"codename": "add_courseregistrationcode", "name": "Can add course registration code", "content_type": 89}}, {"pk": 269, "model": "auth.permission", "fields": {"codename": "change_courseregistrationcode", "name": "Can change course registration code", "content_type": 89}}, {"pk": 270, "model": "auth.permission", "fields": {"codename": "delete_courseregistrationcode", "name": "Can delete course registration code", "content_type": 89}}, {"pk": 298, "model": "auth.permission", "fields": {"codename": "add_donation", "name": "Can add donation", "content_type": 99}}, {"pk": 299, "model": "auth.permission", "fields": {"codename": "change_donation", "name": "Can change donation", "content_type": 99}}, {"pk": 300, "model": "auth.permission", "fields": {"codename": "delete_donation", "name": "Can delete donation", "content_type": 99}}, {"pk": 295, "model": "auth.permission", "fields": {"codename": "add_donationconfiguration", "name": "Can add donation configuration", "content_type": 98}}, {"pk": 296, "model": "auth.permission", "fields": {"codename": "change_donationconfiguration", "name": "Can change donation configuration", "content_type": 98}}, {"pk": 297, "model": "auth.permission", "fields": {"codename": "delete_donationconfiguration", "name": "Can delete donation configuration", "content_type": 98}}, {"pk": 265, "model": "auth.permission", "fields": {"codename": "add_invoice", "name": "Can add invoice", "content_type": 88}}, {"pk": 266, "model": "auth.permission", "fields": {"codename": "change_invoice", "name": "Can change invoice", "content_type": 88}}, {"pk": 267, "model": "auth.permission", "fields": {"codename": "delete_invoice", "name": "Can delete invoice", "content_type": 88}}, {"pk": 259, "model": "auth.permission", "fields": {"codename": "add_order", "name": "Can add order", "content_type": 86}}, {"pk": 260, "model": "auth.permission", "fields": {"codename": "change_order", "name": "Can change order", "content_type": 86}}, {"pk": 261, "model": "auth.permission", "fields": {"codename": "delete_order", "name": "Can delete order", "content_type": 86}}, {"pk": 262, "model": "auth.permission", "fields": {"codename": "add_orderitem", "name": "Can add order item", "content_type": 87}}, {"pk": 263, "model": "auth.permission", "fields": {"codename": "change_orderitem", "name": "Can change order item", "content_type": 87}}, {"pk": 264, "model": "auth.permission", "fields": {"codename": "delete_orderitem", "name": "Can delete order item", "content_type": 87}}, {"pk": 280, "model": "auth.permission", "fields": {"codename": "add_paidcourseregistration", "name": "Can add paid course registration", "content_type": 93}}, {"pk": 281, "model": "auth.permission", "fields": {"codename": "change_paidcourseregistration", "name": "Can change paid course registration", "content_type": 93}}, {"pk": 282, "model": "auth.permission", "fields": {"codename": "delete_paidcourseregistration", "name": "Can delete paid course registration", "content_type": 93}}, {"pk": 289, "model": "auth.permission", "fields": {"codename": "add_paidcourseregistrationannotation", "name": "Can add paid course registration annotation", "content_type": 96}}, {"pk": 290, "model": "auth.permission", "fields": {"codename": "change_paidcourseregistrationannotation", "name": "Can change paid course registration annotation", "content_type": 96}}, {"pk": 291, "model": "auth.permission", "fields": {"codename": "delete_paidcourseregistrationannotation", "name": "Can delete paid course registration annotation", "content_type": 96}}, {"pk": 271, "model": "auth.permission", "fields": {"codename": "add_registrationcoderedemption", "name": "Can add registration code redemption", "content_type": 90}}, {"pk": 272, "model": "auth.permission", "fields": {"codename": "change_registrationcoderedemption", "name": "Can change registration code redemption", "content_type": 90}}, {"pk": 273, "model": "auth.permission", "fields": {"codename": "delete_registrationcoderedemption", "name": "Can delete registration code redemption", "content_type": 90}}, {"pk": 16, "model": "auth.permission", "fields": {"codename": "add_site", "name": "Can add site", "content_type": 6}}, {"pk": 17, "model": "auth.permission", "fields": {"codename": "change_site", "name": "Can change site", "content_type": 6}}, {"pk": 18, "model": "auth.permission", "fields": {"codename": "delete_site", "name": "Can delete site", "content_type": 6}}, {"pk": 43, "model": "auth.permission", "fields": {"codename": "add_migrationhistory", "name": "Can add migration history", "content_type": 15}}, {"pk": 44, "model": "auth.permission", "fields": {"codename": "change_migrationhistory", "name": "Can change migration history", "content_type": 15}}, {"pk": 45, "model": "auth.permission", "fields": {"codename": "delete_migrationhistory", "name": "Can delete migration history", "content_type": 15}}, {"pk": 247, "model": "auth.permission", "fields": {"codename": "add_splashconfig", "name": "Can add splash config", "content_type": 82}}, {"pk": 248, "model": "auth.permission", "fields": {"codename": "change_splashconfig", "name": "Can change splash config", "content_type": 82}}, {"pk": 249, "model": "auth.permission", "fields": {"codename": "delete_splashconfig", "name": "Can delete splash config", "content_type": 82}}, {"pk": 97, "model": "auth.permission", "fields": {"codename": "add_anonymoususerid", "name": "Can add anonymous user id", "content_type": 33}}, {"pk": 98, "model": "auth.permission", "fields": {"codename": "change_anonymoususerid", "name": "Can change anonymous user id", "content_type": 33}}, {"pk": 99, "model": "auth.permission", "fields": {"codename": "delete_anonymoususerid", "name": "Can delete anonymous user id", "content_type": 33}}, {"pk": 133, "model": "auth.permission", "fields": {"codename": "add_courseaccessrole", "name": "Can add course access role", "content_type": 45}}, {"pk": 134, "model": "auth.permission", "fields": {"codename": "change_courseaccessrole", "name": "Can change course access role", "content_type": 45}}, {"pk": 135, "model": "auth.permission", "fields": {"codename": "delete_courseaccessrole", "name": "Can delete course access role", "content_type": 45}}, {"pk": 127, "model": "auth.permission", "fields": {"codename": "add_courseenrollment", "name": "Can add course enrollment", "content_type": 43}}, {"pk": 128, "model": "auth.permission", "fields": {"codename": "change_courseenrollment", "name": "Can change course enrollment", "content_type": 43}}, {"pk": 129, "model": "auth.permission", "fields": {"codename": "delete_courseenrollment", "name": "Can delete course enrollment", "content_type": 43}}, {"pk": 130, "model": "auth.permission", "fields": {"codename": "add_courseenrollmentallowed", "name": "Can add course enrollment allowed", "content_type": 44}}, {"pk": 131, "model": "auth.permission", "fields": {"codename": "change_courseenrollmentallowed", "name": "Can change course enrollment allowed", "content_type": 44}}, {"pk": 132, "model": "auth.permission", "fields": {"codename": "delete_courseenrollmentallowed", "name": "Can delete course enrollment allowed", "content_type": 44}}, {"pk": 136, "model": "auth.permission", "fields": {"codename": "add_dashboardconfiguration", "name": "Can add dashboard configuration", "content_type": 46}}, {"pk": 137, "model": "auth.permission", "fields": {"codename": "change_dashboardconfiguration", "name": "Can change dashboard configuration", "content_type": 46}}, {"pk": 138, "model": "auth.permission", "fields": {"codename": "delete_dashboardconfiguration", "name": "Can delete dashboard configuration", "content_type": 46}}, {"pk": 124, "model": "auth.permission", "fields": {"codename": "add_loginfailures", "name": "Can add login failures", "content_type": 42}}, {"pk": 125, "model": "auth.permission", "fields": {"codename": "change_loginfailures", "name": "Can change login failures", "content_type": 42}}, {"pk": 126, "model": "auth.permission", "fields": {"codename": "delete_loginfailures", "name": "Can delete login failures", "content_type": 42}}, {"pk": 121, "model": "auth.permission", "fields": {"codename": "add_passwordhistory", "name": "Can add password history", "content_type": 41}}, {"pk": 122, "model": "auth.permission", "fields": {"codename": "change_passwordhistory", "name": "Can change password history", "content_type": 41}}, {"pk": 123, "model": "auth.permission", "fields": {"codename": "delete_passwordhistory", "name": "Can delete password history", "content_type": 41}}, {"pk": 118, "model": "auth.permission", "fields": {"codename": "add_pendingemailchange", "name": "Can add pending email change", "content_type": 40}}, {"pk": 119, "model": "auth.permission", "fields": {"codename": "change_pendingemailchange", "name": "Can change pending email change", "content_type": 40}}, {"pk": 120, "model": "auth.permission", "fields": {"codename": "delete_pendingemailchange", "name": "Can delete pending email change", "content_type": 40}}, {"pk": 115, "model": "auth.permission", "fields": {"codename": "add_pendingnamechange", "name": "Can add pending name change", "content_type": 39}}, {"pk": 116, "model": "auth.permission", "fields": {"codename": "change_pendingnamechange", "name": "Can change pending name change", "content_type": 39}}, {"pk": 117, "model": "auth.permission", "fields": {"codename": "delete_pendingnamechange", "name": "Can delete pending name change", "content_type": 39}}, {"pk": 112, "model": "auth.permission", "fields": {"codename": "add_registration", "name": "Can add registration", "content_type": 38}}, {"pk": 113, "model": "auth.permission", "fields": {"codename": "change_registration", "name": "Can change registration", "content_type": 38}}, {"pk": 114, "model": "auth.permission", "fields": {"codename": "delete_registration", "name": "Can delete registration", "content_type": 38}}, {"pk": 103, "model": "auth.permission", "fields": {"codename": "add_userprofile", "name": "Can add user profile", "content_type": 35}}, {"pk": 104, "model": "auth.permission", "fields": {"codename": "change_userprofile", "name": "Can change user profile", "content_type": 35}}, {"pk": 105, "model": "auth.permission", "fields": {"codename": "delete_userprofile", "name": "Can delete user profile", "content_type": 35}}, {"pk": 106, "model": "auth.permission", "fields": {"codename": "add_usersignupsource", "name": "Can add user signup source", "content_type": 36}}, {"pk": 107, "model": "auth.permission", "fields": {"codename": "change_usersignupsource", "name": "Can change user signup source", "content_type": 36}}, {"pk": 108, "model": "auth.permission", "fields": {"codename": "delete_usersignupsource", "name": "Can delete user signup source", "content_type": 36}}, {"pk": 100, "model": "auth.permission", "fields": {"codename": "add_userstanding", "name": "Can add user standing", "content_type": 34}}, {"pk": 101, "model": "auth.permission", "fields": {"codename": "change_userstanding", "name": "Can change user standing", "content_type": 34}}, {"pk": 102, "model": "auth.permission", "fields": {"codename": "delete_userstanding", "name": "Can delete user standing", "content_type": 34}}, {"pk": 109, "model": "auth.permission", "fields": {"codename": "add_usertestgroup", "name": "Can add user test group", "content_type": 37}}, {"pk": 110, "model": "auth.permission", "fields": {"codename": "change_usertestgroup", "name": "Can change user test group", "content_type": 37}}, {"pk": 111, "model": "auth.permission", "fields": {"codename": "delete_usertestgroup", "name": "Can delete user test group", "content_type": 37}}, {"pk": 349, "model": "auth.permission", "fields": {"codename": "add_score", "name": "Can add score", "content_type": 116}}, {"pk": 350, "model": "auth.permission", "fields": {"codename": "change_score", "name": "Can change score", "content_type": 116}}, {"pk": 351, "model": "auth.permission", "fields": {"codename": "delete_score", "name": "Can delete score", "content_type": 116}}, {"pk": 352, "model": "auth.permission", "fields": {"codename": "add_scoresummary", "name": "Can add score summary", "content_type": 117}}, {"pk": 353, "model": "auth.permission", "fields": {"codename": "change_scoresummary", "name": "Can change score summary", "content_type": 117}}, {"pk": 354, "model": "auth.permission", "fields": {"codename": "delete_scoresummary", "name": "Can delete score summary", "content_type": 117}}, {"pk": 343, "model": "auth.permission", "fields": {"codename": "add_studentitem", "name": "Can add student item", "content_type": 114}}, {"pk": 344, "model": "auth.permission", "fields": {"codename": "change_studentitem", "name": "Can change student item", "content_type": 114}}, {"pk": 345, "model": "auth.permission", "fields": {"codename": "delete_studentitem", "name": "Can delete student item", "content_type": 114}}, {"pk": 346, "model": "auth.permission", "fields": {"codename": "add_submission", "name": "Can add submission", "content_type": 115}}, {"pk": 347, "model": "auth.permission", "fields": {"codename": "change_submission", "name": "Can change submission", "content_type": 115}}, {"pk": 348, "model": "auth.permission", "fields": {"codename": "delete_submission", "name": "Can delete submission", "content_type": 115}}, {"pk": 331, "model": "auth.permission", "fields": {"codename": "add_surveyanswer", "name": "Can add survey answer", "content_type": 110}}, {"pk": 332, "model": "auth.permission", "fields": {"codename": "change_surveyanswer", "name": "Can change survey answer", "content_type": 110}}, {"pk": 333, "model": "auth.permission", "fields": {"codename": "delete_surveyanswer", "name": "Can delete survey answer", "content_type": 110}}, {"pk": 328, "model": "auth.permission", "fields": {"codename": "add_surveyform", "name": "Can add survey form", "content_type": 109}}, {"pk": 329, "model": "auth.permission", "fields": {"codename": "change_surveyform", "name": "Can change survey form", "content_type": 109}}, {"pk": 330, "model": "auth.permission", "fields": {"codename": "delete_surveyform", "name": "Can delete survey form", "content_type": 109}}, {"pk": 139, "model": "auth.permission", "fields": {"codename": "add_trackinglog", "name": "Can add tracking log", "content_type": 47}}, {"pk": 140, "model": "auth.permission", "fields": {"codename": "change_trackinglog", "name": "Can change tracking log", "content_type": 47}}, {"pk": 141, "model": "auth.permission", "fields": {"codename": "delete_trackinglog", "name": "Can delete tracking log", "content_type": 47}}, {"pk": 253, "model": "auth.permission", "fields": {"codename": "add_usercoursetag", "name": "Can add user course tag", "content_type": 84}}, {"pk": 254, "model": "auth.permission", "fields": {"codename": "change_usercoursetag", "name": "Can change user course tag", "content_type": 84}}, {"pk": 255, "model": "auth.permission", "fields": {"codename": "delete_usercoursetag", "name": "Can delete user course tag", "content_type": 84}}, {"pk": 256, "model": "auth.permission", "fields": {"codename": "add_userorgtag", "name": "Can add user org tag", "content_type": 85}}, {"pk": 257, "model": "auth.permission", "fields": {"codename": "change_userorgtag", "name": "Can change user org tag", "content_type": 85}}, {"pk": 258, "model": "auth.permission", "fields": {"codename": "delete_userorgtag", "name": "Can delete user org tag", "content_type": 85}}, {"pk": 250, "model": "auth.permission", "fields": {"codename": "add_userpreference", "name": "Can add user preference", "content_type": 83}}, {"pk": 251, "model": "auth.permission", "fields": {"codename": "change_userpreference", "name": "Can change user preference", "content_type": 83}}, {"pk": 252, "model": "auth.permission", "fields": {"codename": "delete_userpreference", "name": "Can delete user preference", "content_type": 83}}, {"pk": 307, "model": "auth.permission", "fields": {"codename": "add_softwaresecurephotoverification", "name": "Can add software secure photo verification", "content_type": 102}}, {"pk": 308, "model": "auth.permission", "fields": {"codename": "change_softwaresecurephotoverification", "name": "Can change software secure photo verification", "content_type": 102}}, {"pk": 309, "model": "auth.permission", "fields": {"codename": "delete_softwaresecurephotoverification", "name": "Can delete software secure photo verification", "content_type": 102}}, {"pk": 193, "model": "auth.permission", "fields": {"codename": "add_article", "name": "Can add article", "content_type": 65}}, {"pk": 197, "model": "auth.permission", "fields": {"codename": "assign", "name": "Can change ownership of any article", "content_type": 65}}, {"pk": 194, "model": "auth.permission", "fields": {"codename": "change_article", "name": "Can change article", "content_type": 65}}, {"pk": 195, "model": "auth.permission", "fields": {"codename": "delete_article", "name": "Can delete article", "content_type": 65}}, {"pk": 198, "model": "auth.permission", "fields": {"codename": "grant", "name": "Can assign permissions to other users", "content_type": 65}}, {"pk": 196, "model": "auth.permission", "fields": {"codename": "moderate", "name": "Can edit all articles and lock/unlock/restore", "content_type": 65}}, {"pk": 199, "model": "auth.permission", "fields": {"codename": "add_articleforobject", "name": "Can add Article for object", "content_type": 66}}, {"pk": 200, "model": "auth.permission", "fields": {"codename": "change_articleforobject", "name": "Can change Article for object", "content_type": 66}}, {"pk": 201, "model": "auth.permission", "fields": {"codename": "delete_articleforobject", "name": "Can delete Article for object", "content_type": 66}}, {"pk": 208, "model": "auth.permission", "fields": {"codename": "add_articleplugin", "name": "Can add article plugin", "content_type": 69}}, {"pk": 209, "model": "auth.permission", "fields": {"codename": "change_articleplugin", "name": "Can change article plugin", "content_type": 69}}, {"pk": 210, "model": "auth.permission", "fields": {"codename": "delete_articleplugin", "name": "Can delete article plugin", "content_type": 69}}, {"pk": 202, "model": "auth.permission", "fields": {"codename": "add_articlerevision", "name": "Can add article revision", "content_type": 67}}, {"pk": 203, "model": "auth.permission", "fields": {"codename": "change_articlerevision", "name": "Can change article revision", "content_type": 67}}, {"pk": 204, "model": "auth.permission", "fields": {"codename": "delete_articlerevision", "name": "Can delete article revision", "content_type": 67}}, {"pk": 223, "model": "auth.permission", "fields": {"codename": "add_articlesubscription", "name": "Can add article subscription", "content_type": 74}}, {"pk": 224, "model": "auth.permission", "fields": {"codename": "change_articlesubscription", "name": "Can change article subscription", "content_type": 74}}, {"pk": 225, "model": "auth.permission", "fields": {"codename": "delete_articlesubscription", "name": "Can delete article subscription", "content_type": 74}}, {"pk": 211, "model": "auth.permission", "fields": {"codename": "add_reusableplugin", "name": "Can add reusable plugin", "content_type": 70}}, {"pk": 212, "model": "auth.permission", "fields": {"codename": "change_reusableplugin", "name": "Can change reusable plugin", "content_type": 70}}, {"pk": 213, "model": "auth.permission", "fields": {"codename": "delete_reusableplugin", "name": "Can delete reusable plugin", "content_type": 70}}, {"pk": 217, "model": "auth.permission", "fields": {"codename": "add_revisionplugin", "name": "Can add revision plugin", "content_type": 72}}, {"pk": 218, "model": "auth.permission", "fields": {"codename": "change_revisionplugin", "name": "Can change revision plugin", "content_type": 72}}, {"pk": 219, "model": "auth.permission", "fields": {"codename": "delete_revisionplugin", "name": "Can delete revision plugin", "content_type": 72}}, {"pk": 220, "model": "auth.permission", "fields": {"codename": "add_revisionpluginrevision", "name": "Can add revision plugin revision", "content_type": 73}}, {"pk": 221, "model": "auth.permission", "fields": {"codename": "change_revisionpluginrevision", "name": "Can change revision plugin revision", "content_type": 73}}, {"pk": 222, "model": "auth.permission", "fields": {"codename": "delete_revisionpluginrevision", "name": "Can delete revision plugin revision", "content_type": 73}}, {"pk": 214, "model": "auth.permission", "fields": {"codename": "add_simpleplugin", "name": "Can add simple plugin", "content_type": 71}}, {"pk": 215, "model": "auth.permission", "fields": {"codename": "change_simpleplugin", "name": "Can change simple plugin", "content_type": 71}}, {"pk": 216, "model": "auth.permission", "fields": {"codename": "delete_simpleplugin", "name": "Can delete simple plugin", "content_type": 71}}, {"pk": 205, "model": "auth.permission", "fields": {"codename": "add_urlpath", "name": "Can add URL path", "content_type": 68}}, {"pk": 206, "model": "auth.permission", "fields": {"codename": "change_urlpath", "name": "Can change URL path", "content_type": 68}}, {"pk": 207, "model": "auth.permission", "fields": {"codename": "delete_urlpath", "name": "Can delete URL path", "content_type": 68}}, {"pk": 403, "model": "auth.permission", "fields": {"codename": "add_assessmentworkflow", "name": "Can add assessment workflow", "content_type": 134}}, {"pk": 404, "model": "auth.permission", "fields": {"codename": "change_assessmentworkflow", "name": "Can change assessment workflow", "content_type": 134}}, {"pk": 405, "model": "auth.permission", "fields": {"codename": "delete_assessmentworkflow", "name": "Can delete assessment workflow", "content_type": 134}}, {"pk": 406, "model": "auth.permission", "fields": {"codename": "add_assessmentworkflowstep", "name": "Can add assessment workflow step", "content_type": 135}}, {"pk": 407, "model": "auth.permission", "fields": {"codename": "change_assessmentworkflowstep", "name": "Can change assessment workflow step", "content_type": 135}}, {"pk": 408, "model": "auth.permission", "fields": {"codename": "delete_assessmentworkflowstep", "name": "Can delete assessment workflow step", "content_type": 135}}, {"pk": 445, "model": "auth.permission", "fields": {"codename": "add_studioconfig", "name": "Can add studio config", "content_type": 148}}, {"pk": 446, "model": "auth.permission", "fields": {"codename": "change_studioconfig", "name": "Can change studio config", "content_type": 148}}, {"pk": 447, "model": "auth.permission", "fields": {"codename": "delete_studioconfig", "name": "Can delete studio config", "content_type": 148}}, {"pk": 1, "model": "dark_lang.darklangconfig", "fields": {"change_date": "2015-01-15T03:15:35Z", "changed_by": null, "enabled": true, "released_languages": ""}}] diff --git a/common/test/db_cache/bok_choy_schema.sql b/common/test/db_cache/bok_choy_schema.sql index 80b3c25e003bd579c15698778cc5ae7c63faeb0e..1fb4b6098095387ce4389ab24b1b3d6d12d8cf5f 100644 --- a/common/test/db_cache/bok_choy_schema.sql +++ b/common/test/db_cache/bok_choy_schema.sql @@ -1102,8 +1102,8 @@ CREATE TABLE `djcelery_periodictask` ( UNIQUE KEY `name` (`name`), KEY `djcelery_periodictask_17d2d99d` (`interval_id`), KEY `djcelery_periodictask_7aa5fda` (`crontab_id`), - CONSTRAINT `crontab_id_refs_id_ebff5e74` FOREIGN KEY (`crontab_id`) REFERENCES `djcelery_crontabschedule` (`id`), - CONSTRAINT `interval_id_refs_id_f2054349` FOREIGN KEY (`interval_id`) REFERENCES `djcelery_intervalschedule` (`id`) + CONSTRAINT `interval_id_refs_id_f2054349` FOREIGN KEY (`interval_id`) REFERENCES `djcelery_intervalschedule` (`id`), + CONSTRAINT `crontab_id_refs_id_ebff5e74` FOREIGN KEY (`crontab_id`) REFERENCES `djcelery_crontabschedule` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; DROP TABLE IF EXISTS `djcelery_periodictasks`; diff --git a/lms/djangoapps/courseware/grades.py b/lms/djangoapps/courseware/grades.py index 41169966e30c974a95587cb5063cc891f3d0197a..e100916fbd013503177fec417a0b4941be939b5d 100644 --- a/lms/djangoapps/courseware/grades.py +++ b/lms/djangoapps/courseware/grades.py @@ -22,33 +22,12 @@ from xmodule.modulestore.exceptions import ItemNotFoundError from xmodule.util.duedate import get_extended_due_date from .models import StudentModule from .module_render import get_module_for_descriptor +from .module_utils import yield_dynamic_descriptor_descendents from submissions import api as sub_api # installed from the edx-submissions repository from opaque_keys import InvalidKeyError -log = logging.getLogger("edx.courseware") - - -def yield_dynamic_descriptor_descendents(descriptor, module_creator): - """ - This returns all of the descendants of a descriptor. If the descriptor - has dynamic children, the module will be created using module_creator - and the children (as descriptors) of that module will be returned. - """ - def get_dynamic_descriptor_children(descriptor): - if descriptor.has_dynamic_children(): - module = module_creator(descriptor) - if module is None: - return [] - return module.get_child_descriptors() - else: - return descriptor.get_children() - stack = [descriptor] - - while len(stack) > 0: - next_descriptor = stack.pop() - stack.extend(get_dynamic_descriptor_children(next_descriptor)) - yield next_descriptor +log = logging.getLogger("edx.courseware") def answer_distributions(course_key): diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index 3d2d6daf5348485e691f1061c4bd3fe259642cbb..fc4d9603e9af6d333ef43833c955f75745dd8285 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -21,9 +21,11 @@ from capa.xqueue_interface import XQueueInterface from courseware.access import has_access, get_user_role from courseware.masquerade import setup_masquerade from courseware.model_data import FieldDataCache, DjangoKeyValueStore +from courseware.models import StudentModule from lms.djangoapps.lms_xblock.field_data import LmsFieldData from lms.djangoapps.lms_xblock.runtime import LmsModuleSystem, unquote_slashes, quote_slashes from lms.djangoapps.lms_xblock.models import XBlockAsidesConfig +from .module_utils import yield_dynamic_descriptor_descendents from edxmako.shortcuts import render_to_string from eventtracking import tracker from psychometrics.psychoanalyze import make_psychometrics_data_update_handler @@ -35,6 +37,7 @@ from xblock.exceptions import NoSuchHandlerError from xblock.django.request import django_to_webob_request, webob_to_django_response from xmodule.error_module import ErrorDescriptor, NonStaffErrorDescriptor from xmodule.exceptions import NotFoundError, ProcessingError +from opaque_keys.edx.keys import UsageKey from opaque_keys.edx.locations import SlashSeparatedCourseKey from xmodule.contentstore.django import contentstore from xmodule.modulestore.django import modulestore, ModuleI18nService @@ -53,7 +56,10 @@ from xmodule.x_module import XModuleDescriptor from util.json_request import JsonResponse from util.sandboxing import can_execute_unsafe_code, get_python_lib_zip - +if settings.FEATURES.get('MILESTONES_APP', False): + from milestones import api as milestones_api + from milestones.exceptions import InvalidMilestoneRelationshipTypeException + from util.milestones_helpers import serialize_user log = logging.getLogger(__name__) @@ -93,6 +99,31 @@ def make_track_function(request): return function +def _get_required_content(course, user): + """ + Queries milestones subsystem to see if the specified course is gated on one or more milestones, + and if those milestones can be fulfilled via completion of a particular course content module + """ + required_content = [] + if settings.FEATURES.get('MILESTONES_APP', False): + # Get all of the outstanding milestones for this course, for this user + try: + milestone_paths = milestones_api.get_course_milestones_fulfillment_paths( + unicode(course.id), + serialize_user(user) + ) + except InvalidMilestoneRelationshipTypeException: + return required_content + + # For each outstanding milestone, see if this content is one of its fulfillment paths + for path_key in milestone_paths: + milestone_path = milestone_paths[path_key] + if milestone_path.get('content') and len(milestone_path['content']): + for content in milestone_path['content']: + required_content.append(content) + return required_content + + def toc_for_course(request, course, active_chapter, active_section, field_data_cache): ''' Create a table of contents from the module store @@ -122,9 +153,20 @@ def toc_for_course(request, course, active_chapter, active_section, field_data_c if course_module is None: return None + # Check to see if the course is gated on required content (such as an Entrance Exam) + required_content = _get_required_content(course, request.user) + chapters = list() for chapter in course_module.get_display_items(): - if chapter.hide_from_toc: + # Only show required content, if there is required content + # chapter.hide_from_toc is read-only (boo) + local_hide_from_toc = False + if len(required_content): + if unicode(chapter.location) not in required_content: + local_hide_from_toc = True + + # Skip the current chapter if a hide flag is tripped + if chapter.hide_from_toc or local_hide_from_toc: continue sections = list() @@ -141,7 +183,6 @@ def toc_for_course(request, course, active_chapter, active_section, field_data_c 'active': active, 'graded': section.graded, }) - chapters.append({'display_name': chapter.display_name_with_default, 'url_name': chapter.url_name, 'sections': sections, @@ -341,7 +382,58 @@ def get_module_system_for_user(user, field_data_cache, request_token=request_token, ) - def handle_grade_event(block, event_type, event): + def _fulfill_content_milestones(course_key, content_key, user_id): # pylint: disable=unused-argument + """ + Internal helper to handle milestone fulfillments for the specified content module + """ + # Fulfillment Use Case: Entrance Exam + # If this module is part of an entrance exam, we'll need to see if the student + # has reached the point at which they can collect the associated milestone + if settings.FEATURES.get('ENTRANCE_EXAMS', False): + course = modulestore().get_course(course_key) + content = modulestore().get_item(content_key) + entrance_exam_enabled = getattr(course, 'entrance_exam_enabled', False) + in_entrance_exam = getattr(content, 'in_entrance_exam', False) + if entrance_exam_enabled and in_entrance_exam: + exam_key = UsageKey.from_string(course.entrance_exam_id) + exam_descriptor = modulestore().get_item(exam_key) + exam_modules = yield_dynamic_descriptor_descendents( + exam_descriptor, + inner_get_module + ) + ignore_categories = ['course', 'chapter', 'sequential', 'vertical'] + module_pcts = [] + exam_pct = 0 + for module in exam_modules: + if module.graded and module.category not in ignore_categories: + module_pct = 0 + try: + student_module = StudentModule.objects.get( + module_state_key=module.scope_ids.usage_id, + student_id=user_id + ) + if student_module.max_grade: + module_pct = student_module.grade / student_module.max_grade + except StudentModule.DoesNotExist: + pass + module_pcts.append(module_pct) + exam_pct = sum(module_pcts) / float(len(module_pcts)) + if exam_pct >= course.entrance_exam_minimum_score_pct: + relationship_types = milestones_api.get_milestone_relationship_types() + content_milestones = milestones_api.get_course_content_milestones( + course_key, + exam_key, + relationship=relationship_types['FULFILLS'] + ) + # Add each milestone to the user's set... + user = {'id': user_id} + for milestone in content_milestones: + milestones_api.add_user_milestone(user, milestone) + + def handle_grade_event(block, event_type, event): # pylint: disable=unused-argument + """ + Manages the workflow for recording and updating of student module grade state + """ user_id = event.get('user_id', user.id) # Construct the key for the module @@ -373,6 +465,16 @@ def get_module_system_for_user(user, field_data_cache, dog_stats_api.increment("lms.courseware.question_answered", tags=tags) + # If we're using the awesome edx-milestones app, we need to cycle + # through the fulfillment scenarios to see if any are now applicable + # thanks to the updated grading information that was just submitted + if settings.FEATURES.get('MILESTONES_APP', False): + _fulfill_content_milestones( + course_id, + descriptor.location, + user_id + ) + def publish(block, event_type, event): """A function that allows XModules to publish events.""" if event_type == 'grade': diff --git a/lms/djangoapps/courseware/module_utils.py b/lms/djangoapps/courseware/module_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..017f879b1dded4765240e7696da1b284ab7eaf71 --- /dev/null +++ b/lms/djangoapps/courseware/module_utils.py @@ -0,0 +1,30 @@ +""" +Utility library containing operations used/shared by multiple courseware modules +""" + + +def yield_dynamic_descriptor_descendents(descriptor, module_creator): # pylint: disable=invalid-name + """ + This returns all of the descendants of a descriptor. If the descriptor + has dynamic children, the module will be created using module_creator + and the children (as descriptors) of that module will be returned. + """ + def get_dynamic_descriptor_children(descriptor): + """ + Internal recursive helper for traversing the child hierarchy + """ + module_children = [] + if descriptor.has_dynamic_children(): + module = module_creator(descriptor) + if module is not None: + module_children = module.get_child_descriptors() + else: + module_children = descriptor.get_children() + return module_children + + stack = [descriptor] + + while len(stack) > 0: + next_descriptor = stack.pop() + stack.extend(get_dynamic_descriptor_children(next_descriptor)) + yield next_descriptor diff --git a/lms/djangoapps/courseware/tabs.py b/lms/djangoapps/courseware/tabs.py new file mode 100644 index 0000000000000000000000000000000000000000..1ba9e153c6fe4fb64f504e2a167474c61d27145f --- /dev/null +++ b/lms/djangoapps/courseware/tabs.py @@ -0,0 +1,59 @@ +""" +This module is essentially a broker to xmodule/tabs.py -- it was originally introduced to +perform some LMS-specific tab display gymnastics for the Entrance Exams feature +""" +from django.conf import settings +from django.utils.translation import ugettext as _ + +from courseware.access import has_access +from student.models import CourseEnrollment +from xmodule.tabs import CourseTabList + +if settings.FEATURES.get('MILESTONES_APP', False): + from milestones.api import get_course_milestones_fulfillment_paths + from util.milestones_helpers import serialize_user + + +def get_course_tab_list(course, user): + """ + Retrieves the course tab list from xmodule.tabs and manipulates the set as necessary + """ + user_is_enrolled = user.is_authenticated() and CourseEnrollment.is_enrolled(user, course.id) + xmodule_tab_list = CourseTabList.iterate_displayable( + course, + settings, + user.is_authenticated(), + has_access(user, 'staff', course, course.id), + user_is_enrolled + ) + + # Entrance Exams Feature + # If the course has an entrance exam, we'll need to see if the user has not passed it + # If so, we'll need to hide away all of the tabs except for Courseware and Instructor + entrance_exam_mode = False + if settings.FEATURES.get('ENTRANCE_EXAMS', False): + if getattr(course, 'entrance_exam_enabled', False): + course_milestones_paths = get_course_milestones_fulfillment_paths( + unicode(course.id), + serialize_user(user) + ) + for __, value in course_milestones_paths.iteritems(): + if len(value.get('content', [])): + for content in value['content']: + if content == course.entrance_exam_id: + entrance_exam_mode = True + break + + # Now that we've loaded the tabs for this course, perform the Entrance Exam mode work + # Majority case is no entrance exam defined + course_tab_list = [] + for tab in xmodule_tab_list: + if entrance_exam_mode: + # Hide all of the tabs except for 'Courseware' and 'Instructor' + # Rename 'Courseware' tab to 'Entrance Exam' + if tab.type not in ['courseware', 'instructor']: + continue + if tab.type == 'courseware': + tab.name = _("Entrance Exam") + course_tab_list.append(tab) + return course_tab_list diff --git a/lms/djangoapps/courseware/tests/test_entrance_exam.py b/lms/djangoapps/courseware/tests/test_entrance_exam.py new file mode 100644 index 0000000000000000000000000000000000000000..7a81e015437efccbd487c52535dc491c0ff03f90 --- /dev/null +++ b/lms/djangoapps/courseware/tests/test_entrance_exam.py @@ -0,0 +1,276 @@ +""" +Tests use cases related to LMS Entrance Exam behavior, such as gated content access (TOC) +""" +from django.test.client import RequestFactory +from django.test.utils import override_settings + +from courseware.model_data import FieldDataCache +from courseware.module_render import get_module, toc_for_course +from courseware.tests.factories import UserFactory +from milestones import api as milestones_api +from milestones.models import MilestoneRelationshipType +from xmodule.modulestore.django import modulestore +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, TEST_DATA_MOCK_MODULESTORE +from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory +from util.milestones_helpers import generate_milestone_namespace, NAMESPACE_CHOICES + + +@override_settings(MODULESTORE=TEST_DATA_MOCK_MODULESTORE) +class EntranceExamTestCases(ModuleStoreTestCase): + """ + Check that content is properly gated. Create a test course from scratch to mess with. + """ + + def setUp(self): + """ + Test case scaffolding + """ + super(EntranceExamTestCases, self).setUp() + self.course = CourseFactory.create( + metadata={ + 'entrance_exam_enabled': True, + } + ) + chapter = ItemFactory.create( + parent=self.course, + display_name='Overview' + ) + ItemFactory.create( + parent=chapter, + display_name='Welcome' + ) + ItemFactory.create( + parent=self.course, + category='chapter', + display_name="Week 1" + ) + ItemFactory.create( + parent=chapter, + category='sequential', + display_name="Lesson 1" + ) + ItemFactory.create( + category="instructor", + parent=self.course, + data="Instructor Tab", + display_name="Instructor" + ) + self.entrance_exam = ItemFactory.create( + parent=self.course, + category="chapter", + display_name="Entrance Exam Section - Chapter 1" + ) + self.exam_1 = ItemFactory.create( + parent=self.entrance_exam, + category='sequential', + display_name="Exam Sequential - Subsection 1", + graded=True, + metadata={'in_entrance_exam': True} + ) + subsection = ItemFactory.create( + parent=self.exam_1, + category='vertical', + display_name='Exam Vertical - Unit 1' + ) + self.problem_1 = ItemFactory.create( + parent=subsection, + category="problem", + display_name="Exam Problem - Problem 1" + ) + self.problem_2 = ItemFactory.create( + parent=subsection, + category="problem", + display_name="Exam Problem - Problem 2" + ) + self.problem_3 = ItemFactory.create( + parent=subsection, + category="problem", + display_name="Exam Problem - Problem 3" + ) + milestone_namespace = generate_milestone_namespace( + NAMESPACE_CHOICES['ENTRANCE_EXAM'], + self.course.id + ) + self.milestone = { + 'name': 'Test Milestone', + 'namespace': milestone_namespace, + 'description': 'Testing Courseware Entrance Exam Chapter', + } + MilestoneRelationshipType.objects.create(name='requires', active=True) + MilestoneRelationshipType.objects.create(name='fulfills', active=True) + self.milestone_relationship_types = milestones_api.get_milestone_relationship_types() + self.milestone = milestones_api.add_milestone(self.milestone) + milestones_api.add_course_milestone( + unicode(self.course.id), + self.milestone_relationship_types['REQUIRES'], + self.milestone + ) + milestones_api.add_course_content_milestone( + unicode(self.course.id), + unicode(self.entrance_exam.location), + self.milestone_relationship_types['FULFILLS'], + self.milestone + ) + user = UserFactory() + self.request = RequestFactory() + self.request.user = user + self.request.COOKIES = {} + self.request.META = {} + self.request.is_secure = lambda: True + self.request.get_host = lambda: "edx.org" + self.request.method = 'GET' + self.field_data_cache = FieldDataCache.cache_for_descriptor_descendents( + self.course.id, + user, + self.entrance_exam + ) + self.entrance_exam.is_entrance_exam = True + self.entrance_exam.in_entrance_exam = True + self.course.entrance_exam_enabled = True + self.course.entrance_exam_minimum_score_pct = 0.50 + self.course.entrance_exam_id = unicode(self.entrance_exam.scope_ids.usage_id) + modulestore().update_item(self.course, user.id) # pylint: disable=no-member + + def test_entrance_exam_gating(self): + """ + Unit Test: test_entrance_exam_gating + """ + # This user helps to cover a discovered bug in the milestone fulfillment logic + chaos_user = UserFactory() + expected_locked_toc = ( + [ + { + 'active': True, + 'sections': [ + { + 'url_name': u'Exam_Sequential_-_Subsection_1', + 'display_name': u'Exam Sequential - Subsection 1', + 'graded': True, + 'format': '', + 'due': None, + 'active': True + } + ], + 'url_name': u'Entrance_Exam_Section_-_Chapter_1', + 'display_name': u'Entrance Exam Section - Chapter 1' + } + ] + ) + locked_toc = toc_for_course( + self.request, + self.course, + self.entrance_exam.url_name, + self.exam_1.url_name, + self.field_data_cache + ) + for toc_section in expected_locked_toc: + self.assertIn(toc_section, locked_toc) + + # Set up the chaos user + # pylint: disable=maybe-no-member,no-member + grade_dict = {'value': 1, 'max_value': 1, 'user_id': chaos_user.id} + field_data_cache = FieldDataCache.cache_for_descriptor_descendents( + self.course.id, + chaos_user, + self.course, + depth=2 + ) + # pylint: disable=protected-access + module = get_module( + chaos_user, + self.request, + self.problem_1.scope_ids.usage_id, + field_data_cache, + )._xmodule + module.system.publish(self.problem_1, 'grade', grade_dict) + + # pylint: disable=maybe-no-member,no-member + grade_dict = {'value': 1, 'max_value': 1, 'user_id': self.request.user.id} + field_data_cache = FieldDataCache.cache_for_descriptor_descendents( + self.course.id, + self.request.user, + self.course, + depth=2 + ) + # pylint: disable=protected-access + module = get_module( + self.request.user, + self.request, + self.problem_1.scope_ids.usage_id, + field_data_cache, + )._xmodule + module.system.publish(self.problem_1, 'grade', grade_dict) + + module = get_module( + self.request.user, + self.request, + self.problem_2.scope_ids.usage_id, + field_data_cache, + )._xmodule # pylint: disable=protected-access + module.system.publish(self.problem_2, 'grade', grade_dict) + + expected_unlocked_toc = ( + [ + { + 'active': False, + 'sections': [ + { + 'url_name': u'Welcome', + 'display_name': u'Welcome', + 'graded': False, + 'format': '', + 'due': None, + 'active': False + }, + { + 'url_name': u'Lesson_1', + 'display_name': u'Lesson 1', + 'graded': False, + 'format': '', + 'due': None, + 'active': False + } + ], + 'url_name': u'Overview', + 'display_name': u'Overview' + }, + { + 'active': False, + 'sections': [], + 'url_name': u'Week_1', + 'display_name': u'Week 1' + }, + { + 'active': False, + 'sections': [], + 'url_name': u'Instructor', + 'display_name': u'Instructor' + }, + { + 'active': True, + 'sections': [ + { + 'url_name': u'Exam_Sequential_-_Subsection_1', + 'display_name': u'Exam Sequential - Subsection 1', + 'graded': True, + 'format': '', + 'due': None, + 'active': True + } + ], + 'url_name': u'Entrance_Exam_Section_-_Chapter_1', + 'display_name': u'Entrance Exam Section - Chapter 1' + } + ] + ) + + unlocked_toc = toc_for_course( + self.request, + self.course, + self.entrance_exam.url_name, + self.exam_1.url_name, + self.field_data_cache + ) + + for toc_section in expected_unlocked_toc: + self.assertIn(toc_section, unlocked_toc) diff --git a/lms/djangoapps/courseware/tests/test_module_render.py b/lms/djangoapps/courseware/tests/test_module_render.py index d6ce93563ecf3a24b78cb17392402a5e5e43ee86..0faff94cf390b7f409593a5ca76748829de2f926 100644 --- a/lms/djangoapps/courseware/tests/test_module_render.py +++ b/lms/djangoapps/courseware/tests/test_module_render.py @@ -30,7 +30,7 @@ from courseware.tests.factories import StudentModuleFactory, UserFactory, Global from courseware.tests.tests import LoginEnrollmentTestCase from xmodule.modulestore.tests.django_utils import ( TEST_DATA_MOCK_MODULESTORE, TEST_DATA_MIXED_TOY_MODULESTORE, - TEST_DATA_XML_MODULESTORE + TEST_DATA_XML_MODULESTORE, TEST_DATA_MIXED_CLOSED_MODULESTORE ) from courseware.tests.test_submitting_problems import TestSubmittingProblems from lms.djangoapps.lms_xblock.runtime import quote_slashes diff --git a/lms/djangoapps/courseware/tests/test_tabs.py b/lms/djangoapps/courseware/tests/test_tabs.py index e1d770b8042441ced3cbf9033760cd61615ebe95..26fadb06342aa90b1548d567ee8d3c40ecc5b81f 100644 --- a/lms/djangoapps/courseware/tests/test_tabs.py +++ b/lms/djangoapps/courseware/tests/test_tabs.py @@ -1,6 +1,8 @@ """ Test cases for tabs. +Note: Tests covering workflows in the actual tabs.py file begin after line 100 """ +from django.conf import settings from django.core.urlresolvers import reverse from django.http import Http404 from django.test.utils import override_settings @@ -18,6 +20,11 @@ from xmodule.tabs import CourseTabList from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory +if settings.FEATURES.get('MILESTONES_APP', False): + from courseware.tabs import get_course_tab_list + from milestones import api as milestones_api + from milestones.models import MilestoneRelationshipType + @override_settings(MODULESTORE=TEST_DATA_MIXED_TOY_MODULESTORE) class StaticTabDateTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase): @@ -97,3 +104,69 @@ class StaticTabDateTestCaseXML(LoginEnrollmentTestCase, ModuleStoreTestCase): resp = self.client.get(url) self.assertEqual(resp.status_code, 200) self.assertIn(self.xml_data, resp.content) + + +@override_settings(MODULESTORE=TEST_DATA_MIXED_CLOSED_MODULESTORE) +class EntranceExamsTabsTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase): + """ + Validate tab behavior when dealing with Entrance Exams + """ + if settings.FEATURES.get('ENTRANCE_EXAMS', False): + + def setUp(self): + """ + Test case scaffolding + """ + self.course = CourseFactory.create() + self.instructor_tab = ItemFactory.create( + category="instructor", parent_location=self.course.location, + data="Instructor Tab", display_name="Instructor" + ) + self.extra_tab_2 = ItemFactory.create( + category="static_tab", parent_location=self.course.location, + data="Extra Tab", display_name="Extra Tab 2" + ) + self.extra_tab_3 = ItemFactory.create( + category="static_tab", parent_location=self.course.location, + data="Extra Tab", display_name="Extra Tab 3" + ) + self.setup_user() + self.enroll(self.course) + self.user.is_staff = True + self.relationship_types = milestones_api.get_milestone_relationship_types() + MilestoneRelationshipType.objects.create(name='requires') + MilestoneRelationshipType.objects.create(name='fulfills') + + def test_get_course_tabs_list_entrance_exam_enabled(self): + """ + Unit Test: test_get_course_tabs_list_entrance_exam_enabled + """ + entrance_exam = ItemFactory.create( + category="chapter", parent_location=self.course.location, + data="Exam Data", display_name="Entrance Exam" + ) + entrance_exam.is_entrance_exam = True + milestone = { + 'name': 'Test Milestone', + 'namespace': '{}.entrance_exams'.format(unicode(self.course.id)), + 'description': 'Testing Courseware Tabs' + } + self.course.entrance_exam_enabled = True + self.course.entrance_exam_id = unicode(entrance_exam.location) + milestone = milestones_api.add_milestone(milestone) + milestones_api.add_course_milestone( + unicode(self.course.id), + self.relationship_types['REQUIRES'], + milestone + ) + milestones_api.add_course_content_milestone( + unicode(self.course.id), + unicode(entrance_exam.location), + self.relationship_types['FULFILLS'], + milestone + ) + course_tab_list = get_course_tab_list(self.course, self.user) + self.assertEqual(len(course_tab_list), 2) + self.assertEqual(course_tab_list[0]['tab_id'], 'courseware') + self.assertEqual(course_tab_list[0]['name'], 'Entrance Exam') + self.assertEqual(course_tab_list[1]['tab_id'], 'instructor') diff --git a/lms/djangoapps/courseware/views.py b/lms/djangoapps/courseware/views.py index 8c16e8b2d1e9f4b83629295894d9049488874088..e6c871733e8dfd58f01f90e163874a110bc59d5d 100644 --- a/lms/djangoapps/courseware/views.py +++ b/lms/djangoapps/courseware/views.py @@ -68,6 +68,7 @@ import survey.utils import survey.views from util.views import ensure_valid_course_key + log = logging.getLogger("edx.courseware") template_imports = {'urllib': urllib} diff --git a/lms/envs/bok_choy.py b/lms/envs/bok_choy.py index a3fc1bbce058b9ac31edf2619948654a169fde9d..14a290b3061b8ae9fd4ce74d29dbcf0c47901b93 100644 --- a/lms/envs/bok_choy.py +++ b/lms/envs/bok_choy.py @@ -92,6 +92,10 @@ FEATURES['ENABLE_PREREQUISITE_COURSES'] = True # Unfortunately, we need to use debug mode to serve staticfiles DEBUG = True +########################### Entrance Exams ################################# +FEATURES['MILESTONES_APP'] = True +FEATURES['ENTRANCE_EXAMS'] = True + # Point the URL used to test YouTube availability to our stub YouTube server YOUTUBE_PORT = 9080 YOUTUBE['API'] = "127.0.0.1:{0}/get_youtube_api/".format(YOUTUBE_PORT) diff --git a/lms/envs/common.py b/lms/envs/common.py index 9b884f1bdffd29c1cda3e0ffc87ffe2d57691a02..f38651b49d9f7c532cee399be3764508d4a0f256 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -1920,7 +1920,9 @@ OPTIONAL_APPS = ( # edxval 'edxval', - 'milestones' + + # milestones + 'milestones', ) for app_name in OPTIONAL_APPS: diff --git a/lms/envs/devstack.py b/lms/envs/devstack.py index c64ebd76a2d5804f107076e1187d6ae9302bb164..f9d4012cebfd63018d10de1367cb41e88843dabc 100644 --- a/lms/envs/devstack.py +++ b/lms/envs/devstack.py @@ -104,6 +104,15 @@ FEATURES['ADVANCED_SECURITY'] = False PASSWORD_MIN_LENGTH = None PASSWORD_COMPLEXITY = {} + +########################### Milestones ################################# +FEATURES['MILESTONES_APP'] = True + + +########################### Entrance Exams ################################# +FEATURES['ENTRANCE_EXAMS'] = True + + ##################################################################### # See if the developer has any local overrides. try: diff --git a/lms/envs/test.py b/lms/envs/test.py index 06148c40b768decaa2de3144350ed7b1a72d244d..07964cf30bf5ba58f69b03dab2c250fd4d479543 100644 --- a/lms/envs/test.py +++ b/lms/envs/test.py @@ -443,3 +443,9 @@ FEATURES['ENABLE_EDXNOTES'] = True # Add milestones to Installed apps for testing INSTALLED_APPS += ('milestones', ) + +# MILESTONES +FEATURES['MILESTONES_APP'] = True + +# ENTRANCE EXAMS +FEATURES['ENTRANCE_EXAMS'] = True diff --git a/lms/templates/courseware/course_navigation.html b/lms/templates/courseware/course_navigation.html index 635be77502fca643b20972c81f711a868843c72c..fe482c5ce6f542f81407d71c90d4d2e234c6b3bc 100644 --- a/lms/templates/courseware/course_navigation.html +++ b/lms/templates/courseware/course_navigation.html @@ -12,17 +12,12 @@ def url_class(is_active): return "active" return "" %> -<%! from xmodule.tabs import CourseTabList %> -<%! from courseware.access import has_access %> -<%! from courseware.masquerade import get_course_masquerade %> +<%! from courseware.tabs import get_course_tab_list %> <%! from courseware.views import notification_image_for_tab %> -<%! from django.conf import settings %> <%! from django.core.urlresolvers import reverse %> -<%! from django.utils.translation import ugettext as _ %> <%! from openedx.core.djangoapps.course_groups.partition_scheme import get_cohorted_user_partition %> <%! from student.models import CourseEnrollment %> <% - user_is_enrolled = user.is_authenticated() and CourseEnrollment.is_enrolled(user, course.id) cohorted_user_partition = get_cohorted_user_partition(course.id) show_preview_menu = staff_access and active_page in ['courseware', 'info'] is_student_masquerade = masquerade and masquerade.role == 'student' @@ -59,7 +54,7 @@ def url_class(is_active): <nav class="${active_page} wrapper-course-material"> <div class="course-material"> <ol class="course-tabs"> - % for tab in CourseTabList.iterate_displayable(course, settings, user.is_authenticated(), has_access(user, 'staff', course, course.id), user_is_enrolled): + % for tab in get_course_tab_list(course, user): <% tab_is_active = (tab.tab_id == active_page) or (tab.tab_id == default_tab) tab_image = notification_image_for_tab(tab, user, course) diff --git a/pavelib/utils/test/suites/bokchoy_suite.py b/pavelib/utils/test/suites/bokchoy_suite.py index 29c545f6c5b27e7c2965ddf841fc42a299981c62..562cbaf74e77d5d2347d798996c9319f67a98259 100644 --- a/pavelib/utils/test/suites/bokchoy_suite.py +++ b/pavelib/utils/test/suites/bokchoy_suite.py @@ -57,10 +57,11 @@ class BokChoyTestSuite(TestSuite): print(msg) bokchoy_utils.check_services() + sh("{}/scripts/reset-test-db.sh".format(Env.REPO_ROOT)) + if not self.fasttest: # Process assets and set up database for bok-choy tests # Reset the database - sh("{}/scripts/reset-test-db.sh".format(Env.REPO_ROOT)) # Collect static assets sh("paver update_assets --settings=bok_choy")