Example #1
0
def _create_comment(request, course_id, thread_id=None, parent_id=None):
    """
    given a course_id, thread_id, and parent_id, create a comment,
    called from create_comment to do the actual creation
    """
    post = request.POST
    comment = cc.Comment(**extract(post, ['body']))

    course = get_course_with_access(request.user, course_id, 'load')
    if course.allow_anonymous:
        anonymous = post.get('anonymous', 'false').lower() == 'true'
    else:
        anonymous = False

    if course.allow_anonymous_to_peers:
        anonymous_to_peers = post.get('anonymous_to_peers', 'false').lower() == 'true'
    else:
        anonymous_to_peers = False

    comment.update_attributes(**{
        'anonymous': anonymous,
        'anonymous_to_peers': anonymous_to_peers,
        'user_id': request.user.id,
        'course_id': course_id,
        'thread_id': thread_id,
        'parent_id': parent_id,
    })
    comment.save()
    if post.get('auto_subscribe', 'false').lower() == 'true':
        user = cc.User.from_django_user(request.user)
        user.follow(comment.thread)
    if request.is_ajax():
        return ajax_content_response(request, course_id, comment.to_dict())
    else:
        return JsonResponse(utils.safe_content(comment.to_dict()))
def update_thread(request, course_id, thread_id, thread_data):
    """
    Given a course id and thread id, update a existing thread, used for both static and ajax submissions
    """
    thread = cc.Thread.find(thread_id)
    thread.update_attributes(**extract(thread_data, ['body', 'title', 'tags']))
    thread.save()
Example #3
0
def _create_comment(request, course_id, thread_id=None, parent_id=None):
    """
    given a course_id, thread_id, and parent_id, create a comment,
    called from create_comment to do the actual creation
    """
    post = request.POST
    comment = cc.Comment(**extract(post, ['body']))

    course = get_course_with_access(request.user, course_id, 'load')
    if course.allow_anonymous:
        anonymous = post.get('anonymous', 'false').lower() == 'true'
    else:
        anonymous = False

    if course.allow_anonymous_to_peers:
        anonymous_to_peers = post.get('anonymous_to_peers', 'false').lower() == 'true'
    else:
        anonymous_to_peers = False

    comment.update_attributes(**{
        'anonymous': anonymous,
        'anonymous_to_peers': anonymous_to_peers,
        'user_id': request.user.id,
        'course_id': course_id,
        'thread_id': thread_id,
        'parent_id': parent_id,
    })
    comment.save()
    if post.get('auto_subscribe', 'false').lower() == 'true':
        user = cc.User.from_django_user(request.user)
        user.follow(comment.thread)
    if request.is_ajax():
        return ajax_content_response(request, course_id, comment.to_dict(), 'discussion/ajax_create_comment.html')
    else:
        return JsonResponse(utils.safe_content(comment.to_dict()))
Example #4
0
def mobi_create_comment(request, course_id, thread_id):
    course_id = course_id.replace('.', '/')

    if cc_settings.MAX_COMMENT_DEPTH is not None:
        if cc_settings.MAX_COMMENT_DEPTH < 0:
            return JsonResponse({
                'success': False,
                'errmsg': 'Comment level too deep'
            })

    post = request.POST

    if 'body' not in post or not post['body'].strip():
        return JsonResponse({
            "success": False,
            'errmsg': 'Body can not be None'
        })
    comment = cc.Comment(**extract(post, ['body']))

    try:
        course = get_course_with_access(request.user, course_id, 'load')
    except:
        return JsonResponse({
            "success":
            False,
            "errmsg":
            "can not find a course with " + course_id.replace("/", ".") + ' id'
        })
    if course.allow_anonymous:
        anonymous = post.get('anonymous', 'false').lower() == 'true'
    else:
        anonymous = False

    if course.allow_anonymous_to_peers:
        anonymous_to_peers = post.get('anonymous_to_peers',
                                      'false').lower() == 'true'
    else:
        anonymous_to_peers = False

    comment.update_attributes(
        **{
            'anonymous': anonymous,
            'anonymous_to_peers': anonymous_to_peers,
            'user_id': request.user.id,
            'course_id': course_id,
            'thread_id': thread_id,
        })

    comment.save()
    if post.get('auto_subscribe', 'false').lower() == 'true':
        user = cc.User.from_django_user(request.user)
        user.follow(comment.thread)

    return JsonResponse({"success": True})
Example #5
0
def update_thread(request, course_id, thread_id):
    """
    Given a course id and thread id, update a existing thread, used for both static and ajax submissions
    """
    thread = cc.Thread.find(thread_id)
    thread.update_attributes(**extract(request.POST, ['body', 'title', 'tags']))
    thread.save()
    if request.is_ajax():
        return ajax_content_response(request, course_id, thread.to_dict())
    else:
        return JsonResponse(utils.safe_content(thread.to_dict()))
Example #6
0
def update_thread(request, course_id, thread_id):
    """
    Given a course id and thread id, update a existing thread, used for both static and ajax submissions
    """
    thread = cc.Thread.find(thread_id)
    thread.update_attributes(**extract(request.POST, ['body', 'title']))
    thread.save()
    if request.is_ajax():
        return ajax_content_response(request, course_id, thread.to_dict())
    else:
        return JsonResponse(utils.safe_content(thread.to_dict()))
Example #7
0
def update_comment(request, course_id, comment_id):
    """
    given a course_id and comment_id, update the comment with payload attributes
    handles static and ajax submissions
    """
    comment = cc.Comment.find(comment_id)
    comment.update_attributes(**extract(request.POST, ['body']))
    comment.save()
    if request.is_ajax():
        return ajax_content_response(request, course_id, comment.to_dict(), 'discussion/ajax_update_comment.html')
    else:
        return JsonResponse(utils.safe_content(comment.to_dict()))
Example #8
0
def update_comment(request, course_id, comment_id):
    """
    given a course_id and comment_id, update the comment with payload attributes
    handles static and ajax submissions
    """
    comment = cc.Comment.find(comment_id)
    comment.update_attributes(**extract(request.POST, ['body']))
    comment.save()
    if request.is_ajax():
        return ajax_content_response(request, course_id, comment.to_dict())
    else:
        return JsonResponse(utils.safe_content(comment.to_dict()))
Example #9
0
def update_comment(request, course_id, comment_id):
    """
    given a course_id and comment_id, update the comment with payload attributes
    handles static and ajax submissions
    """
    comment = cc.Comment.find(comment_id)
    if 'body' not in request.POST or not request.POST['body'].strip():
        return JsonError(_("Body can't be empty"))
    comment.update_attributes(**filterdict(extract(request.POST, ['body'])))
    comment.save()
    if request.is_ajax():
        return ajax_content_response(request, course_id, comment.to_dict())
    else:
        return JsonResponse(utils.safe_content(comment.to_dict()))
Example #10
0
def update_comment(request, course_id, comment_id):
    """
    given a course_id and comment_id, update the comment with payload attributes
    handles static and ajax submissions
    """
    comment = cc.Comment.find(comment_id)
    if 'body' not in request.POST or not request.POST['body'].strip():
        return JsonError(_("Body can't be empty"))
    comment.update_attributes(**extract(request.POST, ['body']))
    comment.save()
    if request.is_ajax():
        return ajax_content_response(request, course_id, comment.to_dict())
    else:
        return JsonResponse(utils.safe_content(comment.to_dict()))
Example #11
0
def update_thread(request, course_id, thread_id):
    """
    Given a course id and thread id, update a existing thread, used for both static and ajax submissions
    """
    if 'title' not in request.POST or not request.POST['title'].strip():
        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"))
    thread = cc.Thread.find(thread_id)
    thread.update_attributes(**extract(request.POST, ['body', 'title']))
    thread.save()
    if request.is_ajax():
        return ajax_content_response(request, course_id, thread.to_dict())
    else:
        return JsonResponse(utils.safe_content(thread.to_dict()))
