Skip to content

Commit

Permalink
Add configuration to studio for asides
Browse files Browse the repository at this point in the history
  • Loading branch information
Don Mitchell committed Dec 18, 2014
1 parent 4360a78 commit d49c82f
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 8 deletions.
5 changes: 4 additions & 1 deletion cms/djangoapps/contentstore/views/preview.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from .helpers import render_from_lms

from contentstore.views.access import get_user_role
from cms.djangoapps.xblock_config.models import StudioConfig

__all__ = ['preview_handler']

Expand Down Expand Up @@ -97,8 +98,10 @@ def local_resource_url(self, block, uri):

def applicable_aside_types(self, block):
"""
Remove acid_aside
Remove acid_aside and honor the config record
"""
if not StudioConfig.asides_enabled(block.scope_ids.block_type):
return []
return [
aside_type
for aside_type in super(PreviewModuleSystem, self).applicable_aside_types(block)
Expand Down
55 changes: 48 additions & 7 deletions cms/djangoapps/contentstore/views/tests/test_preview.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
"""
Tests for contentstore.views.preview.py
"""
import re

from django.test import TestCase
from django.test.client import RequestFactory

from xblock.core import XBlockAside
from student.tests.factories import UserFactory

from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory

from contentstore.views.preview import get_preview_fragment
from xmodule.modulestore import ModuleStoreEnum
from xblock.core import XBlockAside
from xmodule.modulestore.tests.test_asides import AsideTestType
import re
from cms.djangoapps.xblock_config.models import StudioConfig
from xmodule.modulestore.django import modulestore


class GetPreviewHtmlTestCase(TestCase):
Expand All @@ -22,14 +25,11 @@ class GetPreviewHtmlTestCase(TestCase):
Note that there are other existing test cases in test_contentstore that indirectly execute
get_preview_fragment via the xblock RESTful API.
"""

@XBlockAside.register_temp_plugin(AsideTestType, 'test_aside')
def test_preview_fragment(self):
"""
Test for calling get_preview_html.
This test used to be specifically about Locators (ensuring that they did not
get translated to Locations). The test now has questionable value.
Test for calling get_preview_html. Ensures data-usage-id is correctly set and
asides are correctly included.
"""
course = CourseFactory.create(default_store=ModuleStoreEnum.Type.split)
html = ItemFactory.create(
Expand All @@ -38,6 +38,10 @@ def test_preview_fragment(self):
data={'data': "<html>foobar</html>"}
)

config = StudioConfig.current()
config.enabled = True
config.save()

request = RequestFactory().get('/dummy-url')
request.user = UserFactory()
request.session = {}
Expand All @@ -60,3 +64,40 @@ def test_preview_fragment(self):
self.assertRegexpMatches(html, "Aside rendered")
# Now ensure the acid_aside is not in the result
self.assertNotRegexpMatches(html, r"data-block-type=[\"\']acid_aside[\"\']")

# Ensure about pages don't have asides
about = modulestore().get_item(course.id.make_usage_key('about', 'overview'))
html = get_preview_fragment(request, about, context).content
self.assertNotRegexpMatches(html, r"data-block-type=[\"\']test_aside[\"\']")
self.assertNotRegexpMatches(html, "Aside rendered")

@XBlockAside.register_temp_plugin(AsideTestType, 'test_aside')
def test_preview_no_asides(self):
"""
Test for calling get_preview_html. Ensures data-usage-id is correctly set and
asides are correctly excluded because they are not enabled.
"""
course = CourseFactory.create(default_store=ModuleStoreEnum.Type.split)
html = ItemFactory.create(
parent_location=course.location,
category="html",
data={'data': "<html>foobar</html>"}
)

config = StudioConfig.current()
config.enabled = False
config.save()

request = RequestFactory().get('/dummy-url')
request.user = UserFactory()
request.session = {}

# Call get_preview_fragment directly.
context = {
'reorderable_items': set(),
'read_only': True
}
html = get_preview_fragment(request, html, context).content

self.assertNotRegexpMatches(html, r"data-block-type=[\"\']test_aside[\"\']")
self.assertNotRegexpMatches(html, "Aside rendered")
Empty file.
9 changes: 9 additions & 0 deletions cms/djangoapps/xblock_config/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""
Django admin dashboard configuration for LMS XBlock infrastructure.
"""

from django.contrib import admin
from config_models.admin import ConfigurationModelAdmin
from cms.djangoapps.xblock_config.models import StudioConfig

admin.site.register(StudioConfig, ConfigurationModelAdmin)
74 changes: 74 additions & 0 deletions cms/djangoapps/xblock_config/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# -*- 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 'StudioConfig'
db.create_table('xblock_config_studioconfig', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('change_date', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
('changed_by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, on_delete=models.PROTECT)),
('enabled', self.gf('django.db.models.fields.BooleanField')(default=False)),
('disabled_blocks', self.gf('django.db.models.fields.TextField')(default='about course_info static_tab')),
))
db.send_create_signal('xblock_config', ['StudioConfig'])


def backwards(self, orm):
# Deleting model 'StudioConfig'
db.delete_table('xblock_config_studioconfig')


models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'xblock_config.studioconfig': {
'Meta': {'object_name': 'StudioConfig'},
'change_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'changed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'on_delete': 'models.PROTECT'}),
'disabled_blocks': ('django.db.models.fields.TextField', [], {'default': "'about course_info static_tab'"}),
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
}
}

