Commit ad5c1f89 by Xavier Antoviaque

Merge pull request #87 from open-craft/dragonfi/extract-to-xblock-utils

Extract common functionality to xblock-utils
parents 6f4ea850 d78f09d1
...@@ -32,7 +32,7 @@ from xblock.fragment import Fragment ...@@ -32,7 +32,7 @@ from xblock.fragment import Fragment
from .light_children import LightChild, Boolean, Scope, String, Integer, Float from .light_children import LightChild, Boolean, Scope, String, Integer, Float
from .step import StepMixin from .step import StepMixin
from .models import Answer from .models import Answer
from .utils import render_js_template from .utils import loader
# Globals ########################################################### # Globals ###########################################################
...@@ -92,11 +92,11 @@ class AnswerBlock(LightChild, StepMixin): ...@@ -92,11 +92,11 @@ class AnswerBlock(LightChild, StepMixin):
def mentoring_view(self, context=None): def mentoring_view(self, context=None):
if not self.read_only: if not self.read_only:
html = render_js_template('templates/html/answer_editable.html', { html = loader.custom_render_js_template('templates/html/answer_editable.html', {
'self': self, 'self': self,
}) })
else: else:
html = render_js_template('templates/html/answer_read_only.html', { html = loader.custom_render_js_template('templates/html/answer_read_only.html', {
'self': self, 'self': self,
}) })
...@@ -108,7 +108,7 @@ class AnswerBlock(LightChild, StepMixin): ...@@ -108,7 +108,7 @@ class AnswerBlock(LightChild, StepMixin):
return fragment return fragment
def mentoring_table_view(self, context=None): def mentoring_table_view(self, context=None):
html = render_js_template('templates/html/answer_table.html', { html = loader.custom_render_js_template('templates/html/answer_table.html', {
'self': self, 'self': self,
}) })
fragment = Fragment(html) fragment = Fragment(html)
......
...@@ -32,7 +32,7 @@ from xblock.fields import String, Scope ...@@ -32,7 +32,7 @@ from xblock.fields import String, Scope
from xblock.fragment import Fragment from xblock.fragment import Fragment
from .models import Answer from .models import Answer
from .utils import list2csv, render_template from .utils import list2csv, loader
# Globals ########################################################### # Globals ###########################################################
...@@ -50,7 +50,7 @@ class MentoringDataExportBlock(XBlock): ...@@ -50,7 +50,7 @@ class MentoringDataExportBlock(XBlock):
scope=Scope.settings) scope=Scope.settings)
def student_view(self, context): def student_view(self, context):
html = render_template('templates/html/dataexport.html', { html = loader.render_template('templates/html/dataexport.html', {
'self': self, 'self': self,
}) })
......
...@@ -38,6 +38,8 @@ from xblock.core import XBlock ...@@ -38,6 +38,8 @@ from xblock.core import XBlock
from xblock.fragment import Fragment from xblock.fragment import Fragment
from xblock.plugin import Plugin from xblock.plugin import Plugin
from xblockutils.publish_event import PublishEventMixin
from .models import LightChild as LightChildModel from .models import LightChild as LightChildModel
...@@ -83,7 +85,18 @@ class LightChildrenMixin(XBlockWithChildrenFragmentsMixin): ...@@ -83,7 +85,18 @@ class LightChildrenMixin(XBlockWithChildrenFragmentsMixin):
log.debug('parse_xml called') log.debug('parse_xml called')
block = runtime.construct_xblock_from_class(cls, keys) block = runtime.construct_xblock_from_class(cls, keys)
cls.init_block_from_node(block, node, node.items()) cls.init_block_from_node(block, node, node.items())
block.xml_content = getattr(block, 'xml_content', '') or etree.tostring(node)
def _is_default(value):
xml_content_field = getattr(block.__class__, 'xml_content', None)
default_value = getattr(xml_content_field, 'default', None)
return value == default_value
is_default = getattr(block, 'is_default_xml_content', _is_default)
xml_content = getattr(block, 'xml_content', None)
if is_default(xml_content):
block.xml_content = etree.tostring(node)
return block return block
@classmethod @classmethod
...@@ -166,7 +179,7 @@ class LightChildrenMixin(XBlockWithChildrenFragmentsMixin): ...@@ -166,7 +179,7 @@ class LightChildrenMixin(XBlockWithChildrenFragmentsMixin):
return fragment, named_child_frags return fragment, named_child_frags
class XBlockWithLightChildren(LightChildrenMixin, XBlock): class XBlockWithLightChildren(LightChildrenMixin, XBlock, PublishEventMixin):
""" """
XBlock base class with support for LightChild XBlock base class with support for LightChild
""" """
......
...@@ -28,7 +28,7 @@ import logging ...@@ -28,7 +28,7 @@ import logging
from .light_children import Scope, String from .light_children import Scope, String
from .questionnaire import QuestionnaireAbstractBlock from .questionnaire import QuestionnaireAbstractBlock
from .utils import render_template from .utils import loader
# Globals ########################################################### # Globals ###########################################################
...@@ -59,7 +59,7 @@ class MCQBlock(QuestionnaireAbstractBlock): ...@@ -59,7 +59,7 @@ class MCQBlock(QuestionnaireAbstractBlock):
if submission in tip.display_with_defaults: if submission in tip.display_with_defaults:
tips_fragments.append(tip.render()) tips_fragments.append(tip.render())
formatted_tips = render_template('templates/html/tip_choice_group.html', { formatted_tips = loader.render_template('templates/html/tip_choice_group.html', {
'self': self, 'self': self,
'tips_fragments': tips_fragments, 'tips_fragments': tips_fragments,
'completed': correct, 'completed': correct,
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
import logging import logging
import uuid import uuid
import re
from collections import namedtuple from collections import namedtuple
from lxml import etree from lxml import etree
...@@ -40,7 +42,7 @@ from .header import SharedHeaderBlock ...@@ -40,7 +42,7 @@ from .header import SharedHeaderBlock
from .html import HTMLBlock from .html import HTMLBlock
from .message import MentoringMessageBlock from .message import MentoringMessageBlock
from .step import StepParentMixin from .step import StepParentMixin
from .utils import get_scenarios_from_path, load_resource, render_template from .utils import loader
# Globals ########################################################### # Globals ###########################################################
...@@ -48,9 +50,22 @@ from .utils import get_scenarios_from_path, load_resource, render_template ...@@ -48,9 +50,22 @@ from .utils import get_scenarios_from_path, load_resource, render_template
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def default_xml_content(): def _default_xml_content():
return render_template('templates/xml/mentoring_default.xml', { return loader.render_template(
'url_name': 'mentoring-{}'.format(uuid.uuid4())}) 'templates/xml/mentoring_default.xml',
{'url_name': 'mentoring-{}'.format(uuid.uuid4())})
def _is_default_xml_content(value):
UUID_PATTERN = '[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}'
DUMMY_UUID = '12345678-1234-1234-1234-123456789abc'
expected = _default_xml_content()
expected = re.sub(UUID_PATTERN, DUMMY_UUID, expected)
value = re.sub(UUID_PATTERN, DUMMY_UUID, value)
return value == expected
# Classes ########################################################### # Classes ###########################################################
...@@ -66,6 +81,11 @@ class MentoringBlock(XBlockWithLightChildren, StepParentMixin): ...@@ -66,6 +81,11 @@ class MentoringBlock(XBlockWithLightChildren, StepParentMixin):
student is a) provided mentoring advices and asked to alter his answer, or b) is given the student is a) provided mentoring advices and asked to alter his answer, or b) is given the
ok to continue. ok to continue.
""" """
@staticmethod
def is_default_xml_content(value):
return _is_default_xml_content(value)
attempted = Boolean(help="Has the student attempted this mentoring step?", attempted = Boolean(help="Has the student attempted this mentoring step?",
default=False, scope=Scope.user_state) default=False, scope=Scope.user_state)
completed = Boolean(help="Has the student completed this mentoring step?", completed = Boolean(help="Has the student completed this mentoring step?",
...@@ -79,7 +99,7 @@ class MentoringBlock(XBlockWithLightChildren, StepParentMixin): ...@@ -79,7 +99,7 @@ class MentoringBlock(XBlockWithLightChildren, StepParentMixin):
enforce_dependency = Boolean(help="Should the next step be the current block to complete?", enforce_dependency = Boolean(help="Should the next step be the current block to complete?",
default=False, scope=Scope.content, enforce_type=True) default=False, scope=Scope.content, enforce_type=True)
display_submit = Boolean(help="Allow to submit current block?", default=True, scope=Scope.content) display_submit = Boolean(help="Allow to submit current block?", default=True, scope=Scope.content)
xml_content = String(help="XML content", default=default_xml_content, scope=Scope.content) xml_content = String(help="XML content", default=_default_xml_content, scope=Scope.content)
weight = Float(help="Defines the maximum total grade of the block.", weight = Float(help="Defines the maximum total grade of the block.",
default=1, scope=Scope.content, enforce_type=True) default=1, scope=Scope.content, enforce_type=True)
num_attempts = Integer(help="Number of attempts a user has answered for this questions", num_attempts = Integer(help="Number of attempts a user has answered for this questions",
...@@ -127,7 +147,7 @@ class MentoringBlock(XBlockWithLightChildren, StepParentMixin): ...@@ -127,7 +147,7 @@ class MentoringBlock(XBlockWithLightChildren, StepParentMixin):
not_instance_of=self.FLOATING_BLOCKS, not_instance_of=self.FLOATING_BLOCKS,
) )
fragment.add_content(render_template('templates/html/mentoring.html', { fragment.add_content(loader.render_template('templates/html/mentoring.html', {
'self': self, 'self': self,
'named_children': named_children, 'named_children': named_children,
'missing_dependency_url': self.has_missing_dependency and self.next_step_url, 'missing_dependency_url': self.has_missing_dependency and self.next_step_url,
...@@ -145,28 +165,19 @@ class MentoringBlock(XBlockWithLightChildren, StepParentMixin): ...@@ -145,28 +165,19 @@ class MentoringBlock(XBlockWithLightChildren, StepParentMixin):
) )
fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/mentoring.js')) fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/mentoring.js'))
fragment.add_resource(load_resource('templates/html/mentoring_attempts.html'), "text/html") fragment.add_resource(loader.load_unicode('templates/html/mentoring_attempts.html'), "text/html")
fragment.add_resource(load_resource('templates/html/mentoring_grade.html'), "text/html") fragment.add_resource(loader.load_unicode('templates/html/mentoring_grade.html'), "text/html")
fragment.initialize_js('MentoringBlock') fragment.initialize_js('MentoringBlock')
return fragment return fragment
@XBlock.json_handler @property
def publish_event(self, data, suffix=''): def additional_publish_event_data(self):
try: return {
event_type = data.pop('event_type') 'user_id': self.scope_ids.user_id,
except KeyError as e: 'component_id': self.url_name,
return {'result': 'error', 'message': 'Missing event_type in JSON data'} }
return self._publish_event(event_type, data)
def _publish_event(self, event_type, data):
data['user_id'] = self.scope_ids.user_id
data['component_id'] = self.url_name
self.runtime.publish(self, event_type, data)
return {'result': 'success'}
@property @property
def title(self): def title(self):
...@@ -262,7 +273,7 @@ class MentoringBlock(XBlockWithLightChildren, StepParentMixin): ...@@ -262,7 +273,7 @@ class MentoringBlock(XBlockWithLightChildren, StepParentMixin):
raw_score = self.score.raw raw_score = self.score.raw
self._publish_event('xblock.mentoring.submitted', { self.publish_event_from_dict('xblock.mentoring.submitted', {
'num_attempts': self.num_attempts, 'num_attempts': self.num_attempts,
'submitted_answer': submissions, 'submitted_answer': submissions,
'grade': raw_score, 'grade': raw_score,
...@@ -327,7 +338,7 @@ class MentoringBlock(XBlockWithLightChildren, StepParentMixin): ...@@ -327,7 +338,7 @@ class MentoringBlock(XBlockWithLightChildren, StepParentMixin):
event_data['num_attempts'] = self.num_attempts event_data['num_attempts'] = self.num_attempts
event_data['submitted_answer'] = submissions event_data['submitted_answer'] = submissions
self._publish_event('xblock.mentoring.assessment.submitted', event_data) self.publish_event_from_dict('xblock.mentoring.assessment.submitted', event_data)
return { return {
'completed': completed, 'completed': completed,
...@@ -383,7 +394,7 @@ class MentoringBlock(XBlockWithLightChildren, StepParentMixin): ...@@ -383,7 +394,7 @@ class MentoringBlock(XBlockWithLightChildren, StepParentMixin):
Editing view in Studio Editing view in Studio
""" """
fragment = Fragment() fragment = Fragment()
fragment.add_content(render_template('templates/html/mentoring_edit.html', { fragment.add_content(loader.render_template('templates/html/mentoring_edit.html', {
'self': self, 'self': self,
'xml_content': self.xml_content, 'xml_content': self.xml_content,
})) }))
...@@ -451,4 +462,4 @@ class MentoringBlock(XBlockWithLightChildren, StepParentMixin): ...@@ -451,4 +462,4 @@ class MentoringBlock(XBlockWithLightChildren, StepParentMixin):
""" """
Scenarios displayed by the workbench. Load them from external (private) repository Scenarios displayed by the workbench. Load them from external (private) repository
""" """
return get_scenarios_from_path('templates/xml') return loader.load_scenarios_from_path('templates/xml')
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
import logging import logging
from .light_children import LightChild, Scope, String from .light_children import LightChild, Scope, String
from .utils import render_template from .utils import loader
# Globals ########################################################### # Globals ###########################################################
...@@ -47,7 +47,7 @@ class MentoringMessageBlock(LightChild): ...@@ -47,7 +47,7 @@ class MentoringMessageBlock(LightChild):
def mentoring_view(self, context=None): def mentoring_view(self, context=None):
fragment, named_children = self.get_children_fragment(context, view_name='mentoring_view') fragment, named_children = self.get_children_fragment(context, view_name='mentoring_view')
fragment.add_content(render_template('templates/html/message.html', { fragment.add_content(loader.render_template('templates/html/message.html', {
'self': self, 'self': self,
'named_children': named_children, 'named_children': named_children,
})) }))
......
...@@ -28,7 +28,7 @@ import logging ...@@ -28,7 +28,7 @@ import logging
from .light_children import List, Scope, Boolean from .light_children import List, Scope, Boolean
from .questionnaire import QuestionnaireAbstractBlock from .questionnaire import QuestionnaireAbstractBlock
from .utils import render_template from .utils import loader
# Globals ########################################################### # Globals ###########################################################
...@@ -73,7 +73,7 @@ class MRQBlock(QuestionnaireAbstractBlock): ...@@ -73,7 +73,7 @@ class MRQBlock(QuestionnaireAbstractBlock):
# Only include tips/results in returned response if we want to display them # Only include tips/results in returned response if we want to display them
if not self.hide_results: if not self.hide_results:
choice_result['completed'] = choice_completed choice_result['completed'] = choice_completed
choice_result['tips'] = render_template('templates/html/tip_choice_group.html', { choice_result['tips'] = loader.render_template('templates/html/tip_choice_group.html', {
'self': self, 'self': self,
'tips_fragments': choice_tips_fragments, 'tips_fragments': choice_tips_fragments,
'completed': choice_completed, 'completed': choice_completed,
......
...@@ -31,7 +31,7 @@ from .choice import ChoiceBlock ...@@ -31,7 +31,7 @@ from .choice import ChoiceBlock
from .step import StepMixin from .step import StepMixin
from .light_children import LightChild, Scope, String, Float from .light_children import LightChild, Scope, String, Float
from .tip import TipBlock from .tip import TipBlock
from .utils import render_template, render_js_template from .utils import loader
# Globals ########################################################### # Globals ###########################################################
...@@ -82,14 +82,14 @@ class QuestionnaireAbstractBlock(LightChild, StepMixin): ...@@ -82,14 +82,14 @@ class QuestionnaireAbstractBlock(LightChild, StepMixin):
template_path = 'templates/html/{}_{}.html'.format(name.lower(), self.type) template_path = 'templates/html/{}_{}.html'.format(name.lower(), self.type)
render_function = render_js_template if as_template else render_template render_function = loader.custom_render_js_template if as_template else loader.render_template
html = render_function(template_path, { html = render_function(template_path, {
'self': self, 'self': self,
'custom_choices': self.custom_choices 'custom_choices': self.custom_choices
}) })
fragment = Fragment(html) fragment = Fragment(html)
fragment.add_css(render_template('public/css/questionnaire.css', { fragment.add_css(loader.render_template('public/css/questionnaire.css', {
'self': self 'self': self
})) }))
fragment.add_javascript_url(self.runtime.local_resource_url(self.xblock_container, fragment.add_javascript_url(self.runtime.local_resource_url(self.xblock_container,
......
...@@ -29,7 +29,7 @@ import logging ...@@ -29,7 +29,7 @@ import logging
from xblock.fields import Scope from xblock.fields import Scope
from .light_children import LightChild, String from .light_children import LightChild, String
from .utils import load_resource, render_template from .utils import loader
# Globals ########################################################### # Globals ###########################################################
...@@ -58,14 +58,14 @@ class MentoringTableBlock(LightChild): ...@@ -58,14 +58,14 @@ class MentoringTableBlock(LightChild):
# Load an optional description for the background image, for accessibility # Load an optional description for the background image, for accessibility
try: try:
bg_image_description = load_resource('static/text/table-{}.txt'.format(self.type)) bg_image_description = loader.load_unicode('static/text/table-{}.txt'.format(self.type))
except IOError as e: except IOError as e:
if e.errno == errno.ENOENT: if e.errno == errno.ENOENT:
bg_image_description = '' bg_image_description = ''
else: else:
raise raise
fragment.add_content(render_template('templates/html/mentoring-table.html', { fragment.add_content(loader.render_template('templates/html/mentoring-table.html', {
'self': self, 'self': self,
'columns_frags': columns_frags, 'columns_frags': columns_frags,
'header_frags': header_frags, 'header_frags': header_frags,
...@@ -101,7 +101,7 @@ class MentoringTableColumnBlock(LightChild): ...@@ -101,7 +101,7 @@ class MentoringTableColumnBlock(LightChild):
fragment, named_children = self.get_children_fragment( fragment, named_children = self.get_children_fragment(
context, view_name='mentoring_table_view', context, view_name='mentoring_table_view',
not_instance_of=MentoringTableColumnHeaderBlock) not_instance_of=MentoringTableColumnHeaderBlock)
fragment.add_content(render_template('templates/html/mentoring-table-column.html', { fragment.add_content(loader.render_template('templates/html/mentoring-table-column.html', {
'self': self, 'self': self,
'named_children': named_children, 'named_children': named_children,
})) }))
...@@ -114,7 +114,7 @@ class MentoringTableColumnBlock(LightChild): ...@@ -114,7 +114,7 @@ class MentoringTableColumnBlock(LightChild):
fragment, named_children = self.get_children_fragment( fragment, named_children = self.get_children_fragment(
context, view_name='mentoring_table_header_view', context, view_name='mentoring_table_header_view',
instance_of=MentoringTableColumnHeaderBlock) instance_of=MentoringTableColumnHeaderBlock)
fragment.add_content(render_template('templates/html/mentoring-table-header.html', { fragment.add_content(loader.render_template('templates/html/mentoring-table-header.html', {
'self': self, 'self': self,
'named_children': named_children, 'named_children': named_children,
})) }))
......
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 Harvard
#
# Authors:
# Xavier Antoviaque <xavier@antoviaque.org>
#
# This software's license gives you freedom; you can copy, convey,
# propagate, redistribute and/or modify this program under the terms of
# the GNU Affero General Public License (AGPL) as published by the Free
# Software Foundation (FSF), either version 3 of the License, or (at your
# option) any later version of the AGPL published by the FSF.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
# General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program in a file in the toplevel directory called
# "AGPLv3". If not, see <http://www.gnu.org/licenses/>.
#
# Imports ###########################################################
import time
from selenium.webdriver.support.ui import WebDriverWait
from workbench import scenarios
from workbench.test.selenium_test import SeleniumTest
from .utils import load_scenarios_from_path
# Classes ###########################################################
class MentoringBaseTest(SeleniumTest):
def setUp(self):
super(MentoringBaseTest, self).setUp()
# Use test scenarios
self.browser.get(self.live_server_url) # Needed to load tests once
scenarios.SCENARIOS.clear()
scenarios_list = load_scenarios_from_path('../tests/integration/xml')
for identifier, title, xml in scenarios_list:
scenarios.add_xml_scenario(identifier, title, xml)
self.addCleanup(scenarios.remove_scenario, identifier)
# Suzy opens the browser to visit the workbench
self.browser.get(self.live_server_url)
# She knows it's the site by the header
header1 = self.browser.find_element_by_css_selector('h1')
self.assertEqual(header1.text, 'XBlock scenarios')
def wait_until_disabled(self, submit):
wait = WebDriverWait(submit, 10)
wait.until(lambda s: not s.is_enabled(), "{} should be disabled".format(submit.text))
def wait_until_clickable(self, submit):
wait = WebDriverWait(submit, 10)
wait.until(lambda s: s.is_displayed() and s.is_enabled(), "{} should be cliclable".format(submit.text))
def wait_until_text_in(self, text, elem):
wait = WebDriverWait(elem, 10)
wait.until(lambda elem: text in elem.text, "{} should be in {}".format(text, elem.text))
def go_to_page(self, page_name, css_selector='div.mentoring'):
"""
Navigate to the page `page_name`, as listed on the workbench home
Returns the DOM element on the visited page located by the `css_selector`
"""
self.browser.get(self.live_server_url)
self.browser.find_element_by_link_text(page_name).click()
time.sleep(1)
mentoring = self.browser.find_element_by_css_selector(css_selector)
return mentoring
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
import logging import logging
from .light_children import LightChild, Scope, String from .light_children import LightChild, Scope, String
from .utils import render_template from .utils import loader
# Globals ########################################################### # Globals ###########################################################
...@@ -65,7 +65,7 @@ class TipBlock(LightChild): ...@@ -65,7 +65,7 @@ class TipBlock(LightChild):
Returns a fragment containing the formatted tip Returns a fragment containing the formatted tip
""" """
fragment, named_children = self.get_children_fragment({}) fragment, named_children = self.get_children_fragment({})
fragment.add_content(render_template('templates/html/tip.html', { fragment.add_content(loader.render_template('templates/html/tip.html', {
'self': self, 'self': self,
'named_children': named_children, 'named_children': named_children,
})) }))
......
...@@ -21,8 +21,6 @@ ...@@ -21,8 +21,6 @@
# "AGPLv3". If not, see <http://www.gnu.org/licenses/>. # "AGPLv3". If not, see <http://www.gnu.org/licenses/>.
# #
# Imports ###########################################################
import logging import logging
import os import os
import pkg_resources import pkg_resources
...@@ -32,39 +30,18 @@ from cStringIO import StringIO ...@@ -32,39 +30,18 @@ from cStringIO import StringIO
from django.template import Context, Template from django.template import Context, Template
from xblock.fragment import Fragment from xblock.fragment import Fragment
from xblockutils.resources import ResourceLoader
# Globals ###########################################################
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
# Functions ######################################################### class MentoringResourceLoader(ResourceLoader):
def custom_render_js_template(self, template_path, context={}):
def load_resource(resource_path): return self.render_js_template(template_path, 'light-child-template', context)
"""
Gets the content of a resource
"""
resource_content = pkg_resources.resource_string(__name__, resource_path)
return unicode(resource_content)
def render_template(template_path, context={}): loader = MentoringResourceLoader(__name__)
"""
Evaluate a template by resource path, applying the provided context
"""
template_str = load_resource(template_path)
template = Template(template_str)
return template.render(Context(context))
def render_js_template(template_path, context={}, id='light-child-template'):
"""
Render a js template.
"""
return u"<script type='text/template' id='{}'>\n{}\n</script>".format(
id,
render_template(template_path, context)
)
def list2csv(row): def list2csv(row):
...@@ -78,40 +55,6 @@ def list2csv(row): ...@@ -78,40 +55,6 @@ def list2csv(row):
return f.read() return f.read()
def get_scenarios_from_path(scenarios_path, include_identifier=False):
"""
Returns an array of (title, xmlcontent) from files contained in a specified directory,
formatted as expected for the return value of the workbench_scenarios() method
"""
base_fullpath = os.path.dirname(os.path.realpath(__file__))
scenarios_fullpath = os.path.join(base_fullpath, scenarios_path)
scenarios = []
if os.path.isdir(scenarios_fullpath):
for template in os.listdir(scenarios_fullpath):
if not template.endswith('.xml'):
continue
identifier = template[:-4]
title = identifier.replace('_', ' ').title()
template_path = os.path.join(scenarios_path, template)
scenario = unicode(render_template(template_path, {"url_name": identifier}))
if not include_identifier:
scenarios.append((title, scenario))
else:
scenarios.append((identifier, title, scenario))
return scenarios
def load_scenarios_from_path(scenarios_path):
"""
Load all xml files contained in a specified directory, as workbench scenarios
"""
return get_scenarios_from_path(scenarios_path, include_identifier=True)
# Classes ###########################################################
class XBlockWithChildrenFragmentsMixin(object): class XBlockWithChildrenFragmentsMixin(object):
def get_children_fragment(self, context, view_name='student_view', instance_of=None, def get_children_fragment(self, context, view_name='student_view', instance_of=None,
not_instance_of=None): not_instance_of=None):
......
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 Harvard
#
# Authors:
# Xavier Antoviaque <xavier@antoviaque.org>
#
# This software's license gives you freedom; you can copy, convey,
# propagate, redistribute and/or modify this program under the terms of
# the GNU Affero General Public License (AGPL) as published by the Free
# Software Foundation (FSF), either version 3 of the License, or (at your
# option) any later version of the AGPL published by the FSF.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
# General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program in a file in the toplevel directory called
# "AGPLv3". If not, see <http://www.gnu.org/licenses/>.
#
from xblockutils.base_test import SeleniumBaseTest
class MentoringBaseTest(SeleniumBaseTest):
module_name = __name__
default_css_selector = 'div.mentoring'
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
# Imports ########################################################### # Imports ###########################################################
from mentoring.test_base import MentoringBaseTest from .base_test import MentoringBaseTest
# Classes ########################################################### # Classes ###########################################################
......
from mentoring.test_base import MentoringBaseTest from .base_test import MentoringBaseTest
class MentoringAssessmentTest(MentoringBaseTest): class MentoringAssessmentTest(MentoringBaseTest):
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
# Imports ########################################################### # Imports ###########################################################
from mentoring.test_base import MentoringBaseTest from .base_test import MentoringBaseTest
# Classes ########################################################### # Classes ###########################################################
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
# Imports ########################################################### # Imports ###########################################################
from mentoring.test_base import MentoringBaseTest from .base_test import MentoringBaseTest
# Classes ########################################################### # Classes ###########################################################
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
# Imports ########################################################### # Imports ###########################################################
from mentoring.test_base import MentoringBaseTest from .base_test import MentoringBaseTest
# Classes ########################################################### # Classes ###########################################################
......
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