Instead, we use XModule field default values when creating an empty XModule. Driven by this use case, we also allow for XModules to be created in memory without being persisted to the database at all. This necessitates a change to the Modulestore api, replacing clone_item with create_draft and save_xmodule.
171 lines
6.4 KiB
Python
171 lines
6.4 KiB
Python
# pylint: disable=C0111
|
|
# pylint: disable=W0621
|
|
|
|
from __future__ import absolute_import
|
|
|
|
from lettuce import world, step
|
|
from nose.tools import assert_equals, assert_in
|
|
from lettuce.django import django_url
|
|
from django.contrib.auth.models import User
|
|
from student.models import CourseEnrollment
|
|
from xmodule.modulestore import Location
|
|
from xmodule.modulestore.django import _MODULESTORES, modulestore
|
|
from xmodule.course_module import CourseDescriptor
|
|
from courseware.courses import get_course_by_id
|
|
from xmodule import seq_module, vertical_module
|
|
|
|
from logging import getLogger
|
|
logger = getLogger(__name__)
|
|
|
|
|
|
@step(u'The course "([^"]*)" exists$')
|
|
def create_course(step, course):
|
|
|
|
# First clear the modulestore so we don't try to recreate
|
|
# the same course twice
|
|
# This also ensures that the necessary templates are loaded
|
|
world.clear_courses()
|
|
|
|
# Create the course
|
|
# We always use the same org and display name,
|
|
# but vary the course identifier (e.g. 600x or 191x)
|
|
world.scenario_dict['COURSE'] = world.CourseFactory.create(org='edx',
|
|
number=course,
|
|
display_name='Test Course')
|
|
|
|
# Add a section to the course to contain problems
|
|
world.scenario_dict['SECTION'] = world.ItemFactory.create(parent_location=world.scenario_dict['COURSE'].location,
|
|
display_name='Test Section')
|
|
|
|
problem_section = world.ItemFactory.create(parent_location=world.scenario_dict['SECTION'].location,
|
|
category='sequential'
|
|
display_name='Test Section')
|
|
|
|
|
|
@step(u'I am registered for the course "([^"]*)"$')
|
|
def i_am_registered_for_the_course(step, course):
|
|
# Create the course
|
|
create_course(step, course)
|
|
|
|
# Create the user
|
|
world.create_user('robot', 'test')
|
|
u = User.objects.get(username='robot')
|
|
|
|
# If the user is not already enrolled, enroll the user.
|
|
# TODO: change to factory
|
|
CourseEnrollment.objects.get_or_create(user=u, course_id=course_id(course))
|
|
|
|
world.log_in('robot', 'test')
|
|
|
|
|
|
@step(u'The course "([^"]*)" has extra tab "([^"]*)"$')
|
|
def add_tab_to_course(step, course, extra_tab_name):
|
|
section_item = world.ItemFactory.create(parent_location=course_location(course),
|
|
category="static_tab",
|
|
display_name=str(extra_tab_name))
|
|
|
|
|
|
def course_id(course_num):
|
|
return "%s/%s/%s" % (world.scenario_dict['COURSE'].org, course_num,
|
|
world.scenario_dict['COURSE'].display_name.replace(" ", "_"))
|
|
|
|
|
|
def course_location(course_num):
|
|
return Location(loc_or_tag="i4x",
|
|
org=world.scenario_dict['COURSE'].org,
|
|
course=course_num,
|
|
category='course',
|
|
name=world.scenario_dict['COURSE'].display_name.replace(" ", "_"))
|
|
|
|
|
|
def section_location(course_num):
|
|
return Location(loc_or_tag="i4x",
|
|
org=world.scenario_dict['COURSE'].org,
|
|
course=course_num,
|
|
category='sequential',
|
|
name=world.scenario_dict['SECTION'].display_name.replace(" ", "_"))
|
|
|
|
|
|
def get_courses():
|
|
'''
|
|
Returns dict of lists of courses available, keyed by course.org (ie university).
|
|
Courses are sorted by course.number.
|
|
'''
|
|
courses = [c for c in modulestore().get_courses()
|
|
if isinstance(c, CourseDescriptor)]
|
|
courses = sorted(courses, key=lambda course: course.number)
|
|
return courses
|
|
|
|
|
|
def get_courseware_with_tabs(course_id):
|
|
"""
|
|
Given a course_id (string), return a courseware array of dictionaries for the
|
|
top three levels of navigation. Same as get_courseware() except include
|
|
the tabs on the right hand main navigation page.
|
|
|
|
This hides the appropriate courseware as defined by the hide_from_toc field:
|
|
chapter.lms.hide_from_toc
|
|
|
|
Example:
|
|
|
|
[{
|
|
'chapter_name': 'Overview',
|
|
'sections': [{
|
|
'clickable_tab_count': 0,
|
|
'section_name': 'Welcome',
|
|
'tab_classes': []
|
|
}, {
|
|
'clickable_tab_count': 1,
|
|
'section_name': 'System Usage Sequence',
|
|
'tab_classes': ['VerticalDescriptor']
|
|
}, {
|
|
'clickable_tab_count': 0,
|
|
'section_name': 'Lab0: Using the tools',
|
|
'tab_classes': ['HtmlDescriptor', 'HtmlDescriptor', 'CapaDescriptor']
|
|
}, {
|
|
'clickable_tab_count': 0,
|
|
'section_name': 'Circuit Sandbox',
|
|
'tab_classes': []
|
|
}]
|
|
}, {
|
|
'chapter_name': 'Week 1',
|
|
'sections': [{
|
|
'clickable_tab_count': 4,
|
|
'section_name': 'Administrivia and Circuit Elements',
|
|
'tab_classes': ['VerticalDescriptor', 'VerticalDescriptor', 'VerticalDescriptor', 'VerticalDescriptor']
|
|
}, {
|
|
'clickable_tab_count': 0,
|
|
'section_name': 'Basic Circuit Analysis',
|
|
'tab_classes': ['CapaDescriptor', 'CapaDescriptor', 'CapaDescriptor']
|
|
}, {
|
|
'clickable_tab_count': 0,
|
|
'section_name': 'Resistor Divider',
|
|
'tab_classes': []
|
|
}, {
|
|
'clickable_tab_count': 0,
|
|
'section_name': 'Week 1 Tutorials',
|
|
'tab_classes': []
|
|
}]
|
|
}, {
|
|
'chapter_name': 'Midterm Exam',
|
|
'sections': [{
|
|
'clickable_tab_count': 2,
|
|
'section_name': 'Midterm Exam',
|
|
'tab_classes': ['VerticalDescriptor', 'VerticalDescriptor']
|
|
}]
|
|
}]
|
|
"""
|
|
|
|
course = get_course_by_id(course_id)
|
|
chapters = [chapter for chapter in course.get_children() if not chapter.lms.hide_from_toc]
|
|
courseware = [{'chapter_name': c.display_name_with_default,
|
|
'sections': [{'section_name': s.display_name_with_default,
|
|
'clickable_tab_count': len(s.get_children()) if (type(s) == seq_module.SequenceDescriptor) else 0,
|
|
'tabs': [{'children_count': len(t.get_children()) if (type(t) == vertical_module.VerticalDescriptor) else 0,
|
|
'class': t.__class__.__name__}
|
|
for t in s.get_children()]}
|
|
for s in c.get_children() if not s.lms.hide_from_toc]}
|
|
for c in chapters]
|
|
|
|
return courseware
|