Example #12
0
def mobi_create_comment(request, course_id, thread_id):
    course_id = course_id.replace('.', '/')

    if cc_settings.MAX_COMMENT_DEPTH is not None:
        if cc_settings.MAX_COMMENT_DEPTH < 0:
            return JsonResponse({'success': False, 'errmsg': 'Comment level too deep'})

    post = request.POST

    if 'body' not in post or not post['body'].strip():
        return JsonResponse({"success": False, 'errmsg': 'Body can not be None'})
    comment = cc.Comment(**extract(post, ['body']))

    try:
        course = get_course_with_access(request.user, course_id, 'load')
    except:
        return JsonResponse({"success": False, "errmsg": "can not find a course with " + course_id.replace("/", ".") + ' id'})
    if course.allow_anonymous:
        anonymous = post.get('anonymous', 'false').lower() == 'true'
    else:
        anonymous = False

    if course.allow_anonymous_to_peers:
        anonymous_to_peers = post.get('anonymous_to_peers', 'false').lower() == 'true'
    else:
        anonymous_to_peers = False

    comment.update_attributes(**{
        'anonymous': anonymous,
        'anonymous_to_peers': anonymous_to_peers,
        'user_id': request.user.id,
        'course_id': course_id,
        'thread_id': thread_id,
    })

    comment.save()
    if post.get('auto_subscribe', 'false').lower() == 'true':
        user = cc.User.from_django_user(request.user)
        user.follow(comment.thread)

    return JsonResponse({"success": True})
Example #13
0
def _create_comment(request, course_id, thread_id=None, parent_id=None):
    """
    given a course_id, thread_id, and parent_id, create a comment,
    called from create_comment to do the actual creation
    """
    post = request.POST

    if "body" not in post or not post["body"].strip():
        return JsonError(_("Body can't be empty"))
    comment = cc.Comment(**extract(post, ["body"]))

    course = get_course_with_access(request.user, course_id, "load")
    if course.allow_anonymous:
        anonymous = post.get("anonymous", "false").lower() == "true"
    else:
        anonymous = False

    if course.allow_anonymous_to_peers:
        anonymous_to_peers = post.get("anonymous_to_peers", "false").lower() == "true"
    else:
        anonymous_to_peers = False

    comment.update_attributes(
        **{
            "anonymous": anonymous,
            "anonymous_to_peers": anonymous_to_peers,
            "user_id": request.user.id,
            "course_id": course_id,
            "thread_id": thread_id,
            "parent_id": parent_id,
        }
    )
    comment.save()
    if post.get("auto_subscribe", "false").lower() == "true":
        user = cc.User.from_django_user(request.user)
        user.follow(comment.thread)
    if request.is_ajax():
        return ajax_content_response(request, course_id, comment.to_dict())
    else:
        return JsonResponse(utils.safe_content(comment.to_dict()))
def create_comment(request, course_id, comment_data, portfolio_user, thread_id=None, parent_id=None):
    """
    given a course_id, thread_id, and parent_id, create a comment,
    called from create_comment to do the actual creation
    """
    comment = cc.Comment(**extract(comment_data, ['body']))

    course = get_course_with_access(portfolio_user, course_id, 'load')
    anonymous = False
    anonymous_to_peers = False

    comment.update_attributes(**{
        'anonymous': anonymous,
        'anonymous_to_peers': anonymous_to_peers,
        'user_id': portfolio_user.id,
        'course_id': course_id,
        'thread_id': thread_id,
        'parent_id': parent_id,
    })
    comment.save()
    user = cc.User.from_django_user(portfolio_user)
    user.follow(comment.thread)
def create_comment_auto(request, course_id, thread_id=None, parent_id=None):
    """
    given a course_id, thread_id, and parent_id, create a comment,
    called from create_comment to do the actual creation
    """
    #post = request.POST
    comment_data={"body":"Let's discuss!"}
    comment = cc.Comment(**extract(comment_data, ['body']))
    
    course = get_course_with_access(request.user, course_id, 'load')
    '''
    if course.allow_anonymous:
        anonymous = post.get('anonymous', 'false').lower() == 'true'
    else:
        anonymous = False

    if course.allow_anonymous_to_peers:
        anonymous_to_peers = post.get('anonymous_to_peers', 'false').lower() == 'true'
    else:
        anonymous_to_peers = False
    '''
    anonymous = False
    anonymous_to_peers = False
    comment.update_attributes(**{
        'anonymous': anonymous,
        'anonymous_to_peers': anonymous_to_peers,
        'user_id': request.user.id,
        'course_id': course_id,
        'thread_id': thread_id,
        'parent_id': parent_id,
    })
    comment.save()
    '''
    if post.get('auto_subscribe', 'false').lower() == 'true':
        user = cc.User.from_django_user(request.user)
        user.follow(comment.thread)
    '''
    user = cc.User.from_django_user(request.user)
    user.follow(comment.thread)
def update_thread(request, course_id, thread_id):
    """
    Given a course id and thread id, update a existing thread, used for both static and ajax submissions
    """
    thread = cc.Thread.find(thread_id)
    thread.update_attributes(**extract(request.POST, ['body', 'title', 'tags']))
    thread.update_attributes(**{
        'tags':'default',
    })
   
    thread.save()
    course = get_course_with_access(request.user, course_id, 'load')
    courseware_context = get_courseware_context(thread, course)
    if courseware_context:
        if str(courseware_context.get('courseware_url')).find('__am')>0:
            thread.update_attributes(**{
                'tags':'aboutme',
            })
        thread.save()
    if request.is_ajax():
        return ajax_content_response(request, course_id, thread.to_dict(), 'discussion/ajax_update_thread.html')
    else:
        return JsonResponse(utils.safe_content(thread.to_dict()))
Example #17
0
def get_threads(request,
                course_key,
                discussion_id=None,
                per_page=THREADS_PER_PAGE):
    """
    This may raise an appropriate subclass of cc.utils.CommentClientError
    if something goes wrong, or ValueError if the group_id is invalid.
    """
    default_query_params = {
        'page':
        1,
        'per_page':
        per_page,
        'sort_key':
        'date',
        'sort_order':
        'desc',
        'text':
        '',
        'commentable_id':
        discussion_id,
        'course_id':
        course_key.to_deprecated_string(),
        'user_id':
        request.user.id,
        'group_id':
        get_group_id_for_comments_service(
            request, course_key, discussion_id),  # may raise ValueError
    }

    if not request.GET.get('sort_key'):
        # If the user did not select a sort key, use their last used sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.retrieve()
        # TODO: After the comment service is updated this can just be user.default_sort_key because the service returns the default value
        default_query_params['sort_key'] = cc_user.get(
            'default_sort_key') or default_query_params['sort_key']
    else:
        # If the user clicked a sort key, update their default sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.default_sort_key = request.GET.get('sort_key')
        cc_user.save()

    #there are 2 dimensions to consider when executing a search with respect to group id
    #is user a moderator
    #did the user request a group

    query_params = merge_dict(
        default_query_params,
        strip_none(
            extract(request.GET, [
                'page',
                'sort_key',
                'sort_order',
                'text',
                'commentable_ids',
                'flagged',
                'unread',
                'unanswered',
            ])))

    threads, page, num_pages, corrected_text = cc.Thread.search(query_params)

    #now add the group name if the thread has a group id
    for thread in threads:
        add_thread_group_name(thread, course_key)

        #patch for backward compatibility to comments service
        if not 'pinned' in thread:
            thread['pinned'] = False

    query_params['page'] = page
    query_params['num_pages'] = num_pages
    query_params['corrected_text'] = corrected_text

    return threads, query_params
