Commit 89f93df4 by Andy Armstrong Committed by Brian Jacobel

Refactor out a new discussions Django app

parent c4e5b201
...@@ -1037,7 +1037,7 @@ class DiscussionUserProfileTest(UniqueCourseTest): ...@@ -1037,7 +1037,7 @@ class DiscussionUserProfileTest(UniqueCourseTest):
Tests for user profile page in discussion tab. Tests for user profile page in discussion tab.
""" """
PAGE_SIZE = 20 # django_comment_client.forum.views.THREADS_PER_PAGE PAGE_SIZE = 20 # discussion.views.THREADS_PER_PAGE
PROFILED_USERNAME = "profiled-user" PROFILED_USERNAME = "profiled-user"
def setUp(self): def setUp(self):
......
...@@ -754,7 +754,7 @@ class DiscussionLinkTestCase(TabTestCase): ...@@ -754,7 +754,7 @@ class DiscussionLinkTestCase(TabTestCase):
"""Custom reverse function""" """Custom reverse function"""
def reverse_discussion_link(viewname, args): def reverse_discussion_link(viewname, args):
"""reverse lookup for discussion link""" """reverse lookup for discussion link"""
if viewname == "django_comment_client.forum.views.forum_form_discussion" and args == [unicode(course.id)]: if viewname == "discussion.views.forum_form_discussion" and args == [unicode(course.id)]:
return "default_discussion_link" return "default_discussion_link"
return reverse_discussion_link return reverse_discussion_link
......
"""
Views handling read (GET) requests for the Discussion tab and inline discussions.
"""
from django.conf import settings
from django.utils.translation import ugettext_noop
from courseware.tabs import EnrolledTab
import django_comment_client.utils as utils
class DiscussionTab(EnrolledTab):
"""
A tab for the cs_comments_service forums.
"""
type = 'discussion'
title = ugettext_noop('Discussion')
priority = None
view_name = 'discussion.views.forum_form_discussion'
is_hideable = settings.FEATURES.get('ALLOW_HIDING_DISCUSSION_TAB', False)
is_default = False
@classmethod
def is_enabled(cls, course, user=None):
if not super(DiscussionTab, cls).is_enabled(course, user):
return False
return utils.is_discussion_enabled(course.id)
;(function(define) {
'use strict';
define(['jquery', 'backbone'],
function($, Backbone) {
return function(options) {
var element = options.el,
userInfo = element.data('user-info'),
sortPreference = element.data('sort-preference'),
threads = element.data('threads'),
threadPages = element.data('thread-pages'),
contentInfo = element.data('content-info'),
user = new window.DiscussionUser(userInfo),
discussion,
courseSettings;
// TODO: Perhaps eliminate usage of global variables when possible
window.DiscussionUtil.loadRolesFromContainer();
window.$$course_id = options.courseId;
window.courseName = element.data('course-name');
window.DiscussionUtil.setUser(user);
window.user = user;
window.Content.loadContentInfos(contentInfo);
discussion = new window.Discussion(threads, {pages: threadPages, sort: sortPreference});
courseSettings = new window.DiscussionCourseSettings(element.data('course-settings'));
// jshint nonew:false
new window.DiscussionRouter({
discussion: discussion,
course_settings: courseSettings
});
Backbone.history.start({
pushState: true,
root: '/courses/' + options.courseId + '/discussion/forum/'
});
};
});
}).call(this, define || RequireJS.define);
;(function(define) {
'use strict';
define(['jquery', 'DiscussionUserProfileView'],
function($, DiscussionUserProfileView) {
return function(options) {
var element = options.el,
threads = element.data('threads'),
userInfo = element.data('user-info'),
page = element.data('page'),
numPages = element.data('num-pages');
// Roles are not included in user profile page, but they are not used for anything
window.DiscussionUtil.loadRoles({
'Moderator': [],
'Administrator': [],
'Community TA': []
});
window.$$course_id = element.data('course-id');
window.user = new window.DiscussionUser(userInfo);
// jshint nonew:false
new DiscussionUserProfileView({
el: element,
collection: threads,
page: page,
numPages: numPages
});
};
});
}).call(this, define || RequireJS.define);
...@@ -9,25 +9,38 @@ ...@@ -9,25 +9,38 @@
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.template.defaultfilters import escapejs from django.template.defaultfilters import escapejs
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from openedx.core.djangolib.js_utils import (
dump_js_escaped_json, js_escaped_string
)
%> %>
<%block name="bodyclass">discussion</%block> <%block name="bodyclass">discussion</%block>
<%block name="pagetitle">${_("Discussion - {course_number}").format(course_number=course.display_number_with_default)}</%block> <%block name="pagetitle">${_("Discussion - {course_number}").format(course_number=course.display_number_with_default)}</%block>
<%block name="headextra"> <%block name="headextra">
<%include file="_js_head_dependencies.html" /> <%include file="../discussion/_js_head_dependencies.html" />
</%block> </%block>
<%block name="js_extra"> <%block name="js_extra">
## Enable fast preview to fix discussion MathJax rendering bug when page first loads. ## Enable fast preview to fix discussion MathJax rendering bug when page first loads.
<%include file="_js_body_dependencies.html" args="disable_fast_preview=False"/> <%include file="/discussion/_js_body_dependencies.html" args="disable_fast_preview=False"/>
<%static:js group='discussion'/> <%static:js group='discussion'/>
<script type="text/javascript">
RequireJS.define('DiscussionBoardFactory', [], function() {return window['DiscussionBoardFactory'];});
</script>
<%static:require_module module_name="discussion/js/discussion_board_factory" class_name="DiscussionBoardFactory">
DiscussionBoardFactory({
courseId: '${unicode(course.id) | n, js_escaped_string}',
el: $(".discussion-board")
});
</%static:require_module>
</%block> </%block>
<%include file="_discussion_course_navigation.html" args="active_page='discussion'" /> <%include file="/discussion/_discussion_course_navigation.html" args="active_page='discussion'" />
<%block name="content"> <%block name="content">
<section class="discussion container" id="discussion-container" <section class="discussion discussion-board container" id="discussion-container"
data-roles="${roles}" data-roles="${roles}"
data-course-id="${course_id}" data-course-id="${course_id}"
data-course-name="${course.display_name_with_default}" data-course-name="${course.display_name_with_default}"
......
## mako
<%! main_css = "style-discussion-main" %>
<%page expression_filter="h"/>
<%inherit file="../main.html" />
<%namespace name='static' file='../static_content.html'/>
<%!
from django.utils.translation import ugettext as _
from django.template.defaultfilters import escapejs
from openedx.core.djangolib.js_utils import (
dump_js_escaped_json, js_escaped_string
)
%>
<%block name="bodyclass">discussion-user-profile</%block>
<%block name="pagetitle">${_("Discussion - {course_number}").format(course_number=course.display_number_with_default)}</%block>
<%block name="headextra">
<%include file="_js_head_dependencies.html" />
</%block>
<%block name="js_extra">
<%include file="_js_body_dependencies.html" />
<%static:js group='discussion'/>
<script type="text/javascript">
RequireJS.define('DiscussionUserProfileView', [], function() {return window['DiscussionUserProfileView'];});
</script>
<%static:require_module module_name="discussion/js/discussion_profile_page_factory" class_name="DiscussionProfilePageFactory">
DiscussionProfilePageFactory({
courseId: '${unicode(course.id) | n, js_escaped_string}',
el: $(".discussion-user-threads")
});
</%static:require_module>
</%block>
<%include file="../courseware/course_navigation.html" args="active_page='discussion'" />
<section class="container">
<div class="forum-nav">
<section class="user-profile">
<nav aria-label="${_('User Profile')}">
<article class="sidebar-module discussion-sidebar">
<%include file="_user_profile.html" />
</article>
</nav>
</section>
</div>
<div class="discussion-column" id="discussion-column">
<main id="main" aria-label="Content" tabindex="-1">
<section class="course-content container discussion-user-threads" data-course-id="${course.id}"
data-course-name="${course.display_name_with_default}"
data-threads="${threads}" data-user-info="${user_info}"
data-page="${page}" data-num-pages="${num_pages}"/>
</main>
</div>
</section>
<%include file="_underscore_templates.html" />
...@@ -10,7 +10,6 @@ from django.utils import translation ...@@ -10,7 +10,6 @@ from django.utils import translation
from lms.lib.comment_client.utils import CommentClientPaginatedResult from lms.lib.comment_client.utils import CommentClientPaginatedResult
from django_comment_common.utils import ThreadContext from django_comment_common.utils import ThreadContext
from django_comment_client.forum import views
from django_comment_client.permissions import get_team from django_comment_client.permissions import get_team
from django_comment_client.tests.group_id import ( from django_comment_client.tests.group_id import (
CohortedTopicGroupIdTestMixin, CohortedTopicGroupIdTestMixin,
...@@ -19,6 +18,7 @@ from django_comment_client.tests.group_id import ( ...@@ -19,6 +18,7 @@ from django_comment_client.tests.group_id import (
from django_comment_client.tests.unicode import UnicodeTestMixin from django_comment_client.tests.unicode import UnicodeTestMixin
from django_comment_client.tests.utils import CohortedTestCase from django_comment_client.tests.utils import CohortedTestCase
from django_comment_client.utils import strip_none from django_comment_client.utils import strip_none
from lms.djangoapps.discussion import views
from student.tests.factories import UserFactory, CourseEnrollmentFactory from student.tests.factories import UserFactory, CourseEnrollmentFactory
from util.testing import UrlResetMixin from util.testing import UrlResetMixin
from openedx.core.djangoapps.util.testing import ContentGroupTestCase from openedx.core.djangoapps.util.testing import ContentGroupTestCase
...@@ -87,7 +87,7 @@ class ViewsExceptionTestCase(UrlResetMixin, ModuleStoreTestCase): ...@@ -87,7 +87,7 @@ class ViewsExceptionTestCase(UrlResetMixin, ModuleStoreTestCase):
# that gets the current user's info # that gets the current user's info
mock_from_django_user.return_value = Mock() mock_from_django_user.return_value = Mock()
url = reverse('django_comment_client.forum.views.user_profile', url = reverse('discussion.views.user_profile',
kwargs={'course_id': self.course.id.to_deprecated_string(), 'user_id': '12345'}) # There is no user 12345 kwargs={'course_id': self.course.id.to_deprecated_string(), 'user_id': '12345'}) # There is no user 12345
self.response = self.client.get(url) self.response = self.client.get(url)
self.assertEqual(self.response.status_code, 404) self.assertEqual(self.response.status_code, 404)
...@@ -104,7 +104,7 @@ class ViewsExceptionTestCase(UrlResetMixin, ModuleStoreTestCase): ...@@ -104,7 +104,7 @@ class ViewsExceptionTestCase(UrlResetMixin, ModuleStoreTestCase):
# that gets the current user's info # that gets the current user's info
mock_from_django_user.return_value = Mock() mock_from_django_user.return_value = Mock()
url = reverse('django_comment_client.forum.views.followed_threads', url = reverse('discussion.views.followed_threads',
kwargs={'course_id': self.course.id.to_deprecated_string(), 'user_id': '12345'}) # There is no user 12345 kwargs={'course_id': self.course.id.to_deprecated_string(), 'user_id': '12345'}) # There is no user 12345
self.response = self.client.get(url) self.response = self.client.get(url)
self.assertEqual(self.response.status_code, 404) self.assertEqual(self.response.status_code, 404)
...@@ -1257,7 +1257,7 @@ class CommentsServiceRequestHeadersTestCase(UrlResetMixin, ModuleStoreTestCase): ...@@ -1257,7 +1257,7 @@ class CommentsServiceRequestHeadersTestCase(UrlResetMixin, ModuleStoreTestCase):
self.client.get( self.client.get(
reverse( reverse(
"django_comment_client.forum.views.single_thread", "discussion.views.single_thread",
kwargs={ kwargs={
"course_id": self.course.id.to_deprecated_string(), "course_id": self.course.id.to_deprecated_string(),
"discussion_id": "dummy_discussion_id", "discussion_id": "dummy_discussion_id",
...@@ -1274,7 +1274,7 @@ class CommentsServiceRequestHeadersTestCase(UrlResetMixin, ModuleStoreTestCase): ...@@ -1274,7 +1274,7 @@ class CommentsServiceRequestHeadersTestCase(UrlResetMixin, ModuleStoreTestCase):
self.client.get( self.client.get(
reverse( reverse(
"django_comment_client.forum.views.forum_form_discussion", "discussion.views.forum_form_discussion",
kwargs={"course_id": self.course.id.to_deprecated_string()} kwargs={"course_id": self.course.id.to_deprecated_string()}
), ),
) )
...@@ -1361,7 +1361,7 @@ class ForumDiscussionXSSTestCase(UrlResetMixin, ModuleStoreTestCase): ...@@ -1361,7 +1361,7 @@ class ForumDiscussionXSSTestCase(UrlResetMixin, ModuleStoreTestCase):
Test that XSS attack is prevented Test that XSS attack is prevented
""" """
reverse_url = "%s%s" % (reverse( reverse_url = "%s%s" % (reverse(
"django_comment_client.forum.views.forum_form_discussion", "discussion.views.forum_form_discussion",
kwargs={"course_id": unicode(self.course.id)}), '/forum_form_discussion') kwargs={"course_id": unicode(self.course.id)}), '/forum_form_discussion')
# Test that malicious code does not appear in html # Test that malicious code does not appear in html
url = "%s?%s=%s" % (reverse_url, 'sort_key', malicious_code) url = "%s?%s=%s" % (reverse_url, 'sort_key', malicious_code)
...@@ -1380,7 +1380,7 @@ class ForumDiscussionXSSTestCase(UrlResetMixin, ModuleStoreTestCase): ...@@ -1380,7 +1380,7 @@ class ForumDiscussionXSSTestCase(UrlResetMixin, ModuleStoreTestCase):
mock_from_django_user.return_value = Mock() mock_from_django_user.return_value = Mock()
mock_request.side_effect = make_mock_request_impl(course=self.course, text='dummy') mock_request.side_effect = make_mock_request_impl(course=self.course, text='dummy')
url = reverse('django_comment_client.forum.views.user_profile', url = reverse('discussion.views.user_profile',
kwargs={'course_id': unicode(self.course.id), 'user_id': str(self.student.id)}) kwargs={'course_id': unicode(self.course.id), 'user_id': str(self.student.id)})
# Test that malicious code does not appear in html # Test that malicious code does not appear in html
url_string = "%s?%s=%s" % (url, 'page', malicious_code) url_string = "%s?%s=%s" % (url, 'page', malicious_code)
......
...@@ -4,7 +4,7 @@ Forum urls for the django_comment_client. ...@@ -4,7 +4,7 @@ Forum urls for the django_comment_client.
from django.conf.urls import url, patterns from django.conf.urls import url, patterns
urlpatterns = patterns( urlpatterns = patterns(
'django_comment_client.forum.views', 'discussion.views',
url(r'users/(?P<user_id>\w+)/followed$', 'followed_threads', name='followed_threads'), url(r'users/(?P<user_id>\w+)/followed$', 'followed_threads', name='followed_threads'),
url(r'users/(?P<user_id>\w+)$', 'user_profile', name='user_profile'), url(r'users/(?P<user_id>\w+)$', 'user_profile', name='user_profile'),
......
...@@ -7,23 +7,20 @@ import json ...@@ -7,23 +7,20 @@ import json
import logging import logging
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.conf import settings
from django.core.context_processors import csrf from django.core.context_processors import csrf
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.http import Http404, HttpResponseBadRequest from django.http import Http404, HttpResponseBadRequest
from django.utils.translation import ugettext_noop from django.shortcuts import render_to_response
from django.views.decorators.http import require_GET from django.views.decorators.http import require_GET
import newrelic.agent import newrelic.agent
from edxmako.shortcuts import render_to_response
from courseware.courses import get_course_with_access from courseware.courses import get_course_with_access
from openedx.core.djangoapps.course_groups.cohorts import ( from openedx.core.djangoapps.course_groups.cohorts import (
is_course_cohorted, is_course_cohorted,
get_cohort_id, get_cohort_id,
get_course_cohorts, get_course_cohorts,
) )
from courseware.tabs import EnrolledTab
from courseware.access import has_access from courseware.access import has_access
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
...@@ -48,25 +45,6 @@ PAGES_NEARBY_DELTA = 2 ...@@ -48,25 +45,6 @@ PAGES_NEARBY_DELTA = 2
log = logging.getLogger("edx.discussions") log = logging.getLogger("edx.discussions")
class DiscussionTab(EnrolledTab):
"""
A tab for the cs_comments_service forums.
"""
type = 'discussion'
title = ugettext_noop('Discussion')
priority = None
view_name = 'django_comment_client.forum.views.forum_form_discussion'
is_hideable = settings.FEATURES.get('ALLOW_HIDING_DISCUSSION_TAB', False)
is_default = False
@classmethod
def is_enabled(cls, course, user=None):
if not super(DiscussionTab, cls).is_enabled(course, user):
return False
return utils.is_discussion_enabled(course.id)
@newrelic.agent.function_trace() @newrelic.agent.function_trace()
def make_course_settings(course, user): def make_course_settings(course, user):
""" """
...@@ -115,7 +93,8 @@ def get_threads(request, course, discussion_id=None, per_page=THREADS_PER_PAGE): ...@@ -115,7 +93,8 @@ def get_threads(request, course, discussion_id=None, per_page=THREADS_PER_PAGE):
# If the user did not select a sort key, use their last used sort key # If the user did not select a sort key, use their last used sort key
cc_user = cc.User.from_django_user(request.user) cc_user = cc.User.from_django_user(request.user)
cc_user.retrieve() cc_user.retrieve()
# TODO: After the comment service is updated this can just be user.default_sort_key because the service returns the default value # TODO: After the comment service is updated this can just be
# user.default_sort_key because the service returns the default value
default_query_params['sort_key'] = cc_user.get('default_sort_key') or default_query_params['sort_key'] default_query_params['sort_key'] = cc_user.get('default_sort_key') or default_query_params['sort_key']
else: else:
# If the user clicked a sort key, update their default sort key # If the user clicked a sort key, update their default sort key
...@@ -239,7 +218,10 @@ def forum_form_discussion(request, course_key): ...@@ -239,7 +218,10 @@ def forum_form_discussion(request, course_key):
threads = [utils.prepare_content(thread, course_key, is_staff) for thread in unsafethreads] threads = [utils.prepare_content(thread, course_key, is_staff) for thread in unsafethreads]
except cc.utils.CommentClientMaintenanceError: except cc.utils.CommentClientMaintenanceError:
log.warning("Forum is in maintenance mode") log.warning("Forum is in maintenance mode")
return render_to_response('discussion/maintenance.html', {}) return render_to_response('discussion/maintenance.html', {
'disable_courseware_js': True,
'uses_pattern_library': True,
})
except ValueError: except ValueError:
return HttpResponseBadRequest("Invalid group_id") return HttpResponseBadRequest("Invalid group_id")
...@@ -290,7 +272,7 @@ def forum_form_discussion(request, course_key): ...@@ -290,7 +272,7 @@ def forum_form_discussion(request, course_key):
'uses_pattern_library': True, 'uses_pattern_library': True,
} }
# print "start rendering.." # print "start rendering.."
return render_to_response('discussion/index.html', context) return render_to_response('discussion/discussion_board.html', context)
@require_GET @require_GET
...@@ -318,8 +300,8 @@ def single_thread(request, course_key, discussion_id, thread_id): ...@@ -318,8 +300,8 @@ def single_thread(request, course_key, discussion_id, thread_id):
response_skip=request.GET.get("resp_skip"), response_skip=request.GET.get("resp_skip"),
response_limit=request.GET.get("resp_limit") response_limit=request.GET.get("resp_limit")
) )
except cc.utils.CommentClientRequestError as e: except cc.utils.CommentClientRequestError as error:
if e.status_code == 404: if error.status_code == 404:
raise Http404 raise Http404
raise raise
...@@ -404,7 +386,7 @@ def single_thread(request, course_key, discussion_id, thread_id): ...@@ -404,7 +386,7 @@ def single_thread(request, course_key, discussion_id, thread_id):
'disable_courseware_js': True, 'disable_courseware_js': True,
'uses_pattern_library': True, 'uses_pattern_library': True,
} }
return render_to_response('discussion/index.html', context) return render_to_response('discussion/discussion_board.html', context)
@require_GET @require_GET
...@@ -465,7 +447,9 @@ def user_profile(request, course_key, user_id): ...@@ -465,7 +447,9 @@ def user_profile(request, course_key, user_id):
'annotated_content_info': json.dumps(annotated_content_info), 'annotated_content_info': json.dumps(annotated_content_info),
'page': query_params['page'], 'page': query_params['page'],
'num_pages': query_params['num_pages'], 'num_pages': query_params['num_pages'],
'learner_profile_page_url': reverse('learner_profile', kwargs={'username': django_user.username}) 'learner_profile_page_url': reverse('learner_profile', kwargs={'username': django_user.username}),
'disable_courseware_js': True,
'uses_pattern_library': True,
} }
return render_to_response('discussion/user_profile.html', context) return render_to_response('discussion/user_profile.html', context)
......
...@@ -6,6 +6,5 @@ from django.conf.urls import url, patterns, include ...@@ -6,6 +6,5 @@ from django.conf.urls import url, patterns, include
urlpatterns = patterns( urlpatterns = patterns(
'', '',
url(r'forum/?', include('django_comment_client.forum.urls')),
url(r'', include('django_comment_client.base.urls')), url(r'', include('django_comment_client.base.urls')),
) )
...@@ -591,10 +591,10 @@ def permalink(content): ...@@ -591,10 +591,10 @@ def permalink(content):
else: else:
course_id = content['course_id'] course_id = content['course_id']
if content['type'] == 'thread': if content['type'] == 'thread':
return reverse('django_comment_client.forum.views.single_thread', return reverse('discussion.views.single_thread',
args=[course_id, content['commentable_id'], content['id']]) args=[course_id, content['commentable_id'], content['id']])
else: else:
return reverse('django_comment_client.forum.views.single_thread', return reverse('discussion.views.single_thread',
args=[course_id, content['commentable_id'], content['thread_id']]) + '#' + content['id'] args=[course_id, content['commentable_id'], content['thread_id']]) + '#' + content['id']
......
...@@ -1941,8 +1941,10 @@ INSTALLED_APPS = ( ...@@ -1941,8 +1941,10 @@ INSTALLED_APPS = (
'django_comment_client', 'django_comment_client',
'django_comment_common', 'django_comment_common',
'discussion_api', 'discussion_api',
'notes', 'lms.djangoapps.discussion',
# Notes
'notes',
'edxnotes', 'edxnotes',
# Splash screen # Splash screen
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
* done. * done.
*/ */
modules: getModulesList([ modules: getModulesList([
'discussion/js/discussion_board_factory',
'js/api_admin/catalog_preview_factory', 'js/api_admin/catalog_preview_factory',
'js/courseware/courseware_factory', 'js/courseware/courseware_factory',
'js/discovery/discovery_factory', 'js/discovery/discovery_factory',
......
...@@ -27,6 +27,7 @@ $static-path: '../..' !default; ...@@ -27,6 +27,7 @@ $static-path: '../..' !default;
// Discussion styling // Discussion styling
@import 'mixins'; @import 'mixins';
@import 'discussion'; // Process old file after definitions but before everything else, partial is deprecated. @import 'discussion'; // Process old file after definitions but before everything else, partial is deprecated.
@import 'layouts';
@import 'elements/actions'; @import 'elements/actions';
@import 'elements/editor'; @import 'elements/editor';
@import 'elements/labels'; @import 'elements/labels';
......
...@@ -4,10 +4,6 @@ ...@@ -4,10 +4,6 @@
body.discussion { body.discussion {
.course-tabs .right {
@include float(right);
}
.edit-post-form { .edit-post-form {
@include clearfix(); @include clearfix();
box-sizing: border-box; box-sizing: border-box;
...@@ -65,39 +61,6 @@ body.discussion { ...@@ -65,39 +61,6 @@ body.discussion {
font-size: 21px; font-size: 21px;
} }
section.user-profile {
// TODO: don't use table-cell for layout purposes as it switches the screenreader mode
display: table-cell;
border-right: 1px solid #ddd;
border-radius: 3px 0 0 3px;
background-color: $sidebar-color;
box-shadow: none;
.user-profile {
padding: 32px 36px;
}
.sidebar-username {
font-weight: 700;
font-size: 18px;
}
.sidebar-user-roles {
margin-top: 6px;
font-style: italic;
font-size: 13px;
}
.sidebar-threads-count {
margin-top: 14px;
}
.sidebar-threads-count span,
.sidebar-comments-count span {
font-weight: 700;
}
}
.wmd-panel { .wmd-panel {
width: 100%; width: 100%;
} }
...@@ -227,16 +190,6 @@ body.discussion { ...@@ -227,16 +190,6 @@ body.discussion {
text-align: center; text-align: center;
} }
.discussion-column {
@include float(right);
box-sizing: border-box;
padding-left: ($baseline/2);
width: 68%;
max-width: 800px;
min-height: 500px;
border-radius: 3px;
}
.discussion-article { .discussion-article {
position: relative; position: relative;
min-height: 500px; min-height: 500px;
...@@ -406,108 +359,6 @@ body.discussion { ...@@ -406,108 +359,6 @@ body.discussion {
.threads { .threads {
} }
.discussion-thread {
padding: 0;
margin-bottom: $baseline;
@include transition(all .25s linear 0s);
p {
margin-bottom: 0;
}
.discussion-article {
@include transition(all .2s linear 0s);
border: 1px solid $forum-color-border;
border-radius: 3px;
min-height: 0;
background: $forum-color-background;
box-shadow: 0 1px 0 $shadow;
@include transition(all .2s linear 0s);
.thread-wrapper {
@include border-radius(3px, 3px, 0, 0);
position: relative;
overflow-x: hidden;
overflow-y: auto;
max-height: 600px;
background-color: $forum-color-background;
.discussion-post {
.inline-comment-count {
@extend %ui-depth2;
position: relative;
float: right;
display: block;
height: 27px;
margin-top: 6px;
margin-right: 8px;
padding: 0 8px;
border-radius: ($baseline/4);
font-size: 12px;
font-weight: 400;
line-height: 25px;
color: #888;
}
}
.responses {
header {
padding-bottom: 0;
margin-bottom: ($baseline*0.75);
.posted-by {
float: left;
margin-right: ($baseline/4);
font-size: 16px;
}
}
.response-body {
margin-bottom: 0.2em;
font-size: 14px;
}
}
.discussion-reply-new {
.wmd-input {
height: 120px;
}
}
// Content that is hidden by default in the inline view
.post-extended-content{
display: none;
}
}
.post-tools {
box-shadow: 0 1px 1px $shadow inset;
background: $gray-l6;
&:hover {
background: #fcfcfc;
.icon {
color: $link-hover;
}
}
a {
display: block;
padding: ($baseline*0.25) $baseline;
font-size: 12px;
line-height: 30px;
.icon {
color: $link-color;
margin-right: ($baseline*0.25);
}
}
}
}
}
} }
.new-post-article { .new-post-article {
...@@ -603,14 +454,6 @@ body.discussion { ...@@ -603,14 +454,6 @@ body.discussion {
} }
} }
.discussion-user-threads {
@extend .discussion-module;
.discussion-post {
padding-bottom: $baseline !important;
}
}
.xblock-student_view-discussion { .xblock-student_view-discussion {
@extend %ui-print-excluded; @extend %ui-print-excluded;
} }
......
// Layouts for discussion pages
section.user-profile {
background-color: $sidebar-color;
.user-profile {
padding: 32px 36px;
min-height: 500px;
}
.sidebar-username {
font-weight: 700;
font-size: 18px;
}
.sidebar-user-roles {
margin-top: 6px;
font-style: italic;
font-size: 13px;
}
.sidebar-threads-count {
margin-top: 14px;
}
.sidebar-threads-count span,
.sidebar-comments-count span {
font-weight: 700;
}
}
.discussion-column {
@include float(right);
box-sizing: border-box;
padding-left: ($baseline/2);
width: 68%;
max-width: 800px;
min-height: 500px;
border-radius: 3px;
}
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
} }
.container { .container {
@include clearfix();
border: 1px solid $lms-border-color; border: 1px solid $lms-border-color;
background-color: $lms-container-background-color; background-color: $lms-container-background-color;
padding: $baseline; padding: $baseline;
......
...@@ -726,6 +726,12 @@ if settings.FEATURES.get('ENABLE_DISCUSSION_SERVICE'): ...@@ -726,6 +726,12 @@ if settings.FEATURES.get('ENABLE_DISCUSSION_SERVICE'):
include('django_comment_client.urls') include('django_comment_client.urls')
), ),
url( url(
r'^courses/{}/discussion/forum/'.format(
settings.COURSE_ID_PATTERN,
),
include('discussion.urls')
),
url(
r'^notification_prefs/enable/', r'^notification_prefs/enable/',
'notification_prefs.views.ajax_enable' 'notification_prefs.views.ajax_enable'
), ),
......
...@@ -6,7 +6,7 @@ from setuptools import setup ...@@ -6,7 +6,7 @@ from setuptools import setup
setup( setup(
name="Open edX", name="Open edX",
version="0.5", version="0.6",
install_requires=["setuptools"], install_requires=["setuptools"],
requires=[], requires=[],
# NOTE: These are not the names we should be installing. This tree should # NOTE: These are not the names we should be installing. This tree should
...@@ -23,7 +23,7 @@ setup( ...@@ -23,7 +23,7 @@ setup(
"ccx = lms.djangoapps.ccx.plugins:CcxCourseTab", "ccx = lms.djangoapps.ccx.plugins:CcxCourseTab",
"courseware = lms.djangoapps.courseware.tabs:CoursewareTab", "courseware = lms.djangoapps.courseware.tabs:CoursewareTab",
"course_info = lms.djangoapps.courseware.tabs:CourseInfoTab", "course_info = lms.djangoapps.courseware.tabs:CourseInfoTab",
"discussion = lms.djangoapps.django_comment_client.forum.views:DiscussionTab", "discussion = lms.djangoapps.discussion.plugins:DiscussionTab",
"edxnotes = lms.djangoapps.edxnotes.plugins:EdxNotesTab", "edxnotes = lms.djangoapps.edxnotes.plugins:EdxNotesTab",
"external_discussion = lms.djangoapps.courseware.tabs:ExternalDiscussionCourseTab", "external_discussion = lms.djangoapps.courseware.tabs:ExternalDiscussionCourseTab",
"external_link = lms.djangoapps.courseware.tabs:ExternalLinkCourseTab", "external_link = lms.djangoapps.courseware.tabs:ExternalLinkCourseTab",
......
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