Commit 82daaa5a by Harry Rein

Adding a reviews page to the course and updating the reviews module on the…

Adding a reviews page to the course and updating the reviews module on the course about page. Removed the existing coursetalk implementation and put it in a fragment, removed the tests as well. Added configuration settings to specify the reviews template as well as the reviews provider. This is all protected by a waffle flag.
parent 4622b24a
......@@ -897,7 +897,6 @@ INSTALLED_APPS = (
'openedx.core.djangoapps.external_auth',
'student', # misleading name due to sharing with lms
'openedx.core.djangoapps.course_groups', # not used in cms (yet), but tests run
'openedx.core.djangoapps.coursetalk', # not used in cms (yet), but tests run
'xblock_config',
# Maintenance tools
......
......@@ -7,7 +7,7 @@ from nose.plugins.attrib import attr
from ...fixtures.course import CourseFixture, XBlockFixtureDesc
from ...pages.lms.bookmarks import BookmarksPage
from ...pages.lms.course_home import CourseHomePage, CourseSearchResultsPage
from ...pages.lms.course_home import CourseHomePage
from ...pages.lms.courseware import CoursewarePage
from ..helpers import UniqueCourseTest, auto_auth, load_data_str
......@@ -124,7 +124,7 @@ class CourseHomeTest(CourseHomeBaseTest):
@attr('a11y')
class CourseHomeA11yTest(CourseHomeBaseTest):
"""
Tests the accessibility of the course home page with course outline.
Tests the accessibility of the course home page
"""
def test_course_home_a11y(self):
......
......@@ -385,7 +385,7 @@ class SelfPacedCourseInfoTestCase(LoginEnrollmentTestCase, SharedModuleStoreTest
self.assertEqual(resp.status_code, 200)
def test_num_queries_instructor_paced(self):
self.fetch_course_info_with_queries(self.instructor_paced_course, 24, 4)
self.fetch_course_info_with_queries(self.instructor_paced_course, 26, 4)
def test_num_queries_self_paced(self):
self.fetch_course_info_with_queries(self.self_paced_course, 24, 4)
self.fetch_course_info_with_queries(self.self_paced_course, 26, 4)
......@@ -32,8 +32,8 @@ from openedx.core.djangoapps.monitoring_utils import set_custom_metrics_for_cour
from openedx.core.djangoapps.user_api.preferences.api import get_user_preference
from openedx.core.djangoapps.waffle_utils import WaffleSwitchNamespace
from openedx.features.course_experience import UNIFIED_COURSE_VIEW_FLAG, default_course_url_name
from openedx.features.enterprise_support.api import data_sharing_consent_required
from openedx.features.course_experience.views.course_sock import CourseSockFragmentView
from openedx.features.enterprise_support.api import data_sharing_consent_required
from request_cache.middleware import RequestCache
from shoppingcart.models import CourseRegistrationCode
from student.views import is_course_blocked
......
......@@ -6,7 +6,6 @@ import logging
import urllib
from collections import OrderedDict, namedtuple
from datetime import datetime, timedelta
from pytz import utc
import analytics
from django.conf import settings
......@@ -30,6 +29,7 @@ from ipware.ip import get_ip
from markupsafe import escape
from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey, UsageKey
from pytz import utc
from rest_framework import status
from web_fragments.fragment import Fragment
......@@ -73,7 +73,6 @@ from lms.djangoapps.instructor.views.api import require_global_staff
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification
from openedx.core.djangoapps.catalog.utils import get_programs, get_programs_with_type
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from openedx.core.djangoapps.coursetalk.helpers import inject_coursetalk_keys_into_context
from openedx.core.djangoapps.credit.api import (
get_credit_requirement_status,
is_credit_course,
......@@ -85,7 +84,7 @@ from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
from openedx.core.djangoapps.programs.utils import ProgramMarketingDataExtender
from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.features.course_experience import UNIFIED_COURSE_TAB_FLAG, UNIFIED_COURSE_VIEW_FLAG, course_home_url_name
from openedx.features.course_experience import UNIFIED_COURSE_TAB_FLAG, course_home_url_name
from openedx.features.course_experience.views.course_dates import CourseDatesFragmentView
from openedx.features.enterprise_support.api import data_sharing_consent_required
from shoppingcart.utils import is_shopping_cart_enabled
......@@ -324,6 +323,14 @@ def course_info(request, course_id):
if SelfPacedConfiguration.current().enable_course_home_improvements:
dates_fragment = CourseDatesFragmentView().render_to_fragment(request, course_id=course_id)
# This local import is due to the circularity of lms and openedx references.
# This may be resolved by using stevedore to allow web fragments to be used
# as plugins, and to avoid the direct import.
from openedx.features.course_experience.views.course_reviews import CourseReviewsModuleFragmentView
# Decide whether or not to show the reviews link in the course tools bar
show_reviews_link = CourseReviewsModuleFragmentView.is_configured()
context = {
'request': request,
'masquerade_user': user,
......@@ -338,6 +345,7 @@ def course_info(request, course_id):
'user_is_enrolled': user_is_enrolled,
'dates_fragment': dates_fragment,
'url_to_enroll': url_to_enroll,
'show_reviews_link': show_reviews_link,
# TODO: (Experimental Code). See https://openedx.atlassian.net/wiki/display/RET/2.+In-course+Verification+Prompts
'upgrade_link': check_and_get_upgrade_link(request, user, course.id),
'upgrade_price': get_cosmetic_verified_display_price(course),
......@@ -355,9 +363,6 @@ def course_info(request, course_id):
context['disable_student_access'] = True
context['supports_preview_menu'] = False
if CourseEnrollment.is_enrolled(request.user, course.id):
inject_coursetalk_keys_into_context(context, course_key)
return render_to_response('courseware/info.html', context)
......@@ -694,7 +699,6 @@ def course_about(request, course_id):
"""
Display the course's about page.
"""
course_key = CourseKey.from_string(course_id)
if hasattr(course_key, 'ccx'):
......@@ -776,7 +780,7 @@ def course_about(request, course_id):
# - Student is already registered for course
# - Course is already full
# - Student cannot enroll in course
active_reg_button = not(registered or is_course_full or not can_enroll)
active_reg_button = not (registered or is_course_full or not can_enroll)
is_shib_course = uses_shib(course)
......@@ -786,6 +790,14 @@ def course_about(request, course_id):
# Overview
overview = CourseOverview.get_from_id(course.id)
# This local import is due to the circularity of lms and openedx references.
# This may be resolved by using stevedore to allow web fragments to be used
# as plugins, and to avoid the direct import.
from openedx.features.course_experience.views.course_reviews import CourseReviewsModuleFragmentView
# Embed the course reviews tool
reviews_fragment_view = CourseReviewsModuleFragmentView().render_to_fragment(request, course=course)
context = {
'course': course,
'course_details': course_details,
......@@ -814,8 +826,8 @@ def course_about(request, course_id):
'cart_link': reverse('shoppingcart.views.show_cart'),
'pre_requisite_courses': pre_requisite_courses,
'course_image_urls': overview.image_urls,
'reviews_fragment_view': reviews_fragment_view,
}
inject_coursetalk_keys_into_context(context, course_key)
return render_to_response('courseware/course_about.html', context)
......
......@@ -389,6 +389,10 @@ FEATURES = {
'DISPLAY_ACCOUNT_ACTIVATION_MESSAGE_ON_SIDEBAR': False,
}
# Settings for the course reviews tool template and identification key, set either to None to disable course reviews
COURSE_REVIEWS_TOOL_PROVIDER_FRAGMENT_NAME = 'coursetalk-reviews-fragment.html'
COURSE_REVIEWS_TOOL_PROVIDER_PLATFORM_KEY = 'edx'
# Ignore static asset files on import which match this pattern
ASSET_IGNORE_REGEX = r"(^\._.*$)|(^\.DS_Store$)|(^.*~$)"
......@@ -2172,9 +2176,6 @@ INSTALLED_APPS = (
# Static i18n support
'statici18n',
# Review widgets
'openedx.core.djangoapps.coursetalk',
# API access administration
'openedx.core.djangoapps.api_admin',
......
......@@ -295,6 +295,17 @@ div.info-wrapper {
a {
color: $link-color;
display: block;
font-size: 16px;
span {
width: 20px;
text-align: center;
}
&:not(:first-child) {
margin-top: 10px;
}
}
&:after {
......@@ -307,7 +318,7 @@ div.info-wrapper {
@extend %t-strong;
@extend %t-title6;
margin-bottom: 0;
padding: 12px 26px 20px 0;
padding: 12px 26px 10px 0;
}
ul {
......
......@@ -20,6 +20,10 @@
.course-sidebar {
@include margin-left(0);
@include padding-left($baseline);
.section-tools li:not(:first-child) {
margin-top: ($baseline / 5);
}
}
// Course outline
......@@ -194,3 +198,8 @@
}
}
}
// Course Reviews Page
.course-reviews-tool {
margin: ($baseline * 2) ($baseline * 3);
}
......@@ -392,11 +392,6 @@
}
}
>.coursetalk-read-reviews {
margin-top: -200px;
margin-bottom: 220px;
}
header {
margin-bottom: 30px;
padding-bottom: 16px;
......
......@@ -5,6 +5,7 @@ from django.core.urlresolvers import reverse
from courseware.courses import get_course_about_section
from django.conf import settings
from edxmako.shortcuts import marketing_link
from openedx.core.djangolib.markup import HTML
from openedx.core.lib.courses import course_image_url
%>
......@@ -17,10 +18,6 @@ from openedx.core.lib.courses import course_image_url
</%block>
<%block name="js_extra">
## CourseTalk widget js script
% if show_coursetalk_widget:
<script src="//d3q6qq2zt8nhwv.cloudfront.net/s/js/widgets/coursetalk-read-reviews.js"></script>
% endif
<script type="text/javascript">
(function() {
$(".register").click(function(event) {
......@@ -296,11 +293,9 @@ from openedx.core.lib.courses import course_image_url
</ol>
</div>
## CourseTalk widget
% if show_coursetalk_widget:
<div class="coursetalk-read-reviews">
<div id="ct-custom-read-review-widget" data-provider="${platform_key}" data-course="${course_review_key}"></div>
</div>
## Course reviews tool
% if reviews_fragment_view:
${HTML(reviews_fragment_view.body_html())}
% endif
## For now, ocw links are the only thing that goes in additional resources
......
......@@ -12,6 +12,7 @@ from django.utils.translation import ugettext as _
from courseware.courses import get_course_info_section, get_course_date_blocks
from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration
from openedx.core.djangolib.markup import HTML, Text
from openedx.features.course_experience import SHOW_REVIEWS_TOOL_FLAG
%>
<%block name="pagetitle">${_("{course_number} Course Info").format(course_number=course.display_number_with_default)}</%block>
......@@ -48,13 +49,6 @@ from openedx.core.djangolib.markup import HTML, Text
CourseHomeEvents();
</%static:require_module_async>
<%block name="js_extra">
## CourseTalk widget js script
% if show_coursetalk_widget:
<script src="//d3q6qq2zt8nhwv.cloudfront.net/s/js/widgets/coursetalk-write-reviews.js"></script>
% endif
</%block>
<%block name="bodyclass">view-in-course view-course-info ${course.css_class or ''}</%block>
<main id="main" aria-label="Content" tabindex="-1">
......@@ -89,14 +83,7 @@ from openedx.core.djangolib.markup import HTML, Text
<h3 class="hd hd-3">${_("Course Updates and News")}</h3>
${HTML(get_course_info_section(request, masquerade_user, course, 'updates'))}
## CourseTalk widget
% if show_coursetalk_widget:
<div class="coursetalk-write-reviews">
<div id="ct-custom-read-review-widget" data-provider="${platform_key}" data-course="${course_review_key}"></div>
</div>
% endif
</section>
<section aria-label="${_('Handout Navigation')}" class="handouts">
<h3 class="hd hd-3 handouts-header">${_("Course Tools")}</h3>
<div>
......@@ -104,6 +91,12 @@ from openedx.core.djangolib.markup import HTML, Text
<span class="icon fa fa-bookmark" aria-hidden="true"></span>
${_("Bookmarks")}
</a>
% if SHOW_REVIEWS_TOOL_FLAG.is_enabled(course.id) and show_reviews_link:
<a href="${reverse('openedx.course_experience.course_reviews', args=[course.id])}">
<span class="icon fa fa-star" aria-hidden="true"></span>
${_("Reviews")}
</a>
% endif
</div>
% if SelfPacedConfiguration.current().enable_course_home_improvements:
......
"""Manage coursetalk configuration. """
from config_models.admin import ConfigurationModelAdmin
from django.contrib import admin
from openedx.core.djangoapps.coursetalk.models import CourseTalkWidgetConfiguration
admin.site.register(CourseTalkWidgetConfiguration, ConfigurationModelAdmin)
"""
CourseTalk widget helpers
"""
from __future__ import unicode_literals
from openedx.core.djangoapps.coursetalk import models
def get_coursetalk_course_key(course_key):
"""
Return course key for coursetalk widget
CourseTalk unique key for a course contains only organization and course code.
:param course_key: SlashSeparatedCourseKey instance
:type course_key: SlashSeparatedCourseKey
:return: CourseTalk course key
:rtype: str
"""
return '{0.org}_{0.course}'.format(course_key)
def inject_coursetalk_keys_into_context(context, course_key):
"""
Set params to view context based on course_key and CourseTalkWidgetConfiguration
:param context: view context
:type context: dict
:param course_key: SlashSeparatedCourseKey instance
:type course_key: SlashSeparatedCourseKey
"""
show_coursetalk_widget = models.CourseTalkWidgetConfiguration.is_enabled()
if show_coursetalk_widget:
context['show_coursetalk_widget'] = True
context['platform_key'] = models.CourseTalkWidgetConfiguration.get_platform_key()
context['course_review_key'] = get_coursetalk_course_key(course_key)
"""
Models for CourseTalk configurations
"""
from __future__ import unicode_literals
from config_models.models import ConfigurationModel
from django.db import models
from django.utils.translation import ugettext_lazy as _
class CourseTalkWidgetConfiguration(ConfigurationModel):
"""
This model represents Enable Configuration for CourseTalk widget.
If the setting enabled, widget will will be available on course
info page and on course about page.
"""
platform_key = models.fields.CharField(
max_length=50,
help_text=_(
"The platform key associates CourseTalk widgets with your platform. "
"Generally, it is the domain name for your platform. For example, "
"if your platform is http://edx.org, the platform key is \"edx\"."
)
)
@classmethod
def get_platform_key(cls):
"""
Return platform_key for current active configuration.
If current configuration is not enabled - return empty string
:return: Platform key
:rtype: unicode
"""
return cls.current().platform_key if cls.is_enabled() else ''
def __unicode__(self):
return 'CourseTalkWidgetConfiguration - {0}'.format(self.enabled)
""" CourseTalk widget helpers tests """
from __future__ import unicode_literals
from django import test
from opaque_keys.edx.locations import SlashSeparatedCourseKey
from openedx.core.djangoapps.coursetalk import helpers
from openedx.core.djangoapps.coursetalk import models
from openedx.core.djangolib.testing.utils import skip_unless_lms
@skip_unless_lms
class CourseTalkKeyTests(test.TestCase):
"""
CourseTalkKeyTests:
tests for function get_coursetalk_course_key
tests for function inject_coursetalk_keys_into_context
"""
PLATFORM_KEY = 'some_platform'
def setUp(self):
super(CourseTalkKeyTests, self).setUp()
self.course_key = SlashSeparatedCourseKey('org', 'course', 'run')
self.context = {}
def db_set_up(self, enabled):
"""
Setup database for this test:
Create CourseTalkWidgetConfiguration
"""
config = models.CourseTalkWidgetConfiguration.current()
config.enabled = enabled
config.platform_key = self.PLATFORM_KEY
config.save()
def test_simple_key(self):
coursetalk_course_key = helpers.get_coursetalk_course_key(self.course_key)
self.assertEqual(coursetalk_course_key, 'org_course')
def test_inject_coursetalk_keys_when_widget_not_enabled(self):
self.db_set_up(False)
helpers.inject_coursetalk_keys_into_context(self.context, self.course_key)
self.assertNotIn('show_coursetalk_widget', self.context)
self.assertNotIn('platform_key', self.context)
self.assertNotIn('course_review_key', self.context)
def test_inject_coursetalk_keys_when_widget_enabled(self):
self.db_set_up(True)
helpers.inject_coursetalk_keys_into_context(self.context, self.course_key)
self.assertIn('show_coursetalk_widget', self.context)
self.assertIn('platform_key', self.context)
self.assertIn('course_review_key', self.context)
self.assertEqual(self.context.get('show_coursetalk_widget'), True)
self.assertEqual(self.context.get('platform_key'), self.PLATFORM_KEY)
self.assertEqual(self.context.get('course_review_key'), 'org_course')
......@@ -20,7 +20,10 @@ WAFFLE_FLAG_NAMESPACE = WaffleFlagNamespace(name='course_experience')
UNIFIED_COURSE_TAB_FLAG = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'unified_course_tab')
# Waffle flag to enable the sock on the footer of the home and courseware pages
DISPLAY_COURSE_SOCK = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'display_course_sock')
DISPLAY_COURSE_SOCK_FLAG = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'display_course_sock')
# Waffle flag to enable a review page link from the unified home page
SHOW_REVIEWS_TOOL_FLAG = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'show_reviews_tool')
def course_home_page_title(course): # pylint: disable=unused-argument
......
......@@ -14,7 +14,7 @@ from django.core.urlresolvers import reverse
from django_comment_client.permissions import has_permission
from openedx.core.djangolib.js_utils import dump_js_escaped_json, js_escaped_string
from openedx.core.djangolib.markup import HTML
from openedx.features.course_experience import UNIFIED_COURSE_TAB_FLAG
from openedx.features.course_experience import UNIFIED_COURSE_TAB_FLAG, SHOW_REVIEWS_TOOL_FLAG
%>
<%block name="content">
......@@ -75,6 +75,14 @@ from openedx.features.course_experience import UNIFIED_COURSE_TAB_FLAG
${_("Bookmarks")}
</a>
</li>
% if SHOW_REVIEWS_TOOL_FLAG.is_enabled(course.id) and show_reviews_link:
<li>
<a href="${reverse('openedx.course_experience.course_reviews', args=[course.id])}">
<span class="icon fa fa-star" aria-hidden="true"></span>
${_("Reviews")}
</a>
</li>
% endif
% if UNIFIED_COURSE_TAB_FLAG.is_enabled(course.id):
<li>
<a href="${reverse('openedx.course_experience.course_updates', args=[course.id])}">
......
## mako
<%page expression_filter="h"/>
<%namespace name='static' file='../static_content.html'/>
<%!
from django.utils.translation import ugettext as _
from openedx.core.djangolib.markup import HTML
from openedx.features.course_experience import course_home_page_title
%>
<div class="course-reviews container" tabindex="-1">
<header class="page-header has-secondary">
## Breadcrumb navigation
<div class="page-header-main">
<nav aria-label="${_('Course Reviews')}" class="sr-is-focusable" tabindex="-1">
<div class="has-breadcrumbs">
<div class="breadcrumbs">
<span class="nav-item">
<a href="${course_url}">${course_home_page_title(course)}</a>
</span>
<span class="icon fa fa-angle-right" aria-hidden="true"></span>
<span class="nav-item">${_('Course Reviews')}</span>
</div>
</div>
</nav>
</div>
</header>
<div class="course-reviews-tool">
% if course_reviews_provider_fragment:
${HTML(course_reviews_provider_fragment.body_html())}
% endif
</div>
</div>
......@@ -5,11 +5,11 @@
<%!
from openedx.core.djangolib.markup import HTML
from openedx.features.course_experience import DISPLAY_COURSE_SOCK
from openedx.features.course_experience import DISPLAY_COURSE_SOCK_FLAG
%>
<%block name="content">
% if show_course_sock and DISPLAY_COURSE_SOCK.is_enabled(course_id):
% if show_course_sock and DISPLAY_COURSE_SOCK_FLAG.is_enabled(course_id):
<div class="verification-sock">
<button type="button" class="btn btn-brand focusable action-toggle-verification-sock">
Learn About Verified Certificate
......
## mako
<%page expression_filter="h"/>
<%namespace name='static' file='../static_content.html'/>
<%!
from openedx.features.course_experience import SHOW_REVIEWS_TOOL_FLAG
%>
% if SHOW_REVIEWS_TOOL_FLAG.is_enabled(course.id):
<div class="coursetalk-read-reviews">
## Coursetalk Widget
<div id="ct-custom-read-review-widget" data-provider="${platform_key}" data-course="${course.id}"></div>
</div>
<script src="//d3q6qq2zt8nhwv.cloudfront.net/s/js/widgets/coursetalk-read-reviews.js"></script>
% endif
......@@ -89,7 +89,7 @@ class TestCourseHomePage(SharedModuleStoreTestCase):
course_home_url(self.course)
# Fetch the view and verify the query counts
with self.assertNumQueries(49):
with self.assertNumQueries(51):
with check_mongo_calls(5):
url = course_home_url(self.course)
self.client.get(url)
......@@ -7,7 +7,7 @@ import ddt
from course_modes.models import CourseMode
from openedx.core.djangoapps.waffle_utils.testutils import override_waffle_flag
from openedx.features.course_experience import DISPLAY_COURSE_SOCK
from openedx.features.course_experience import DISPLAY_COURSE_SOCK_FLAG
from student.tests.factories import UserFactory, CourseEnrollmentFactory
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
......@@ -51,7 +51,7 @@ class TestCourseSockView(SharedModuleStoreTestCase):
# Log the user in
self.client.login(username=self.user.username, password=TEST_PASSWORD)
@override_waffle_flag(DISPLAY_COURSE_SOCK, active=True)
@override_waffle_flag(DISPLAY_COURSE_SOCK_FLAG, active=True)
def test_standard_course(self):
"""
Assure that a course that cannot be verified does
......@@ -61,7 +61,7 @@ class TestCourseSockView(SharedModuleStoreTestCase):
self.assertEqual(self.is_verified_sock_visible(response), False,
'Student should not be able to see sock in a unverifiable course.')
@override_waffle_flag(DISPLAY_COURSE_SOCK, active=True)
@override_waffle_flag(DISPLAY_COURSE_SOCK_FLAG, active=True)
def test_verified_course(self):
"""
Assure that a course that can be verified has a
......@@ -71,7 +71,7 @@ class TestCourseSockView(SharedModuleStoreTestCase):
self.assertEqual(self.is_verified_sock_visible(response), True,
'Student should be able to see sock in a verifiable course.')
@override_waffle_flag(DISPLAY_COURSE_SOCK, active=True)
@override_waffle_flag(DISPLAY_COURSE_SOCK_FLAG, active=True)
def test_verified_course_updated_expired(self):
"""
Assure that a course that has an expired upgrade
......@@ -81,7 +81,7 @@ class TestCourseSockView(SharedModuleStoreTestCase):
self.assertEqual(self.is_verified_sock_visible(response), False,
'Student should be able to see sock in a verifiable course if the update expiration date has passed.')
@override_waffle_flag(DISPLAY_COURSE_SOCK, active=True)
@override_waffle_flag(DISPLAY_COURSE_SOCK_FLAG, active=True)
def test_verified_course_user_already_upgraded(self):
"""
Assure that a user that has already upgraded to a
......
......@@ -6,6 +6,7 @@ from django.conf.urls import url
from views.course_home import CourseHomeFragmentView, CourseHomeView
from views.course_outline import CourseOutlineFragmentView
from views.course_reviews import CourseReviewsView
from views.course_updates import CourseUpdatesFragmentView, CourseUpdatesView
from views.course_sock import CourseSockFragmentView
from views.welcome_message import WelcomeMessageFragmentView, dismiss_welcome_message
......@@ -22,6 +23,11 @@ urlpatterns = [
name='openedx.course_experience.course_updates',
),
url(
r'^reviews$',
CourseReviewsView.as_view(),
name='openedx.course_experience.course_reviews',
),
url(
r'^home_fragment$',
CourseHomeFragmentView.as_view(),
name='openedx.course_experience.course_home_fragment_view',
......
......@@ -19,6 +19,7 @@ from util.views import ensure_valid_course_key
from ..utils import get_course_outline_block_tree
from .course_dates import CourseDatesFragmentView
from .course_outline import CourseOutlineFragmentView
from .course_reviews import CourseReviewsModuleFragmentView
from .welcome_message import WelcomeMessageFragmentView
from .course_sock import CourseSockFragmentView
......@@ -112,6 +113,9 @@ class CourseHomeFragmentView(EdxFragmentView):
# Get the handouts
handouts_html = get_course_info_section(request, request.user, course, 'handouts')
# Only show the reviews button if configured
show_reviews_link = CourseReviewsModuleFragmentView.is_configured()
# Render the course home fragment
context = {
'csrf': csrf(request)['csrf_token'],
......@@ -126,6 +130,7 @@ class CourseHomeFragmentView(EdxFragmentView):
'course_sock_fragment': course_sock_fragment,
'disable_courseware_js': True,
'uses_pattern_library': True,
'show_reviews_link': show_reviews_link,
}
html = render_to_string('course_experience/course-home-fragment.html', context)
return Fragment(html)
"""
Fragment for rendering the course reviews panel
"""
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse
from django.template.loader import render_to_string
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_control
from opaque_keys.edx.keys import CourseKey
from web_fragments.fragment import Fragment
from courseware.courses import get_course_with_access
from lms.djangoapps.courseware.views.views import CourseTabView
from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
from openedx.features.course_experience import default_course_url_name
class CourseReviewsView(CourseTabView):
"""
The course reviews page.
"""
@method_decorator(login_required)
@method_decorator(cache_control(no_cache=True, no_store=True, must_revalidate=True))
def get(self, request, course_id, **kwargs):
"""
Displays the reviews page for the specified course.
"""
return super(CourseReviewsView, self).get(request, course_id, 'courseware', **kwargs)
def render_to_fragment(self, request, course=None, tab=None, **kwargs):
course_id = unicode(course.id)
reviews_fragment_view = CourseReviewsFragmentView()
return reviews_fragment_view.render_to_fragment(request, course_id=course_id, **kwargs)
class CourseReviewsFragmentView(EdxFragmentView):
"""
A fragment to display course reviews.
"""
def render_to_fragment(self, request, course_id=None, **kwargs):
"""
Fragment to render the course reviews fragment.
"""
course_key = CourseKey.from_string(course_id)
course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True)
course_url_name = default_course_url_name(request)
course_url = reverse(course_url_name, kwargs={'course_id': unicode(course.id)})
# Create the fragment
course_reviews_provider_fragment = CourseReviewsModuleFragmentView().render_to_fragment(
request,
course=course,
**kwargs
)
context = {
'course': course,
'course_url': course_url,
'course_reviews_provider_fragment': course_reviews_provider_fragment
}
html = render_to_string('course_experience/course-reviews-fragment.html', context)
return Fragment(html)
class CourseReviewsModuleFragmentView(EdxFragmentView):
"""
A fragment to display the course reviews module as specified by
the configured template.
"""
def render_to_fragment(self, request, course=None, **kwargs):
"""
Renders the configured template as a module.
There are two relevant configuration settings:
COURSE_REVIEWS_TOOL_PROVIDER_FRAGMENT_NAME points to the template that
will be rendered and returned.
COURSE_REVIEWS_TOOL_PROVIDER_PLATFORM_KEY references the platform that
hosts the course. Generally, this is the domain name of the platform,
for example, 'edx.org' would have a platform key of 'edx'.
"""
# Grab the fragment type and provider from the configuration file
course_reviews_fragment_provider_template = \
settings.COURSE_REVIEWS_TOOL_PROVIDER_FRAGMENT_NAME
course_platform_key = \
settings.COURSE_REVIEWS_TOOL_PROVIDER_PLATFORM_KEY
if not self.is_configured():
return None
context = {
'course': course,
'platform_key': course_platform_key
}
# Create the fragment from the given template
provider_reviews_template = 'course_experience/course_reviews_modules/%s' \
% course_reviews_fragment_provider_template
html = render_to_string(provider_reviews_template, context)
return Fragment(html)
@classmethod
def is_configured(self):
return settings.COURSE_REVIEWS_TOOL_PROVIDER_FRAGMENT_NAME \
and settings.COURSE_REVIEWS_TOOL_PROVIDER_PLATFORM_KEY
"""
Fragment for rendering the course's sock and associated toggle button.
"""
from datetime import datetime
from django.conf import settings
from django.template.loader import render_to_string
from opaque_keys.edx.keys import CourseKey
from web_fragments.fragment import Fragment
......@@ -11,7 +8,6 @@ from web_fragments.fragment import Fragment
from student.models import CourseEnrollment
from course_modes.models import CourseMode
from courseware.date_summary import VerifiedUpgradeDeadlineDate
from courseware.courses import get_course_with_access
from courseware.views.views import get_course_prices
from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
......
......@@ -39,7 +39,7 @@ class CourseUpdatesView(CourseTabView):
class CourseUpdatesFragmentView(EdxFragmentView):
"""
A fragment to render the home page for a course.
A fragment to render the updates page for a course.
"""
STATUS_VISIBLE = 'visible'
STATUS_DELETED = 'deleted'
......
......@@ -130,6 +130,7 @@ var wpconfig = {
externals: {
backbone: 'Backbone',
coursetalk: 'CourseTalk',
gettext: 'gettext',
jquery: 'jQuery',
logger: 'Logger',
......
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