예제 #1
0
def next_course_to_review():
    current_user = view_helpers.get_current_user()
    uc = current_user.next_course_to_review() if current_user else None
    if not uc:
        return util.json_dumps({})

    uc.select_for_review(current_user)
    return util.json_dumps(uc.to_dict())
예제 #2
0
파일: server.py 프로젝트: Kapin/rmc
def next_course_to_review():
    current_user = view_helpers.get_current_user()
    uc = current_user.next_course_to_review() if current_user else None
    if not uc:
        return util.json_dumps({})

    uc.select_for_review(current_user)
    return util.json_dumps(uc.to_dict())
예제 #3
0
def schedule_screenshot_url():
    user = view_helpers.get_current_user()

    return util.json_dumps({
        # Note that this may be None
        "url": schedule_screenshot.get_screenshot_url(user)
    })
예제 #4
0
파일: server.py 프로젝트: Kapin/rmc
def user_course_share():
    user_course_id = flask.request.form['user_course_id']
    review_type = flask.request.form['review_type']
    current_user = view_helpers.get_current_user()

    review = None
    points_gained = 0

    user_course = m.UserCourse.objects.get(
            id=user_course_id, user_id=current_user.id)
    if review_type == 'course':
        review = user_course.course_review
        points_gained = m.PointSource.SHARE_COURSE_REVIEW
    elif review_type == 'professor':
        review = user_course.professor_review
        points_gained = m.PointSource.SHARE_PROFESSOR_REVIEW

    # Only award points on the first share
    if not review.share_date:
        redis = view_helpers.get_redis_instance()
        current_user.award_points(points_gained, redis)
    else:
        points_gained = 0

    review.share_date = datetime.now()
    user_course.save()
    current_user.save()

    return util.json_dumps({
        'points_gained': points_gained,
    })
예제 #5
0
파일: server.py 프로젝트: Kapin/rmc
def search_courses():
    current_user = view_helpers.get_current_user()
    courses, has_more = m.Course.search(flask.request.values, current_user)

    course_dict_list, user_course_dict_list, user_course_list = (
            m.Course.get_course_and_user_course_dicts(
                courses, current_user, include_friends=True,
                full_user_courses=False, include_sections=True))

    professor_dict_list = m.Professor.get_reduced_professors_for_courses(
            courses)

    user_dict_list = []
    if current_user:
        user_ids = [uc['user_id'] for uc in user_course_dict_list
                if uc['user_id'] != current_user.id]
        users = m.User.objects(id__in=user_ids).only(*m.User.CORE_FIELDS)
        user_dict_list = [u.to_dict() for u in users]

    return util.json_dumps({
        'user_objs': user_dict_list,
        'course_objs': course_dict_list,
        'professor_objs': professor_dict_list,
        'user_course_objs': user_course_dict_list,
        'has_more': has_more,
    })
예제 #6
0
def user_course_share():
    user_course_id = flask.request.form['user_course_id']
    review_type = flask.request.form['review_type']
    current_user = view_helpers.get_current_user()

    review = None
    points_gained = 0

    user_course = m.UserCourse.objects.get(id=user_course_id,
                                           user_id=current_user.id)
    if review_type == 'course':
        review = user_course.course_review
        points_gained = m.PointSource.SHARE_COURSE_REVIEW
    elif review_type == 'professor':
        review = user_course.professor_review
        points_gained = m.PointSource.SHARE_PROFESSOR_REVIEW

    # Only award points on the first share
    if not review.share_date:
        redis = view_helpers.get_redis_instance()
        current_user.award_points(points_gained, redis)
    else:
        points_gained = 0

    review.share_date = datetime.now()
    user_course.save()
    current_user.save()

    return util.json_dumps({
        'points_gained': points_gained,
    })
예제 #7
0
파일: server.py 프로젝트: Kapin/rmc
def schedule_screenshot_url():
    user = view_helpers.get_current_user()

    return util.json_dumps({
        # Note that this may be None
        "url": schedule_screenshot.get_screenshot_url(user)
    })
