def test_tree_with_duplicate_targets(self): self.create_discussion("Chapter 1", "Discussion A") self.create_discussion("Chapter 1", "Discussion B") self.create_discussion("Chapter 1", "Discussion A") # duplicate self.create_discussion("Chapter 1", "Discussion A") # another duplicate self.create_discussion("Chapter 2 / Section 1 / Subsection 1", "Discussion") self.create_discussion("Chapter 2 / Section 1 / Subsection 1", "Discussion") # duplicate category_map = utils.get_discussion_category_map( self.course, self.user) chapter1 = category_map["subcategories"]["Chapter 1"] chapter1_discussions = set([ "Discussion A", "Discussion B", "Discussion A (1)", "Discussion A (2)" ]) self.assertEqual(set(chapter1["children"]), chapter1_discussions) self.assertEqual(set(chapter1["entries"].keys()), chapter1_discussions) chapter2 = category_map["subcategories"]["Chapter 2"] subsection1 = chapter2["subcategories"]["Section 1"]["subcategories"][ "Subsection 1"] subsection1_discussions = set(["Discussion", "Discussion (1)"]) self.assertEqual(set(subsection1["children"]), subsection1_discussions) self.assertEqual(set(subsection1["entries"].keys()), subsection1_discussions)
def assert_category_map_equals(self, expected, cohorted_if_in_list=False, exclude_unstarted=True): # pylint: disable=arguments-differ """ Asserts the expected map with the map returned by get_discussion_category_map method. """ self.assertEqual( utils.get_discussion_category_map(self.course, self.instructor, cohorted_if_in_list, exclude_unstarted), expected )
def assert_category_map_equals(self, expected, requesting_user=None): """ Call `get_discussion_category_map`, and verify that it returns what is expected. """ self.assertEqual( utils.get_discussion_category_map(self.course, requesting_user or self.user), expected)
def assert_category_map_equals(self, expected, cohorted_if_in_list=False, exclude_unstarted=True): # pylint: disable=arguments-differ """ Asserts the expected map with the map returned by get_discussion_category_map method. """ self.assertEqual( utils.get_discussion_category_map(self.course, self.instructor, cohorted_if_in_list, exclude_unstarted), expected )
def assert_category_map_equals(self, expected, requesting_user=None): """ Call `get_discussion_category_map`, and verify that it returns what is expected. """ self.assertEqual( utils.get_discussion_category_map(self.course, requesting_user or self.user), expected )
def make_course_settings(course, user): """ Generate a JSON-serializable model for course settings, which will be used to initialize a DiscussionCourseSettings object on the client. """ return { 'is_cohorted': is_course_cohorted(course.id), 'allow_anonymous': course.allow_anonymous, 'allow_anonymous_to_peers': course.allow_anonymous_to_peers, 'cohorts': [{"id": str(g.id), "name": g.name} for g in get_course_cohorts(course)], 'category_map': utils.get_discussion_category_map(course, user) }
def make_course_settings(course, user): """ Generate a JSON-serializable model for course settings, which will be used to initialize a DiscussionCourseSettings object on the client. """ return { 'is_cohorted': is_course_cohorted(course.id), 'allow_anonymous': course.allow_anonymous, 'allow_anonymous_to_peers': course.allow_anonymous_to_peers, 'cohorts': [{"id": str(g.id), "name": g.name} for g in get_course_cohorts(course)], 'category_map': utils.get_discussion_category_map(course, user) }
def mobi_forum_course_discussion(request, course_id): """ mobile api get all discussions about the course """ course_id = course_id.replace('.', '/') nr_transaction = newrelic.agent.current_transaction() course = get_course_with_access(request.user, course_id, 'load_forum') with newrelic.agent.FunctionTrace(nr_transaction, "get_discussion_category_map"): category_map = utils.get_discussion_category_map(course) try: unsafethreads, query_params = get_threads(request, course_id) # This might process a search query threads = [utils.safe_content(thread) for thread in unsafethreads] except cc.utils.CommentClientMaintenanceError: return JsonResponse({'success': False, 'errmsg': 'errors occur!'}) user = cc.User.from_django_user(request.user) user_info = user.to_dict() with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"): add_courseware_context(threads, course) page = request.GET.get('page') or 0 num_pages = query_params['num_pages'] threads_list = [] if int(page) <= num_pages: for th in threads: def format_thread_info(thread_id): thread = cc.Thread.find(thread_id).to_dict() if thread: return { "id": thread['id'], "course_id": thread['course_id'].replace('/', '.'), "time": dateutil.parser.parse(thread['created_at']).strftime("%Y-%m-%d %H:%M:%S"), "name": thread['title'], "number": len(thread['children']) } else: raise Exception try: threads_list.append(format_thread_info(th['id'])) except: continue return JsonResponse({'course_threads': threads_list, "success": True, 'page': page, 'num_pages': num_pages})
def mobi_disscussion_search(request, course_id): nr_transaction = newrelic.agent.current_transaction() course_id = course_id.replace('.', '/') try: course = get_course_with_access(request.user, course_id, 'load_forum') except: return JsonResponse({"success": False, "errmsg": "can not find a course with " + course_id.replace('/', '.') + " id"}) with newrelic.agent.FunctionTrace(nr_transaction, "get_discussion_category_map"): category_map = utils.get_discussion_category_map(course) try: unsafethreads, query_params = get_threads(request, course_id) # This might process a search query threads = [utils.safe_content(thread) for thread in unsafethreads] except cc.utils.CommentClientMaintenanceError: log.warning("Forum is in maintenance mode") # return render_to_response('discussion/maintenance.html', {}) return JsonResponse({"success": False, "errmsg": "Forum is in maintenance mode"}) user = cc.User.from_django_user(request.user) user_info = user.to_dict() with newrelic.agent.FunctionTrace(nr_transaction, "get_metadata_for_threads"): annotated_content_info = utils.get_metadata_for_threads(course_id, threads, request.user, user_info) with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"): add_courseware_context(threads, course) search_list = [] page = request.GET.get('page') or 0 num_pages = query_params['num_pages'] if int(page) <= num_pages: for thread in threads: thread = cc.Thread.find(thread['id']).to_dict() thread_info = {} if thread: thread_info['id'] = thread['id'] thread_info['course_id'] = thread['course_id'].replace('/', '.') thread_info['name'] = thread['title'] thread_info['time'] = dateutil.parser.parse(thread['created_at']).strftime("%Y-%m-%d %H:%M:%S") thread_info['number'] = len(thread['children']) search_list.append(thread_info) else: continue else: page = 0 return JsonResponse({'count': len(search_list), 'search_results': search_list, 'success': True, 'page': page, 'num_pages': num_pages})
def make_course_settings(course, user): """ Generate a JSON-serializable model for course settings, which will be used to initialize a DiscussionCourseSettings object on the client. """ course_discussion_settings = get_course_discussion_settings(course.id) group_names_by_id = get_group_names_by_id(course_discussion_settings) return { 'is_discussion_division_enabled': course_discussion_division_enabled(course_discussion_settings), 'allow_anonymous': course.allow_anonymous, 'allow_anonymous_to_peers': course.allow_anonymous_to_peers, 'groups': [ {"id": str(group_id), "name": group_name} for group_id, group_name in group_names_by_id.iteritems() ], 'category_map': utils.get_discussion_category_map(course, user) }
def make_course_settings(course, user): """ Generate a JSON-serializable model for course settings, which will be used to initialize a DiscussionCourseSettings object on the client. """ course_discussion_settings = get_course_discussion_settings(course.id) group_names_by_id = get_group_names_by_id(course_discussion_settings) return { 'is_discussion_division_enabled': course_discussion_division_enabled(course_discussion_settings), 'allow_anonymous': course.allow_anonymous, 'allow_anonymous_to_peers': course.allow_anonymous_to_peers, 'groups': [ {"id": str(group_id), "name": group_name} for group_id, group_name in group_names_by_id.iteritems() ], 'category_map': utils.get_discussion_category_map(course, user) }
def test_tree_with_duplicate_targets(self): self.create_discussion("Chapter 1", "Discussion A") self.create_discussion("Chapter 1", "Discussion B") self.create_discussion("Chapter 1", "Discussion A") # duplicate self.create_discussion("Chapter 1", "Discussion A") # another duplicate self.create_discussion("Chapter 2 / Section 1 / Subsection 1", "Discussion") self.create_discussion("Chapter 2 / Section 1 / Subsection 1", "Discussion") # duplicate category_map = utils.get_discussion_category_map(self.course, self.user) chapter1 = category_map["subcategories"]["Chapter 1"] chapter1_discussions = set(["Discussion A", "Discussion B", "Discussion A (1)", "Discussion A (2)"]) self.assertEqual(set(chapter1["children"]), chapter1_discussions) self.assertEqual(set(chapter1["entries"].keys()), chapter1_discussions) chapter2 = category_map["subcategories"]["Chapter 2"] subsection1 = chapter2["subcategories"]["Section 1"]["subcategories"]["Subsection 1"] subsection1_discussions = set(["Discussion", "Discussion (1)"]) self.assertEqual(set(subsection1["children"]), subsection1_discussions) self.assertEqual(set(subsection1["entries"].keys()), subsection1_discussions)
def single_thread(request, course_id, discussion_id, thread_id): nr_transaction = newrelic.agent.current_transaction() course = get_course_with_access(request.user, course_id, 'load_forum') cc_user = cc.User.from_django_user(request.user) user_info = cc_user.to_dict() # Currently, the front end always loads responses via AJAX, even for this # page; it would be a nice optimization to avoid that extra round trip to # the comments service. try: thread = cc.Thread.find(thread_id).retrieve( recursive=request.is_ajax(), user_id=request.user.id, response_skip=request.GET.get("resp_skip"), response_limit=request.GET.get("resp_limit")) except cc.utils.CommentClientRequestError as e: if e.status_code == 404: raise Http404 raise if request.is_ajax(): with newrelic.agent.FunctionTrace(nr_transaction, "get_annotated_content_infos"): annotated_content_info = utils.get_annotated_content_infos( course_id, thread, request.user, user_info=user_info) content = utils.safe_content(thread.to_dict()) with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"): add_courseware_context([content], course) return utils.JsonResponse({ 'content': content, 'annotated_content_info': annotated_content_info, }) else: with newrelic.agent.FunctionTrace(nr_transaction, "get_discussion_category_map"): category_map = utils.get_discussion_category_map(course) threads, query_params = get_threads(request, course_id) threads.append(thread.to_dict()) course = get_course_with_access(request.user, course_id, 'load_forum') with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"): add_courseware_context(threads, course) for thread in threads: if thread.get('group_id') and not thread.get('group_name'): thread['group_name'] = get_cohort_by_id( course_id, thread.get('group_id')).name #patch for backward compatibility with comments service if not "pinned" in thread: thread["pinned"] = False threads = [utils.safe_content(thread) for thread in threads] with newrelic.agent.FunctionTrace(nr_transaction, "get_metadata_for_threads"): annotated_content_info = utils.get_metadata_for_threads( course_id, threads, request.user, user_info) with newrelic.agent.FunctionTrace(nr_transaction, "get_cohort_info"): cohorts = get_course_cohorts(course_id) cohorted_commentables = get_cohorted_commentables(course_id) user_cohort = get_cohort_id(request.user, course_id) context = { 'discussion_id': discussion_id, 'csrf': csrf(request)['csrf_token'], 'init': '', # TODO: What is this? 'user_info': saxutils.escape(json.dumps(user_info), escapedict), 'annotated_content_info': saxutils.escape(json.dumps(annotated_content_info), escapedict), 'course': course, #'recent_active_threads': recent_active_threads, 'course_id': course.id, # TODO: Why pass both course and course.id to template? 'thread_id': thread_id, 'threads': saxutils.escape(json.dumps(threads), escapedict), 'category_map': category_map, 'roles': saxutils.escape(json.dumps(utils.get_role_ids(course_id)), escapedict), 'thread_pages': query_params['num_pages'], 'is_course_cohorted': is_course_cohorted(course_id), 'is_moderator': cached_has_permission(request.user, "see_all_cohorts", course_id), 'flag_moderator': cached_has_permission(request.user, 'openclose_thread', course.id) or has_access(request.user, course, 'staff'), 'cohorts': cohorts, 'user_cohort': get_cohort_id(request.user, course_id), 'cohorted_commentables': cohorted_commentables } return render_to_response('discussion/index.html', context)
def forum_form_discussion(request, course_id): """ Renders the main Discussion page, potentially filtered by a search query """ nr_transaction = newrelic.agent.current_transaction() course = get_course_with_access(request.user, course_id, 'load_forum') with newrelic.agent.FunctionTrace(nr_transaction, "get_discussion_category_map"): category_map = utils.get_discussion_category_map(course) try: unsafethreads, query_params = get_threads( request, course_id) # This might process a search query threads = [utils.safe_content(thread) for thread in unsafethreads] except cc.utils.CommentClientMaintenanceError: log.warning("Forum is in maintenance mode") return render_to_response('discussion/maintenance.html', {}) user = cc.User.from_django_user(request.user) user_info = user.to_dict() with newrelic.agent.FunctionTrace(nr_transaction, "get_metadata_for_threads"): annotated_content_info = utils.get_metadata_for_threads( course_id, threads, request.user, user_info) with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"): add_courseware_context(threads, course) if request.is_ajax(): return utils.JsonResponse({ 'discussion_data': threads, # TODO: Standardize on 'discussion_data' vs 'threads' 'annotated_content_info': annotated_content_info, 'num_pages': query_params['num_pages'], 'page': query_params['page'], }) else: with newrelic.agent.FunctionTrace(nr_transaction, "get_cohort_info"): cohorts = get_course_cohorts(course_id) cohorted_commentables = get_cohorted_commentables(course_id) user_cohort_id = get_cohort_id(request.user, course_id) context = { 'csrf': csrf(request)['csrf_token'], 'course': course, #'recent_active_threads': recent_active_threads, 'staff_access': has_access(request.user, course, 'staff'), 'threads': saxutils.escape(json.dumps(threads), escapedict), 'thread_pages': query_params['num_pages'], 'user_info': saxutils.escape(json.dumps(user_info), escapedict), 'flag_moderator': cached_has_permission(request.user, 'openclose_thread', course.id) or has_access(request.user, course, 'staff'), 'annotated_content_info': saxutils.escape(json.dumps(annotated_content_info), escapedict), 'course_id': course.id, 'category_map': category_map, 'roles': saxutils.escape(json.dumps(utils.get_role_ids(course_id)), escapedict), 'is_moderator': cached_has_permission(request.user, "see_all_cohorts", course_id), 'cohorts': cohorts, 'user_cohort': user_cohort_id, 'cohorted_commentables': cohorted_commentables, 'is_course_cohorted': is_course_cohorted(course_id) } # print "start rendering.." return render_to_response('discussion/index.html', context)
def mobi_forum_course_discussion(request, course_id): """ mobile api get all discussions about the course """ course_id = course_id.replace('.', '/') nr_transaction = newrelic.agent.current_transaction() course = get_course_with_access(request.user, course_id, 'load_forum') with newrelic.agent.FunctionTrace(nr_transaction, "get_discussion_category_map"): category_map = utils.get_discussion_category_map(course) try: unsafethreads, query_params = get_threads( request, course_id) # This might process a search query threads = [utils.safe_content(thread) for thread in unsafethreads] except cc.utils.CommentClientMaintenanceError: return JsonResponse({'success': False, 'errmsg': 'errors occur!'}) user = cc.User.from_django_user(request.user) user_info = user.to_dict() with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"): add_courseware_context(threads, course) page = request.GET.get('page') or 0 num_pages = query_params['num_pages'] threads_list = [] if int(page) <= num_pages: for th in threads: def format_thread_info(thread_id): thread = cc.Thread.find(thread_id).to_dict() if thread: return { "id": thread['id'], "course_id": thread['course_id'].replace('/', '.'), "time": dateutil.parser.parse(thread['created_at']).strftime( "%Y-%m-%d %H:%M:%S"), "name": thread['title'], "number": len(thread['children']) } else: raise Exception try: threads_list.append(format_thread_info(th['id'])) except: continue return JsonResponse({ 'course_threads': threads_list, "success": True, 'page': page, 'num_pages': num_pages })
def mobi_disscussion_search(request, course_id): nr_transaction = newrelic.agent.current_transaction() course_id = course_id.replace('.', '/') try: course = get_course_with_access(request.user, course_id, 'load_forum') except: return JsonResponse({ "success": False, "errmsg": "can not find a course with " + course_id.replace('/', '.') + " id" }) with newrelic.agent.FunctionTrace(nr_transaction, "get_discussion_category_map"): category_map = utils.get_discussion_category_map(course) try: unsafethreads, query_params = get_threads( request, course_id) # This might process a search query threads = [utils.safe_content(thread) for thread in unsafethreads] except cc.utils.CommentClientMaintenanceError: log.warning("Forum is in maintenance mode") # return render_to_response('discussion/maintenance.html', {}) return JsonResponse({ "success": False, "errmsg": "Forum is in maintenance mode" }) user = cc.User.from_django_user(request.user) user_info = user.to_dict() with newrelic.agent.FunctionTrace(nr_transaction, "get_metadata_for_threads"): annotated_content_info = utils.get_metadata_for_threads( course_id, threads, request.user, user_info) with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"): add_courseware_context(threads, course) search_list = [] page = request.GET.get('page') or 0 num_pages = query_params['num_pages'] if int(page) <= num_pages: for thread in threads: thread = cc.Thread.find(thread['id']).to_dict() thread_info = {} if thread: thread_info['id'] = thread['id'] thread_info['course_id'] = thread['course_id'].replace( '/', '.') thread_info['name'] = thread['title'] thread_info['time'] = dateutil.parser.parse( thread['created_at']).strftime("%Y-%m-%d %H:%M:%S") thread_info['number'] = len(thread['children']) search_list.append(thread_info) else: continue else: page = 0 return JsonResponse({ 'count': len(search_list), 'search_results': search_list, 'success': True, 'page': page, 'num_pages': num_pages })
def single_thread(request, course_id, discussion_id, thread_id): nr_transaction = newrelic.agent.current_transaction() course = get_course_with_access(request.user, course_id, 'load_forum') cc_user = cc.User.from_django_user(request.user) user_info = cc_user.to_dict() try: thread = cc.Thread.find(thread_id).retrieve(recursive=True, user_id=request.user.id) except (cc.utils.CommentClientError, cc.utils.CommentClientUnknownError): log.error("Error loading single thread.") raise if request.is_ajax(): with newrelic.agent.FunctionTrace(nr_transaction, "get_courseware_context"): courseware_context = get_courseware_context(thread, course) with newrelic.agent.FunctionTrace(nr_transaction, "get_annotated_content_infos"): annotated_content_info = utils.get_annotated_content_infos(course_id, thread, request.user, user_info=user_info) context = {'thread': thread.to_dict(), 'course_id': course_id} # TODO: Remove completely or switch back to server side rendering # html = render_to_string('discussion/_ajax_single_thread.html', context) content = utils.safe_content(thread.to_dict()) if courseware_context: content.update(courseware_context) return utils.JsonResponse({ #'html': html, 'content': content, 'annotated_content_info': annotated_content_info, }) else: with newrelic.agent.FunctionTrace(nr_transaction, "get_discussion_category_map"): category_map = utils.get_discussion_category_map(course) try: threads, query_params = get_threads(request, course_id) threads.append(thread.to_dict()) except (cc.utils.CommentClientError, cc.utils.CommentClientUnknownError): log.error("Error loading single thread.") raise course = get_course_with_access(request.user, course_id, 'load_forum') with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context_to_threads"): for thread in threads: courseware_context = get_courseware_context(thread, course) if courseware_context: thread.update(courseware_context) if thread.get('group_id') and not thread.get('group_name'): thread['group_name'] = get_cohort_by_id(course_id, thread.get('group_id')).name #patch for backward compatibility with comments service if not "pinned" in thread: thread["pinned"] = False threads = [utils.safe_content(thread) for thread in threads] #recent_active_threads = cc.search_recent_active_threads( # course_id, # recursive=False, # query_params={'follower_id': request.user.id}, #) #trending_tags = cc.search_trending_tags( # course_id, #) with newrelic.agent.FunctionTrace(nr_transaction, "get_metadata_for_threads"): annotated_content_info = utils.get_metadata_for_threads(course_id, threads, request.user, user_info) with newrelic.agent.FunctionTrace(nr_transaction, "get_cohort_info"): cohorts = get_course_cohorts(course_id) cohorted_commentables = get_cohorted_commentables(course_id) user_cohort = get_cohort_id(request.user, course_id) context = { 'discussion_id': discussion_id, 'csrf': csrf(request)['csrf_token'], 'init': '', # TODO: What is this? 'user_info': saxutils.escape(json.dumps(user_info), escapedict), 'annotated_content_info': saxutils.escape(json.dumps(annotated_content_info), escapedict), 'course': course, #'recent_active_threads': recent_active_threads, #'trending_tags': trending_tags, 'course_id': course.id, # TODO: Why pass both course and course.id to template? 'thread_id': thread_id, 'threads': saxutils.escape(json.dumps(threads), escapedict), 'category_map': category_map, 'roles': saxutils.escape(json.dumps(utils.get_role_ids(course_id)), escapedict), 'thread_pages': query_params['num_pages'], 'is_course_cohorted': is_course_cohorted(course_id), 'is_moderator': cached_has_permission(request.user, "see_all_cohorts", course_id), 'flag_moderator': cached_has_permission(request.user, 'openclose_thread', course.id) or has_access(request.user, course, 'staff'), 'cohorts': cohorts, 'user_cohort': get_cohort_id(request.user, course_id), 'cohorted_commentables': cohorted_commentables } return render_to_response('discussion/single_thread.html', context)
def single_thread(request, course_id, discussion_id, thread_id): course = get_course_with_access(request.user, course_id, 'load_forum') cc_user = cc.User.from_django_user(request.user) user_info = cc_user.to_dict() try: thread = cc.Thread.find(thread_id).retrieve(recursive=True, user_id=request.user.id) except (cc.utils.CommentClientError, cc.utils.CommentClientUnknownError): log.error("Error loading single thread.") context = {'window_title':'Message', 'error_title':'', 'error_message':"This discussion has been deleted. <a href='/dashboard'>Click here</a> to go back to your dashboard. \ For additional help contact <a href='mailto:[email protected]'>[email protected]</a>."} return render_to_response('error.html', context) # raise Http404 if len(thread.get('children'))<1: create_comment_auto_load(request, course_id, thread_id,User.objects.get(id=thread.get("user_id"))) if request.is_ajax(): annotated_content_info = utils.get_annotated_content_infos(course_id, thread, request.user, user_info=user_info) context = {'thread': thread.to_dict(), 'course_id': course_id} # TODO: Remove completely or switch back to server side rendering # html = render_to_string('discussion/_ajax_single_thread.html', context) content = utils.safe_content(thread.to_dict()) #courseware_context = get_courseware_context(thread, course) #if courseware_context: # content.update(courseware_context) if thread.get('tags')[0]!='portfolio': id_map = get_discussion_id_map(course) id = content['commentable_id'] content_info = None if id in id_map: location = id_map[id]["location"].url() title = id_map[id]["title"] url = reverse('jump_to', kwargs={"course_id": course.location.course_id, "location": location}) content.update({"courseware_url": url, "courseware_title": title}) return utils.JsonResponse({ #'html': html, 'content': content, 'annotated_content_info': annotated_content_info, }) else: category_map = utils.get_discussion_category_map(course) id_map = get_discussion_id_map(course) try: threads, query_params = get_threads_tags(request, course_id) threads.append(thread.to_dict()) except (cc.utils.CommentClientError, cc.utils.CommentClientUnknownError): log.error("Error loading single thread.") raise Http404 course = get_course_with_access(request.user, course_id, 'load_forum') thread_output = [] for thread in threads: #courseware_context = get_courseware_context(thread, course) #if courseware_context: # thread.update(courseware_context) id = thread['commentable_id'] content_info = None if id in id_map: location = id_map[id]["location"].url() title = id_map[id]["title"] url = reverse('jump_to', kwargs={"course_id": course.location.course_id, "location": location}) thread.update({"courseware_url": url, "courseware_title": title}) if thread.get('group_id') and not thread.get('group_name'): thread['group_name'] = get_cohort_by_id(course_id, thread.get('group_id')).name #patch for backward compatibility with comments service if not "pinned" in thread: thread["pinned"] = False if len(thread.get('tags'))>0: #if thread.get('tags')[0]!='portfolio' and str(thread.get('courseware_url')).find('__am')<0: if thread.get('tags')[0]!='portfolio' and thread.get('tags')[0]!='aboutme': thread_output.append(thread) thread_output = [utils.safe_content(thread) for thread in thread_output] #recent_active_threads = cc.search_recent_active_threads( # course_id, # recursive=False, # query_params={'follower_id': request.user.id}, #) #trending_tags = cc.search_trending_tags( # course_id, #) annotated_content_info = utils.get_metadata_for_threads(course_id, thread_output, request.user, user_info) cohorts = get_course_cohorts(course_id) cohorted_commentables = get_cohorted_commentables(course_id) user_cohort = get_cohort_id(request.user, course_id) context = { 'discussion_id': discussion_id, 'csrf': csrf(request)['csrf_token'], 'init': '', # TODO: What is this? 'user_info': saxutils.escape(json.dumps(user_info), escapedict), 'annotated_content_info': saxutils.escape(json.dumps(annotated_content_info), escapedict), 'course': course, #'recent_active_threads': recent_active_threads, #'trending_tags': trending_tags, 'course_id': course.id, # TODO: Why pass both course and course.id to template? 'thread_id': thread_id, 'threads': saxutils.escape(json.dumps(thread_output), escapedict), 'category_map': category_map, 'roles': saxutils.escape(json.dumps(utils.get_role_ids(course_id)), escapedict), 'thread_pages': query_params['num_pages'], 'is_course_cohorted': is_course_cohorted(course_id), 'is_moderator': cached_has_permission(request.user, "see_all_cohorts", course_id), 'flag_moderator': cached_has_permission(request.user, 'openclose_thread', course.id) or has_access(request.user, course, 'staff'), 'cohorts': cohorts, 'user_cohort': get_cohort_id(request.user, course_id), 'cohorted_commentables': cohorted_commentables } return render_to_response('discussion/single_thread.html', context)
def forum_form_discussion(request, course_id): """ Renders the main Discussion page, potentially filtered by a search query """ course = get_course_with_access(request.user, course_id, 'load') category_map = utils.get_discussion_category_map(course) try: unsafethreads, query_params = get_threads( request, course_id) # This might process a search query threads = [utils.safe_content(thread) for thread in unsafethreads] except cc.utils.CommentClientMaintenanceError: log.warning("Forum is in maintenance mode") return render_to_response('discussion/maintenance.html', {}) except (cc.utils.CommentClientError, cc.utils.CommentClientUnknownError) as err: log.error("Error loading forum discussion threads: %s", str(err)) raise Http404 user = cc.User.from_django_user(request.user) user_info = user.to_dict() annotated_content_info = utils.get_metadata_for_threads( course_id, threads, request.user, user_info) for thread in threads: courseware_context = get_courseware_context(thread, course) if courseware_context: thread.update(courseware_context) if request.is_ajax(): return utils.JsonResponse({ 'discussion_data': threads, # TODO: Standardize on 'discussion_data' vs 'threads' 'annotated_content_info': annotated_content_info, 'num_pages': query_params['num_pages'], 'page': query_params['page'], }) else: #recent_active_threads = cc.search_recent_active_threads( # course_id, # recursive=False, # query_params={'follower_id': request.user.id}, #) #trending_tags = cc.search_trending_tags( # course_id, #) cohorts = get_course_cohorts(course_id) cohorted_commentables = get_cohorted_commentables(course_id) user_cohort_id = get_cohort_id(request.user, course_id) context = { 'csrf': csrf(request)['csrf_token'], 'course': course, #'recent_active_threads': recent_active_threads, #'trending_tags': trending_tags, 'staff_access': has_access(request.user, course, 'staff'), 'threads': saxutils.escape(json.dumps(threads), escapedict), 'thread_pages': query_params['num_pages'], 'user_info': saxutils.escape(json.dumps(user_info), escapedict), 'flag_moderator': cached_has_permission(request.user, 'openclose_thread', course.id) or has_access(request.user, course, 'staff'), 'annotated_content_info': saxutils.escape(json.dumps(annotated_content_info), escapedict), 'course_id': course.id, 'category_map': category_map, 'roles': saxutils.escape(json.dumps(utils.get_role_ids(course_id)), escapedict), 'is_moderator': cached_has_permission(request.user, "see_all_cohorts", course_id), 'cohorts': cohorts, 'user_cohort': user_cohort_id, 'cohorted_commentables': cohorted_commentables, 'is_course_cohorted': is_course_cohorted(course_id) } # print "start rendering.." return render_to_response('discussion/index.html', context)
def discussion_topics(request, course_key_string): """ The handler for divided discussion categories requests. This will raise 404 if user is not staff. Returns the JSON representation of discussion topics w.r.t categories for the course. Example: >>> example = { >>> "course_wide_discussions": { >>> "entries": { >>> "General": { >>> "sort_key": "General", >>> "is_divided": True, >>> "id": "i4x-edx-eiorguegnru-course-foobarbaz" >>> } >>> } >>> "children": ["General", "entry"] >>> }, >>> "inline_discussions" : { >>> "subcategories": { >>> "Getting Started": { >>> "subcategories": {}, >>> "children": [ >>> ["Working with Videos", "entry"], >>> ["Videos on edX", "entry"] >>> ], >>> "entries": { >>> "Working with Videos": { >>> "sort_key": None, >>> "is_divided": False, >>> "id": "d9f970a42067413cbb633f81cfb12604" >>> }, >>> "Videos on edX": { >>> "sort_key": None, >>> "is_divided": False, >>> "id": "98d8feb5971041a085512ae22b398613" >>> } >>> } >>> }, >>> "children": ["Getting Started", "subcategory"] >>> }, >>> } >>> } """ course_key = CourseKey.from_string(course_key_string) course = get_course_with_access(request.user, 'staff', course_key) discussion_topics = {} discussion_category_map = utils.get_discussion_category_map( course, request.user, divided_only_if_explicit=True, exclude_unstarted=False ) # We extract the data for the course wide discussions from the category map. course_wide_entries = discussion_category_map.pop('entries') course_wide_children = [] inline_children = [] for name, c_type in discussion_category_map['children']: if name in course_wide_entries and c_type == TYPE_ENTRY: course_wide_children.append([name, c_type]) else: inline_children.append([name, c_type]) discussion_topics['course_wide_discussions'] = { 'entries': course_wide_entries, 'children': course_wide_children } discussion_category_map['children'] = inline_children discussion_topics['inline_discussions'] = discussion_category_map return JsonResponse(discussion_topics)
def test_empty(self): self.assertEqual( utils.get_discussion_category_map(self.course), {"entries": {}, "subcategories": {}, "children": []} )
def assertCategoryMapEquals(self, expected): self.assertEqual( utils.get_discussion_category_map(self.course), expected )
def single_thread(request, course_id, discussion_id, thread_id): nr_transaction = newrelic.agent.current_transaction() course = get_course_with_access(request.user, course_id, 'load_forum') cc_user = cc.User.from_django_user(request.user) user_info = cc_user.to_dict() thread = cc.Thread.find(thread_id).retrieve(recursive=True, user_id=request.user.id) if request.is_ajax(): with newrelic.agent.FunctionTrace(nr_transaction, "get_annotated_content_infos"): annotated_content_info = utils.get_annotated_content_infos( course_id, thread, request.user, user_info=user_info) context = {'thread': thread.to_dict(), 'course_id': course_id} # TODO: Remove completely or switch back to server side rendering # html = render_to_string('discussion/_ajax_single_thread.html', context) content = utils.safe_content(thread.to_dict()) with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"): add_courseware_context([content], course) return utils.JsonResponse({ #'html': html, 'content': content, 'annotated_content_info': annotated_content_info, }) else: with newrelic.agent.FunctionTrace(nr_transaction, "get_discussion_category_map"): category_map = utils.get_discussion_category_map(course) threads, query_params = get_threads(request, course_id) threads.append(thread.to_dict()) course = get_course_with_access(request.user, course_id, 'load_forum') with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"): add_courseware_context(threads, course) for thread in threads: if thread.get('group_id') and not thread.get('group_name'): thread['group_name'] = get_cohort_by_id( course_id, thread.get('group_id')).name #patch for backward compatibility with comments service if not "pinned" in thread: thread["pinned"] = False threads = [utils.safe_content(thread) for thread in threads] #recent_active_threads = cc.search_recent_active_threads( # course_id, # recursive=False, # query_params={'follower_id': request.user.id}, #) #trending_tags = cc.search_trending_tags( # course_id, #) with newrelic.agent.FunctionTrace(nr_transaction, "get_metadata_for_threads"): annotated_content_info = utils.get_metadata_for_threads( course_id, threads, request.user, user_info) with newrelic.agent.FunctionTrace(nr_transaction, "get_cohort_info"): cohorts = get_course_cohorts(course_id) cohorted_commentables = get_cohorted_commentables(course_id) user_cohort = get_cohort_id(request.user, course_id) context = { 'discussion_id': discussion_id, 'csrf': csrf(request)['csrf_token'], 'init': '', # TODO: What is this? 'user_info': saxutils.escape(json.dumps(user_info), escapedict), 'annotated_content_info': saxutils.escape(json.dumps(annotated_content_info), escapedict), 'course': course, #'recent_active_threads': recent_active_threads, #'trending_tags': trending_tags, 'course_id': course.id, # TODO: Why pass both course and course.id to template? 'thread_id': thread_id, 'threads': saxutils.escape(json.dumps(threads), escapedict), 'category_map': category_map, 'roles': saxutils.escape(json.dumps(utils.get_role_ids(course_id)), escapedict), 'thread_pages': query_params['num_pages'], 'is_course_cohorted': is_course_cohorted(course_id), 'is_moderator': cached_has_permission(request.user, "see_all_cohorts", course_id), 'flag_moderator': cached_has_permission(request.user, 'openclose_thread', course.id) or has_access(request.user, course, 'staff'), 'cohorts': cohorts, 'user_cohort': get_cohort_id(request.user, course_id), 'cohorted_commentables': cohorted_commentables } return render_to_response('discussion/single_thread.html', context)
def single_thread(request, course_id, discussion_id, thread_id): nr_transaction = newrelic.agent.current_transaction() course = get_course_with_access(request.user, course_id, 'load_forum') cc_user = cc.User.from_django_user(request.user) user_info = cc_user.to_dict() # Currently, the front end always loads responses via AJAX, even for this # page; it would be a nice optimization to avoid that extra round trip to # the comments service. thread = cc.Thread.find(thread_id).retrieve( recursive=request.is_ajax(), user_id=request.user.id, response_skip=request.GET.get("resp_skip"), response_limit=request.GET.get("resp_limit") ) if request.is_ajax(): with newrelic.agent.FunctionTrace(nr_transaction, "get_annotated_content_infos"): annotated_content_info = utils.get_annotated_content_infos(course_id, thread, request.user, user_info=user_info) content = utils.safe_content(thread.to_dict()) with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"): add_courseware_context([content], course) return utils.JsonResponse({ 'content': content, 'annotated_content_info': annotated_content_info, }) else: with newrelic.agent.FunctionTrace(nr_transaction, "get_discussion_category_map"): category_map = utils.get_discussion_category_map(course) threads, query_params = get_threads(request, course_id) threads.append(thread.to_dict()) course = get_course_with_access(request.user, course_id, 'load_forum') with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"): add_courseware_context(threads, course) for thread in threads: if thread.get('group_id') and not thread.get('group_name'): thread['group_name'] = get_cohort_by_id(course_id, thread.get('group_id')).name #patch for backward compatibility with comments service if not "pinned" in thread: thread["pinned"] = False threads = [utils.safe_content(thread) for thread in threads] #recent_active_threads = cc.search_recent_active_threads( # course_id, # recursive=False, # query_params={'follower_id': request.user.id}, #) with newrelic.agent.FunctionTrace(nr_transaction, "get_metadata_for_threads"): annotated_content_info = utils.get_metadata_for_threads(course_id, threads, request.user, user_info) with newrelic.agent.FunctionTrace(nr_transaction, "get_cohort_info"): cohorts = get_course_cohorts(course_id) cohorted_commentables = get_cohorted_commentables(course_id) user_cohort = get_cohort_id(request.user, course_id) context = { 'discussion_id': discussion_id, 'csrf': csrf(request)['csrf_token'], 'init': '', # TODO: What is this? 'user_info': saxutils.escape(json.dumps(user_info), escapedict), 'annotated_content_info': saxutils.escape(json.dumps(annotated_content_info), escapedict), 'course': course, #'recent_active_threads': recent_active_threads, 'course_id': course.id, # TODO: Why pass both course and course.id to template? 'thread_id': thread_id, 'threads': saxutils.escape(json.dumps(threads), escapedict), 'category_map': category_map, 'roles': saxutils.escape(json.dumps(utils.get_role_ids(course_id)), escapedict), 'thread_pages': query_params['num_pages'], 'is_course_cohorted': is_course_cohorted(course_id), 'is_moderator': cached_has_permission(request.user, "see_all_cohorts", course_id), 'flag_moderator': cached_has_permission(request.user, 'openclose_thread', course.id) or has_access(request.user, course, 'staff'), 'cohorts': cohorts, 'user_cohort': get_cohort_id(request.user, course_id), 'cohorted_commentables': cohorted_commentables } return render_to_response('discussion/index.html', context)
def forum_form_discussion(request, course_id): """ Renders the main Discussion page, potentially filtered by a search query """ from student.models import UserTestGroup, CourseEnrollment registered=CourseEnrollment.is_enrolled(request.user, course_id) if not registered: return redirect(reverse('cabout', args=[course_id])) course = get_course_with_access(request.user, course_id, 'load_forum') category_map = utils.get_discussion_category_map(course) id_map = get_discussion_id_map(course) try: unsafethreads, query_params = get_threads_tags(request, course_id) # This might process a search query threads = [utils.safe_content(thread) for thread in unsafethreads] except cc.utils.CommentClientMaintenanceError: log.warning("Forum is in maintenance mode") return render_to_response('discussion/maintenance.html', {}) except (cc.utils.CommentClientError, cc.utils.CommentClientUnknownError) as err: log.error("Error loading forum discussion threads: %s", str(err)) raise Http404 user = cc.User.from_django_user(request.user) user_info = user.to_dict() thread_output = [] for thread in threads: #courseware_context = get_courseware_context(thread, course) #if courseware_context: # thread.update(courseware_context) id = thread['commentable_id'] content_info = None if id in id_map: location = id_map[id]["location"].url() title = id_map[id]["title"] url = reverse('jump_to', kwargs={"course_id": course.location.course_id, "location": location}) thread.update({"courseware_url": url, "courseware_title": title}) if len(thread.get('tags'))>0: #if thread.get('tags')[0]!='portfolio' and str(thread.get('courseware_url')).find('__am')<0: if thread.get('tags')[0]!='portfolio' and thread.get('tags')[0]!='aboutme': thread_output.append(thread) annotated_content_info = utils.get_metadata_for_threads(course_id, thread_output, request.user, user_info) if request.is_ajax(): return utils.JsonResponse({ 'discussion_data': thread_output, # TODO: Standardize on 'discussion_data' vs 'threads' 'annotated_content_info': annotated_content_info, 'num_pages': query_params['num_pages'], 'page': query_params['page'], }) else: #recent_active_threads = cc.search_recent_active_threads( # course_id, # recursive=False, # query_params={'follower_id': request.user.id}, #) #trending_tags = cc.search_trending_tags( # course_id, #) cohorts = get_course_cohorts(course_id) cohorted_commentables = get_cohorted_commentables(course_id) user_cohort_id = get_cohort_id(request.user, course_id) if request.GET.get('pf_id') != None: curr_user = User.objects.get(id=int(request.GET.get('pf_id'))) else: curr_user = None context = { 'curr_user':curr_user, 'csrf': csrf(request)['csrf_token'], 'course': course, #'recent_active_threads': recent_active_threads, #'trending_tags': trending_tags, 'staff_access': has_access(request.user, course, 'staff'), 'threads': saxutils.escape(json.dumps(thread_output), escapedict), 'thread_pages': query_params['num_pages'], 'user_info': saxutils.escape(json.dumps(user_info), escapedict), 'flag_moderator': cached_has_permission(request.user, 'openclose_thread', course.id) or has_access(request.user, course, 'staff'), 'annotated_content_info': saxutils.escape(json.dumps(annotated_content_info), escapedict), 'course_id': course.id, 'category_map': category_map, 'roles': saxutils.escape(json.dumps(utils.get_role_ids(course_id)), escapedict), 'is_moderator': cached_has_permission(request.user, "see_all_cohorts", course_id), 'cohorts': cohorts, 'user_cohort': user_cohort_id, 'cohorted_commentables': cohorted_commentables, 'is_course_cohorted': is_course_cohorted(course_id) } # print "start rendering.." return render_to_response('discussion/index.html', context)
def discussion_topics(request, course_key_string): """ The handler for divided discussion categories requests. This will raise 404 if user is not staff. Returns the JSON representation of discussion topics w.r.t categories for the course. Example: >>> example = { >>> "course_wide_discussions": { >>> "entries": { >>> "General": { >>> "sort_key": "General", >>> "is_divided": True, >>> "id": "i4x-edx-eiorguegnru-course-foobarbaz" >>> } >>> } >>> "children": ["General", "entry"] >>> }, >>> "inline_discussions" : { >>> "subcategories": { >>> "Getting Started": { >>> "subcategories": {}, >>> "children": [ >>> ["Working with Videos", "entry"], >>> ["Videos on edX", "entry"] >>> ], >>> "entries": { >>> "Working with Videos": { >>> "sort_key": None, >>> "is_divided": False, >>> "id": "d9f970a42067413cbb633f81cfb12604" >>> }, >>> "Videos on edX": { >>> "sort_key": None, >>> "is_divided": False, >>> "id": "98d8feb5971041a085512ae22b398613" >>> } >>> } >>> }, >>> "children": ["Getting Started", "subcategory"] >>> }, >>> } >>> } """ course_key = CourseKey.from_string(course_key_string) course = get_course_with_access(request.user, 'staff', course_key) discussion_topics = {} discussion_category_map = utils.get_discussion_category_map( course, request.user, divided_only_if_explicit=True, exclude_unstarted=False) # We extract the data for the course wide discussions from the category map. course_wide_entries = discussion_category_map.pop('entries') course_wide_children = [] inline_children = [] for name, c_type in discussion_category_map['children']: if name in course_wide_entries and c_type == TYPE_ENTRY: course_wide_children.append([name, c_type]) else: inline_children.append([name, c_type]) discussion_topics['course_wide_discussions'] = { 'entries': course_wide_entries, 'children': course_wide_children } discussion_category_map['children'] = inline_children discussion_topics['inline_discussions'] = discussion_category_map return JsonResponse(discussion_topics)
def forum_form_discussion(request, course_id): """ Renders the main Discussion page, potentially filtered by a search query """ nr_transaction = newrelic.agent.current_transaction() course = get_course_with_access(request.user, course_id, 'load_forum') with newrelic.agent.FunctionTrace(nr_transaction, "get_discussion_category_map"): category_map = utils.get_discussion_category_map(course) try: unsafethreads, query_params = get_threads(request, course_id) # This might process a search query threads = [utils.safe_content(thread) for thread in unsafethreads] except cc.utils.CommentClientMaintenanceError: log.warning("Forum is in maintenance mode") return render_to_response('discussion/maintenance.html', {}) user = cc.User.from_django_user(request.user) user_info = user.to_dict() with newrelic.agent.FunctionTrace(nr_transaction, "get_metadata_for_threads"): annotated_content_info = utils.get_metadata_for_threads(course_id, threads, request.user, user_info) with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"): add_courseware_context(threads, course) if request.is_ajax(): return utils.JsonResponse({ 'discussion_data': threads, # TODO: Standardize on 'discussion_data' vs 'threads' 'annotated_content_info': annotated_content_info, 'num_pages': query_params['num_pages'], 'page': query_params['page'], }) else: #recent_active_threads = cc.search_recent_active_threads( # course_id, # recursive=False, # query_params={'follower_id': request.user.id}, #) with newrelic.agent.FunctionTrace(nr_transaction, "get_cohort_info"): cohorts = get_course_cohorts(course_id) cohorted_commentables = get_cohorted_commentables(course_id) user_cohort_id = get_cohort_id(request.user, course_id) context = { 'csrf': csrf(request)['csrf_token'], 'course': course, #'recent_active_threads': recent_active_threads, 'staff_access': has_access(request.user, course, 'staff'), 'threads': saxutils.escape(json.dumps(threads), escapedict), 'thread_pages': query_params['num_pages'], 'user_info': saxutils.escape(json.dumps(user_info), escapedict), 'flag_moderator': cached_has_permission(request.user, 'openclose_thread', course.id) or has_access(request.user, course, 'staff'), 'annotated_content_info': saxutils.escape(json.dumps(annotated_content_info), escapedict), 'course_id': course.id, 'category_map': category_map, 'roles': saxutils.escape(json.dumps(utils.get_role_ids(course_id)), escapedict), 'is_moderator': cached_has_permission(request.user, "see_all_cohorts", course_id), 'cohorts': cohorts, 'user_cohort': user_cohort_id, 'cohorted_commentables': cohorted_commentables, 'is_course_cohorted': is_course_cohorted(course_id) } # print "start rendering.." return render_to_response('discussion/index.html', context)