From ae09598d9a388b261b1cc2b72e1d58942d4c5cf4 Mon Sep 17 00:00:00 2001 From: Matthew Mongeau Date: Sun, 12 Aug 2012 20:10:34 -0400 Subject: [PATCH 1/6] Display textbooks in course navigation, handle in urls and views. --- common/lib/xmodule/setup.py | 1 + common/lib/xmodule/xmodule/course_module.py | 5 ++++ common/lib/xmodule/xmodule/textbook_module.py | 27 +++++++++++++++++++ lms/djangoapps/staticbook/views.py | 8 +++--- lms/templates/course_navigation.html | 8 +++--- lms/urls.py | 4 +-- 6 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 common/lib/xmodule/xmodule/textbook_module.py diff --git a/common/lib/xmodule/setup.py b/common/lib/xmodule/setup.py index 8a0a6bb139..31918c0250 100644 --- a/common/lib/xmodule/setup.py +++ b/common/lib/xmodule/setup.py @@ -31,6 +31,7 @@ setup( "section = xmodule.backcompat_module:SemanticSectionDescriptor", "sequential = xmodule.seq_module:SequenceDescriptor", "slides = xmodule.backcompat_module:TranslateCustomTagDescriptor", + "textbook = xmodule.textbook_module:TextbookDescriptor", "vertical = xmodule.vertical_module:VerticalDescriptor", "video = xmodule.video_module:VideoDescriptor", "videodev = xmodule.backcompat_module:TranslateCustomTagDescriptor", diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py index 11d4e090f9..8674b8b443 100644 --- a/common/lib/xmodule/xmodule/course_module.py +++ b/common/lib/xmodule/xmodule/course_module.py @@ -7,6 +7,7 @@ from xmodule.graders import load_grading_policy from xmodule.modulestore import Location from xmodule.seq_module import SequenceDescriptor, SequenceModule from xmodule.timeparse import parse_time, stringify_time +from xmodule.textbook_module import TextbookDescriptor log = logging.getLogger(__name__) @@ -53,6 +54,10 @@ class CourseDescriptor(SequenceDescriptor): return grading_policy + @property + def textbooks(self): + return [child for child in self.get_children() if type(child) == TextbookDescriptor] + @lazyproperty def grading_context(self): diff --git a/common/lib/xmodule/xmodule/textbook_module.py b/common/lib/xmodule/xmodule/textbook_module.py new file mode 100644 index 0000000000..bd1c422643 --- /dev/null +++ b/common/lib/xmodule/xmodule/textbook_module.py @@ -0,0 +1,27 @@ +from xmodule.x_module import XModule +from xmodule.xml_module import XmlDescriptor +from lxml import etree + +class TextbookModule(XModule): + def __init__(self, system, location, definition, instance_state=None, + shared_state=None, **kwargs): + XModule.__init__(self, system, location, definition, + instance_state, shared_state, **kwargs) + +class TextbookDescriptor(XmlDescriptor): + + module_class = TextbookModule + + def __init__(self, system, definition=None, **kwargs): + super(TextbookDescriptor, self).__init__(system, definition, **kwargs) + self.title = self.metadata["title"] + + @classmethod + def definition_from_xml(cls, xml_object, system): + return { 'children': [] } + + @property + def table_of_contents(self): + raw_table_of_contents = open(self.metadata['table_of_contents_url'], 'r') # TODO: This will need to come from S3 + table_of_contents = etree.parse(raw_table_of_contents).getroot() + return table_of_contents diff --git a/lms/djangoapps/staticbook/views.py b/lms/djangoapps/staticbook/views.py index 2e19ab6425..aaafb60dd8 100644 --- a/lms/djangoapps/staticbook/views.py +++ b/lms/djangoapps/staticbook/views.py @@ -6,19 +6,17 @@ from courseware.courses import get_course_with_access from lxml import etree @login_required -def index(request, course_id, page=0): +def index(request, course_id, book_index, page=0): course = get_course_with_access(request.user, course_id, 'load') staff_access = has_access(request.user, course, 'staff') - # TODO: This will need to come from S3 - raw_table_of_contents = open('lms/templates/book_toc.xml', 'r') - table_of_contents = etree.parse(raw_table_of_contents).getroot() + textbook = course.textbooks[int(book_index)] + table_of_contents = textbook.table_of_contents return render_to_response('staticbook.html', {'page': int(page), 'course': course, 'table_of_contents': table_of_contents, 'staff_access': staff_access}) - def index_shifted(request, course_id, page): return index(request, course_id=course_id, page=int(page) + 24) diff --git a/lms/templates/course_navigation.html b/lms/templates/course_navigation.html index 9e93b2fb14..b75c12064d 100644 --- a/lms/templates/course_navigation.html +++ b/lms/templates/course_navigation.html @@ -16,8 +16,10 @@ def url_class(url):
  • Course Info
  • % if user.is_authenticated(): % if settings.MITX_FEATURES.get('ENABLE_TEXTBOOK'): -
  • Textbook
  • -% endif + % for index, textbook in enumerate(course.textbooks): +
  • ${textbook.title}
  • + % endfor +% endif % if settings.MITX_FEATURES.get('ENABLE_DISCUSSION'):
  • Discussion
  • % endif @@ -34,4 +36,4 @@ def url_class(url): - \ No newline at end of file + diff --git a/lms/urls.py b/lms/urls.py index aaeba1b51e..6850b65644 100644 --- a/lms/urls.py +++ b/lms/urls.py @@ -126,9 +126,9 @@ if settings.COURSEWARE_ENABLED: #Inside the course url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/info$', 'courseware.views.course_info', name="info"), - url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/book$', + url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/book/(?P[^/]*)/$', 'staticbook.views.index', name="book"), - url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/book/(?P[^/]*)$', + url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/book/(?P[^/]*)/(?P[^/]*)$', 'staticbook.views.index'), url(r'^courses/(?P[^/]+/[^/]+/[^/]+)/book-shifted/(?P[^/]*)$', 'staticbook.views.index_shifted'), From 34010a38a822394e9d611117285a2fe03166c82d Mon Sep 17 00:00:00 2001 From: Matthew Mongeau Date: Wed, 15 Aug 2012 11:35:39 -0400 Subject: [PATCH 2/6] Fix textbook module. --- common/lib/xmodule/xmodule/textbook_module.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/common/lib/xmodule/xmodule/textbook_module.py b/common/lib/xmodule/xmodule/textbook_module.py index bd1c422643..d0f7400cfc 100644 --- a/common/lib/xmodule/xmodule/textbook_module.py +++ b/common/lib/xmodule/xmodule/textbook_module.py @@ -3,11 +3,14 @@ from xmodule.xml_module import XmlDescriptor from lxml import etree class TextbookModule(XModule): - def __init__(self, system, location, definition, instance_state=None, + def __init__(self, system, location, definition, descriptor, instance_state=None, shared_state=None, **kwargs): - XModule.__init__(self, system, location, definition, + XModule.__init__(self, system, location, definition, descriptor, instance_state, shared_state, **kwargs) + def get_display_items(self): + return [] + class TextbookDescriptor(XmlDescriptor): module_class = TextbookModule From 4a7b163ce34628ac5392e27ca682cc7487459d94 Mon Sep 17 00:00:00 2001 From: Matthew Mongeau Date: Wed, 15 Aug 2012 11:37:44 -0400 Subject: [PATCH 3/6] Keep textbooks out of displayable items. --- common/lib/xmodule/xmodule/textbook_module.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/lib/xmodule/xmodule/textbook_module.py b/common/lib/xmodule/xmodule/textbook_module.py index d0f7400cfc..e0d0730627 100644 --- a/common/lib/xmodule/xmodule/textbook_module.py +++ b/common/lib/xmodule/xmodule/textbook_module.py @@ -11,6 +11,9 @@ class TextbookModule(XModule): def get_display_items(self): return [] + def displayable_items(self): + return [] + class TextbookDescriptor(XmlDescriptor): module_class = TextbookModule From 945632362b410f6cccaf7279910ebd7ecb61d52d Mon Sep 17 00:00:00 2001 From: Matthew Mongeau Date: Thu, 16 Aug 2012 11:49:03 -0400 Subject: [PATCH 4/6] Get rid of TextbookModule and TextbookDescriptor. --- common/lib/xmodule/xmodule/course_module.py | 35 +++++++++++++++---- common/lib/xmodule/xmodule/textbook_module.py | 33 ----------------- 2 files changed, 28 insertions(+), 40 deletions(-) delete mode 100644 common/lib/xmodule/xmodule/textbook_module.py diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py index 8674b8b443..b04a0cdf69 100644 --- a/common/lib/xmodule/xmodule/course_module.py +++ b/common/lib/xmodule/xmodule/course_module.py @@ -1,22 +1,38 @@ from fs.errors import ResourceNotFoundError import time import logging +from lxml import etree from xmodule.util.decorators import lazyproperty from xmodule.graders import load_grading_policy from xmodule.modulestore import Location from xmodule.seq_module import SequenceDescriptor, SequenceModule from xmodule.timeparse import parse_time, stringify_time -from xmodule.textbook_module import TextbookDescriptor log = logging.getLogger(__name__) - class CourseDescriptor(SequenceDescriptor): module_class = SequenceModule + class Textbook: + def __init__(self, title, table_of_contents_url): + self.title = title + self.table_of_contents_url = table_of_contents_url + + @classmethod + def from_xml_object(cls, xml_object): + return cls(xml_object.get('title'), xml_object.get('table_of_contents_url')) + + @property + def table_of_contents(self): + raw_table_of_contents = open(self.table_of_contents_url, 'r') # TODO: This will need to come from S3 + table_of_contents = etree.parse(raw_table_of_contents).getroot() + return table_of_contents + + def __init__(self, system, definition=None, **kwargs): super(CourseDescriptor, self).__init__(system, definition, **kwargs) + self.textbooks = self.definition['textbooks'] msg = None if self.start is None: @@ -29,6 +45,16 @@ class CourseDescriptor(SequenceDescriptor): self.enrollment_start = self._try_parse_time("enrollment_start") self.enrollment_end = self._try_parse_time("enrollment_end") + @classmethod + def definition_from_xml(cls, xml_object, system): + textbooks = [] + for textbook in xml_object.findall("textbook"): + textbooks.append(cls.Textbook.from_xml_object(textbook)) + xml_object.remove(textbook) + definition = super(CourseDescriptor, cls).definition_from_xml(xml_object, system) + definition['textbooks'] = textbooks + return definition + def has_started(self): return time.gmtime() > self.start @@ -54,11 +80,6 @@ class CourseDescriptor(SequenceDescriptor): return grading_policy - @property - def textbooks(self): - return [child for child in self.get_children() if type(child) == TextbookDescriptor] - - @lazyproperty def grading_context(self): """ diff --git a/common/lib/xmodule/xmodule/textbook_module.py b/common/lib/xmodule/xmodule/textbook_module.py deleted file mode 100644 index e0d0730627..0000000000 --- a/common/lib/xmodule/xmodule/textbook_module.py +++ /dev/null @@ -1,33 +0,0 @@ -from xmodule.x_module import XModule -from xmodule.xml_module import XmlDescriptor -from lxml import etree - -class TextbookModule(XModule): - def __init__(self, system, location, definition, descriptor, instance_state=None, - shared_state=None, **kwargs): - XModule.__init__(self, system, location, definition, descriptor, - instance_state, shared_state, **kwargs) - - def get_display_items(self): - return [] - - def displayable_items(self): - return [] - -class TextbookDescriptor(XmlDescriptor): - - module_class = TextbookModule - - def __init__(self, system, definition=None, **kwargs): - super(TextbookDescriptor, self).__init__(system, definition, **kwargs) - self.title = self.metadata["title"] - - @classmethod - def definition_from_xml(cls, xml_object, system): - return { 'children': [] } - - @property - def table_of_contents(self): - raw_table_of_contents = open(self.metadata['table_of_contents_url'], 'r') # TODO: This will need to come from S3 - table_of_contents = etree.parse(raw_table_of_contents).getroot() - return table_of_contents From 4ff80287f7bd0e88c87cba546e03bb39b5dbca8b Mon Sep 17 00:00:00 2001 From: Matthew Mongeau Date: Thu, 16 Aug 2012 11:52:10 -0400 Subject: [PATCH 5/6] Remove TextbookDescriptor from setup. --- common/lib/xmodule/setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/common/lib/xmodule/setup.py b/common/lib/xmodule/setup.py index 31918c0250..8a0a6bb139 100644 --- a/common/lib/xmodule/setup.py +++ b/common/lib/xmodule/setup.py @@ -31,7 +31,6 @@ setup( "section = xmodule.backcompat_module:SemanticSectionDescriptor", "sequential = xmodule.seq_module:SequenceDescriptor", "slides = xmodule.backcompat_module:TranslateCustomTagDescriptor", - "textbook = xmodule.textbook_module:TextbookDescriptor", "vertical = xmodule.vertical_module:VerticalDescriptor", "video = xmodule.video_module:VideoDescriptor", "videodev = xmodule.backcompat_module:TranslateCustomTagDescriptor", From ae3cb4ec7b1c70344c14a4cc95b36457ac6ff27a Mon Sep 17 00:00:00 2001 From: Matthew Mongeau Date: Thu, 16 Aug 2012 12:06:37 -0400 Subject: [PATCH 6/6] Nest textbooks under data --- common/lib/xmodule/xmodule/course_module.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py index b04a0cdf69..d003ff42fd 100644 --- a/common/lib/xmodule/xmodule/course_module.py +++ b/common/lib/xmodule/xmodule/course_module.py @@ -32,7 +32,7 @@ class CourseDescriptor(SequenceDescriptor): def __init__(self, system, definition=None, **kwargs): super(CourseDescriptor, self).__init__(system, definition, **kwargs) - self.textbooks = self.definition['textbooks'] + self.textbooks = self.definition['data']['textbooks'] msg = None if self.start is None: @@ -52,7 +52,7 @@ class CourseDescriptor(SequenceDescriptor): textbooks.append(cls.Textbook.from_xml_object(textbook)) xml_object.remove(textbook) definition = super(CourseDescriptor, cls).definition_from_xml(xml_object, system) - definition['textbooks'] = textbooks + definition.setdefault('data', {})['textbooks'] = textbooks return definition def has_started(self):