예제 #8
0
def search_courses():
    current_user = view_helpers.get_current_user()
    courses, has_more = m.Course.search(flask.request.values, current_user)

    course_dict_list, user_course_dict_list, user_course_list = (
        m.Course.get_course_and_user_course_dicts(courses,
                                                  current_user,
                                                  include_friends=True,
                                                  full_user_courses=False,
                                                  include_sections=True))

    professor_dict_list = m.Professor.get_reduced_professors_for_courses(
        courses)

    user_dict_list = []
    if current_user:
        user_ids = [
            uc['user_id'] for uc in user_course_dict_list
            if uc['user_id'] != current_user.id
        ]
        users = m.User.objects(id__in=user_ids).only(*m.User.CORE_FIELDS)
        user_dict_list = [u.to_dict() for u in users]

    return util.json_dumps({
        'user_objs': user_dict_list,
        'course_objs': course_dict_list,
        'professor_objs': professor_dict_list,
        'user_course_objs': user_course_dict_list,
        'has_more': has_more,
    })
예제 #9
0
def get_courses(course_ids):
    course_ids = [c.lower() for c in course_ids.split(',')]
    courses = m.Course.objects(id__in=course_ids, )

    # TODO(mack): not currently being called, fix it when it is needed
    # course_objs = map(clean_course, courses)
    course_objs = []
    professor_objs = m.Professor.get_reduced_professor_for_courses(courses)

    return util.json_dumps({
        'course_objs': course_objs,
        'professor_objs': professor_objs,
    })
예제 #10
0
파일: server.py 프로젝트: Kapin/rmc
def invite_friend():
    current_user = view_helpers.get_current_user()
    orig_points = current_user.num_points

    current_user.invite_friend(view_helpers.get_redis_instance())
    current_user.save()

    points_gained = current_user.num_points - orig_points

    return util.json_dumps({
        'num_invites': current_user.num_invites,
        'points_gained': points_gained,
    })
예제 #11
0
def invite_friend():
    current_user = view_helpers.get_current_user()
    orig_points = current_user.num_points

    current_user.invite_friend(view_helpers.get_redis_instance())
    current_user.save()

    points_gained = current_user.num_points - orig_points

    return util.json_dumps({
        'num_invites': current_user.num_invites,
        'points_gained': points_gained,
    })
예제 #12
0
def last_schedule_paste():

    user_id = flask.request.values.get('user_id')
    if not user_id:
        user_id = view_helpers.get_current_user().id
    else:
        user_id = bson.ObjectId(user_id)

    user = m.User.objects.with_id(user_id)
    last_schedule_paste = user.last_schedule_paste

    return util.json_dumps({
        'last_schedule_paste': last_schedule_paste,
    })
예제 #13
0
def add_course_to_shortlist():
    current_user = view_helpers.get_current_user()

    user_course = m.UserCourse(
        user_id=current_user.id,
        course_id=flask.request.form.get('course_id'),
        term_id=m.Term.SHORTLIST_TERM_ID,
    )
    user_course.save()
    current_user.update(add_to_set__course_history=user_course.id)

    return util.json_dumps({
        'user_course': user_course.to_dict(),
    })
예제 #14
0
파일: server.py 프로젝트: sunapi386/rmc
def add_course_to_shortlist():
    current_user = view_helpers.get_current_user()

    user_course = m.UserCourse(
        user_id=current_user.id,
        course_id=flask.request.form.get('course_id'),
        term_id=m.Term.SHORTLIST_TERM_ID,
    )
    user_course.save()
    current_user.update(add_to_set__course_history=user_course.id)

    return util.json_dumps({
        'user_course': user_course.to_dict(),
    })
예제 #15
0
파일: server.py 프로젝트: Kapin/rmc
def last_schedule_paste():

    user_id = flask.request.values.get('user_id')
    if not user_id:
        user_id = view_helpers.get_current_user().id
    else:
        user_id = bson.ObjectId(user_id)

    user = m.User.objects.with_id(user_id)
    last_schedule_paste = user.last_schedule_paste

    return util.json_dumps({
        'last_schedule_paste': last_schedule_paste,
    })
예제 #16
0
파일: server.py 프로젝트: Kapin/rmc
def get_courses(course_ids):
    course_ids = [c.lower() for c in course_ids.split(',')]
    courses = m.Course.objects(
      id__in=course_ids,
    )

    # TODO(mack): not currently being called, fix it when it is needed
    # course_objs = map(clean_course, courses)
    course_objs = []
    professor_objs = m.Professor.get_reduced_professor_for_courses(courses)

    return util.json_dumps({
        'course_objs': course_objs,
        'professor_objs': professor_objs,
    })
