def inline_discussion(request, course_key, discussion_id): """ Renders JSON for DiscussionModules """ course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True) cc_user = cc.User.from_django_user(request.user) user_info = cc_user.to_dict() try: threads, query_params = get_threads(request, course, user_info, discussion_id, per_page=INLINE_THREADS_PER_PAGE) except ValueError: return HttpResponseServerError("Invalid group_id") with function_trace("get_metadata_for_threads"): annotated_content_info = utils.get_metadata_for_threads(course_key, threads, request.user, user_info) is_staff = has_permission(request.user, 'openclose_thread', course.id) threads = [utils.prepare_content(thread, course_key, is_staff) for thread in threads] with function_trace("add_courseware_context"): add_courseware_context(threads, course, request.user) course_discussion_settings = get_course_discussion_settings(course.id) return utils.JsonResponse({ 'is_commentable_divided': is_commentable_divided(course_key, discussion_id), 'discussion_data': threads, 'user_info': user_info, 'user_group_id': get_group_id_for_user(request.user, course_discussion_settings), 'annotated_content_info': annotated_content_info, 'page': query_params['page'], 'num_pages': query_params['num_pages'], 'roles': utils.get_role_ids(course_key), 'course_settings': make_course_settings(course, request.user) })
def forum_form_discussion(request, course_key): """ Renders the main Discussion page, potentially filtered by a search query """ course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True) if request.is_ajax(): user = cc.User.from_django_user(request.user) user_info = user.to_dict() try: unsafethreads, query_params = get_threads(request, course, user_info) # This might process a search query is_staff = has_permission(request.user, 'openclose_thread', course.id) threads = [utils.prepare_content(thread, course_key, is_staff) for thread in unsafethreads] except cc.utils.CommentClientMaintenanceError: return HttpResponseServerError('Forum is in maintenance mode', status=status.HTTP_503_SERVICE_UNAVAILABLE) except ValueError: return HttpResponseServerError("Invalid group_id") with function_trace("get_metadata_for_threads"): annotated_content_info = utils.get_metadata_for_threads(course_key, threads, request.user, user_info) with function_trace("add_courseware_context"): add_courseware_context(threads, course, request.user) 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'], 'corrected_text': query_params['corrected_text'], }) else: course_id = unicode(course.id) tab_view = CourseTabView() return tab_view.get(request, course_id, 'discussion')
def inline_discussion(request, course_key, discussion_id): """ Renders JSON for DiscussionModules """ course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True) cc_user = cc.User.from_django_user(request.user) user_info = cc_user.to_dict() try: threads, query_params = get_threads(request, course, user_info, discussion_id, per_page=INLINE_THREADS_PER_PAGE) except ValueError: return HttpResponseServerError("Invalid group_id") with function_trace("get_metadata_for_threads"): annotated_content_info = utils.get_metadata_for_threads(course_key, threads, request.user, user_info) is_staff = has_permission(request.user, 'openclose_thread', course.id) threads = [utils.prepare_content(thread, course_key, is_staff) for thread in threads] with function_trace("add_courseware_context"): add_courseware_context(threads, course, request.user) return utils.JsonResponse({ 'is_commentable_divided': is_commentable_divided(course_key, discussion_id), 'discussion_data': threads, 'user_info': user_info, 'annotated_content_info': annotated_content_info, 'page': query_params['page'], 'num_pages': query_params['num_pages'], 'roles': utils.get_role_ids(course_key), 'course_settings': make_course_settings(course, request.user) })
def inline_discussion(request, course_key, discussion_id): """ Renders JSON for DiscussionModules """ with function_trace('get_course_and_user_info'): course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True) cc_user = cc.User.from_django_user(request.user) user_info = cc_user.to_dict() try: with function_trace('get_threads'): threads, query_params = get_threads( request, course, user_info, discussion_id, per_page=INLINE_THREADS_PER_PAGE ) except ValueError: return HttpResponseServerError('Invalid group_id') with function_trace('get_metadata_for_threads'): annotated_content_info = utils.get_metadata_for_threads(course_key, threads, request.user, user_info) with function_trace('determine_group_permissions'): is_staff = has_permission(request.user, 'openclose_thread', course.id) course_discussion_settings = get_course_discussion_settings(course.id) group_names_by_id = get_group_names_by_id(course_discussion_settings) course_is_divided = course_discussion_settings.division_scheme is not CourseDiscussionSettings.NONE with function_trace('prepare_content'): threads = [ utils.prepare_content( thread, course_key, is_staff, course_is_divided, group_names_by_id ) for thread in threads ] return utils.JsonResponse({ 'is_commentable_divided': is_commentable_divided(course_key, discussion_id), 'discussion_data': threads, 'user_info': user_info, 'user_group_id': get_group_id_for_user(request.user, course_discussion_settings), 'annotated_content_info': annotated_content_info, 'page': query_params['page'], 'num_pages': query_params['num_pages'], 'roles': utils.get_role_ids(course_key), 'course_settings': make_course_settings(course, request.user, False) })
def single_thread(request, course_key, discussion_id, thread_id): """ Renders a response to display a single discussion thread. This could either be a page refresh after navigating to a single thread, a direct link to a single thread, or an AJAX call from the discussions UI loading the responses/comments for a single thread. Depending on the HTTP headers, we'll adjust our response accordingly. """ course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True) request.user.is_community_ta = utils.is_user_community_ta( request.user, course.id) if request.is_ajax(): cc_user = cc.User.from_django_user(request.user) user_info = cc_user.to_dict() is_staff = has_permission(request.user, 'openclose_thread', course.id) thread = _load_thread_for_viewing( request, course, discussion_id=discussion_id, thread_id=thread_id, raise_event=True, ) with function_trace("get_annotated_content_infos"): annotated_content_info = utils.get_annotated_content_infos( course_key, thread, request.user, user_info=user_info) content = utils.prepare_content(thread.to_dict(), course_key, is_staff) with function_trace("add_courseware_context"): add_courseware_context([content], course, request.user) return utils.JsonResponse({ 'content': content, 'annotated_content_info': annotated_content_info, }) else: course_id = unicode(course.id) tab_view = CourseTabView() return tab_view.get(request, course_id, 'discussion', discussion_id=discussion_id, thread_id=thread_id)
def recurring_nudge_schedule_bin( site_id, target_day_str, day_offset, bin_num, org_list, exclude_orgs=False, override_recipient_email=None, ): target_datetime = deserialize(target_day_str) # TODO: in the next refactor of this task, pass in current_datetime instead of reproducing it here current_datetime = target_datetime - datetime.timedelta(days=day_offset) msg_type = RecurringNudge(abs(day_offset)) site = Site.objects.get(id=site_id) _annotate_for_monitoring(msg_type, site, bin_num, target_day_str, day_offset) for (user, language, context) in _recurring_nudge_schedules_for_bin( site, current_datetime, target_datetime, bin_num, org_list, exclude_orgs ): msg = msg_type.personalize( Recipient( user.username, override_recipient_email or user.email, ), language, context, ) with function_trace('enqueue_send_task'): _recurring_nudge_schedule_send.apply_async((site_id, str(msg)), retry=False)
def recurring_nudge_schedule_bin( site_id, target_day_str, day_offset, bin_num, org_list, exclude_orgs=False, override_recipient_email=None, ): target_datetime = deserialize(target_day_str) # TODO: in the next refactor of this task, pass in current_datetime instead of reproducing it here current_datetime = target_datetime - datetime.timedelta(days=day_offset) msg_type = RecurringNudge(abs(day_offset)) site = Site.objects.get(id=site_id) _annotate_for_monitoring(msg_type, site, bin_num, target_day_str, day_offset) for (user, language, context) in _recurring_nudge_schedules_for_bin( site, current_datetime, target_datetime, bin_num, org_list, exclude_orgs): msg = msg_type.personalize( Recipient( user.username, override_recipient_email or user.email, ), language, context, ) with function_trace('enqueue_send_task'): _recurring_nudge_schedule_send.apply_async((site_id, str(msg)), retry=False)
def get_schedules_with_target_date_by_bin_and_orgs( self, order_by='enrollment__user__id' ): """ Returns Schedules with the target_date, related to Users whose id matches the bin_num, and filtered by org_list. Arguments: order_by -- string for field to sort the resulting Schedules by """ target_day = _get_datetime_beginning_of_day(self.target_datetime) schedule_day_equals_target_day_filter = { 'courseenrollment__schedule__{}__gte'.format(self.schedule_date_field): target_day, 'courseenrollment__schedule__{}__lt'.format(self.schedule_date_field): target_day + datetime.timedelta(days=1), } users = User.objects.filter( courseenrollment__is_active=True, **schedule_day_equals_target_day_filter ).annotate( id_mod=F('id') % self.num_bins ).filter( id_mod=self.bin_num ) schedule_day_equals_target_day_filter = { '{}__gte'.format(self.schedule_date_field): target_day, '{}__lt'.format(self.schedule_date_field): target_day + datetime.timedelta(days=1), } schedules = Schedule.objects.select_related( 'enrollment__user__profile', 'enrollment__course', ).filter( Q(enrollment__course__end__isnull=True) | Q( enrollment__course__end__gte=self.current_datetime ), self.experience_filter, enrollment__user__in=users, enrollment__is_active=True, active=True, **schedule_day_equals_target_day_filter ).order_by(order_by) schedules = self.filter_by_org(schedules) if "read_replica" in settings.DATABASES: schedules = schedules.using("read_replica") LOG.info('Query = %r', schedules.query.sql_with_params()) with function_trace('schedule_query_set_evaluation'): # This will run the query and cache all of the results in memory. num_schedules = len(schedules) LOG.info('Number of schedules = %d', num_schedules) # This should give us a sense of the volume of data being processed by each task. set_custom_metric('num_schedules', num_schedules) return schedules
def get_schedules_with_target_date_by_bin_and_orgs( self, order_by='enrollment__user__id' ): """ Returns Schedules with the target_date, related to Users whose id matches the bin_num, and filtered by org_list. Arguments: order_by -- string for field to sort the resulting Schedules by """ target_day = _get_datetime_beginning_of_day(self.target_datetime) schedule_day_equals_target_day_filter = { 'courseenrollment__schedule__{}__gte'.format(self.schedule_date_field): target_day, 'courseenrollment__schedule__{}__lt'.format(self.schedule_date_field): target_day + datetime.timedelta(days=1), } users = User.objects.filter( courseenrollment__is_active=True, **schedule_day_equals_target_day_filter ).annotate( id_mod=F('id') % self.num_bins ).filter( id_mod=self.bin_num ) schedule_day_equals_target_day_filter = { '{}__gte'.format(self.schedule_date_field): target_day, '{}__lt'.format(self.schedule_date_field): target_day + datetime.timedelta(days=1), } schedules = Schedule.objects.select_related( 'enrollment__user__profile', 'enrollment__course', ).filter( Q(enrollment__course__end__isnull=True) | Q( enrollment__course__end__gte=self.current_datetime ), self.experience_filter, enrollment__user__in=users, enrollment__is_active=True, active=True, **schedule_day_equals_target_day_filter ).order_by(order_by) schedules = self.filter_by_org(schedules) if "read_replica" in settings.DATABASES: schedules = schedules.using("read_replica") LOG.info('Query = %r', schedules.query.sql_with_params()) with function_trace('schedule_query_set_evaluation'): # This will run the query and cache all of the results in memory. num_schedules = len(schedules) LOG.info('Number of schedules = %d', num_schedules) # This should give us a sense of the volume of data being processed by each task. set_custom_metric('num_schedules', num_schedules) return schedules
def single_thread(request, course_key, discussion_id, thread_id): """ Renders a response to display a single discussion thread. This could either be a page refresh after navigating to a single thread, a direct link to a single thread, or an AJAX call from the discussions UI loading the responses/comments for a single thread. Depending on the HTTP headers, we'll adjust our response accordingly. """ course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True) if request.is_ajax(): cc_user = cc.User.from_django_user(request.user) user_info = cc_user.to_dict() is_staff = has_permission(request.user, 'openclose_thread', course.id) thread = _load_thread_for_viewing( request, course, discussion_id=discussion_id, thread_id=thread_id, raise_event=True, ) with function_trace("get_annotated_content_infos"): annotated_content_info = utils.get_annotated_content_infos( course_key, thread, request.user, user_info=user_info ) content = utils.prepare_content(thread.to_dict(), course_key, is_staff) with function_trace("add_courseware_context"): add_courseware_context([content], course, request.user) return utils.JsonResponse({ 'content': content, 'annotated_content_info': annotated_content_info, }) else: course_id = unicode(course.id) tab_view = CourseTabView() return tab_view.get(request, course_id, 'discussion', discussion_id=discussion_id, thread_id=thread_id)
def send(self, msg_type): for (user, language, context) in self.schedules_for_bin(): msg = msg_type.personalize( Recipient( user.username, self.override_recipient_email or user.email, ), language, context, ) with function_trace('enqueue_send_task'): self.async_send_task.apply_async((self.site.id, str(msg)), retry=False)
def send(self, msg_type): for (user, language, context) in self.schedules_for_bin(): msg = msg_type.personalize( Recipient( user.username, self.override_recipient_email or user.email, ), language, context, ) with function_trace('enqueue_send_task'): self.async_send_task.apply_async((self.site.id, str(msg)), retry=False)
def _create_discussion_board_context(request, base_context, thread=None): """ Returns the template context for rendering the discussion board. """ context = base_context.copy() course = context['course'] course_key = course.id thread_id = thread.id if thread else None discussion_id = thread.commentable_id if thread else None course_settings = context['course_settings'] user = context['user'] cc_user = cc.User.from_django_user(user) user_info = context['user_info'] if thread: # Since we're in page render mode, and the discussions UI will request the thread list itself, # we need only return the thread information for this one. threads = [thread.to_dict()] for thread in threads: # patch for backward compatibility with comments service if "pinned" not in thread: thread["pinned"] = False thread_pages = 1 root_url = reverse('forum_form_discussion', args=[unicode(course.id)]) else: threads, query_params = get_threads(request, course, user_info) # This might process a search query thread_pages = query_params['num_pages'] root_url = request.path is_staff = has_permission(user, 'openclose_thread', course.id) threads = [utils.prepare_content(thread, course_key, is_staff) for thread in threads] with function_trace("get_metadata_for_threads"): annotated_content_info = utils.get_metadata_for_threads(course_key, threads, user, user_info) with function_trace("add_courseware_context"): add_courseware_context(threads, course, user) with function_trace("get_cohort_info"): course_discussion_settings = get_course_discussion_settings(course_key) user_group_id = get_group_id_for_user(user, course_discussion_settings) context.update({ 'root_url': root_url, 'discussion_id': discussion_id, 'thread_id': thread_id, 'threads': threads, 'thread_pages': thread_pages, 'annotated_content_info': annotated_content_info, 'is_moderator': has_permission(user, "see_all_cohorts", course_key), 'groups': course_settings["groups"], # still needed to render _thread_list_template 'user_group_id': user_group_id, # read from container in NewPostView 'sort_preference': cc_user.default_sort_key, 'category_map': course_settings["category_map"], 'course_settings': course_settings, 'is_commentable_divided': is_commentable_divided(course_key, discussion_id, course_discussion_settings), # If the default topic id is None the front-end code will look for a topic that contains "General" 'discussion_default_topic_id': _get_discussion_default_topic_id(course), }) context.update( get_experiment_user_metadata_context( course, user, ) ) return context
def get_schedules_with_target_date_by_bin_and_orgs(schedule_date_field, current_datetime, target_datetime, bin_num, num_bins=DEFAULT_NUM_BINS, org_list=None, exclude_orgs=False, order_by='enrollment__user__id'): """ Returns Schedules with the target_date, related to Users whose id matches the bin_num, and filtered by org_list. Arguments: schedule_date_field -- string field name to query on the User's Schedule model current_datetime -- datetime that will be used as "right now" in the query target_datetime -- datetime that the User's Schedule's schedule_date_field value should fall under bin_num -- int for selecting the bin of Users whose id % num_bins == bin_num num_bin -- int specifying the number of bins to separate the Users into (default: DEFAULT_NUM_BINS) org_list -- list of course_org names (strings) that the returned Schedules must or must not be in (default: None) exclude_orgs -- boolean indicating whether the returned Schedules should exclude (True) the course_orgs in org_list or strictly include (False) them (default: False) order_by -- string for field to sort the resulting Schedules by """ target_day = _get_datetime_beginning_of_day(target_datetime) schedule_day_equals_target_day_filter = { 'courseenrollment__schedule__{}__gte'.format(schedule_date_field): target_day, 'courseenrollment__schedule__{}__lt'.format(schedule_date_field): target_day + datetime.timedelta(days=1), } users = User.objects.filter( courseenrollment__is_active=True, **schedule_day_equals_target_day_filter ).annotate( id_mod=F('id') % num_bins ).filter( id_mod=bin_num ) schedule_day_equals_target_day_filter = { '{}__gte'.format(schedule_date_field): target_day, '{}__lt'.format(schedule_date_field): target_day + datetime.timedelta(days=1), } schedules = Schedule.objects.select_related( 'enrollment__user__profile', 'enrollment__course', ).prefetch_related( 'enrollment__course__modes' ).filter( Q(enrollment__course__end__isnull=True) | Q(enrollment__course__end__gte=current_datetime), enrollment__user__in=users, enrollment__is_active=True, **schedule_day_equals_target_day_filter ).order_by(order_by) if org_list is not None: if exclude_orgs: schedules = schedules.exclude(enrollment__course__org__in=org_list) else: schedules = schedules.filter(enrollment__course__org__in=org_list) if "read_replica" in settings.DATABASES: schedules = schedules.using("read_replica") LOG.debug('Query = %r', schedules.query.sql_with_params()) with function_trace('schedule_query_set_evaluation'): # This will run the query and cache all of the results in memory. num_schedules = len(schedules) # This should give us a sense of the volume of data being processed by each task. set_custom_metric('num_schedules', num_schedules) return schedules
def user_profile(request, course_key, user_id): """ Renders a response to display the user profile page (shown after clicking on a post author's username). """ user = cc.User.from_django_user(request.user) course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True) try: # If user is not enrolled in the course, do not proceed. django_user = User.objects.get(id=user_id) if not CourseEnrollment.is_enrolled(django_user, course.id): raise Http404 query_params = { 'page': request.GET.get('page', 1), 'per_page': THREADS_PER_PAGE, # more than threads_per_page to show more activities } try: group_id = get_group_id_for_comments_service(request, course_key) except ValueError: return HttpResponseServerError("Invalid group_id") if group_id is not None: query_params['group_id'] = group_id profiled_user = cc.User(id=user_id, course_id=course_key, group_id=group_id) else: profiled_user = cc.User(id=user_id, course_id=course_key) threads, page, num_pages = profiled_user.active_threads(query_params) query_params['page'] = page query_params['num_pages'] = num_pages with function_trace("get_metadata_for_threads"): user_info = cc.User.from_django_user(request.user).to_dict() annotated_content_info = utils.get_metadata_for_threads( course_key, threads, request.user, user_info) is_staff = has_permission(request.user, 'openclose_thread', course.id) threads = [ utils.prepare_content(thread, course_key, is_staff) for thread in threads ] with function_trace("add_courseware_context"): add_courseware_context(threads, course, request.user) if request.is_ajax(): return utils.JsonResponse({ 'discussion_data': threads, 'page': query_params['page'], 'num_pages': query_params['num_pages'], 'annotated_content_info': annotated_content_info, }) else: user_roles = django_user.roles.filter( course_id=course.id).order_by("name").values_list( "name", flat=True).distinct() with function_trace("get_cohort_info"): course_discussion_settings = get_course_discussion_settings( course_key) user_group_id = get_group_id_for_user( request.user, course_discussion_settings) context = _create_base_discussion_view_context(request, course_key) context.update({ 'django_user': django_user, 'django_user_roles': user_roles, 'profiled_user': profiled_user.to_dict(), 'threads': threads, 'user_group_id': user_group_id, 'annotated_content_info': annotated_content_info, 'page': query_params['page'], 'num_pages': query_params['num_pages'], 'sort_preference': user.default_sort_key, 'learner_profile_page_url': reverse('learner_profile', kwargs={'username': django_user.username}), }) return render_to_response( 'discussion/discussion_profile_page.html', context) except User.DoesNotExist: raise Http404
def user_profile(request, course_key, user_id): """ Renders a response to display the user profile page (shown after clicking on a post author's username). """ user = cc.User.from_django_user(request.user) course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True) try: # If user is not enrolled in the course, do not proceed. django_user = User.objects.get(id=user_id) if not CourseEnrollment.is_enrolled(django_user, course.id): raise Http404 query_params = { 'page': request.GET.get('page', 1), 'per_page': THREADS_PER_PAGE, # more than threads_per_page to show more activities } try: group_id = get_group_id_for_comments_service(request, course_key) except ValueError: return HttpResponseServerError("Invalid group_id") if group_id is not None: query_params['group_id'] = group_id profiled_user = cc.User(id=user_id, course_id=course_key, group_id=group_id) else: profiled_user = cc.User(id=user_id, course_id=course_key) threads, page, num_pages = profiled_user.active_threads(query_params) query_params['page'] = page query_params['num_pages'] = num_pages with function_trace("get_metadata_for_threads"): user_info = cc.User.from_django_user(request.user).to_dict() annotated_content_info = utils.get_metadata_for_threads(course_key, threads, request.user, user_info) is_staff = has_permission(request.user, 'openclose_thread', course.id) threads = [utils.prepare_content(thread, course_key, is_staff) for thread in threads] with function_trace("add_courseware_context"): add_courseware_context(threads, course, request.user) if request.is_ajax(): return utils.JsonResponse({ 'discussion_data': threads, 'page': query_params['page'], 'num_pages': query_params['num_pages'], 'annotated_content_info': annotated_content_info, }) else: user_roles = django_user.roles.filter( course_id=course.id ).order_by("name").values_list("name", flat=True).distinct() with function_trace("get_cohort_info"): course_discussion_settings = get_course_discussion_settings(course_key) user_group_id = get_group_id_for_user(request.user, course_discussion_settings) context = _create_base_discussion_view_context(request, course_key) context.update({ 'django_user': django_user, 'django_user_roles': user_roles, 'profiled_user': profiled_user.to_dict(), 'threads': threads, 'user_group_id': user_group_id, 'annotated_content_info': annotated_content_info, 'page': query_params['page'], 'num_pages': query_params['num_pages'], 'sort_preference': user.default_sort_key, 'learner_profile_page_url': reverse('learner_profile', kwargs={'username': django_user.username}), }) return render_to_response('discussion/discussion_profile_page.html', context) except User.DoesNotExist: raise Http404
def create_user_profile_context(request, course_key, user_id): """ Generate a context dictionary for the user profile. """ user = cc.User.from_django_user(request.user) course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True) # If user is not enrolled in the course, do not proceed. django_user = User.objects.get(id=user_id) if not CourseEnrollment.is_enrolled(django_user, course.id): raise Http404 query_params = { 'page': request.GET.get('page', 1), 'per_page': THREADS_PER_PAGE, # more than threads_per_page to show more activities } group_id = get_group_id_for_comments_service(request, course_key) if group_id is not None: query_params['group_id'] = group_id profiled_user = cc.User(id=user_id, course_id=course_key, group_id=group_id) else: profiled_user = cc.User(id=user_id, course_id=course_key) threads, page, num_pages = profiled_user.active_threads(query_params) query_params['page'] = page query_params['num_pages'] = num_pages with function_trace("get_metadata_for_threads"): user_info = cc.User.from_django_user(request.user).to_dict() annotated_content_info = utils.get_metadata_for_threads(course_key, threads, request.user, user_info) is_staff = has_permission(request.user, 'openclose_thread', course.id) threads = [utils.prepare_content(thread, course_key, is_staff) for thread in threads] with function_trace("add_courseware_context"): add_courseware_context(threads, course, request.user) # TODO: LEARNER-3854: If we actually implement Learner Analytics code, this # code was original protected to not run in user_profile() if is_ajax(). # Someone should determine if that is still necessary (i.e. was that ever # called as is_ajax()) and clean this up as necessary. user_roles = django_user.roles.filter( course_id=course.id ).order_by("name").values_list("name", flat=True).distinct() with function_trace("get_cohort_info"): course_discussion_settings = get_course_discussion_settings(course_key) user_group_id = get_group_id_for_user(request.user, course_discussion_settings) context = _create_base_discussion_view_context(request, course_key) context.update({ 'django_user': django_user, 'django_user_roles': user_roles, 'profiled_user': profiled_user.to_dict(), 'threads': threads, 'user_group_id': user_group_id, 'annotated_content_info': annotated_content_info, 'page': query_params['page'], 'num_pages': query_params['num_pages'], 'sort_preference': user.default_sort_key, 'learner_profile_page_url': reverse('learner_profile', kwargs={'username': django_user.username}), }) return context
def followed_threads(request, course_key, user_id): """ Ajax-only endpoint retrieving the threads followed by a specific user. """ course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True) try: profiled_user = cc.User(id=user_id, course_id=course_key) query_params = { 'page': 1, 'per_page': THREADS_PER_PAGE, # more than threads_per_page to show more activities 'sort_key': 'date', } query_params.update( strip_none( extract( request.GET, [ 'page', 'sort_key', 'flagged', 'unread', 'unanswered', ] ) ) ) try: group_id = get_group_id_for_comments_service(request, course_key) except ValueError: return HttpResponseServerError("Invalid group_id") if group_id is not None: query_params['group_id'] = group_id paginated_results = profiled_user.subscribed_threads(query_params) print "\n \n \n paginated results \n \n \n " print paginated_results query_params['page'] = paginated_results.page query_params['num_pages'] = paginated_results.num_pages user_info = cc.User.from_django_user(request.user).to_dict() with function_trace("get_metadata_for_threads"): annotated_content_info = utils.get_metadata_for_threads( course_key, paginated_results.collection, request.user, user_info ) if request.is_ajax(): is_staff = has_permission(request.user, 'openclose_thread', course.id) return utils.JsonResponse({ 'annotated_content_info': annotated_content_info, 'discussion_data': [ utils.prepare_content(thread, course_key, is_staff) for thread in paginated_results.collection ], 'page': query_params['page'], 'num_pages': query_params['num_pages'], }) #TODO remove non-AJAX support, it does not appear to be used and does not appear to work. else: context = { 'course': course, 'user': request.user, 'django_user': User.objects.get(id=user_id), 'profiled_user': profiled_user.to_dict(), 'threads': paginated_results.collection, 'user_info': user_info, 'annotated_content_info': annotated_content_info, # 'content': content, } return render_to_response('discussion/user_profile.html', context) except User.DoesNotExist: raise Http404
def get_schedules_with_target_date_by_bin_and_orgs( schedule_date_field, current_datetime, target_datetime, bin_num, num_bins=DEFAULT_NUM_BINS, org_list=None, exclude_orgs=False, order_by='enrollment__user__id'): """ Returns Schedules with the target_date, related to Users whose id matches the bin_num, and filtered by org_list. Arguments: schedule_date_field -- string field name to query on the User's Schedule model current_datetime -- datetime that will be used as "right now" in the query target_datetime -- datetime that the User's Schedule's schedule_date_field value should fall under bin_num -- int for selecting the bin of Users whose id % num_bins == bin_num num_bin -- int specifying the number of bins to separate the Users into (default: DEFAULT_NUM_BINS) org_list -- list of course_org names (strings) that the returned Schedules must or must not be in (default: None) exclude_orgs -- boolean indicating whether the returned Schedules should exclude (True) the course_orgs in org_list or strictly include (False) them (default: False) order_by -- string for field to sort the resulting Schedules by """ target_day = _get_datetime_beginning_of_day(target_datetime) schedule_day_equals_target_day_filter = { 'courseenrollment__schedule__{}__gte'.format(schedule_date_field): target_day, 'courseenrollment__schedule__{}__lt'.format(schedule_date_field): target_day + datetime.timedelta(days=1), } users = User.objects.filter( courseenrollment__is_active=True, **schedule_day_equals_target_day_filter).annotate( id_mod=F('id') % num_bins).filter(id_mod=bin_num) schedule_day_equals_target_day_filter = { '{}__gte'.format(schedule_date_field): target_day, '{}__lt'.format(schedule_date_field): target_day + datetime.timedelta(days=1), } schedules = Schedule.objects.select_related( 'enrollment__user__profile', 'enrollment__course', ).prefetch_related('enrollment__course__modes').filter( Q(enrollment__course__end__isnull=True) | Q(enrollment__course__end__gte=current_datetime), enrollment__user__in=users, enrollment__is_active=True, **schedule_day_equals_target_day_filter).order_by(order_by) if org_list is not None: if exclude_orgs: schedules = schedules.exclude(enrollment__course__org__in=org_list) else: schedules = schedules.filter(enrollment__course__org__in=org_list) if "read_replica" in settings.DATABASES: schedules = schedules.using("read_replica") LOG.debug('Query = %r', schedules.query.sql_with_params()) with function_trace('schedule_query_set_evaluation'): # This will run the query and cache all of the results in memory. num_schedules = len(schedules) # This should give us a sense of the volume of data being processed by each task. set_custom_metric('num_schedules', num_schedules) return schedules