Commit 90304396 by Braden MacDonald

Merge pull request #1 from open-craft/rename-mentoring

Rename mentoring to problem builder to allow simultaneous installation
parents dfb4cea9 ea383e29
*~
*.pyc
/.coverage
/xblock_mentoring.egg-info
/xblock_problem_builder.egg-info
/workbench.*
/dist
/templates
......@@ -9,11 +9,11 @@ install:
- "pip install -r $VIRTUAL_ENV/src/xblock-sdk/requirements.txt"
- "pip install -r $VIRTUAL_ENV/src/xblock-sdk/test-requirements.txt"
- "pip install -r requirements.txt"
- "pip uninstall -y xblock-mentoring && python setup.py sdist && pip install dist/xblock-mentoring-2.0.tar.gz"
- "pip uninstall -y xblock-problem-builder && python setup.py sdist && pip install dist/xblock-problem-builder-2.0.tar.gz"
script:
- pep8 mentoring --max-line-length=120
- pylint mentoring --disable=all --enable=function-redefined,undefined-variable,unused-variable
- python run_tests.py --with-coverage --cover-package=mentoring
- pep8 problem_builder --max-line-length=120
- pylint problem_builder --disable=all --enable=function-redefined,undefined-variable,unused-variable
- python run_tests.py --with-coverage --cover-package=problem_builder
notifications:
email: false
branches:
......
Mentoring XBlock
----------------
Problem Builder XBlock
----------------------
[![Build Status](https://travis-ci.org/open-craft/xblock-mentoring.svg?branch=master)](https://travis-ci.org/open-craft/xblock-mentoring)
[![Build Status](https://travis-ci.org/open-craft/xblock-problem-builder.svg?branch=master)](https://travis-ci.org/open-craft/xblock-problem-builder)
This XBlock allows to automate the workflow of real-life mentoring,
within an edX course.
This XBlock allows creation of questions of various types and simulating the
workflow of real-life mentoring, within an edX course.
It supports:
......@@ -24,10 +24,10 @@ It supports:
* **Tables**, which allow to present answers from the student to
free-form answers in a concise way. Supports custom headers.
The screenshot shows an example of a mentoring block containing a
The screenshot shows an example of a problem builder block containing a
free-form question, two MCQs and one MRQ.
![Mentoring Example](doc/img/mentoring-example.png)
![Problem Builder Example](doc/img/mentoring-example.png)
Installation
------------
......@@ -43,23 +43,23 @@ $ pip install -r requirements.txt
Enabling in Studio
------------------
You can enable the Mentoring XBlock in studio through the advanced
You can enable the Problem Builder XBlock in studio through the advanced
settings.
1. From the main page of a specific course, navigate to `Settings ->
Advanced Settings` from the top menu.
2. Check for the `advanced_modules` policy key, and add `"mentoring"`
2. Check for the `advanced_modules` policy key, and add `"problem-builder"`
to the policy value list.
3. Click the "Save changes" button.
Usage
-----
When you add the `Mentoring` component to a course in the studio, the
When you add the `Problem Builder` component to a course in the studio, the
built-in editing tools guide you through the process of configuring the
block and adding individual questions.
### Mentoring modes
### Problem Builder modes
There are 2 mentoring modes available:
......@@ -71,7 +71,7 @@ There are 2 mentoring modes available:
students don't get tips or feedback, but only know if their answer was
correct. Assessment mode comes with a default `max_attempts` of `2`.
Below are some LMS screenshots of a mentoring block in assessment mode.
Below are some LMS screenshots of a problem builder block in assessment mode.
Question before submitting an answer:
......@@ -101,7 +101,7 @@ Screenshot after answering the question:
![Answer Complete](doc/img/answer-2.png)
You can add "Long Answer Recap" components to mentoring blocks later on
You can add "Long Answer Recap" components to problem builder blocks later on
in the course to provide a read-only view of any answer that the student
entered earlier.
......@@ -111,14 +111,14 @@ The read-only answer is rendered as a quote in the LMS:
### Multiple Choice Questions (MCQ)
Multiple Choice Questions can be added to a mentoring component and
Multiple Choice Questions can be added to a problem builder component and
have the following configurable options:
* Question - The question to ask the student
* Message - A feedback message to display to the student after they
have made their choice.
* Weight - The weight is used when computing total grade/score of
the mentoring block. The larger the weight, the more influence this
the problem builder block. The larger the weight, the more influence this
question will have on the grade. Value of zero means this question
has no influence on the grade (float, defaults to `1`).
* Correct Choice - Specify which choice[s] is considered correct. If
......@@ -175,7 +175,7 @@ MRQ questions have these configurable settings:
* Message - A feedback message to display to the student after they
have made their choice.
* Weight - The weight is used when computing total grade/score of
the mentoring block. The larger the weight, the more influence this
the problem builder block. The larger the weight, the more influence this
question will have on the grade. Value of zero means this question
has no influence on the grade (float, defaults to `1`).
* Hide Result - If set to True, the feedback icons next to each
......@@ -202,7 +202,7 @@ After successfully completing the questions:
### Tables
The mentoring table allows you to present answers to multiple
The problem builder table allows you to present answers to multiple
free-form questions in a concise way. Once you create an "Answer
Recap Table" inside a Mentoring component in Studio, you will be
able to add columns to the table. Each column has an optional
......@@ -212,7 +212,7 @@ well as HTML components.
Screenshot:
![Mentoring Table](doc/img/mentoring-table.png)
![Table Screenshot](doc/img/mentoring-table.png)
### Maximum Attempts
......@@ -236,19 +236,20 @@ be valid CSS (e.g. `50px`).
Workbench installation and settings
-----------------------------------
Install to the workbench's virtualenv by running the following command form the mentoring repo root:
Install to the workbench's virtualenv by running the following command from the
problem builder repo root:
```bash
pip install -r requirements.txt
```
In the main XBlock repository, create the following configuration file
in `workbench/settings_mentoring.py` in the XBlock repository:
in `workbench/settings_pb.py` in the XBlock repository:
```python
from settings import *
INSTALLED_APPS += ('mentoring',)
INSTALLED_APPS += ('problem_builder',)
DATABASES['default']['NAME'] = 'workbench.sqlite'
```
......@@ -257,14 +258,14 @@ before starting the workbench. Run this from the XBlock repository
root:
```bash
$ ./manage.py syncdb --settings=workbench.settings_mentoring
$ ./manage.py syncdb --settings=workbench.settings_pb
```
Running the workbench
---------------------
```bash
$ ./manage.py runserver 8000 --settings=workbench.settings_mentoring
$ ./manage.py runserver 8000 --settings=workbench.settings_pb
```
Access it at [http://localhost:8000/](http://localhost:8000).
......@@ -273,9 +274,9 @@ Running tests
-------------
First, make sure the [XBlock SDK (Workbench)](https://github.com/edx/xblock-sdk)
is installed in the same virtual environment as xblock-mentoring.
is installed in the same virtual environment as xblock-problem-builder.
From the xblock-mentoring repository root, run the tests with the
From the xblock-problem-builder repository root, run the tests with the
following command:
```bash
......@@ -285,7 +286,7 @@ $ ./run_tests.py
If you want to run only the integration or the unit tests, append the directory to the command. You can also run separate modules in this manner.
```bash
$ ./run_tests.py mentoring/tests/unit
$ ./run_tests.py problem_builder/tests/unit
```
Extracting Translatable Strings
......@@ -308,13 +309,13 @@ i18n_tool dummy && i18n_tool generate
Adding custom scenarios to the workbench
----------------------------------------
Within the xblock-mentoring repository, create the `templates/xml` and
Within the xblock-problem-builder repository, create the `templates/xml` and
add XML scenarios to it - all files with the `*.xml` extension will be
automatically loaded by the workbench:
```bash
$ mkdir templates/xml
$ cat > templates/xml/my_mentoring_scenario.xml
$ cat > templates/xml/my_pb_scenario.xml
```
Restart the workbench to take the new scenarios into account.
......@@ -322,16 +323,16 @@ Restart the workbench to take the new scenarios into account.
Upgrading from Version 1
------------------------
To upgrade a course from the earlier version of this XBlock, run the following
command on a system with edx-platform and xblock-mentoring installed:
To upgrade a course from xblock-mentoring ("v1") to xblock-problem-builder
("v2"), run the following command on a system with edx-platform,
xblock-mentoring, and xblock-problem-builder installed:
```bash
$ SERVICE_VARIANT=cms DJANGO_SETTINGS_MODULE="cms.envs.devstack" python -m mentoring.v1.upgrade "Org/Course/Run"
$ SERVICE_VARIANT=cms DJANGO_SETTINGS_MODULE="cms.envs.devstack" python -m problem_builder.v1.upgrade "Org/Course/Run"
```
Where "Org/Course/Run" is replaced with the ID of the course to upgrade.
License
-------
The Mentoring XBlock is available under the GNU Affero General
Public License (AGPLv3).
This XBlock is available under the GNU Affero General Public License (AGPLv3).
../conf/locale/
\ No newline at end of file
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'Answer'
db.create_table('mentoring_answer', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('name', self.gf('django.db.models.fields.CharField')(max_length=50, db_index=True)),
('student_id', self.gf('django.db.models.fields.CharField')(max_length=20, db_index=True)),
('student_input', self.gf('django.db.models.fields.TextField')(default='', blank=True)),
('created_on', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
('modified_on', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)),
))
db.send_create_signal('mentoring', ['Answer'])
# Adding unique constraint on 'Answer', fields ['student_id', 'name']
db.create_unique('mentoring_answer', ['student_id', 'name'])
def backwards(self, orm):
# Removing unique constraint on 'Answer', fields ['student_id', 'name']
db.delete_unique('mentoring_answer', ['student_id', 'name'])
# Deleting model 'Answer'
db.delete_table('mentoring_answer')
models = {
'mentoring.answer': {
'Meta': {'unique_together': "(('student_id', 'name'),)", 'object_name': 'Answer'},
'created_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified_on': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'student_id': ('django.db.models.fields.CharField', [], {'max_length': '20', 'db_index': 'True'}),
'student_input': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'})
}
}
complete_apps = ['mentoring']
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Answer.course_id'
db.add_column('mentoring_answer', 'course_id',
self.gf('django.db.models.fields.CharField')(default='default', max_length=50, db_index=True),
keep_default=False)
# Changing field 'Answer.student_id'
db.alter_column('mentoring_answer', 'student_id', self.gf('django.db.models.fields.CharField')(max_length=32))
def backwards(self, orm):
# Deleting field 'Answer.course_id'
db.delete_column('mentoring_answer', 'course_id')
# Changing field 'Answer.student_id'
db.alter_column('mentoring_answer', 'student_id', self.gf('django.db.models.fields.CharField')(max_length=20))
models = {
'mentoring.answer': {
'Meta': {'unique_together': "(('student_id', 'name'),)", 'object_name': 'Answer'},
'course_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'created_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified_on': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'student_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
'student_input': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'})
}
}
complete_apps = ['mentoring']
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Removing unique constraint on 'Answer', fields ['student_id', 'name']
db.delete_unique('mentoring_answer', ['student_id', 'name'])
# Adding unique constraint on 'Answer', fields ['course_id', 'student_id', 'name']
db.create_unique('mentoring_answer', ['course_id', 'student_id', 'name'])
def backwards(self, orm):
# Removing unique constraint on 'Answer', fields ['course_id', 'student_id', 'name']
db.delete_unique('mentoring_answer', ['course_id', 'student_id', 'name'])
# Adding unique constraint on 'Answer', fields ['student_id', 'name']
db.create_unique('mentoring_answer', ['student_id', 'name'])
models = {
'mentoring.answer': {
'Meta': {'unique_together': "(('student_id', 'course_id', 'name'),)", 'object_name': 'Answer'},
'course_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'created_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified_on': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'student_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
'student_input': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'})
}
}
complete_apps = ['mentoring']
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'LightChild'
db.create_table('mentoring_lightchild', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('name', self.gf('django.db.models.fields.CharField')(max_length=50, db_index=True)),
('student_id', self.gf('django.db.models.fields.CharField')(max_length=32, db_index=True)),
('course_id', self.gf('django.db.models.fields.CharField')(max_length=50, db_index=True)),
('student_data', self.gf('django.db.models.fields.TextField')(default='', blank=True)),
('created_on', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
('modified_on', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)),
))
db.send_create_signal('mentoring', ['LightChild'])
# Adding unique constraint on 'LightChild', fields ['student_id', 'course_id', 'name']
db.create_unique('mentoring_lightchild', ['student_id', 'course_id', 'name'])
def backwards(self, orm):
# Removing unique constraint on 'LightChild', fields ['student_id', 'course_id', 'name']
db.delete_unique('mentoring_lightchild', ['student_id', 'course_id', 'name'])
# Deleting model 'LightChild'
db.delete_table('mentoring_lightchild')
models = {
'mentoring.answer': {
'Meta': {'unique_together': "(('student_id', 'course_id', 'name'),)", 'object_name': 'Answer'},
'course_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'created_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified_on': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'student_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
'student_input': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'})
},
'mentoring.lightchild': {
'Meta': {'unique_together': "(('student_id', 'course_id', 'name'),)", 'object_name': 'LightChild'},
'course_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'created_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'student_data': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified_on': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'student_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'})
}
}
complete_apps = ['mentoring']
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Changing field 'LightChild.name'
db.alter_column('mentoring_lightchild', 'name', self.gf('django.db.models.fields.CharField')(max_length=100))
def backwards(self, orm):
# Changing field 'LightChild.name'
db.alter_column('mentoring_lightchild', 'name', self.gf('django.db.models.fields.CharField')(max_length=50))
models = {
'mentoring.answer': {
'Meta': {'unique_together': "(('student_id', 'course_id', 'name'),)", 'object_name': 'Answer'},
'course_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'created_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified_on': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'student_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
'student_input': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'})
},
'mentoring.lightchild': {
'Meta': {'unique_together': "(('student_id', 'course_id', 'name'),)", 'object_name': 'LightChild'},
'course_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'created_on': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified_on': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'db_index': 'True'}),
'student_data': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
'student_id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'})
}
}
complete_apps = ['mentoring']
../conf/locale/
\ No newline at end of file
......@@ -48,7 +48,7 @@ log = logging.getLogger(__name__)
loader = ResourceLoader(__name__)
_default_theme_config = {
'package': 'mentoring',
'package': 'problem_builder',
'locations': ['public/themes/lms.css']
}
......
......@@ -32,7 +32,7 @@ class Answer(models.Model):
"""
class Meta:
app_label = 'mentoring'
db_table = 'mentoring_answer'
unique_together = (('student_id', 'course_id', 'name'),)
name = models.CharField(max_length=50, db_index=True)
......@@ -46,27 +46,3 @@ class Answer(models.Model):
# Force validation of max_length
self.full_clean()
super(Answer, self).save(*args, **kwargs)
class LightChild(models.Model):
"""
DEPRECATED.
Django model previously used to store LightChild student data.
This is not used at all by any of the mentoring blocks but will
be kept here for the purpose of migrating data for other
LightChildren that are converted to XBlocks and need to migrate
data from Django to native XBlock fields.
"""
class Meta:
app_label = 'mentoring'
managed = False # Don't create this table. This class is only to migrate data from an existing table.
unique_together = (('student_id', 'course_id', 'name'),)
name = models.CharField(max_length=100, db_index=True)
student_id = models.CharField(max_length=32, db_index=True)
course_id = models.CharField(max_length=50, db_index=True)
student_data = models.TextField(blank=True, default='')
created_on = models.DateTimeField('created on', auto_now_add=True)
modified_on = models.DateTimeField('modified on', auto_now=True)
......@@ -24,7 +24,7 @@ from xblockutils.base_test import SeleniumBaseTest
# Studio adds a url_name property to each XBlock but Workbench doesn't.
# Since we rely on it, we need to mock url_name support so it can be set via XML and
# accessed like a normal field.
from mentoring import MentoringBlock
from problem_builder import MentoringBlock
MentoringBlock.url_name = String()
......
......@@ -23,7 +23,7 @@
import ddt
from mock import patch, Mock
from mentoring import MentoringBlock
from problem_builder import MentoringBlock
from .base_test import MentoringBaseTest
......@@ -262,7 +262,7 @@ class MCQBlockTest(MentoringBaseTest):
self.assertIn('Congratulations!', messages.text)
@patch.object(MentoringBlock, 'get_theme', Mock(return_value={'package': 'mentoring',
@patch.object(MentoringBlock, 'get_theme', Mock(return_value={'package': 'problem_builder',
'locations': ['public/themes/lms.css']}))
class MCQBlockAprosThemeTest(MCQBlockTest):
"""
......
......@@ -33,7 +33,7 @@ class MentoringTest(MentoringBaseTest):
def _get_mentoring_theme_settings(theme):
return {
'package': 'mentoring',
'package': 'problem_builder',
'locations': ['public/themes/{}.css'.format(theme)]
}
......@@ -69,6 +69,6 @@ class MentoringThemeTest(MentoringAssessmentBaseTest):
('apros', "#ff0000")
)
def test_lms_theme_applied(self, theme, expected_color):
with mock.patch("mentoring.MentoringBlock.get_theme") as patched_theme:
with mock.patch("problem_builder.MentoringBlock.get_theme") as patched_theme:
patched_theme.return_value = _get_mentoring_theme_settings(theme)
self.assert_status_icon_color(expected_color)
......@@ -2,8 +2,8 @@ import unittest
import ddt
from mock import MagicMock, Mock, patch
from xblock.field_data import DictFieldData
from mentoring import MentoringBlock
from mentoring.mentoring import _default_theme_config
from problem_builder import MentoringBlock
from problem_builder.mentoring import _default_theme_config
class TestMentoringBlock(unittest.TestCase):
......@@ -78,13 +78,13 @@ class TestMentoringBlockTheming(unittest.TestCase):
package_name = 'some_package'
theme_config = {MentoringBlock.theme_key: {'package': package_name, 'locations': ['lms.css']}}
self.service_mock.get_settings_bucket = Mock(return_value=theme_config)
with patch("mentoring.mentoring.ResourceLoader") as patched_resource_loader:
with patch("problem_builder.mentoring.ResourceLoader") as patched_resource_loader:
self.block.include_theme_files(fragment)
patched_resource_loader.assert_called_with(package_name)
@ddt.data(
('mentoring', ['public/themes/lms.css']),
('mentoring', ['public/themes/lms.css', 'public/themes/lms.part2.css']),
('problem_builder', ['public/themes/lms.css']),
('problem_builder', ['public/themes/lms.css', 'public/themes/lms.part2.css']),
('my_app.my_rules', ['typography.css', 'icons.css']),
)
@ddt.unpack
......@@ -92,7 +92,7 @@ class TestMentoringBlockTheming(unittest.TestCase):
fragment = MagicMock()
theme_config = {MentoringBlock.theme_key: {'package': package_name, 'locations': locations}}
self.service_mock.get_settings_bucket = Mock(return_value=theme_config)
with patch("mentoring.mentoring.ResourceLoader.load_unicode") as patched_load_unicode:
with patch("problem_builder.mentoring.ResourceLoader.load_unicode") as patched_load_unicode:
self.block.include_theme_files(fragment)
for location in locations:
patched_load_unicode.assert_any_call(location)
......
import copy
from mentoring import MentoringBlock
from problem_builder import MentoringBlock
from mock import MagicMock, Mock
import unittest
from xblock.field_data import DictFieldData
......
import unittest
from mentoring.step import StepMixin, StepParentMixin
from problem_builder.step import StepMixin, StepParentMixin
from mock import Mock
......
......@@ -18,11 +18,12 @@
# "AGPLv3". If not, see <http://www.gnu.org/licenses/>.
#
"""
Test that we can upgrade from mentoring v1 to mentoring v2.
Test that we can upgrade from mentoring v1 to problem builder (v2).
"""
import ddt
from lxml import etree
from mentoring.v1.xml_changes import convert_xml_v1_to_v2
from problem_builder import MentoringBlock
from problem_builder.v1.xml_changes import convert_xml_v1_to_v2
import os.path
from StringIO import StringIO
import unittest
......@@ -53,6 +54,7 @@ class TestUpgrade(unittest.TestCase):
"v1_upgrade_c",
)
@XBlock.register_temp_plugin(HtmlBlock, "html")
@XBlock.register_temp_plugin(MentoringBlock, "mentoring")
def test_xml_upgrade(self, file_name):
"""
Convert a v1 mentoring block to v2 and then compare the resulting block to a
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Run tests for the Mentoring XBlock
Run tests for the Problem Builder XBlock
This script is required to run our selenium tests inside the xblock-sdk workbench
because the workbench SDK's settings file is not inside any python module.
......@@ -17,12 +17,12 @@ if __name__ == "__main__":
os.environ.setdefault("DJANGO_LIVE_TEST_SERVER_ADDRESS", "localhost:8081-8099")
from django.conf import settings
settings.INSTALLED_APPS += ("mentoring", )
settings.INSTALLED_APPS += ("problem_builder", )
from django.core.management import execute_from_command_line
args = sys.argv[1:]
paths = [arg for arg in args if arg[0] != '-']
if not paths:
paths = ["mentoring/tests/", "mentoring/v1/tests/"]
paths = ["problem_builder/tests/", "problem_builder/v1/tests/"]
options = [arg for arg in args if arg not in paths]
execute_from_command_line([sys.argv[0], "test"] + paths + options)
......@@ -40,49 +40,48 @@ def package_data(pkg, root_list):
# Main ##############################################################
BLOCKS = [
'problem-builder = mentoring:MentoringBlock',
'mentoring = mentoring:MentoringBlock', # Deprecated alias for problem-builder. Required to import older blocks.
'problem-builder = problem_builder:MentoringBlock',
'pb-table = mentoring:MentoringTableBlock',
'pb-column = mentoring:MentoringTableColumn',
'pb-answer = mentoring:AnswerBlock',
'pb-answer-recap = mentoring:AnswerRecapBlock',
'pb-mcq = mentoring:MCQBlock',
'pb-rating = mentoring:RatingBlock',
'pb-mrq = mentoring:MRQBlock',
'pb-message = mentoring:MentoringMessageBlock',
'pb-tip = mentoring:TipBlock',
'pb-choice = mentoring:ChoiceBlock',
'pb-table = problem_builder:MentoringTableBlock',
'pb-column = problem_builder:MentoringTableColumn',
'pb-answer = problem_builder:AnswerBlock',
'pb-answer-recap = problem_builder:AnswerRecapBlock',
'pb-mcq = problem_builder:MCQBlock',
'pb-rating = problem_builder:RatingBlock',
'pb-mrq = problem_builder:MRQBlock',
'pb-message = problem_builder:MentoringMessageBlock',
'pb-tip = problem_builder:TipBlock',
'pb-choice = problem_builder:ChoiceBlock',
# Deprecated. You can temporarily uncomment and run 'python setup.py develop' if you have these blocks
# installed from testing mentoring v2 and need to get past an error message.
#'answer = mentoring:AnswerBlock',
#'mentoring-answer = mentoring:AnswerBlock',
#'answer-recap = mentoring:AnswerRecapBlock',
#'mentoring-answer-recap = mentoring:AnswerRecapBlock',
#'mcq = mentoring:MCQBlock',
#'mentoring-mcq = mentoring:MCQBlock',
#'rating = mentoring:RatingBlock',
#'mentoring-rating = mentoring:RatingBlock',
#'mrq = mentoring:MRQBlock',
#'mentoring-mrq = mentoring:MRQBlock',
#'tip = mentoring:TipBlock',
#'mentoring-tip = mentoring:TipBlock',
#'choice = mentoring:ChoiceBlock',
#'mentoring-choice = mentoring:ChoiceBlock',
#'mentoring = problem_builder:MentoringBlock', # Deprecated alias for problem-builder
#'answer = problem_builder:AnswerBlock',
#'mentoring-answer = problem_builder:AnswerBlock',
#'answer-recap = problem_builder:AnswerRecapBlock',
#'mentoring-answer-recap = problem_builder:AnswerRecapBlock',
#'mcq = problem_builder:MCQBlock',
#'mentoring-mcq = problem_builder:MCQBlock',
#'rating = problem_builder:RatingBlock',
#'mentoring-rating = problem_builder:RatingBlock',
#'mrq = problem_builder:MRQBlock',
#'mentoring-mrq = problem_builder:MRQBlock',
#'tip = problem_builder:TipBlock',
#'mentoring-tip = problem_builder:TipBlock',
#'choice = problem_builder:ChoiceBlock',
#'mentoring-choice = problem_builder:ChoiceBlock',
]
setup(
name='xblock-mentoring',
name='xblock-problem-builder',
version='2.0',
description='XBlock - Mentoring',
packages=['mentoring', 'mentoring.v1'],
description='XBlock - Problem Builder',
packages=['problem_builder', 'problem_builder.v1'],
install_requires=[
'XBlock',
'xblock-utils',
],
dependency_links = ['http://github.com/edx-solutions/xblock-utils/tarball/master#egg=xblock-utils'],
entry_points={
'xblock.v1': BLOCKS,
},
package_data=package_data("mentoring", ["templates", "public", "migrations"]),
package_data=package_data("problem_builder", ["templates", "public", "migrations"]),
)
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