예제 #17
0
def pasted_schedule_users():
    include_good_paste = bool(flask.request.values.get('include_good_paste'))
    include_bad_paste = bool(flask.request.values.get('include_bad_paste'))

    # Start off with a query that maches no one
    query = me.Q(id__exists=False)
    if include_good_paste:
        query = query | me.Q(last_good_schedule_paste__exists=True)
    if include_bad_paste:
        query = query | me.Q(last_bad_schedule_paste__exists=True)

    users = m.User.objects.filter(query).only('id')
    user_ids = [user.id for user in users]
    print 'num_users', len(user_ids)
    return util.json_dumps({
        'user_ids': user_ids,
    })
예제 #18
0
파일: server.py 프로젝트: Kapin/rmc
def pasted_schedule_users():
    include_good_paste = bool(flask.request.values.get('include_good_paste'))
    include_bad_paste = bool(flask.request.values.get('include_bad_paste'))

    # Start off with a query that maches no one
    query = me.Q(id__exists=False)
    if include_good_paste:
        query = query | me.Q(last_good_schedule_paste__exists=True)
    if include_bad_paste:
        query = query | me.Q(last_bad_schedule_paste__exists=True)

    users = m.User.objects.filter(query).only('id')
    user_ids = [user.id for user in users]
    print 'num_users', len(user_ids)
    return util.json_dumps({
        'user_ids': user_ids,
    })
예제 #19
0
 def test_json_dumps_prevents_xss(self):
     self.assertEquals('["<\\/script>"]', util.json_dumps(["</script>"]))
예제 #20
0
파일: server.py 프로젝트: Kapin/rmc
def user_course():
    uc_data = util.json_loads(flask.request.data)
    user = view_helpers.get_current_user()

    rmclogger.log_event(
        rmclogger.LOG_CATEGORY_API,
        rmclogger.LOG_EVENT_USER_COURSE, {
            'uc_data': uc_data,
            'user_id': user.id,
        },
    )

    # Validate request object
    course_id = uc_data.get('course_id')
    term_id = uc_data.get('term_id')
    if course_id is None or term_id is None:
        logging.error("/api/user/course got course_id (%s) and term_id (%s)" %
            (course_id, term_id))
        # TODO(david): Perhaps we should have a request error function that
        # returns a 400
        raise exceptions.ImATeapot('No course_id or term_id set')

    if not m.UserCourse.can_review(term_id):
        logging.warning("%s attempted to rate %s in future/shortlist term %s"
                % (user.id, course_id, term_id))
        raise exceptions.ImATeapot(
                "Can't review a course in the future or shortlist")

    # Fetch existing UserCourse
    uc = m.UserCourse.objects(
        user_id=user.id,
        course_id=uc_data['course_id'],
        term_id=uc_data['term_id']
    ).first()

    if uc is None:
        logging.error("/api/user/course User course not found for "
            "user_id=%s course_id=%s term_id=%s" %
            (user.id, course_id, term_id))
        # TODO(david): Perhaps we should have a request error function that
        # returns a 400
        raise exceptions.ImATeapot('No user course found')

    orig_points = uc.num_points

    # TODO(Sandy): Consider the case where the user picked a professor and
    # rates them, but then changes the professor. We need to remove the ratings
    # from the old prof's aggregated ratings and add them to the new prof's
    # Maybe create professor if newly added
    if uc_data.get('new_prof_added'):

        new_prof_name = uc_data['new_prof_added']

        # TODO(mack): should do guess_names first, and use that to
        # generate the id
        prof_id = m.Professor.get_id_from_name(new_prof_name)
        uc.professor_id = prof_id

        # TODO(Sandy): Have some kind of sanity check for professor names.
        # Don't allow ridiculousness like "Santa Claus", "aksnlf",
        # "swear words"
        if m.Professor.objects(id=prof_id).count() == 0:
            first_name, last_name = m.Professor.guess_names(new_prof_name)
            m.Professor(
                id=prof_id,
                first_name=first_name,
                last_name=last_name,
            ).save()

        course = m.Course.objects.with_id(uc.course_id)
        course.professor_ids = list(set(course.professor_ids) | {prof_id})
        course.save()

        logging.info("Added new course professor %s (name: %s)" % (prof_id,
                new_prof_name))
    elif uc_data.get('professor_id'):
        uc.professor_id = uc_data['professor_id']
    else:
        uc.professor_id = None

    now = datetime.now()

    if uc_data.get('course_review'):
        # New course review data
        uc_data['course_review']['comment_date'] = now
        uc.course_review.update(**uc_data['course_review'])

    if uc_data.get('professor_review'):
        # New prof review data
        uc_data['professor_review']['comment_date'] = now
        uc.professor_review.update(**uc_data['professor_review'])

    uc.save()

    points_gained = uc.num_points - orig_points
    user.award_points(points_gained, view_helpers.get_redis_instance())
    user.save()

    return util.json_dumps({
        'professor_review.comment_date': uc['professor_review'][
            'comment_date'],
        'course_review.comment_date': uc['course_review']['comment_date'],
        'points_gained': points_gained,
    })