Example #18
0
def create_thread(request, course_id, commentable_id, thread_data):
    """
    Given a course and commentble ID, create the thread
    """
    course = get_course_with_access(request.user, course_id, 'load')
   
    if course.allow_anonymous:
        anonymous = thread_data.get('anonymous', 'false').lower() == 'true'
    else:
        anonymous = False

    if course.allow_anonymous_to_peers:
        anonymous_to_peers = thread_data.get('anonymous_to_peers', 'false').lower() == 'true'
    else:
        anonymous_to_peers = False
    thread = cc.Thread(**extract(thread_data, ['body', 'title', 'tags']))
    thread.update_attributes(**{
        'anonymous': anonymous,
        'anonymous_to_peers': anonymous_to_peers,
        'commentable_id': commentable_id,
        'course_id': course_id,
        'user_id': request.user.id,
    })
    
    user = cc.User.from_django_user(request.user)

    #kevinchugh because the new requirement is that all groups will be determined
    #by the group id in the request this all goes away
    #not anymore, only for admins

    # Cohort the thread if the commentable is cohorted.
    if is_commentable_cohorted(course_id, commentable_id):
        user_group_id = get_cohort_id(user, course_id)

        # TODO (vshnayder): once we have more than just cohorts, we'll want to
        # change this to a single get_group_for_user_and_commentable function
        # that can do different things depending on the commentable_id
        if cached_has_permission(request.user, "see_all_cohorts", course_id):
            # admins can optionally choose what group to post as
            group_id = thread_data.get('group_id', user_group_id)
        else:
            # regular users always post with their own id.
            group_id = user_group_id

        if group_id:
            thread.update_attributes(group_id=group_id)

    thread.save()
    #patch for backward compatibility to comments service
    if not 'pinned' in thread.attributes:
        thread['pinned'] = False

    if thread_data.get('auto_subscribe', 'false').lower() == 'true':
        user = cc.User.from_django_user(request.user)
        user.follow(thread)
    courseware_context = get_courseware_context(thread, course)
    data = thread.to_dict()
    if courseware_context:
        data.update(courseware_context)  
    return ajax_content_response(request, course_id, data, 'discussion/ajax_create_thread.html')
    '''
Example #19
0
def get_threads(request, course, user_info, discussion_id=None, per_page=THREADS_PER_PAGE):
    """
    This may raise an appropriate subclass of cc.utils.CommentClientError
    if something goes wrong, or ValueError if the group_id is invalid.

    Arguments:
        request (WSGIRequest): The user request.
        course (CourseDescriptorWithMixins): The course object.
        user_info (dict): The comment client User object as a dict.
        discussion_id (unicode): Optional discussion id/commentable id for context.
        per_page (int): Optional number of threads per page.

    Returns:
        (tuple of list, dict): A tuple of the list of threads and a dict of the
            query parameters used for the search.

    """
    default_query_params = {
        'page': 1,
        'per_page': per_page,
        'sort_key': 'activity',
        'text': '',
        'course_id': unicode(course.id),
        'user_id': request.user.id,
        'context': ThreadContext.COURSE,
        'group_id': get_group_id_for_comments_service(request, course.id, discussion_id),  # may raise ValueError
    }

    # If provided with a discussion id, filter by discussion id in the
    # comments_service.
    if discussion_id is not None:
        default_query_params['commentable_id'] = discussion_id
        # Use the discussion id/commentable id to determine the context we are going to pass through to the backend.
        if get_team(discussion_id) is not None:
            default_query_params['context'] = ThreadContext.STANDALONE

    if not request.GET.get('sort_key'):
        # If the user did not select a sort key, use their last used sort key
        default_query_params['sort_key'] = user_info.get('default_sort_key') or default_query_params['sort_key']

    elif request.GET.get('sort_key') != user_info.get('default_sort_key'):
        # If the user clicked a sort key, update their default sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.default_sort_key = request.GET.get('sort_key')
        cc_user.save()

    # there are 2 dimensions to consider when executing a search with respect to group id
    # is user a moderator
    # did the user request a group

    # if the user requested a group explicitly, give them that group, otherwise, if mod, show all, else if student, use cohort

    if discussion_id:
        is_cohorted = is_commentable_divided(course.id, discussion_id)
    else:
        is_cohorted = is_course_cohorted(course.id)

    if has_permission(request.user, "see_all_cohorts", course.id):
        group_id = request.GET.get('group_id')
        if group_id in ("all", "None"):
            group_id = None
    else:
        group_id = get_cohort_id(request.user, course.id)
        if not group_id:
            default_query_params['exclude_groups'] = True

    if group_id:
        group_id = int(group_id)
        try:
            CourseUserGroup.objects.get(course_id=course.id, id=group_id)
        except CourseUserGroup.DoesNotExist:
            if not is_cohorted:
                group_id = None
            else:
                raise ValueError("Invalid Group ID")
        default_query_params["group_id"] = group_id

    #so by default, a moderator sees all items, and a student sees his cohort

    query_params = merge_dict(
        default_query_params,
        strip_none(
            extract(
                request.GET,
                [
                    'page',
                    'sort_key',
                    'text',
                    'commentable_ids',
                    'flagged',
                    'unread',
                    'unanswered',
                ]
            )
        )
    )

    if not is_cohorted:
        query_params.pop('group_id', None)

    paginated_results = cc.Thread.search(query_params)
    threads = paginated_results.collection

    # If not provided with a discussion id, filter threads by commentable ids
    # which are accessible to the current user.
    if discussion_id is None:
        discussion_category_ids = set(utils.get_discussion_categories_ids(course, request.user))
        threads = [
            thread for thread in threads
            if thread.get('commentable_id') in discussion_category_ids
        ]

    for thread in threads:
        # patch for backward compatibility to comments service
        if 'pinned' not in thread:
            thread['pinned'] = False

    query_params['page'] = paginated_results.page
    query_params['num_pages'] = paginated_results.num_pages
    query_params['corrected_text'] = paginated_results.corrected_text

    return threads, query_params
Example #20
0
def followed_threads(request, course_id, user_id):
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    nr_transaction = newrelic.agent.current_transaction()

    course = get_course_with_access(request.user, 'load_forum', course_key)
    try:
        profiled_user = cc.User(id=user_id, course_id=course_key)

        default_query_params = {
            'page': 1,
            'per_page':
            THREADS_PER_PAGE,  # more than threads_per_page to show more activities
            'sort_key': 'date',
            'sort_order': 'desc',
        }

        query_params = merge_dict(
            default_query_params,
            strip_none(
                extract(request.GET, [
                    'page',
                    'sort_key',
                    'sort_order',
                    'flagged',
                    'unread',
                    'unanswered',
                ])))

        try:
            group_id = get_group_id_for_comments_service(request, course_key)
        except ValueError:
            return HttpResponseBadRequest("Invalid group_id")
        if group_id is not None:
            query_params['group_id'] = group_id

        threads, page, num_pages = profiled_user.subscribed_threads(
            query_params)
        query_params['page'] = page
        query_params['num_pages'] = num_pages
        user_info = cc.User.from_django_user(request.user).to_dict()

        with newrelic.agent.FunctionTrace(nr_transaction,
                                          "get_metadata_for_threads"):
            annotated_content_info = utils.get_metadata_for_threads(
                course_key, threads, request.user, user_info)
        if request.is_ajax():
            is_staff = cached_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 threads
                ],
                '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': _attr_safe_json(threads),
                'user_info': _attr_safe_json(user_info),
                'annotated_content_info':
                _attr_safe_json(annotated_content_info),
                #                'content': content,
            }

            return render_to_response('discussion/user_profile.html', context)
    except User.DoesNotExist:
        raise Http404
Example #21
0
def create_thread(request, course_id, commentable_id):
    """
    Given a course and commentble ID, create the thread
    """

    log.debug("Creating new thread in %r, id %r", course_id, commentable_id)
    course = get_course_with_access(request.user, course_id, 'load')
    post = request.POST

    if course.allow_anonymous:
        anonymous = post.get('anonymous', 'false').lower() == 'true'
    else:
        anonymous = False

    if course.allow_anonymous_to_peers:
        anonymous_to_peers = post.get('anonymous_to_peers',
                                      'false').lower() == 'true'
    else:
        anonymous_to_peers = False

    if 'title' not in post or not post['title'].strip():
        return JsonError(_("Title can't be empty"))
    if 'body' not in post or not post['body'].strip():
        return JsonError(_("Body can't be empty"))

    thread = cc.Thread(**extract(post, ['body', 'title']))
    thread.update_attributes(
        **{
            'anonymous': anonymous,
            'anonymous_to_peers': anonymous_to_peers,
            'commentable_id': commentable_id,
            'course_id': course_id,
            'user_id': request.user.id,
        })

    user = cc.User.from_django_user(request.user)

    #kevinchugh because the new requirement is that all groups will be determined
    #by the group id in the request this all goes away
    #not anymore, only for admins

    # Cohort the thread if the commentable is cohorted.
    if is_commentable_cohorted(course_id, commentable_id):
        user_group_id = get_cohort_id(user, course_id)

        # TODO (vshnayder): once we have more than just cohorts, we'll want to
        # change this to a single get_group_for_user_and_commentable function
        # that can do different things depending on the commentable_id
        if cached_has_permission(request.user, "see_all_cohorts", course_id):
            # admins can optionally choose what group to post as
            group_id = post.get('group_id', user_group_id)
        else:
            # regular users always post with their own id.
            group_id = user_group_id

        if group_id:
            thread.update_attributes(group_id=group_id)

    thread.save()

    #patch for backward compatibility to comments service
    if not 'pinned' in thread.attributes:
        thread['pinned'] = False

    if post.get('auto_subscribe', 'false').lower() == 'true':
        user = cc.User.from_django_user(request.user)
        user.follow(thread)
    data = thread.to_dict()
    add_courseware_context([data], course)
    if request.is_ajax():
        return ajax_content_response(request, course_id, data)
    else:
        return JsonResponse(utils.safe_content(data))
Example #22
0
def get_threads(request, course_id, discussion_id=None, per_page=THREADS_PER_PAGE):
    """
    This may raise an appropriate subclass of cc.utils.CommentClientError
    if something goes wrong.
    """
    default_query_params = {
        'page': 1,
        'per_page': per_page,
        'sort_key': 'date',
        'sort_order': 'desc',
        'text': '',
        'commentable_id': discussion_id,
        'course_id': course_id,
        'user_id': request.user.id,
    }

    if not request.GET.get('sort_key'):
        # If the user did not select a sort key, use their last used sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.retrieve()
        # TODO: After the comment service is updated this can just be user.default_sort_key because the service returns the default value
        default_query_params['sort_key'] = cc_user.get('default_sort_key') or default_query_params['sort_key']
    else:
        # If the user clicked a sort key, update their default sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.default_sort_key = request.GET.get('sort_key')
        cc_user.save()

    #there are 2 dimensions to consider when executing a search with respect to group id
    #is user a moderator
    #did the user request a group

    #if the user requested a group explicitly, give them that group, othewrise, if mod, show all, else if student, use cohort

    group_id = request.GET.get('group_id')

    if group_id == "all":
        group_id = None

    if not group_id:
        if not cached_has_permission(request.user, "see_all_cohorts", course_id):
            group_id = get_cohort_id(request.user, course_id)

    if group_id:
        default_query_params["group_id"] = group_id

    #so by default, a moderator sees all items, and a student sees his cohort

    query_params = merge_dict(default_query_params,
                              strip_none(extract(request.GET,
                                                 ['page', 'sort_key',
                                                  'sort_order', 'text',
                                                  'commentable_ids', 'flagged'])))

    threads, page, num_pages = cc.Thread.search(query_params)

    #now add the group name if the thread has a group id
    for thread in threads:

        if thread.get('group_id'):
            thread['group_name'] = get_cohort_by_id(course_id, thread.get('group_id')).name
            thread['group_string'] = "This post visible only to Group %s." % (thread['group_name'])
        else:
            thread['group_name'] = ""
            thread['group_string'] = "This post visible to everyone."

        #patch for backward compatibility to comments service
        if not 'pinned' in thread:
            thread['pinned'] = False

    query_params['page'] = page
    query_params['num_pages'] = num_pages

    return threads, query_params
Example #23
0
def get_threads(request, course_key, discussion_id=None, per_page=THREADS_PER_PAGE):
    """
    This may raise an appropriate subclass of cc.utils.CommentClientError
    if something goes wrong, or ValueError if the group_id is invalid.
    """
    default_query_params = {
        'page': 1,
        'per_page': per_page,
        'sort_key': 'date',
        'sort_order': 'desc',
        'text': '',
        'commentable_id': discussion_id,
        'course_id': course_key.to_deprecated_string(),
        'user_id': request.user.id,
        'group_id': get_group_id_for_comments_service(request, course_key, discussion_id),  # may raise ValueError
    }

    if not request.GET.get('sort_key'):
        # If the user did not select a sort key, use their last used sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.retrieve()
        # TODO: After the comment service is updated this can just be user.default_sort_key because the service returns the default value
        default_query_params['sort_key'] = cc_user.get('default_sort_key') or default_query_params['sort_key']
    else:
        # If the user clicked a sort key, update their default sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.default_sort_key = request.GET.get('sort_key')
        cc_user.save()

    #there are 2 dimensions to consider when executing a search with respect to group id
    #is user a moderator
    #did the user request a group

    query_params = merge_dict(
        default_query_params,
        strip_none(
            extract(
                request.GET,
                [
                    'page',
                    'sort_key',
                    'sort_order',
                    'text',
                    'commentable_ids',
                    'flagged',
                    'unread',
                    'unanswered',
                ]
            )
        )
    )

    threads, page, num_pages, corrected_text = cc.Thread.search(query_params)

    for thread in threads:
        #patch for backward compatibility to comments service
        if not 'pinned' in thread:
            thread['pinned'] = False

    query_params['page'] = page
    query_params['num_pages'] = num_pages
    query_params['corrected_text'] = corrected_text

    return threads, query_params
Example #24
0
def get_threads(request, course, discussion_id=None, per_page=THREADS_PER_PAGE):
    """
    This may raise an appropriate subclass of cc.utils.CommentClientError
    if something goes wrong, or ValueError if the group_id is invalid.
    """
    default_query_params = {
        "page": 1,
        "per_page": per_page,
        "sort_key": "date",
        "sort_order": "desc",
        "text": "",
        "course_id": unicode(course.id),
        "user_id": request.user.id,
        "group_id": get_group_id_for_comments_service(request, course.id, discussion_id),  # may raise ValueError
    }

    # If provided with a discussion id, filter by discussion id in the
    # comments_service.
    if discussion_id is not None:
        default_query_params["commentable_id"] = discussion_id

    if not request.GET.get("sort_key"):
        # If the user did not select a sort key, use their last used sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.retrieve()
        # TODO: After the comment service is updated this can just be user.default_sort_key because the service returns the default value
        default_query_params["sort_key"] = cc_user.get("default_sort_key") or default_query_params["sort_key"]
    else:
        # If the user clicked a sort key, update their default sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.default_sort_key = request.GET.get("sort_key")
        cc_user.save()

    # there are 2 dimensions to consider when executing a search with respect to group id
    # is user a moderator
    # did the user request a group

    query_params = merge_dict(
        default_query_params,
        strip_none(
            extract(
                request.GET,
                ["page", "sort_key", "sort_order", "text", "commentable_ids", "flagged", "unread", "unanswered"],
            )
        ),
    )

    threads, page, num_pages, corrected_text = cc.Thread.search(query_params)

    # If not provided with a discussion id, filter threads by commentable ids
    # which are accessible to the current user.
    if discussion_id is None:
        discussion_category_ids = set(utils.get_discussion_categories_ids(course, request.user))
        threads = [thread for thread in threads if thread.get("commentable_id") in discussion_category_ids]

    for thread in threads:
        # patch for backward compatibility to comments service
        if "pinned" not in thread:
            thread["pinned"] = False

    query_params["page"] = page
    query_params["num_pages"] = num_pages
    query_params["corrected_text"] = corrected_text

    return threads, query_params
Example #25
0
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_forum',
                                    course_key,
                                    check_if_enrolled=True)
    try:
        profiled_user = cc.User(id=user_id, course_id=course_key)

        default_query_params = {
            'page': 1,
            'per_page':
            THREADS_PER_PAGE,  # more than threads_per_page to show more activities
            'sort_key': 'date',
        }

        query_params = merge_dict(
            default_query_params,
            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 newrelic_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
Example #26
0
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
Example #27
0
def get_threads(request, course, discussion_id=None, per_page=THREADS_PER_PAGE):
    """
    This may raise an appropriate subclass of cc.utils.CommentClientError
    if something goes wrong, or ValueError if the group_id is invalid.
    """
    default_query_params = {
        'page': 1,
        'per_page': per_page,
        'sort_key': 'activity',
        'sort_order': 'desc',
        'text': '',
        'course_id': unicode(course.id),
        'user_id': request.user.id,
        'context': ThreadContext.COURSE,
        'group_id': get_group_id_for_comments_service(request, course.id, discussion_id),  # may raise ValueError
    }

    # If provided with a discussion id, filter by discussion id in the
    # comments_service.
    if discussion_id is not None:
        default_query_params['commentable_id'] = discussion_id
        # Use the discussion id/commentable id to determine the context we are going to pass through to the backend.
        if get_team(discussion_id) is not None:
            default_query_params['context'] = ThreadContext.STANDALONE

    if not request.GET.get('sort_key'):
        # If the user did not select a sort key, use their last used sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.retrieve()
        # TODO: After the comment service is updated this can just be
        # user.default_sort_key because the service returns the default value
        default_query_params['sort_key'] = cc_user.get('default_sort_key') or default_query_params['sort_key']
    else:
        # If the user clicked a sort key, update their default sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.default_sort_key = request.GET.get('sort_key')
        cc_user.save()

    #there are 2 dimensions to consider when executing a search with respect to group id
    #is user a moderator
    #did the user request a group

    query_params = merge_dict(
        default_query_params,
        strip_none(
            extract(
                request.GET,
                [
                    'page',
                    'sort_key',
                    'sort_order',
                    'text',
                    'commentable_ids',
                    'flagged',
                    'unread',
                    'unanswered',
                ]
            )
        )
    )

    paginated_results = cc.Thread.search(query_params)
    threads = paginated_results.collection

    # If not provided with a discussion id, filter threads by commentable ids
    # which are accessible to the current user.
    if discussion_id is None:
        discussion_category_ids = set(utils.get_discussion_categories_ids(course, request.user))
        threads = [
            thread for thread in threads
            if thread.get('commentable_id') in discussion_category_ids
        ]

    for thread in threads:
        # patch for backward compatibility to comments service
        if 'pinned' not in thread:
            thread['pinned'] = False

    query_params['page'] = paginated_results.page
    query_params['num_pages'] = paginated_results.num_pages
    query_params['corrected_text'] = paginated_results.corrected_text

    return threads, query_params
Example #28
0
def get_threads(request,
                course_id,
                discussion_id=None,
                per_page=THREADS_PER_PAGE):
    """
    This may raise an appropriate subclass of cc.utils.CommentClientError
    if something goes wrong.
    """
    default_query_params = {
        'page': 1,
        'per_page': per_page,
        'sort_key': 'date',
        'sort_order': 'desc',
        'text': '',
        'commentable_id': discussion_id,
        'course_id': course_id,
        'user_id': request.user.id,
    }

    if not request.GET.get('sort_key'):
        # If the user did not select a sort key, use their last used sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.retrieve()
        # TODO: After the comment service is updated this can just be user.default_sort_key because the service returns the default value
        default_query_params['sort_key'] = cc_user.get(
            'default_sort_key') or default_query_params['sort_key']
    else:
        # If the user clicked a sort key, update their default sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.default_sort_key = request.GET.get('sort_key')
        cc_user.save()

    #there are 2 dimensions to consider when executing a search with respect to group id
    #is user a moderator
    #did the user request a group

    #if the user requested a group explicitly, give them that group, othewrise, if mod, show all, else if student, use cohort

    group_id = request.GET.get('group_id')

    if group_id == "all":
        group_id = None

    if not group_id:
        if not cached_has_permission(request.user, "see_all_cohorts",
                                     course_id):
            group_id = get_cohort_id(request.user, course_id)

    if group_id:
        default_query_params["group_id"] = group_id

    #so by default, a moderator sees all items, and a student sees his cohort

    query_params = merge_dict(
        default_query_params,
        strip_none(
            extract(request.GET, [
                'page', 'sort_key', 'sort_order', 'text', 'commentable_ids',
                'flagged'
            ])))

    threads, page, num_pages = cc.Thread.search(query_params)

    #now add the group name if the thread has a group id
    for thread in threads:

        if thread.get('group_id'):
            thread['group_name'] = get_cohort_by_id(
                course_id, thread.get('group_id')).name
            thread['group_string'] = "This post visible only to Group %s." % (
                thread['group_name'])
        else:
            thread['group_name'] = ""
            thread['group_string'] = "This post visible to everyone."

        #patch for backward compatibility to comments service
        if not 'pinned' in thread:
            thread['pinned'] = False

    query_params['page'] = page
    query_params['num_pages'] = num_pages

    return threads, query_params
Example #29
0
def followed_threads(request, course_key, user_id):
    """
    Ajax-only endpoint retrieving the threads followed by a specific user.
    """

    #    nr_transaction = newrelic.agent.current_transaction()

    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)

        default_query_params = {
            "page": 1,
            "per_page": THREADS_PER_PAGE,  # more than threads_per_page to show more activities
            "sort_key": "date",
            "sort_order": "desc",
        }

        query_params = merge_dict(
            default_query_params,
            strip_none(extract(request.GET, ["page", "sort_key", "sort_order", "flagged", "unread", "unanswered"])),
        )

        try:
            group_id = get_group_id_for_comments_service(request, course_key)
        except ValueError:
            return HttpResponseBadRequest("Invalid group_id")
        if group_id is not None:
            query_params["group_id"] = group_id

        threads, page, num_pages = profiled_user.subscribed_threads(query_params)
        query_params["page"] = page
        query_params["num_pages"] = num_pages
        user_info = cc.User.from_django_user(request.user).to_dict()

        #        with newrelic.agent.FunctionTrace(nr_transaction, "get_metadata_for_threads"):
        annotated_content_info = utils.get_metadata_for_threads(course_key, threads, 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 threads],
                    "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": _attr_safe_json(threads),
                "user_info": _attr_safe_json(user_info),
                "annotated_content_info": _attr_safe_json(annotated_content_info),
                #                'content': content,
            }

            return render_to_response("discussion/user_profile.html", context)
    except User.DoesNotExist:
        raise Http404
Example #30
0
def create_thread(request, course_id, commentable_id):
    """
    Given a course and commentble ID, create the thread
    """

    log.debug("Creating new thread in %r, id %r", course_id, commentable_id)
    course = get_course_with_access(request.user, course_id, 'load')
    post = request.POST

    if course.allow_anonymous:
        anonymous = post.get('anonymous', 'false').lower() == 'true'
    else:
        anonymous = False

    if course.allow_anonymous_to_peers:
        anonymous_to_peers = post.get('anonymous_to_peers', 'false').lower() == 'true'
    else:
        anonymous_to_peers = False

    if 'title' not in post or not post['title'].strip():
        return JsonError(_("Title can't be empty"))
    if 'body' not in post or not post['body'].strip():
        return JsonError(_("Body can't be empty"))

    thread = cc.Thread(**extract(post, ['body', 'title']))
    thread.update_attributes(**{
        'anonymous': anonymous,
        'anonymous_to_peers': anonymous_to_peers,
        'commentable_id': commentable_id,
        'course_id': course_id,
        'user_id': request.user.id,
    })

    user = cc.User.from_django_user(request.user)

    #kevinchugh because the new requirement is that all groups will be determined
    #by the group id in the request this all goes away
    #not anymore, only for admins

    # Cohort the thread if the commentable is cohorted.
    if is_commentable_cohorted(course_id, commentable_id):
        user_group_id = get_cohort_id(user, course_id)

        # TODO (vshnayder): once we have more than just cohorts, we'll want to
        # change this to a single get_group_for_user_and_commentable function
        # that can do different things depending on the commentable_id
        if cached_has_permission(request.user, "see_all_cohorts", course_id):
            # admins can optionally choose what group to post as
            group_id = post.get('group_id', user_group_id)
        else:
            # regular users always post with their own id.
            group_id = user_group_id

        if group_id:
            thread.update_attributes(group_id=group_id)

    thread.save()

    #patch for backward compatibility to comments service
    if not 'pinned' in thread.attributes:
        thread['pinned'] = False

    if post.get('auto_subscribe', 'false').lower() == 'true':
        user = cc.User.from_django_user(request.user)
        user.follow(thread)
    data = thread.to_dict()
    add_courseware_context([data], course)
    if request.is_ajax():
        return ajax_content_response(request, course_id, data)
    else:
        return JsonResponse(utils.safe_content(data))
Example #31
0
def mobi_create_thread(request, course_id, topic_id):
    """
    Given a course and commentable_id from mobile. create the thread
    """
    course_id = course_id.replace('.', '/')
    log.debug("Creating new thread in %r, id %r", course_id, topic_id)
    course = get_course_with_access(request.user, course_id, 'load')
    post = request.POST

    if course.allow_anonymous:
        anonymous = post.get('anonymous', 'false').lower() == 'true'
    else:
        anonymous = False

    if course.allow_anonymous_to_peers:
        anonymous_to_peers = post.get('anonymous_to_peers', 'false').lower() == 'true'
    else:
        anonymous_to_peers = False

    if 'title' not in post or not post['title'].strip():
        return JsonResponse({'success': False, 'errmsg': "Title can't be empty"})
    if 'body' not in post or not post['body'].strip():
        return JsonResponse({'success': False, 'errmsg': "Body can't be empty"})

    thread = cc.Thread(**extract(post, ['body', 'title']))

    user = cc.User.from_django_user(request.user)

    thread.update_attributes(**{
        'anonymous': anonymous,
        'anonymous_to_peers': anonymous_to_peers,
        'commentable_id': topic_id,
        'course_id': course_id,
        'user_id': request.user.id,
    })

    if is_commentable_cohorted(course_id, topic_id):
        user_group_id = get_cohort_id(user, course_id)

        # TODO (vshnayder): once we have more than just cohorts, we'll want to
        # change this to a single get_group_for_user_and_commentable function
        # that can do different things depending on the commentable_id
        if cached_has_permission(request.user, "see_all_cohorts", course_id):
            # admins can optionally choose what group to post as
            group_id = post.get('group_id', user_group_id)
        else:
            # regular users always post with their own id.
            group_id = user_group_id

        if group_id:
            thread.update_attributes(group_id=group_id)

    thread.save()

    if not 'pinned' in thread.attributes:
        thread['pinned'] = False

    # if post.get('auto_subscribe', 'false').lower() == 'true':
    user = cc.User.from_django_user(request.user)
    user.follow(thread)

    return JsonResponse({"success": True})
Example #32
0
 def test_extract(self):
     d = {'cats': 'meow', 'dogs': 'woof'}
     k = ['cats', 'dogs', 'hamsters']
     expected = {'cats': 'meow', 'dogs': 'woof', 'hamsters': None}
     self.assertEqual(utils.extract(d, k), expected)
Example #33
0
def mobi_create_thread(request, course_id, topic_id):
    """
    Given a course and commentable_id from mobile. create the thread
    """
    course_id = course_id.replace('.', '/')
    log.debug("Creating new thread in %r, id %r", course_id, topic_id)
    course = get_course_with_access(request.user, course_id, 'load')
    post = request.POST

    if course.allow_anonymous:
        anonymous = post.get('anonymous', 'false').lower() == 'true'
    else:
        anonymous = False

    if course.allow_anonymous_to_peers:
        anonymous_to_peers = post.get('anonymous_to_peers',
                                      'false').lower() == 'true'
    else:
        anonymous_to_peers = False

    if 'title' not in post or not post['title'].strip():
        return JsonResponse({
            'success': False,
            'errmsg': "Title can't be empty"
        })
    if 'body' not in post or not post['body'].strip():
        return JsonResponse({
            'success': False,
            'errmsg': "Body can't be empty"
        })

    thread = cc.Thread(**extract(post, ['body', 'title']))

    user = cc.User.from_django_user(request.user)

    thread.update_attributes(
        **{
            'anonymous': anonymous,
            'anonymous_to_peers': anonymous_to_peers,
            'commentable_id': topic_id,
            'course_id': course_id,
            'user_id': request.user.id,
        })

    if is_commentable_cohorted(course_id, topic_id):
        user_group_id = get_cohort_id(user, course_id)

        # TODO (vshnayder): once we have more than just cohorts, we'll want to
        # change this to a single get_group_for_user_and_commentable function
        # that can do different things depending on the commentable_id
        if cached_has_permission(request.user, "see_all_cohorts", course_id):
            # admins can optionally choose what group to post as
            group_id = post.get('group_id', user_group_id)
        else:
            # regular users always post with their own id.
            group_id = user_group_id

        if group_id:
            thread.update_attributes(group_id=group_id)

    thread.save()

    if not 'pinned' in thread.attributes:
        thread['pinned'] = False

    # if post.get('auto_subscribe', 'false').lower() == 'true':
    user = cc.User.from_django_user(request.user)
    user.follow(thread)

    return JsonResponse({"success": True})
Example #34
0
 def test_extract(self):
     d = {'cats': 'meow', 'dogs': 'woof'}
     k = ['cats', 'dogs', 'hamsters']
     expected = {'cats': 'meow', 'dogs': 'woof', 'hamsters': None}
     self.assertEqual(utils.extract(d, k), expected)
Example #35
0
def get_threads(request,
                course,
                user_info,
                discussion_id=None,
                per_page=THREADS_PER_PAGE):
    """
    This may raise an appropriate subclass of cc.utils.CommentClientError
    if something goes wrong, or ValueError if the group_id is invalid.

    Arguments:
        request (WSGIRequest): The user request.
        course (CourseDescriptorWithMixins): The course object.
        user_info (dict): The comment client User object as a dict.
        discussion_id (unicode): Optional discussion id/commentable id for context.
        per_page (int): Optional number of threads per page.

    Returns:
        (tuple of list, dict): A tuple of the list of threads and a dict of the
            query parameters used for the search.

    """
    default_query_params = {
        'page':
        1,
        'per_page':
        per_page,
        'sort_key':
        'activity',
        'text':
        '',
        'course_id':
        unicode(course.id),
        'user_id':
        request.user.id,
        'context':
        ThreadContext.COURSE,
        'group_id':
        get_group_id_for_comments_service(
            request, course.id, discussion_id),  # may raise ValueError
    }

    # If provided with a discussion id, filter by discussion id in the
    # comments_service.
    if discussion_id is not None:
        default_query_params['commentable_id'] = discussion_id
        # Use the discussion id/commentable id to determine the context we are going to pass through to the backend.
        if get_team(discussion_id) is not None:
            default_query_params['context'] = ThreadContext.STANDALONE

    if not request.GET.get('sort_key'):
        # If the user did not select a sort key, use their last used sort key
        default_query_params['sort_key'] = user_info.get(
            'default_sort_key') or default_query_params['sort_key']

    elif request.GET.get('sort_key') != user_info.get('default_sort_key'):
        # If the user clicked a sort key, update their default sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.default_sort_key = request.GET.get('sort_key')
        cc_user.save()

    #there are 2 dimensions to consider when executing a search with respect to group id
    #is user a moderator
    #did the user request a group

    # if the user requested a group explicitly, give them that group, otherwise, if mod, show all, else if student, use cohort

    if discussion_id:
        is_cohorted = is_commentable_divided(course.id, discussion_id)
    else:
        is_cohorted = is_course_cohorted(course.id)

    if has_permission(request.user, "see_all_cohorts", course.id):
        group_id = request.GET.get('group_id')
        if group_id in ("all", "None"):
            group_id = None
    else:
        group_id = get_cohort_id(request.user, course.id)
        if not group_id:
            default_query_params['exclude_groups'] = True

    if group_id:
        group_id = int(group_id)
        try:
            CourseUserGroup.objects.get(course_id=course.id, id=group_id)
        except CourseUserGroup.DoesNotExist:
            if not is_cohorted:
                group_id = None
            else:
                raise ValueError("Invalid Group ID")
        default_query_params["group_id"] = group_id

    #so by default, a moderator sees all items, and a student sees his cohort

    query_params = default_query_params.copy()
    query_params.update(
        strip_none(
            extract(request.GET, [
                'page',
                'sort_key',
                'text',
                'commentable_ids',
                'flagged',
                'unread',
                'unanswered',
            ])))

    if not is_cohorted:
        query_params.pop('group_id', None)

    paginated_results = cc.Thread.search(query_params)
    threads = paginated_results.collection

    # If not provided with a discussion id, filter threads by commentable ids
    # which are accessible to the current user.
    if discussion_id is None:
        discussion_category_ids = set(
            utils.get_discussion_categories_ids(course, request.user))
        threads = [
            thread for thread in threads
            if thread.get('commentable_id') in discussion_category_ids
        ]

    for thread in threads:
        # patch for backward compatibility to comments service
        if 'pinned' not in thread:
            thread['pinned'] = False

    query_params['page'] = paginated_results.page
    query_params['num_pages'] = paginated_results.num_pages
    query_params['corrected_text'] = paginated_results.corrected_text

    return threads, query_params
Example #36
0
def get_threads(request,
                course,
                discussion_id=None,
                per_page=THREADS_PER_PAGE):
    """
    This may raise an appropriate subclass of cc.utils.CommentClientError
    if something goes wrong, or ValueError if the group_id is invalid.
    """
    default_query_params = {
        'page':
        1,
        'per_page':
        per_page,
        'sort_key':
        'date',
        'sort_order':
        'desc',
        'text':
        '',
        'course_id':
        unicode(course.id),
        'user_id':
        request.user.id,
        'group_id':
        get_group_id_for_comments_service(
            request, course.id, discussion_id),  # may raise ValueError
    }

    # If provided with a discussion id, filter by discussion id in the
    # comments_service.
    if discussion_id is not None:
        default_query_params['commentable_id'] = discussion_id

    if not request.GET.get('sort_key'):
        # If the user did not select a sort key, use their last used sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.retrieve()
        # TODO: After the comment service is updated this can just be user.default_sort_key because the service returns the default value
        default_query_params['sort_key'] = cc_user.get(
            'default_sort_key') or default_query_params['sort_key']
    else:
        # If the user clicked a sort key, update their default sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.default_sort_key = request.GET.get('sort_key')
        cc_user.save()

    #there are 2 dimensions to consider when executing a search with respect to group id
    #is user a moderator
    #did the user request a group

    query_params = merge_dict(
        default_query_params,
        strip_none(
            extract(request.GET, [
                'page',
                'sort_key',
                'sort_order',
                'text',
                'commentable_ids',
                'flagged',
                'unread',
                'unanswered',
            ])))

    threads, page, num_pages, corrected_text = cc.Thread.search(query_params)

    # If not provided with a discussion id, filter threads by commentable ids
    # which are accessible to the current user.
    if discussion_id is None:
        discussion_category_ids = set(
            utils.get_discussion_categories_ids(course, request.user))
        threads = [
            thread for thread in threads
            if thread.get('commentable_id') in discussion_category_ids
        ]

    for thread in threads:
        # patch for backward compatibility to comments service
        if 'pinned' not in thread:
            thread['pinned'] = False

    query_params['page'] = page
    query_params['num_pages'] = num_pages
    query_params['corrected_text'] = corrected_text

    return threads, query_params
Example #37
0
 def test_extract(self):
     d = {"cats": "meow", "dogs": "woof"}
     k = ["cats", "dogs", "hamsters"]
     expected = {"cats": "meow", "dogs": "woof", "hamsters": None}
     self.assertEqual(utils.extract(d, k), expected)
Example #38
0
def get_threads(request, course, user_info, discussion_id=None, per_page=THREADS_PER_PAGE):
    """
    This may raise an appropriate subclass of cc.utils.CommentClientError
    if something goes wrong, or ValueError if the group_id is invalid.

    Arguments:
        request (WSGIRequest): The user request.
        course (CourseDescriptorWithMixins): The course object.
        user_info (dict): The comment client User object as a dict.
        discussion_id (unicode): Optional discussion id/commentable id for context.
        per_page (int): Optional number of threads per page.

    Returns:
        (tuple of list, dict): A tuple of the list of threads and a dict of the
            query parameters used for the search.

    """
    default_query_params = {
        'page': 1,
        'per_page': per_page,
        'sort_key': 'activity',
        'text': '',
        'course_id': unicode(course.id),
        'user_id': request.user.id,
        'context': ThreadContext.COURSE,
        'group_id': get_group_id_for_comments_service(request, course.id, discussion_id),  # may raise ValueError
    }

    # If provided with a discussion id, filter by discussion id in the
    # comments_service.
    if discussion_id is not None:
        default_query_params['commentable_id'] = discussion_id
        # Use the discussion id/commentable id to determine the context we are going to pass through to the backend.
        if get_team(discussion_id) is not None:
            default_query_params['context'] = ThreadContext.STANDALONE

    if not request.GET.get('sort_key'):
        # If the user did not select a sort key, use their last used sort key
        default_query_params['sort_key'] = user_info.get('default_sort_key') or default_query_params['sort_key']

    elif request.GET.get('sort_key') != user_info.get('default_sort_key'):
        # If the user clicked a sort key, update their default sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.default_sort_key = request.GET.get('sort_key')
        cc_user.save()

    #there are 2 dimensions to consider when executing a search with respect to group id
    #is user a moderator
    #did the user request a group

    query_params = default_query_params.copy()
    query_params.update(
        strip_none(
            extract(
                request.GET,
                [
                    'page',
                    'sort_key',
                    'text',
                    'commentable_ids',
                    'flagged',
                    'unread',
                    'unanswered',
                ]
            )
        )
    )

    paginated_results = cc.Thread.search(query_params)
    threads = paginated_results.collection

    # If not provided with a discussion id, filter threads by commentable ids
    # which are accessible to the current user.
    if discussion_id is None:
        discussion_category_ids = set(utils.get_discussion_categories_ids(course, request.user))
        threads = [
            thread for thread in threads
            if thread.get('commentable_id') in discussion_category_ids
        ]

    for thread in threads:
        # patch for backward compatibility to comments service
        if 'pinned' not in thread:
            thread['pinned'] = False

    query_params['page'] = paginated_results.page
    query_params['num_pages'] = paginated_results.num_pages
    query_params['corrected_text'] = paginated_results.corrected_text

    return threads, query_params
Example #39
0
def get_threads(request, course, discussion_id=None, per_page=THREADS_PER_PAGE):
    """
    This may raise an appropriate subclass of cc.utils.CommentClientError
    if something goes wrong. It may also raise ValueError if the group_id is invalid.
    """
    default_query_params = {
        'page': 1,
        'per_page': per_page,
        'sort_key': 'date',
        'sort_order': 'desc',
        'text': '',
        'course_id': unicode(course.id),
        'commentable_id': discussion_id,
        'user_id': request.user.id,
        'group_id': get_group_id_for_comments_service(request, course.id, discussion_id),  # may raise ValueError
    }

    # If provided with a discussion id, filter by discussion id in the
    # comments_service.
    if discussion_id is not None:
        default_query_params['commentable_id'] = discussion_id

    if not request.GET.get('sort_key'):
        # If the user did not select a sort key, use their last used sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.retrieve()
        # TODO: After the comment service is updated this can just be user.default_sort_key because the service returns the default value
        default_query_params['sort_key'] = cc_user.get('default_sort_key') or default_query_params['sort_key']
    else:
        # If the user clicked a sort key, update their default sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.default_sort_key = request.GET.get('sort_key')
        cc_user.save()

    #there are 2 dimensions to consider when executing a search with respect to group id
    #is user a moderator
    #did the user request a group

    #if the user requested a group explicitly, give them that group, otherwise, if mod, show all, else if student, use cohort

    is_cohorted = is_commentable_cohorted(course.id, discussion_id)

    if has_permission(request.user, "see_all_cohorts", course.id):
        group_id = request.GET.get('group_id')
        if group_id in ("all", "None"):
            group_id = None
    else:
        group_id = get_cohort_id(request.user, course.id)
        if not group_id:
            default_query_params['exclude_groups'] = True

    if group_id:
        group_id = int(group_id)
        try:
            CourseUserGroup.objects.get(course_id=course.id, id=group_id)
        except CourseUserGroup.DoesNotExist:
            if not is_cohorted:
                group_id = None
            else:
                raise ValueError("Invalid Group ID")
        default_query_params["group_id"] = group_id

    #so by default, a moderator sees all items, and a student sees his cohort

    query_params = merge_dict(
        default_query_params,
        strip_none(
            extract(
                request.GET,
                [
                    'page',
                    'sort_key',
                    'sort_order',
                    'text',
                    'commentable_ids',
                    'flagged',
                    'unread',
                    'unanswered',
                ]
            )
        )
    )

    if not is_cohorted:
        query_params.pop('group_id', None)

    threads, page, num_pages, corrected_text = cc.Thread.search(query_params)
    threads = _set_group_names(course.id, threads)

    query_params['page'] = page
    query_params['num_pages'] = num_pages
    query_params['corrected_text'] = corrected_text

    return threads, query_params
Example #40
0
def get_threads(request,
                course,
                user_info,
                discussion_id=None,
                per_page=THREADS_PER_PAGE):
    """
    This may raise an appropriate subclass of cc.utils.CommentClientError
    if something goes wrong, or ValueError if the group_id is invalid.

    Arguments:
        request (WSGIRequest): The user request.
        course (CourseDescriptorWithMixins): The course object.
        user_info (dict): The comment client User object as a dict.
        discussion_id (unicode): Optional discussion id/commentable id for context.
        per_page (int): Optional number of threads per page.

    Returns:
        (tuple of list, dict): A tuple of the list of threads and a dict of the
            query parameters used for the search.

    """
    default_query_params = {
        'page':
        1,
        'per_page':
        per_page,
        'sort_key':
        'activity',
        'text':
        '',
        'course_id':
        unicode(course.id),
        'user_id':
        request.user.id,
        'context':
        ThreadContext.COURSE,
        'group_id':
        get_group_id_for_comments_service(
            request, course.id, discussion_id),  # may raise ValueError
    }

    # If provided with a discussion id, filter by discussion id in the
    # comments_service.
    if discussion_id is not None:
        default_query_params['commentable_id'] = discussion_id
        # Use the discussion id/commentable id to determine the context we are going to pass through to the backend.
        if get_team(discussion_id) is not None:
            default_query_params['context'] = ThreadContext.STANDALONE

    if not request.GET.get('sort_key'):
        # If the user did not select a sort key, use their last used sort key
        default_query_params['sort_key'] = user_info.get(
            'default_sort_key') or default_query_params['sort_key']

    elif request.GET.get('sort_key') != user_info.get('default_sort_key'):
        # If the user clicked a sort key, update their default sort key
        cc_user = cc.User.from_django_user(request.user)
        cc_user.default_sort_key = request.GET.get('sort_key')
        cc_user.save()

    #there are 2 dimensions to consider when executing a search with respect to group id
    #is user a moderator
    #did the user request a group

    query_params = merge_dict(
        default_query_params,
        strip_none(
            extract(request.GET, [
                'page',
                'sort_key',
                'text',
                'commentable_ids',
                'flagged',
                'unread',
                'unanswered',
            ])))

    paginated_results = cc.Thread.search(query_params)
    threads = paginated_results.collection

    # If not provided with a discussion id, filter threads by commentable ids
    # which are accessible to the current user.
    if discussion_id is None:
        discussion_category_ids = set(
            utils.get_discussion_categories_ids(course, request.user))
        threads = [
            thread for thread in threads
            if thread.get('commentable_id') in discussion_category_ids
        ]

    for thread in threads:
        # patch for backward compatibility to comments service
        if 'pinned' not in thread:
            thread['pinned'] = False

    query_params['page'] = paginated_results.page
    query_params['num_pages'] = paginated_results.num_pages
    query_params['corrected_text'] = paginated_results.corrected_text

    return threads, query_params
Example #41
0
def followed_threads(request, course_id, user_id):
    course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    nr_transaction = newrelic.agent.current_transaction()

    course = get_course_with_access(request.user, 'load_forum', course_key)
    try:
        profiled_user = cc.User(id=user_id, course_id=course_key)

        default_query_params = {
            'page': 1,
            'per_page': THREADS_PER_PAGE,   # more than threads_per_page to show more activities
            'sort_key': 'date',
            'sort_order': 'desc',
        }

        query_params = merge_dict(
            default_query_params,
            strip_none(
                extract(
                    request.GET,
                    [
                        'page',
                        'sort_key',
                        'sort_order',
                        'flagged',
                        'unread',
                        'unanswered',
                    ]
                )
            )
        )

        try:
            group_id = get_group_id_for_comments_service(request, course_key)
        except ValueError:
            return HttpResponseBadRequest("Invalid group_id")
        if group_id is not None:
            query_params['group_id'] = group_id

        threads, page, num_pages = profiled_user.subscribed_threads(query_params)
        query_params['page'] = page
        query_params['num_pages'] = num_pages
        user_info = cc.User.from_django_user(request.user).to_dict()

        with newrelic.agent.FunctionTrace(nr_transaction, "get_metadata_for_threads"):
            annotated_content_info = utils.get_metadata_for_threads(course_key, threads, request.user, user_info)
        if request.is_ajax():
            is_staff = cached_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 threads],
                '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': _attr_safe_json(threads),
                'user_info': _attr_safe_json(user_info),
                'annotated_content_info': _attr_safe_json(annotated_content_info),
                #                'content': content,
            }

            return render_to_response('discussion/user_profile.html', context)
    except User.DoesNotExist:
        raise Http404