Merge pull request #5276 from edx/anton/forums-topic
Change the topic of a previously posted post.
This commit is contained in:
@@ -15,7 +15,7 @@ from django_comment_client.base import views
|
||||
from django_comment_client.tests.group_id import CohortedTopicGroupIdTestMixin, NonCohortedTopicGroupIdTestMixin, GroupIdAssertionMixin
|
||||
from django_comment_client.tests.utils import CohortedContentTestCase
|
||||
from django_comment_client.tests.unicode import UnicodeTestMixin
|
||||
from django_comment_common.models import Role, FORUM_ROLE_STUDENT
|
||||
from django_comment_common.models import Role
|
||||
from django_comment_common.utils import seed_permissions_roles
|
||||
from student.tests.factories import CourseEnrollmentFactory, UserFactory
|
||||
from util.testing import UrlResetMixin
|
||||
@@ -160,7 +160,6 @@ class ThreadActionGroupIdTestCase(
|
||||
)
|
||||
|
||||
|
||||
|
||||
@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE)
|
||||
@patch('lms.lib.comment_client.utils.requests.request')
|
||||
class ViewsTestCase(UrlResetMixin, ModuleStoreTestCase, MockRequestSetupMixin):
|
||||
@@ -369,6 +368,15 @@ class ViewsTestCase(UrlResetMixin, ModuleStoreTestCase, MockRequestSetupMixin):
|
||||
mock_request
|
||||
)
|
||||
|
||||
@patch('django_comment_client.base.views.get_discussion_id_map', return_value={"test_commentable": {}})
|
||||
def test_update_thread_wrong_commentable_id(self, mock_get_discussion_id_map, mock_request):
|
||||
self._test_request_error(
|
||||
"update_thread",
|
||||
{"thread_id": "dummy", "course_id": self.course_id.to_deprecated_string()},
|
||||
{"body": "foo", "title": "foo", "commentable_id": "wrong_commentable"},
|
||||
mock_request
|
||||
)
|
||||
|
||||
def test_create_comment_no_body(self, mock_request):
|
||||
self._test_request_error(
|
||||
"create_comment",
|
||||
@@ -460,7 +468,7 @@ class ViewsTestCase(UrlResetMixin, ModuleStoreTestCase, MockRequestSetupMixin):
|
||||
"at_position_list": [],
|
||||
"closed": is_closed,
|
||||
"id": "518d4237b023791dca00000d",
|
||||
"user_id": "1","username": "robot",
|
||||
"user_id": "1", "username": "robot",
|
||||
"votes": {
|
||||
"count": 0,
|
||||
"up_count": 0,
|
||||
@@ -853,13 +861,14 @@ class UpdateThreadUnicodeTestCase(ModuleStoreTestCase, UnicodeTestMixin, MockReq
|
||||
self.student = UserFactory.create()
|
||||
CourseEnrollmentFactory(user=self.student, course_id=self.course.id)
|
||||
|
||||
@patch('django_comment_client.base.views.get_discussion_id_map', return_value={"test_commentable": {}})
|
||||
@patch('lms.lib.comment_client.utils.requests.request')
|
||||
def _test_unicode_data(self, text, mock_request):
|
||||
def _test_unicode_data(self, text, mock_request, mock_get_discussion_id_map):
|
||||
self._set_mock_request_data(mock_request, {
|
||||
"user_id": str(self.student.id),
|
||||
"closed": False,
|
||||
})
|
||||
request = RequestFactory().post("dummy_url", {"body": text, "title": text})
|
||||
request = RequestFactory().post("dummy_url", {"body": text, "title": text, "commentable_id": "test_commentable"})
|
||||
request.user = self.student
|
||||
request.view_name = "update_thread"
|
||||
response = views.update_thread(request, course_id=self.course.id.to_deprecated_string(), thread_id="dummy_thread_id")
|
||||
@@ -868,6 +877,7 @@ class UpdateThreadUnicodeTestCase(ModuleStoreTestCase, UnicodeTestMixin, MockReq
|
||||
self.assertTrue(mock_request.called)
|
||||
self.assertEqual(mock_request.call_args[1]["data"]["body"], text)
|
||||
self.assertEqual(mock_request.call_args[1]["data"]["title"], text)
|
||||
self.assertEqual(mock_request.call_args[1]["data"]["commentable_id"], "test_commentable")
|
||||
|
||||
|
||||
@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE)
|
||||
|
||||
@@ -18,8 +18,6 @@ from opaque_keys.edx.locations import SlashSeparatedCourseKey
|
||||
|
||||
from courseware.access import has_access
|
||||
from courseware.courses import get_course_with_access, get_course_by_id
|
||||
from course_groups.models import CourseUserGroup
|
||||
from course_groups.cohorts import get_cohort_by_id, get_cohort_id, is_commentable_cohorted
|
||||
import django_comment_client.settings as cc_settings
|
||||
from django_comment_client.utils import (
|
||||
add_courseware_context,
|
||||
@@ -28,7 +26,8 @@ from django_comment_client.utils import (
|
||||
JsonError,
|
||||
JsonResponse,
|
||||
prepare_content,
|
||||
get_group_id_for_comments_service
|
||||
get_group_id_for_comments_service,
|
||||
get_discussion_id_map,
|
||||
)
|
||||
from django_comment_client.permissions import check_permissions_by_view, cached_has_permission
|
||||
import lms.lib.comment_client as cc
|
||||
@@ -139,12 +138,21 @@ def update_thread(request, course_id, thread_id):
|
||||
return JsonError(_("Title can't be empty"))
|
||||
if 'body' not in request.POST or not request.POST['body'].strip():
|
||||
return JsonError(_("Body can't be empty"))
|
||||
|
||||
course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
|
||||
thread = cc.Thread.find(thread_id)
|
||||
thread.body = request.POST["body"]
|
||||
thread.title = request.POST["title"]
|
||||
thread.save()
|
||||
|
||||
if "commentable_id" in request.POST:
|
||||
course = get_course_with_access(request.user, 'load', course_key)
|
||||
id_map = get_discussion_id_map(course)
|
||||
if request.POST.get("commentable_id") in id_map:
|
||||
thread.commentable_id = request.POST["commentable_id"]
|
||||
else:
|
||||
return JsonError(_("Topic doesn't exist"))
|
||||
|
||||
thread.save()
|
||||
if request.is_ajax():
|
||||
return ajax_content_response(request, course_key, thread.to_dict())
|
||||
else:
|
||||
@@ -614,6 +622,7 @@ def upload(request, course_id): # ajax upload file to a question or answer
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@require_GET
|
||||
@login_required
|
||||
def users(request, course_id):
|
||||
@@ -640,7 +649,7 @@ def users(request, course_id):
|
||||
try:
|
||||
matched_user = User.objects.get(username=username)
|
||||
cc_user = cc.User.from_django_user(matched_user)
|
||||
cc_user.course_id=course_key
|
||||
cc_user.course_id = course_key
|
||||
cc_user.retrieve(complete=False)
|
||||
if (cc_user['threads_count'] + cc_user['comments_count']) > 0:
|
||||
user_objs.append({
|
||||
|
||||
@@ -71,7 +71,7 @@ def _get_discussion_modules(course):
|
||||
return filter(has_required_keys, all_modules)
|
||||
|
||||
|
||||
def _get_discussion_id_map(course):
|
||||
def get_discussion_id_map(course):
|
||||
def get_entry(module):
|
||||
discussion_id = module.discussion_id
|
||||
title = module.discussion_target
|
||||
@@ -352,7 +352,7 @@ def extend_content(content):
|
||||
|
||||
|
||||
def add_courseware_context(content_list, course):
|
||||
id_map = _get_discussion_id_map(course)
|
||||
id_map = get_discussion_id_map(course)
|
||||
|
||||
for content in content_list:
|
||||
commentable_id = content['commentable_id']
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
@import "discussion/elements/labels";
|
||||
@import "discussion/elements/navigation";
|
||||
@import "discussion/views/thread";
|
||||
@import "discussion/views/new-post";
|
||||
@import "discussion/views/create-edit-post";
|
||||
@import "discussion/views/response";
|
||||
@import 'discussion/utilities/developer';
|
||||
@import 'discussion/utilities/shame';
|
||||
|
||||
@@ -107,7 +107,8 @@ li[class*=forum-nav-thread-label-] {
|
||||
// new post form
|
||||
// -------------
|
||||
|
||||
.forum-new-post-form {
|
||||
.forum-new-post-form,
|
||||
.edit-post-form {
|
||||
// Override global label rules
|
||||
.post-type {
|
||||
text-shadow: none;
|
||||
@@ -127,7 +128,7 @@ li[class*=forum-nav-thread-label-] {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
// Override global span rules
|
||||
// Override global span rules
|
||||
.post-topic-button .drop-arrow {
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
// ====================
|
||||
|
||||
// UI: form structure
|
||||
.forum-new-post-form {
|
||||
.forum-new-post-form,
|
||||
.edit-post-form {
|
||||
@include clearfix;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
@@ -64,7 +65,8 @@
|
||||
// ====================
|
||||
|
||||
// UI: inputs
|
||||
.forum-new-post-form {
|
||||
.forum-new-post-form,
|
||||
.edit-post-form {
|
||||
.post-topic-button {
|
||||
@include white-button;
|
||||
@extend %cont-truncated;
|
||||
@@ -172,7 +174,8 @@
|
||||
// ====================
|
||||
|
||||
// UI: errors - new post creation
|
||||
.forum-new-post-form {
|
||||
.forum-new-post-form,
|
||||
.edit-post-form {
|
||||
.post-errors {
|
||||
margin-bottom: $baseline;
|
||||
border-radius: 3px;
|
||||
@@ -199,7 +202,8 @@
|
||||
// UI: topic menu
|
||||
|
||||
// TO-DO: refactor to use _navigation.scss as general topic selector
|
||||
.forum-new-post-form .post-topic {
|
||||
.forum-new-post-form .post-topic ,
|
||||
.edit-post-form .post-topic {
|
||||
position: relative;
|
||||
|
||||
.topic-menu-wrapper {
|
||||
@@ -54,9 +54,9 @@
|
||||
% endfor
|
||||
|
||||
<script aria-hidden="true" type="text/template" id="thread-edit-template">
|
||||
<div class="discussion-post edit-post-form">
|
||||
<h1>${_("Editing post")}</h1>
|
||||
<ul class="edit-post-form-errors"></ul>
|
||||
<ul class="post-errors"></ul>
|
||||
<div class="forum-edit-post-form-wrapper"></div>
|
||||
<div class="form-row">
|
||||
<label class="sr" for="edit-post-title">${_("Edit post title")}</label>
|
||||
<input type="text" id="edit-post-title" class="edit-post-title" name="title" value="${"<%-title %>"}" placeholder="${_('Title') | h}">
|
||||
@@ -66,7 +66,6 @@
|
||||
</div>
|
||||
<input type="submit" id="edit-post-submit" class="post-update" value="${_("Update post") | h}">
|
||||
<a href="#" class="post-cancel">${_("Cancel")}</a>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script aria-hidden="true" type="text/template" id="thread-response-template">
|
||||
@@ -408,31 +407,7 @@
|
||||
${_("Questions raise issues that need answers. Discussions share ideas and start conversations.")}
|
||||
</span>
|
||||
</div>
|
||||
${'<% if (mode=="tab") { %>'}
|
||||
<div class="post-field">
|
||||
## Using div here instead of label because we are using a non-native control
|
||||
<div class="field-label">
|
||||
<span class="field-label-text">
|
||||
${_("Topic Area:")}
|
||||
</span><div class="field-input post-topic">
|
||||
<a href="#" class="post-topic-button">
|
||||
<span class="sr">${_("Discussion topics; current selection is: ")}</span>
|
||||
<span class="js-selected-topic"></span>
|
||||
<span class="drop-arrow" aria-hidden="true">▾</span>
|
||||
</a>
|
||||
<div class="topic-menu-wrapper">
|
||||
<label class="topic-filter-label">
|
||||
<span class="sr">${_("Filter topics")}</span>
|
||||
<input type="text" class="topic-filter-input" placeholder="${_('Filter topics')}">
|
||||
</label>
|
||||
<ul class="topic-menu" role="menu">${'<%= topics_html %>'}</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div><span class="field-help">
|
||||
${_("Add your post to a relevant topic to help others find it.")}
|
||||
</span>
|
||||
</div>
|
||||
${'<% } %>'}
|
||||
<div class="forum-new-post-form-wrapper"></div>
|
||||
${'<% if (cohort_options) { %>'}
|
||||
<div class="post-field">
|
||||
<label class="field-label">
|
||||
@@ -497,6 +472,28 @@
|
||||
</li>
|
||||
</script>
|
||||
|
||||
<script aria-hidden="true" type="text/template" id="topic-template">
|
||||
## Using div here instead of label because we are using a non-native control
|
||||
<div class="field-label">
|
||||
<span class="field-label-text">${_("Topic Area:")}</span><div class="field-input post-topic">
|
||||
<a href="#" class="post-topic-button">
|
||||
<span class="sr">${_("Discussion topics; current selection is: ")}</span>
|
||||
<span class="js-selected-topic"></span>
|
||||
<span class="drop-arrow" aria-hidden="true">▾</span>
|
||||
</a>
|
||||
<div class="topic-menu-wrapper">
|
||||
<label class="topic-filter-label">
|
||||
<span class="sr">${_("Filter topics")}</span>
|
||||
<input type="text" class="topic-filter-input" placeholder="${_('Filter topics')}">
|
||||
</label>
|
||||
<ul class="topic-menu" role="menu">${'<%= topics_html %>'}</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div><span class="field-help">
|
||||
${_("Add your post to a relevant topic to help others find it.")}
|
||||
</span>
|
||||
</script>
|
||||
|
||||
<%def name="primaryAction(action_class, icon, sr_label, unchecked_label, checked_label)">
|
||||
<script type="text/template" id="forum-action-${action_class}">
|
||||
<li class="actions-item">
|
||||
|
||||
Reference in New Issue
Block a user