예제 #21
0
def user_course():
    uc_data = util.json_loads(flask.request.data)
    user = view_helpers.get_current_user()

    rmclogger.log_event(
        rmclogger.LOG_CATEGORY_API,
        rmclogger.LOG_EVENT_USER_COURSE,
        {
            'uc_data': uc_data,
            'user_id': user.id,
        },
    )

    # Validate request object
    course_id = uc_data.get('course_id')
    term_id = uc_data.get('term_id')
    if course_id is None or term_id is None:
        logging.error("/api/user/course got course_id (%s) and term_id (%s)" %
                      (course_id, term_id))
        # TODO(david): Perhaps we should have a request error function that
        # returns a 400
        raise exceptions.ImATeapot('No course_id or term_id set')

    if not m.UserCourse.can_review(term_id):
        logging.warning("%s attempted to rate %s in future/shortlist term %s" %
                        (user.id, course_id, term_id))
        raise exceptions.ImATeapot(
            "Can't review a course in the future or shortlist")

    # Fetch existing UserCourse
    uc = m.UserCourse.objects(user_id=user.id,
                              course_id=uc_data['course_id'],
                              term_id=uc_data['term_id']).first()

    if uc is None:
        logging.error("/api/user/course User course not found for "
                      "user_id=%s course_id=%s term_id=%s" %
                      (user.id, course_id, term_id))
        # TODO(david): Perhaps we should have a request error function that
        # returns a 400
        raise exceptions.ImATeapot('No user course found')

    orig_points = uc.num_points

    # TODO(Sandy): Consider the case where the user picked a professor and
    # rates them, but then changes the professor. We need to remove the ratings
    # from the old prof's aggregated ratings and add them to the new prof's
    # Maybe create professor if newly added
    if uc_data.get('new_prof_added'):

        new_prof_name = uc_data['new_prof_added']

        # TODO(mack): should do guess_names first, and use that to
        # generate the id
        prof_id = m.Professor.get_id_from_name(new_prof_name)
        uc.professor_id = prof_id

        # TODO(Sandy): Have some kind of sanity check for professor names.
        # Don't allow ridiculousness like "Santa Claus", "aksnlf",
        # "swear words"
        if m.Professor.objects(id=prof_id).count() == 0:
            first_name, last_name = m.Professor.guess_names(new_prof_name)
            m.Professor(
                id=prof_id,
                first_name=first_name,
                last_name=last_name,
            ).save()

        course = m.Course.objects.with_id(uc.course_id)
        course.professor_ids = list(set(course.professor_ids) | {prof_id})
        course.save()

        logging.info("Added new course professor %s (name: %s)" %
                     (prof_id, new_prof_name))
    elif uc_data.get('professor_id'):
        uc.professor_id = uc_data['professor_id']
    else:
        uc.professor_id = None

    now = datetime.now()

    if uc_data.get('course_review'):
        # New course review data
        uc_data['course_review']['comment_date'] = now
        uc.course_review.update(**uc_data['course_review'])

    if uc_data.get('professor_review'):
        # New prof review data
        uc_data['professor_review']['comment_date'] = now
        uc.professor_review.update(**uc_data['professor_review'])

    uc.save()

    points_gained = uc.num_points - orig_points
    user.award_points(points_gained, view_helpers.get_redis_instance())
    user.save()

    return util.json_dumps({
        'professor_review.comment_date':
        uc['professor_review']['comment_date'],
        'course_review.comment_date':
        uc['course_review']['comment_date'],
        'points_gained':
        points_gained,
    })
예제 #22
0
파일: server.py 프로젝트: Kapin/rmc
def tojson(obj):
    return util.json_dumps(obj)
예제 #23
0
파일: server.py 프로젝트: Kapin/rmc
def generic_stats():
    return util.json_dumps(dashboard_data())
예제 #24
0
def generic_stats():
    return util.json_dumps(dashboard_data())
