From 3d5dde8195c35af5bb50c794d2fc56e197e399bd Mon Sep 17 00:00:00 2001 From: Waqas Khalid Date: Thu, 17 Jul 2014 16:26:02 +0500 Subject: [PATCH] Fix inconsistent ui issues on discussion during blackout period FOR-108 --- .../lib/xmodule/xmodule/discussion_module.py | 7 ++++ .../xmodule/tests/test_xblock_wrappers.py | 4 ++ .../test/acceptance/pages/lms/discussion.py | 6 +++ .../test/acceptance/tests/test_discussion.py | 38 ++++++++++++++++++- .../discussion/_discussion_module.html | 5 ++- .../mustache/_inline_thread.mustache | 2 + 6 files changed, 59 insertions(+), 3 deletions(-) diff --git a/common/lib/xmodule/xmodule/discussion_module.py b/common/lib/xmodule/xmodule/discussion_module.py index ff42688d91..1bcdf20fb9 100644 --- a/common/lib/xmodule/xmodule/discussion_module.py +++ b/common/lib/xmodule/xmodule/discussion_module.py @@ -52,6 +52,7 @@ class DiscussionModule(DiscussionFields, XModule): def get_html(self): context = { 'discussion_id': self.discussion_id, + 'course': self.get_course(), } if getattr(self.system, 'is_author_mode', False): template = 'discussion/_discussion_module_studio.html' @@ -59,6 +60,12 @@ class DiscussionModule(DiscussionFields, XModule): template = 'discussion/_discussion_module.html' return self.system.render_template(template, context) + def get_course(self): + """ + Return course by course id. + """ + return self.descriptor.runtime.modulestore.get_course(self.course_id) + class DiscussionDescriptor(DiscussionFields, MetadataOnlyEditingDescriptor, RawDescriptor): diff --git a/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py b/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py index 62add6cca3..647a92f27c 100644 --- a/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py +++ b/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py @@ -286,6 +286,10 @@ class XBlockWrapperTestMixin(object): descriptor_cls, fields = cls_and_fields self.skip_if_invalid(descriptor_cls) descriptor = LeafModuleFactory(descriptor_cls=descriptor_cls, **fields) + mocked_course = Mock() + modulestore = Mock() + modulestore.get_course.return_value = mocked_course + descriptor.runtime.modulestore = modulestore self.check_property(descriptor) # Test that when an xmodule is generated from descriptor_cls diff --git a/common/test/acceptance/pages/lms/discussion.py b/common/test/acceptance/pages/lms/discussion.py index fd433fa699..7f01c4b85c 100644 --- a/common/test/acceptance/pages/lms/discussion.py +++ b/common/test/acceptance/pages/lms/discussion.py @@ -83,6 +83,10 @@ class DiscussionThreadPage(PageObject, DiscussionPageMixin): """Returns true if the response editor is present, false otherwise""" return self._is_element_visible(".response_{} .edit-post-body".format(response_id)) + def is_response_editable(self, response_id): + """Returns true if the edit response button is present, false otherwise""" + return self._is_element_visible(".response_{} .discussion-response .action-edit".format(response_id)) + def start_response_edit(self, response_id): """Click the edit button for the response, loading the editing view""" self._find_within(".response_{} .discussion-response .action-edit".format(response_id)).first.click() @@ -251,6 +255,8 @@ class InlineDiscussionPage(PageObject): def get_num_displayed_threads(self): return len(self._find_within(".discussion-thread")) + def element_exists(self, selector): + return self.q(css=self._discussion_selector + " " + selector).present class InlineDiscussionThreadPage(DiscussionThreadPage): def __init__(self, browser, thread_id): diff --git a/common/test/acceptance/tests/test_discussion.py b/common/test/acceptance/tests/test_discussion.py index ff37d417f3..9391ac3df6 100644 --- a/common/test/acceptance/tests/test_discussion.py +++ b/common/test/acceptance/tests/test_discussion.py @@ -2,6 +2,8 @@ Tests for discussion pages """ +import datetime +from pytz import UTC from uuid import uuid4 from nose.plugins.attrib import attr @@ -286,7 +288,7 @@ class InlineDiscussionTest(UniqueCourseTest, DiscussionResponsePaginationTestMix def setUp(self): super(InlineDiscussionTest, self).setUp() self.discussion_id = "test_discussion_{}".format(uuid4().hex) - CourseFixture(**self.course_info).add_children( + self.course_fix = CourseFixture(**self.course_info).add_children( XBlockFixtureDesc("chapter", "Test Section").add_children( XBlockFixtureDesc("sequential", "Test Subsection").add_children( XBlockFixtureDesc("vertical", "Test Unit").add_children( @@ -300,7 +302,7 @@ class InlineDiscussionTest(UniqueCourseTest, DiscussionResponsePaginationTestMix ) ).install() - AutoAuthPage(self.browser, course_id=self.course_id).visit() + self.user_id = AutoAuthPage(self.browser, course_id=self.course_id).visit().get_user_id() self.courseware_page = CoursewarePage(self.browser, self.course_id) self.courseware_page.visit() @@ -334,6 +336,38 @@ class InlineDiscussionTest(UniqueCourseTest, DiscussionResponsePaginationTestMix def test_anonymous_to_peers_threads_as_peer(self): self.check_anonymous_to_peers(False) + def test_discussion_blackout_period(self): + now = datetime.datetime.now(UTC) + self.course_fix.add_advanced_settings( + { + u"discussion_blackouts": { + "value": [ + [ + (now - datetime.timedelta(days=14)).isoformat(), + (now + datetime.timedelta(days=2)).isoformat() + ] + ] + } + } + ) + self.course_fix._add_advanced_settings() + self.browser.refresh() + thread = Thread(id=uuid4().hex, commentable_id=self.discussion_id) + thread_fixture = SingleThreadViewFixture(thread) + thread_fixture.addResponse( + Response(id="response1"), + [Comment(id="comment1", user_id="other"), Comment(id="comment2", user_id=self.user_id)]) + thread_fixture.push() + self.setup_thread_page(thread.get("id")) + self.assertFalse(self.discussion_page.element_exists(".new-post-btn")) + self.assertFalse(self.thread_page.has_add_response_button()) + self.assertFalse(self.thread_page.is_response_editable("response1")) + self.assertFalse(self.thread_page.is_add_comment_visible("response1")) + self.assertFalse(self.thread_page.is_comment_editable("comment1")) + self.assertFalse(self.thread_page.is_comment_editable("comment2")) + self.assertFalse(self.thread_page.is_comment_deletable("comment1")) + self.assertFalse(self.thread_page.is_comment_deletable("comment2")) + @attr('shard_1') class DiscussionUserProfileTest(UniqueCourseTest): diff --git a/lms/templates/discussion/_discussion_module.html b/lms/templates/discussion/_discussion_module.html index d84ecb7b85..26e6df6f5c 100644 --- a/lms/templates/discussion/_discussion_module.html +++ b/lms/templates/discussion/_discussion_module.html @@ -1,7 +1,10 @@ <%! from django.utils.translation import ugettext as _ %> +<%! from django_comment_client.permissions import has_permission %> <%include file="_underscore_templates.html" />
${_("Show Discussion")} - ${_("New Post")} + % if has_permission(user, 'create_thread', course.id): + ${_("New Post")} + % endif
diff --git a/lms/templates/discussion/mustache/_inline_thread.mustache b/lms/templates/discussion/mustache/_inline_thread.mustache index 8345b0cfec..eda47700e2 100644 --- a/lms/templates/discussion/mustache/_inline_thread.mustache +++ b/lms/templates/discussion/mustache/_inline_thread.mustache @@ -13,6 +13,7 @@
    + {{#ability.can_reply}}

    ${_("Post a response:")}

      @@ -21,6 +22,7 @@ ${_("Submit")}
      + {{/ability.can_reply}}