complete_apps = ['xblock_config']
Empty file.
28 changes: 28 additions & 0 deletions cms/djangoapps/xblock_config/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
Models used by Studio XBlock infrastructure.
Includes:
StudioConfig: A ConfigurationModel for managing Studio.
"""

from django.db.models import TextField

from config_models.models import ConfigurationModel


class StudioConfig(ConfigurationModel):
"""
Configuration for XBlockAsides.
"""
disabled_blocks = TextField(
default="about course_info static_tab",
help_text="Space-separated list of XBlocks on which XBlockAsides should never render in studio",
)

@classmethod
def asides_enabled(cls, block_type):
"""
Return True if asides are enabled for this type of block in studio
"""
studio_config = cls.current()
return studio_config.enabled and block_type not in studio_config.disabled_blocks.split()
1 change: 1 addition & 0 deletions cms/envs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,7 @@
'course_creators',
'student', # misleading name due to sharing with lms
'openedx.core.djangoapps.course_groups', # not used in cms (yet), but tests run
'xblock_config',

# Tracking
'track',
Expand Down
3 changes: 3 additions & 0 deletions pavelib/utils/test/suites/acceptance_suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,13 @@ def _setup_acceptance_db(self):

# Run migrations to update the db, starting from its cached state
sh("./manage.py lms --settings acceptance migrate --traceback --noinput")
sh("./manage.py cms --settings acceptance migrate --traceback --noinput")
else:
# If no cached database exists, syncdb before migrating, then create the cache
sh("./manage.py lms --settings acceptance syncdb --traceback --noinput")
sh("./manage.py cms --settings acceptance syncdb --traceback --noinput")
sh("./manage.py lms --settings acceptance migrate --traceback --noinput")
sh("./manage.py cms --settings acceptance migrate --traceback --noinput")

# Create the cache if it doesn't already exist
sh("cp {db} {db_cache}".format(db_cache=self.db_cache, db=self.db))
3 changes: 3 additions & 0 deletions scripts/reset-test-db.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ if [[ -f $DB_CACHE_DIR/bok_choy_schema.sql && -f $DB_CACHE_DIR/bok_choy_data.jso

# Re-run migrations to ensure we are up-to-date
./manage.py lms --settings bok_choy migrate --traceback --noinput
./manage.py cms --settings bok_choy migrate --traceback --noinput

# Otherwise, update the test database and update the cache
else
Expand All @@ -48,7 +49,9 @@ else

# Re-run migrations on the test database
./manage.py lms --settings bok_choy syncdb --traceback --noinput
./manage.py cms --settings bok_choy syncdb --traceback --noinput
./manage.py lms --settings bok_choy migrate --traceback --noinput
./manage.py cms --settings bok_choy migrate --traceback --noinput

# Dump the schema and data to the cache
./manage.py lms --settings bok_choy dumpdata > $DB_CACHE_DIR/bok_choy_data.json
Expand Down

0 comments on commit d49c82f

Please sign in to comment.