예제 #25
0
def search_courses():
    # TODO(mack): create enum of sort options
    # num_friends, num_ratings, overall, interest, easiness

    request = flask.request
    keywords = request.values.get('keywords')
    sort_mode = request.values.get('sort_mode', 'popular')
    default_direction = COURSES_SORT_MODES_BY_NAME[sort_mode]['direction']
    direction = int(request.values.get('direction', default_direction))
    count = int(request.values.get('count', 10))
    offset = int(request.values.get('offset', 0))
    exclude_taken_courses = request.values.get('exclude_taken_courses')

    current_user = view_helpers.get_current_user()

    # TODO(david): These logging things should be done asynchronously
    rmclogger.log_event(rmclogger.LOG_CATEGORY_COURSE_SEARCH,
                        rmclogger.LOG_EVENT_SEARCH_PARAMS, request.values)

    filters = {}
    if keywords:
        # Clean keywords to just alphanumeric and space characters
        keywords = re.sub(r'[^\w ]', ' ', keywords)

        keywords = re.sub('\s+', ' ', keywords)
        keywords = keywords.split(' ')

        def regexify_keywords(keyword):
            keyword = keyword.lower()
            return re.compile('^%s' % keyword)

        keywords = map(regexify_keywords, keywords)
        filters['_keywords__all'] = keywords

    if exclude_taken_courses == "yes":
        if current_user:
            ucs = (current_user.get_user_courses().only(
                'course_id', 'term_id'))
            filters['id__nin'] = [
                uc.course_id for uc in ucs
                if not m.term.Term.is_shortlist_term(uc.term_id)
            ]
        else:
            logging.error('Anonymous user tried excluding taken courses')

    if sort_mode == 'friends_taken':
        # TODO(mack): should only do if user is logged in
        friends = m.User.objects(
            id__in=current_user.friend_ids).only('course_history')
        # TODO(mack): need to majorly optimize this
        num_friends_by_course = {}
        for friend in friends:
            for course_id in friend.course_ids:
                if not course_id in num_friends_by_course:
                    num_friends_by_course[course_id] = 0
                num_friends_by_course[course_id] += 1

        filters['id__in'] = num_friends_by_course.keys()
        existing_courses = m.Course.objects(**filters).only('id')
        existing_course_ids = set(c.id for c in existing_courses)
        for course_id in num_friends_by_course.keys():
            if course_id not in existing_course_ids:
                del num_friends_by_course[course_id]

        sorted_course_count_tuples = sorted(
            num_friends_by_course.items(),
            key=lambda (_, total): total,
            reverse=direction < 0,
        )[offset:offset + count]

        sorted_course_ids = [
            course_id for (course_id, total) in sorted_course_count_tuples
        ]

        unsorted_limited_courses = m.Course.objects(id__in=sorted_course_ids)

        limited_courses_by_id = {}
        for course in unsorted_limited_courses:
            limited_courses_by_id[course.id] = course

        limited_courses = []
        for course_id in sorted_course_ids:
            limited_courses.append(limited_courses_by_id[course_id])

    else:
        sort_options = COURSES_SORT_MODES_BY_NAME[sort_mode]

        if sort_mode in RATING_SORT_MODES:
            sort_instr = '-' + sort_options['field']
            sort_instr += "_positive" if direction < 0 else "_negative"
        else:
            sort_instr = ''
            if direction < 0:
                sort_instr = '-'
            sort_instr += sort_options['field']

        unsorted_courses = m.Course.objects(**filters)
        sorted_courses = unsorted_courses.order_by(sort_instr)
        limited_courses = sorted_courses.skip(offset).limit(count)

    has_more = len(limited_courses) == count

    course_dict_list, user_course_dict_list, user_course_list = (
        m.Course.get_course_and_user_course_dicts(limited_courses,
                                                  current_user,
                                                  include_friends=True,
                                                  full_user_courses=False,
                                                  include_sections=True))
    professor_dict_list = m.Professor.get_reduced_professors_for_courses(
        limited_courses)

    user_dict_list = []
    if current_user:
        user_ids = [
            uc['user_id'] for uc in user_course_dict_list
            if uc['user_id'] != current_user.id
        ]
        users = m.User.objects(id__in=user_ids).only(*m.User.CORE_FIELDS)
        user_dict_list = [u.to_dict() for u in users]

    return util.json_dumps({
        'user_objs': user_dict_list,
        'course_objs': course_dict_list,
        'professor_objs': professor_dict_list,
        'user_course_objs': user_course_dict_list,
        'has_more': has_more,
    })
예제 #26
0
def tojson(obj):
    return util.json_dumps(obj)
