Commit cd121cf4 by Chris Dodge

initial implementation

parent eda70ad7
......@@ -12,6 +12,6 @@ urlpatterns = patterns(
url(r'^(?P<course_id>[a-zA-Z0-9/_:]+)/modules/*$', 'modules_list'),
url(r'^(?P<course_id>[a-zA-Z0-9/_:]+)/groups/(?P<group_id>[0-9]+)$', 'courses_groups_detail'),
url(r'^(?P<course_id>[a-zA-Z0-9/_:]+)/groups/*$', 'courses_groups_list'),
url(r'^(?P<course_id>[a-zA-Z0-9/_:]+)/about$', 'course_about'),
url(r'^(?P<course_id>[a-zA-Z0-9/_:]+)/overview$', 'course_overview'),
url(r'^(?P<course_id>[a-zA-Z0-9/_:]+)$', 'courses_detail'),
)
......@@ -221,6 +221,7 @@ def courses_detail(request, course_id):
return Response(response_data, status=status_code)
<<<<<<< HEAD
@api_view(['POST'])
@permission_classes((ApiKeyHeaderPermission,))
def courses_groups_list(request, course_id):
......@@ -302,6 +303,19 @@ def courses_groups_detail(request, course_id, group_id):
def _parse_about_html(html):
=======
def _inner_content(tag):
"""
Helper method
"""
inner_content = None
if tag is not None:
inner_content = u''.join(etree.tostring(e) for e in tag)
return inner_content
def _parse_overview_html(html):
>>>>>>> initial implementation
"""
Helper method to break up the course about HTML into components
"""
......@@ -346,11 +360,11 @@ def _parse_about_html(html):
if bio_html:
article_data['bio'] = bio_html
else:
article_data['body'] = etree.tostring(article)
article_data['body'] = _inner_content(article)
section_data['articles'].append(article_data)
else:
section_data['body'] = etree.tostring(section)
section_data['body'] = _inner_content(section)
result.append(section_data)
......@@ -359,7 +373,7 @@ def _parse_about_html(html):
@api_view(['GET'])
@permission_classes((ApiKeyHeaderPermission,))
def course_about(request, course_id):
def course_overview(request, course_id):
"""
GET retrieves the course overview module, which - in MongoDB - is stored with the following
naming convention {"_id.org":"i4x", "_id.course":<course_num>, "_id.category":"about", "_id.name":"overview"}
......@@ -374,8 +388,11 @@ def course_about(request, course_id):
overview = get_course_about_section(course_module, 'overview')
if request.GET.get('parsed'):
response_data['sections'] = _parse_about_html(overview)
if request.GET.get('parse') and request.GET.get('parse') in ['True', 'true']:
try:
response_data['sections'] = _parse_overview_html(overview)
except:
return Response({'err': 'could_not_parse'}, status=status.HTTP_409_CONFLICT)
else:
response_data['overview_html'] = overview
......
......@@ -4,11 +4,15 @@
Run these tests @ Devstack:
rake fasttest_lms[common/djangoapps/api_manager/tests/test_group_views.py]
"""
<<<<<<< HEAD
import simplejson as json
import unittest
=======
>>>>>>> initial implementation
import uuid
from django.conf import settings
from textwrap import dedent
from django.core.cache import cache
from django.test import TestCase, Client
from django.test.utils import override_settings
......@@ -19,6 +23,45 @@ from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
TEST_API_KEY = str(uuid.uuid4())
TEST_COURSE_OVERVIEW_CONTENT = dedent("""
<section class="about">
<h2>About This Course</h2>
<p>Include your long course description here. The long course description should contain 150-400 words.</p>
<p>This is paragraph 2 of the long course description. Add more paragraphs as needed. Make sure to enclose them in paragraph tags.</p>
</section>
<section class="prerequisites">
<h2>Prerequisites</h2>
<p>Add information about course prerequisites here.</p>
</section>
<section class="course-staff">
<h2>Course Staff</h2>
<article class="teacher">
<div class="teacher-image">
<img src="/images/pl-faculty.png" align="left" style="margin:0 20 px 0" alt="Course Staff Image #1">
</div>
<h3>Staff Member #1</h3>
<p>Biography of instructor/staff member #1</p>
</article>
<article class="teacher">
<div class="teacher-image">
<img src="/images/pl-faculty.png" align="left" style="margin:0 20 px 0" alt="Course Staff Image #2">
</div>
<h3>Staff Member #2</h3>
<p>Biography of instructor/staff member #2</p>
</article>
</section>
<section class="faq">
<p>Some text here</p>
</section>
""")
class SecureClient(Client):
""" Django test client using a "secure" connection. """
......@@ -34,6 +77,7 @@ class CoursesApiTests(TestCase):
""" Test suite for Courses API views """
def setUp(self):
self.maxDiff = 3000
self.test_server_prefix = 'https://testserver'
self.base_courses_uri = '/api/courses'
self.base_groups_uri = '/api/groups'
......@@ -63,6 +107,13 @@ class CoursesApiTests(TestCase):
display_name="Video_Resources"
)
self.overview = ItemFactory.create(
category="about",
parent_location=self.course.location,
data=TEST_COURSE_OVERVIEW_CONTENT,
display_name="overview"
)
self.test_course_id = self.course.id
self.test_course_name = self.course.display_name
self.test_course_number = self.course.number
......@@ -86,6 +137,7 @@ class CoursesApiTests(TestCase):
response = self.client.get(uri, headers=headers)
return response
<<<<<<< HEAD
def do_post(self, uri, data):
"""Submit an HTTP POST request"""
headers = {
......@@ -109,6 +161,8 @@ class CoursesApiTests(TestCase):
return response
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
=======
>>>>>>> initial implementation
def test_course_list_get(self):
test_uri = self.base_courses_uri
response = self.do_get(test_uri)
......@@ -125,7 +179,6 @@ class CoursesApiTests(TestCase):
matched_course = True
self.assertTrue(matched_course)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
def test_course_detail_get(self):
test_uri = self.base_courses_uri + '/' + self.test_course_id
response = self.do_get(test_uri)
......@@ -139,13 +192,11 @@ class CoursesApiTests(TestCase):
self.assertEqual(response.data['uri'], confirm_uri)
self.assertGreater(len(response.data['modules']), 0)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
def test_course_detail_get_notfound(self):
test_uri = self.base_courses_uri + '/' + 'p29038cvp9hjwefion'
response = self.do_get(test_uri)
self.assertEqual(response.status_code, 404)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
def test_chapter_list_get(self):
test_uri = self.base_chapters_uri
response = self.do_get(test_uri)
......@@ -161,7 +212,6 @@ class CoursesApiTests(TestCase):
matched_chapter = True
self.assertTrue(matched_chapter)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
def test_chapter_detail_get(self):
test_uri = self.base_modules_uri + '/' + self.test_chapter_id
response = self.do_get(test_uri)
......@@ -172,7 +222,6 @@ class CoursesApiTests(TestCase):
self.assertEqual(response.data['uri'], confirm_uri)
self.assertGreater(len(response.data['modules']), 0)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
def test_modules_list_get(self):
test_uri = self.base_modules_uri + '/' + self.test_module_id
response = self.do_get(test_uri)
......@@ -188,7 +237,6 @@ class CoursesApiTests(TestCase):
matched_submodule = True
self.assertTrue(matched_submodule)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
def test_modules_detail_get(self):
test_uri = self.base_modules_uri + '/' + self.test_module_id
response = self.do_get(test_uri)
......@@ -199,13 +247,11 @@ class CoursesApiTests(TestCase):
self.assertEqual(response.data['uri'], confirm_uri)
self.assertGreater(len(response.data['modules']), 0)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
def test_modules_detail_get_notfound(self):
test_uri = self.base_modules_uri + '/' + '2p38fp2hjfp9283'
response = self.do_get(test_uri)
self.assertEqual(response.status_code, 404)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
def test_modules_list_get_filtered_submodules_for_module(self):
test_uri = self.base_modules_uri + '/' + self.test_module_id + '/submodules?type=video'
response = self.do_get(test_uri)
......@@ -219,13 +265,11 @@ class CoursesApiTests(TestCase):
matched_submodule = True
self.assertTrue(matched_submodule)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
def test_modules_list_get_notfound(self):
test_uri = self.base_modules_uri + '/2p38fp2hjfp9283/submodules?type=video'
response = self.do_get(test_uri)
self.assertEqual(response.status_code, 404)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
def test_course_groups_list_post(self):
data = {'name': self.test_group_name}
......@@ -311,3 +355,46 @@ class CoursesApiTests(TestCase):
test_uri = '{}/{}/groups/{}'.format(self.base_courses_uri, self.test_course_id, group_id)
response = self.do_get(test_uri)
self.assertEqual(response.status_code, 404)
def test_get_course_overview_unparsed(self):
test_uri = self.base_courses_uri + '/' + self.test_course_id + '/overview'
response = self.do_get(test_uri)
self.assertEqual(response.status_code, 200)
self.assertGreater(len(response.data), 0)
self.assertEqual(response.data['overview_html'], self.overview.data)
def _find_item_by_class(self, items, class_name):
for item in items:
if item['class'] == class_name:
return item
return None
def test_get_course_overview_parsed(self):
test_uri = self.base_courses_uri + '/' + self.test_course_id + '/overview?parse=true'
response = self.do_get(test_uri)
self.assertEqual(response.status_code, 200)
self.assertGreater(len(response.data), 0)
sections = response.data['sections']
self.assertEqual(len(sections), 4)
self.assertIsNotNone(self._find_item_by_class(sections, 'about'))
self.assertIsNotNone(self._find_item_by_class(sections, 'prerequisites'))
self.assertIsNotNone(self._find_item_by_class(sections, 'course-staff'))
self.assertIsNotNone(self._find_item_by_class(sections, 'faq'))
course_staff = self._find_item_by_class(sections, 'course-staff')
teachers = course_staff['articles']
self.assertEqual(len(teachers), 2)
self.assertEqual(teachers[0]['name'], "Staff Member #1")
self.assertEqual(teachers[0]['image_src'], "/images/pl-faculty.png")
self.assertIn("<p>Biography of instructor/staff member #1</p>", teachers[0]['bio'])
self.assertEqual(teachers[1]['name'], "Staff Member #2")
self.assertEqual(teachers[1]['image_src'], "/images/pl-faculty.png")
self.assertIn("<p>Biography of instructor/staff member #2</p>", teachers[1]['bio'])
about = self._find_item_by_class(sections, 'about')
self.assertGreater(len(about['body']), 0)
prerequisites = self._find_item_by_class(sections, 'prerequisites')
self.assertGreater(len(prerequisites['body']), 0)
faq = self._find_item_by_class(sections, 'faq')
self.assertGreater(len(faq['body']), 0)
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