Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 20 additions & 19 deletions cms/djangoapps/contentstore/course_info_model.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from xmodule.modulestore.exceptions import ItemNotFoundError
from xmodule.modulestore import Location
from xmodule.modulestore.django import modulestore
from lxml import html, etree
import re
Expand Down Expand Up @@ -39,18 +38,12 @@ def get_course_updates(location):
if course_html_parsed.tag == 'ol':
# 0 is the newest
for idx, update in enumerate(course_html_parsed):
if (len(update) == 0):
continue
elif (len(update) == 1):
# could enforce that update[0].tag == 'h2'
content = update[0].tail
else:
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
course_upd_collection.append({"id": location_base + "/" + str(len(course_html_parsed) - idx),
"date": update.findtext("h2"),
"content": content})
if len(update) > 0:
content = _course_info_content(update)
# 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),
"date": update.findtext("h2"),
"content": content})

return course_upd_collection

Expand Down Expand Up @@ -104,14 +97,22 @@ def update_course_updates(location, update, passed_id=None):
course_updates.data = html.tostring(course_html_parsed)
modulestore('direct').update_item(location, course_updates.data)

if (len(new_html_parsed) == 1):
content = new_html_parsed[0].tail
else:
content = "\n".join([html.tostring(ele) for ele in new_html_parsed[1:]])

return {"id": passed_id,
"date": update['date'],
"content": content}
"content": _course_info_content(new_html_parsed)}


def _course_info_content(html_parsed):
"""
Constructs the HTML for the course info update, not including the header.
"""
if len(html_parsed) == 1:
# could enforce that update[0].tag == 'h2'
content = html_parsed[0].tail
else:
content = html_parsed[0].tail if html_parsed[0].tail is not None else ""
content += "\n".join([html.tostring(ele) for ele in html_parsed[1:]])
return content


def delete_course_update(location, update, passed_id):
Expand Down
8 changes: 8 additions & 0 deletions cms/djangoapps/contentstore/features/course-updates.feature
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ Feature: CMS.Course updates
Then I see the handout "Test"
And I see a "saving" notification

Scenario: Text outside of tags is preserved
Given I have opened a new course in Studio
And I go to the course updates page
When I add a new update with the text "before <strong>middle</strong> after"
Then I should see the update "before <strong>middle</strong> after"
And when I reload the page
Then I should see the update "before <strong>middle</strong> after"

Scenario: Static links are rewritten when previewing a course update
Given I have opened a new course in Studio
And I go to the course updates page
Expand Down
67 changes: 27 additions & 40 deletions cms/djangoapps/contentstore/tests/test_course_updates.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@ class CourseUpdateTest(CourseTestCase):
'''The do all and end all of unit test cases.'''
def test_course_update(self):
'''Go through each interface and ensure it works.'''
def get_response(content, date):
"""
Helper method for making call to server and returning response.

Does not supply a provided_id.
"""
payload = {'content': content,
'date': date}
url = reverse('course_info_json',
kwargs={'org': self.course.location.org,
'course': self.course.location.course,
'provided_id': ''})

resp = self.client.post(url, json.dumps(payload), "application/json")

return json.loads(resp.content)

# first get the update to force the creation
url = reverse('course_info',
kwargs={'org': self.course.location.org,
Expand All @@ -18,17 +35,7 @@ def test_course_update(self):

init_content = '<iframe width="560" height="315" src="http://www.youtube.com/embed/RocY-Jd93XU" frameborder="0">'
content = init_content + '</iframe>'
payload = {'content': content,
'date': 'January 8, 2013'}
url = reverse('course_info_json',
kwargs={'org': self.course.location.org,
'course': self.course.location.course,
'provided_id': ''})

resp = self.client.post(url, json.dumps(payload), "application/json")

payload = json.loads(resp.content)

payload = get_response(content, 'January 8, 2013')
self.assertHTMLEqual(payload['content'], content)

first_update_url = reverse('course_info_json',
Expand All @@ -48,17 +55,7 @@ def test_course_update(self):

# now put in an evil update
content = '<ol/>'
payload = {'content': content,
'date': 'January 11, 2013'}
url = reverse('course_info_json',
kwargs={'org': self.course.location.org,
'course': self.course.location.course,
'provided_id': ''})

resp = self.client.post(url, json.dumps(payload), "application/json")

payload = json.loads(resp.content)

payload = get_response(content, 'January 11, 2013')
self.assertHTMLEqual(content, payload['content'], "self closing ol")

url = reverse('course_info_json',
Expand All @@ -75,6 +72,11 @@ def test_course_update(self):
"application/json"),
'Failed to save', status_code=400)

# test an update with text in the tail of the header
content = 'outside <strong>inside</strong> after'
payload = get_response(content, 'June 22, 2000')
self.assertHTMLEqual(content, payload['content'], "text outside tag")

# now try to update a non-existent update
url = reverse('course_info_json',
kwargs={'org': self.course.location.org,
Expand All @@ -101,33 +103,18 @@ def test_course_update(self):

# set to valid html which would break an xml parser
content = "<p><br><br></p>"
payload = {'content': content,
'date': 'January 11, 2013'}
url = reverse('course_info_json', kwargs={'org': self.course.location.org,
'course': self.course.location.course,
'provided_id': ''})

resp = self.client.post(url, json.dumps(payload), "application/json")
payload = json.loads(resp.content)
self.assertHTMLEqual(content, json.loads(resp.content)['content'])
payload = get_response(content, 'January 11, 2013')
self.assertHTMLEqual(content, payload['content'])

# now try to delete a non-existent update
url = reverse('course_info_json', kwargs={'org': self.course.location.org,
'course': self.course.location.course,
'provided_id': '19'})
payload = {'content': content,
'date': 'January 21, 2013'}
self.assertContains(self.client.delete(url), "delete", status_code=400)

# now delete a real update
content = 'blah blah'
payload = {'content': content,
'date': 'January 28, 2013'}
url = reverse('course_info_json', kwargs={'org': self.course.location.org,
'course': self.course.location.course,
'provided_id': ''})
resp = self.client.post(url, json.dumps(payload), "application/json")
payload = json.loads(resp.content)
payload = get_response(content, 'January 28, 2013')
this_id = payload['id']
self.assertHTMLEqual(content, payload['content'], "single iframe")
# first count the entries
Expand Down