예제 #27
0
파일: server.py 프로젝트: sunapi386/rmc
def search_courses():
    # TODO(mack): create enum of sort options
    # num_friends, num_ratings, overall, interest, easiness

    request = flask.request
    keywords = request.values.get('keywords')
    sort_mode = request.values.get('sort_mode', 'popular')
    default_direction = COURSES_SORT_MODES_BY_NAME[sort_mode]['direction']
    direction = int(request.values.get('direction', default_direction))
    count = int(request.values.get('count', 10))
    offset = int(request.values.get('offset', 0))
    exclude_taken_courses = request.values.get('exclude_taken_courses')

    current_user = view_helpers.get_current_user()

    # TODO(david): These logging things should be done asynchronously
    rmclogger.log_event(
        rmclogger.LOG_CATEGORY_COURSE_SEARCH,
        rmclogger.LOG_EVENT_SEARCH_PARAMS,
        request.values
    )

    filters = {}
    if keywords:
        # Clean keywords to just alphanumeric and space characters
        keywords = re.sub(r'[^\w ]', ' ', keywords)

        keywords = re.sub('\s+', ' ', keywords)
        keywords = keywords.split(' ')

        def regexify_keywords(keyword):
            keyword = keyword.lower()
            return re.compile('^%s' % keyword)

        keywords = map(regexify_keywords, keywords)
        filters['_keywords__all'] = keywords

    if exclude_taken_courses == "yes":
        if current_user:
            ucs = (current_user.get_user_courses()
                    .only('course_id', 'term_id'))
            filters['id__nin'] = [
                uc.course_id for uc in ucs
                if not m.term.Term.is_shortlist_term(uc.term_id)
            ]
        else:
            logging.error('Anonymous user tried excluding taken courses')

    if sort_mode == 'friends_taken':
        # TODO(mack): should only do if user is logged in
        friends = m.User.objects(id__in=current_user.friend_ids).only(
                'course_history')
        # TODO(mack): need to majorly optimize this
        num_friends_by_course = {}
        for friend in friends:
            for course_id in friend.course_ids:
                if not course_id in num_friends_by_course:
                    num_friends_by_course[course_id] = 0
                num_friends_by_course[course_id] += 1

        filters['id__in'] = num_friends_by_course.keys()
        existing_courses = m.Course.objects(**filters).only('id')
        existing_course_ids = set(c.id for c in existing_courses)
        for course_id in num_friends_by_course.keys():
            if course_id not in existing_course_ids:
                del num_friends_by_course[course_id]

        sorted_course_count_tuples = sorted(
            num_friends_by_course.items(),
            key=lambda (_, total): total,
            reverse=direction < 0,
        )[offset:offset + count]

        sorted_course_ids = [course_id for (course_id, total)
                in sorted_course_count_tuples]

        unsorted_limited_courses = m.Course.objects(id__in=sorted_course_ids)

        limited_courses_by_id = {}
        for course in unsorted_limited_courses:
            limited_courses_by_id[course.id] = course

        limited_courses = []
        for course_id in sorted_course_ids:
            limited_courses.append(limited_courses_by_id[course_id])

    else:
        sort_options = COURSES_SORT_MODES_BY_NAME[sort_mode]

        if sort_mode in RATING_SORT_MODES:
            sort_instr = '-' + sort_options['field']
            sort_instr += "_positive" if direction < 0 else "_negative"
        else:
            sort_instr = ''
            if direction < 0:
                sort_instr = '-'
            sort_instr += sort_options['field']

        unsorted_courses = m.Course.objects(**filters)
        sorted_courses = unsorted_courses.order_by(sort_instr)
        limited_courses = sorted_courses.skip(offset).limit(count)

    has_more = len(limited_courses) == count

    course_dict_list, user_course_dict_list, user_course_list = (
            m.Course.get_course_and_user_course_dicts(
                limited_courses, current_user, include_friends=True,
                full_user_courses=False, include_sections=True))
    professor_dict_list = m.Professor.get_reduced_professors_for_courses(
            limited_courses)

    user_dict_list = []
    if current_user:
        user_ids = [uc['user_id'] for uc in user_course_dict_list
                if uc['user_id'] != current_user.id]
        users = m.User.objects(id__in=user_ids).only(*m.User.CORE_FIELDS)
        user_dict_list = [u.to_dict() for u in users]

    return util.json_dumps({
        'user_objs': user_dict_list,
        'course_objs': course_dict_list,
        'professor_objs': professor_dict_list,
        'user_course_objs': user_course_dict_list,
        'has_more': has_more,
    })