Commit d6ced072 by Nimisha Asthagiri

Refactor CourseDetails

parent d170c92f
......@@ -15,6 +15,7 @@ from unittest import skip
from django.conf import settings
from course_modes.models import CourseMode
from openedx.core.djangoapps.models.course_details import CourseDetails
from xmodule.library_tools import normalize_key_for_search
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.django import SignalHandler, modulestore
......@@ -192,26 +193,6 @@ class MixedWithOptionsTestCase(MixedSplitTestCase):
with store.branch_setting(ModuleStoreEnum.Branch.draft_preferred):
store.update_item(item, ModuleStoreEnum.UserID.test)
def update_about_item(self, store, about_key, data):
"""
Update the about item with the new data blob. If data is None, then
delete the about item.
"""
temploc = self.course.id.make_usage_key('about', about_key)
if data is None:
try:
self.delete_item(store, temploc)
# Ignore an attempt to delete an item that doesn't exist
except ValueError:
pass
else:
try:
about_item = store.get_item(temploc)
except ItemNotFoundError:
about_item = store.create_xblock(self.course.runtime, self.course.id, 'about', about_key)
about_item.data = data
store.update_item(about_item, ModuleStoreEnum.UserID.test, allow_not_found=True)
@ddt.ddt
class TestCoursewareSearchIndexer(MixedWithOptionsTestCase):
......@@ -487,7 +468,9 @@ class TestCoursewareSearchIndexer(MixedWithOptionsTestCase):
def _test_course_about_store_index(self, store):
""" Test that informational properties in the about store end up in the course_info index """
short_description = "Not just anybody"
self.update_about_item(store, "short_description", short_description)
CourseDetails.update_about_item(
self.course, "short_description", short_description, ModuleStoreEnum.UserID.test, store
)
self.reindex_course(store)
response = self.searcher.search(
doc_type=CourseAboutSearchIndexer.DISCOVERY_DOCUMENT_TYPE,
......
......@@ -3,7 +3,6 @@ Common utility functions useful throughout the contentstore
"""
import logging
from opaque_keys import InvalidKeyError
import re
from datetime import datetime
from pytz import UTC
......@@ -14,7 +13,6 @@ from django.utils.translation import ugettext as _
from django_comment_common.models import assign_default_role
from django_comment_common.utils import seed_permissions_roles
from xmodule.contentstore.content import StaticContent
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError
......@@ -304,25 +302,6 @@ def reverse_usage_url(handler_name, usage_key, kwargs=None):
return reverse_url(handler_name, 'usage_key_string', usage_key, kwargs)
def has_active_web_certificate(course):
"""
Returns True if given course has active web certificate configuration.
If given course has no active web certificate configuration returns False.
Returns None If `CERTIFICATES_HTML_VIEW` is not enabled of course has not enabled
`cert_html_view_enabled` settings.
"""
cert_config = None
if settings.FEATURES.get('CERTIFICATES_HTML_VIEW', False) and course.cert_html_view_enabled:
cert_config = False
certificates = getattr(course, 'certificates', {})
configurations = certificates.get('certificates', [])
for config in configurations:
if config.get('is_active'):
cert_config = True
break
return cert_config
def get_user_partition_info(xblock, schemes=None, course=None):
"""
Retrieve user partition information for an XBlock for display in editors.
......
......@@ -58,12 +58,13 @@ from course_action_state.models import CourseRerunState, CourseRerunUIStateManag
from course_creators.views import get_course_creator_status, add_user_with_status_unrequested
from edxmako.shortcuts import render_to_response
from microsite_configuration import microsite
from models.settings.course_details import CourseDetails, CourseSettingsEncoder
from models.settings.course_grading import CourseGradingModel
from models.settings.course_metadata import CourseMetadata
from models.settings.encoder import CourseSettingsEncoder
from openedx.core.djangoapps.content.course_structures.api.v0 import api, errors
from openedx.core.djangoapps.credit.api import is_credit_course, get_credit_requirements
from openedx.core.djangoapps.credit.tasks import update_credit_course_requirements
from openedx.core.djangoapps.models.course_details import CourseDetails
from openedx.core.djangoapps.programs.models import ProgramsApiConfig
from openedx.core.djangoapps.programs.utils import get_programs
from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration
......
"""
CourseSettingsEncoder
"""
import datetime
import json
from json.encoder import JSONEncoder
from opaque_keys.edx.locations import Location
from openedx.core.djangoapps.models.course_details import CourseDetails
from xmodule.fields import Date
from .course_grading import CourseGradingModel
class CourseSettingsEncoder(json.JSONEncoder):
"""
Serialize CourseDetails, CourseGradingModel, datetime, and old
Locations
"""
def default(self, obj): # pylint: disable=method-hidden
if isinstance(obj, (CourseDetails, CourseGradingModel)):
return obj.__dict__
elif isinstance(obj, Location):
return obj.dict()
elif isinstance(obj, datetime.datetime):
return Date().to_json(obj)
else:
return JSONEncoder.default(self, obj)
......@@ -8,8 +8,8 @@
import json
from contentstore import utils
from django.utils.translation import ugettext as _
from models.settings.encoder import CourseSettingsEncoder
from openedx.core.lib.js_utils import escape_json_dumps
from models.settings.course_details import CourseSettingsEncoder
%>
<%block name="header_extras">
......
......@@ -660,7 +660,8 @@ def check_mongo_calls(num_finds=0, num_sends=None):
# This dict represents the attribute keys for a course's 'about' info.
# Note: The 'video' attribute is intentionally excluded as it must be
# handled separately; its value maps to an alternate key name.
# Reference : cms/djangoapps/models/settings/course_details.py
# Reference : from openedx.core.djangoapps.models.course_details.py
ABOUT_ATTRIBUTES = {
'effort': "Testing effort",
......
"""
Tests for CourseDetails
"""
import datetime
from django.utils.timezone import UTC
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration
from openedx.core.djangoapps.models.course_details import CourseDetails
class CourseDetailsTestCase(ModuleStoreTestCase):
"""
Tests the first course settings page (course dates, overview, etc.).
"""
def setUp(self):
super(CourseDetailsTestCase, self).setUp()
self.course = CourseFactory.create()
def test_virgin_fetch(self):
details = CourseDetails.fetch(self.course.id)
self.assertEqual(details.org, self.course.location.org, "Org not copied into")
self.assertEqual(details.course_id, self.course.location.course, "Course_id not copied into")
self.assertEqual(details.run, self.course.location.name, "Course name not copied into")
self.assertEqual(details.course_image_name, self.course.course_image)
self.assertIsNotNone(details.start_date.tzinfo)
self.assertIsNone(details.end_date, "end date somehow initialized " + str(details.end_date))
self.assertIsNone(
details.enrollment_start, "enrollment_start date somehow initialized " + str(details.enrollment_start)
)
self.assertIsNone(
details.enrollment_end, "enrollment_end date somehow initialized " + str(details.enrollment_end)
)
self.assertIsNone(details.syllabus, "syllabus somehow initialized" + str(details.syllabus))
self.assertIsNone(details.intro_video, "intro_video somehow initialized" + str(details.intro_video))
self.assertIsNone(details.effort, "effort somehow initialized" + str(details.effort))
self.assertIsNone(details.language, "language somehow initialized" + str(details.language))
self.assertIsNone(details.has_cert_config)
self.assertFalse(details.self_paced)
def test_update_and_fetch(self):
SelfPacedConfiguration(enabled=True).save()
jsondetails = CourseDetails.fetch(self.course.id)
jsondetails.syllabus = "<a href='foo'>bar</a>"
# encode - decode to convert date fields and other data which changes form
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id):
self.assertEqual(
CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).syllabus,
jsondetails.syllabus, "After set syllabus"
)
jsondetails.short_description = "Short Description"
self.assertEqual(
CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).short_description,
jsondetails.short_description, "After set short_description"
)
jsondetails.overview = "Overview"
self.assertEqual(
CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).overview,
jsondetails.overview, "After set overview"
)
jsondetails.intro_video = "intro_video"
self.assertEqual(
CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).intro_video,
jsondetails.intro_video, "After set intro_video"
)
jsondetails.effort = "effort"
self.assertEqual(
CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).effort,
jsondetails.effort, "After set effort"
)
jsondetails.self_paced = True
self.assertEqual(
CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).self_paced,
jsondetails.self_paced
)
jsondetails.start_date = datetime.datetime(2010, 10, 1, 0, tzinfo=UTC())
self.assertEqual(
CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).start_date,
jsondetails.start_date
)
jsondetails.end_date = datetime.datetime(2011, 10, 1, 0, tzinfo=UTC())
self.assertEqual(
CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).end_date,
jsondetails.end_date
)
jsondetails.course_image_name = "an_image.jpg"
self.assertEqual(
CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).course_image_name,
jsondetails.course_image_name
)
jsondetails.language = "hr"
self.assertEqual(
CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).language,
jsondetails.language
)
def test_toggle_pacing_during_course_run(self):
SelfPacedConfiguration(enabled=True).save()
self.course.start = datetime.datetime.now()
self.store.update_item(self.course, self.user.id)
details = CourseDetails.fetch(self.course.id)
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id):
updated_details = CourseDetails.update_from_json(
self.course.id,
dict(details.__dict__, self_paced=True),
self.user
)
self.assertFalse(updated_details.self_paced)
def test_fetch_effort(self):
effort_value = 'test_hours_of_effort'
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id):
CourseDetails.update_about_item(self.course, 'effort', effort_value, self.user.id)
self.assertEqual(CourseDetails.fetch_effort(self.course.id), effort_value)
def test_fetch_video(self):
video_value = 'test_video_id'
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id):
CourseDetails.update_about_video(self.course, video_value, self.user.id)
self.assertEqual(CourseDetails.fetch_youtube_video_id(self.course.id), video_value)
video_url = CourseDetails.fetch_video_url(self.course.id)
self.assertRegexpMatches(video_url, r'http://.*{}'.format(video_value))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment