Commit 2b879408 by chrisndodge

Merge pull request #1241 from MITx/bug/dhm/jan13

Fix iframe conversion problem (111)
parents 21fc7340 83b7997d
from xmodule.modulestore.exceptions import ItemNotFoundError from xmodule.modulestore.exceptions import ItemNotFoundError
from xmodule.modulestore import Location from xmodule.modulestore import Location
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
from lxml import etree from lxml import html
import re import re
from django.http import HttpResponseBadRequest from django.http import HttpResponseBadRequest
import logging import logging
...@@ -24,9 +24,9 @@ def get_course_updates(location): ...@@ -24,9 +24,9 @@ def get_course_updates(location):
# purely to handle free formed updates not done via editor. Actually kills them, but at least doesn't break. # purely to handle free formed updates not done via editor. Actually kills them, but at least doesn't break.
try: try:
course_html_parsed = etree.fromstring(course_updates.definition['data']) course_html_parsed = html.fromstring(course_updates.definition['data'])
except etree.XMLSyntaxError: except:
course_html_parsed = etree.fromstring("<ol></ol>") course_html_parsed = html.fromstring("<ol></ol>")
# Confirm that root is <ol>, iterate over <li>, pull out <h2> subs and then rest of val # Confirm that root is <ol>, iterate over <li>, pull out <h2> subs and then rest of val
course_upd_collection = [] course_upd_collection = []
...@@ -39,7 +39,7 @@ def get_course_updates(location): ...@@ -39,7 +39,7 @@ def get_course_updates(location):
# could enforce that update[0].tag == 'h2' # could enforce that update[0].tag == 'h2'
content = update[0].tail content = update[0].tail
else: else:
content = "\n".join([etree.tostring(ele) for ele in update[1:]]) content = "\n".join([html.tostring(ele) for ele in update[1:]])
# make the id on the client be 1..len w/ 1 being the oldest and len being the newest # make the id on the client be 1..len w/ 1 being the oldest and len being the newest
course_upd_collection.append({"id" : location_base + "/" + str(len(course_html_parsed) - idx), course_upd_collection.append({"id" : location_base + "/" + str(len(course_html_parsed) - idx),
...@@ -61,17 +61,17 @@ def update_course_updates(location, update, passed_id=None): ...@@ -61,17 +61,17 @@ def update_course_updates(location, update, passed_id=None):
# purely to handle free formed updates not done via editor. Actually kills them, but at least doesn't break. # purely to handle free formed updates not done via editor. Actually kills them, but at least doesn't break.
try: try:
course_html_parsed = etree.fromstring(course_updates.definition['data']) course_html_parsed = html.fromstring(course_updates.definition['data'])
except etree.XMLSyntaxError: except:
course_html_parsed = etree.fromstring("<ol></ol>") course_html_parsed = html.fromstring("<ol></ol>")
# No try/catch b/c failure generates an error back to client # No try/catch b/c failure generates an error back to client
new_html_parsed = etree.fromstring('<li><h2>' + update['date'] + '</h2>' + update['content'] + '</li>') new_html_parsed = html.fromstring('<li><h2>' + update['date'] + '</h2>' + update['content'] + '</li>')
# Confirm that root is <ol>, iterate over <li>, pull out <h2> subs and then rest of val # Confirm that root is <ol>, iterate over <li>, pull out <h2> subs and then rest of val
if course_html_parsed.tag == 'ol': if course_html_parsed.tag == 'ol':
# ??? Should this use the id in the json or in the url or does it matter? # ??? Should this use the id in the json or in the url or does it matter?
if passed_id: if passed_id is not None:
idx = get_idx(passed_id) idx = get_idx(passed_id)
# idx is count from end of list # idx is count from end of list
course_html_parsed[-idx] = new_html_parsed course_html_parsed[-idx] = new_html_parsed
...@@ -82,7 +82,7 @@ def update_course_updates(location, update, passed_id=None): ...@@ -82,7 +82,7 @@ def update_course_updates(location, update, passed_id=None):
passed_id = course_updates.location.url() + "/" + str(idx) passed_id = course_updates.location.url() + "/" + str(idx)
# update db record # update db record
course_updates.definition['data'] = etree.tostring(course_html_parsed) course_updates.definition['data'] = html.tostring(course_html_parsed)
modulestore('direct').update_item(location, course_updates.definition['data']) modulestore('direct').update_item(location, course_updates.definition['data'])
return {"id" : passed_id, return {"id" : passed_id,
...@@ -105,9 +105,9 @@ def delete_course_update(location, update, passed_id): ...@@ -105,9 +105,9 @@ def delete_course_update(location, update, passed_id):
# TODO use delete_blank_text parser throughout and cache as a static var in a class # TODO use delete_blank_text parser throughout and cache as a static var in a class
# purely to handle free formed updates not done via editor. Actually kills them, but at least doesn't break. # purely to handle free formed updates not done via editor. Actually kills them, but at least doesn't break.
try: try:
course_html_parsed = etree.fromstring(course_updates.definition['data']) course_html_parsed = html.fromstring(course_updates.definition['data'])
except etree.XMLSyntaxError: except:
course_html_parsed = etree.fromstring("<ol></ol>") course_html_parsed = html.fromstring("<ol></ol>")
if course_html_parsed.tag == 'ol': if course_html_parsed.tag == 'ol':
# ??? Should this use the id in the json or in the url or does it matter? # ??? Should this use the id in the json or in the url or does it matter?
...@@ -118,7 +118,7 @@ def delete_course_update(location, update, passed_id): ...@@ -118,7 +118,7 @@ def delete_course_update(location, update, passed_id):
course_html_parsed.remove(element_to_delete) course_html_parsed.remove(element_to_delete)
# update db record # update db record
course_updates.definition['data'] = etree.tostring(course_html_parsed) course_updates.definition['data'] = html.tostring(course_html_parsed)
store = modulestore('direct') store = modulestore('direct')
store.update_item(location, course_updates.definition['data']) store.update_item(location, course_updates.definition['data'])
......
from cms.djangoapps.contentstore.tests.test_course_settings import CourseTestCase
from django.core.urlresolvers import reverse
import json
from cms.djangoapps.contentstore.course_info_model import update_course_updates
class CourseUpdateTest(CourseTestCase):
def test_course_update(self):
# first get the update to force the creation
url = reverse('course_info', kwargs={'org' : self.course_location.org, 'course' : self.course_location.course,
'name' : self.course_location.name })
self.client.get(url)
content = '<iframe width="560" height="315" src="http://www.youtube.com/embed/RocY-Jd93XU" frameborder="0"></iframe>'
payload = { 'content' : content,
'date' : 'January 8, 2013'}
# No means to post w/ provided_id missing. django doesn't handle. So, go direct for the create
payload = update_course_updates(['i4x', self.course_location.org, self.course_location.course, 'course_info', "updates"] , payload)
url = reverse('course_info', kwargs={'org' : self.course_location.org, 'course' : self.course_location.course,
'provided_id' : payload['id']})
self.assertHTMLEqual(content, payload['content'], "single iframe")
content += '<div>div <p>p</p></div>'
payload['content'] = content
resp = self.client.post(url, json.dumps(payload), "application/json")
self.assertHTMLEqual(content, json.loads(resp.content)['content'], "iframe w/ div")
...@@ -991,7 +991,7 @@ def course_info_updates(request, org, course, provided_id=None): ...@@ -991,7 +991,7 @@ def course_info_updates(request, org, course, provided_id=None):
elif request.method == 'POST': elif request.method == 'POST':
try: try:
return HttpResponse(json.dumps(update_course_updates(location, request.POST, provided_id)), mimetype="application/json") return HttpResponse(json.dumps(update_course_updates(location, request.POST, provided_id)), mimetype="application/json")
except etree.XMLSyntaxError: except:
return HttpResponseBadRequest("Failed to save: malformed html", content_type="text/plain") return HttpResponseBadRequest("Failed to save: malformed html", content_type="text/plain")
......
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