Example #1
0
def use_promotion_code(course_id):
    course_id = course_id.lower()
    ucs = m.UserCourse.objects(course_id=course_id,
                               user_id=current_identity.id).first()
    promotion = util.json_loads(flask.request.data)
    promotion_code = m.PromotionCode.objects(code=promotion['code']).first()

    if not ucs:
        ucs = m.UserCourse(course_id=course_id, user_id=current_identity.id)
        ucs.save()

    if not promotion_code or promotion_code.quantity <= 0:
        flask.abort(403)

    promotion_code.quantity = promotion_code.quantity - 1

    if promotion_code._type == 'halfmonthfree':
        ucs.payment_success = True
        ucs.read = True
        ucs.payment_at = datetime.utcnow()
        ucs.start_from = datetime.utcnow()
        ucs.expired_at = datetime.utcnow() + timedelta(days=15)
        ucs.promotion_code = promotion_code['code']
    ucs.save()
    promotion_code.save()

    return util.json_dumps(ucs.to_mongo())
Example #2
0
def update_prof_comment(prof_id):
    course_prof_comment = m.CourseProfessorComment.objects(id=prof_id).first()
    comment = util.json_loads(flask.request.data)
    current_user = view_helpers.get_current_user()
    if not current_user or comment[
            'user_id'] != current_user.id or course_prof_comment is None:
        return flask.abort(400)
    if 'course_id' not in comment or 'professor_id' not in comment:
        return flask.abort(400)

    course_prof_comment.update_by_dict(comment)
    course_prof_comment.save()

    return util.json_dumps({})
Example #3
0
def code_for_token(code, config, cmd_line_debug=False):
    """Returns a dictionary containing the user's Facebook access token and
    seconds until it expires from now

    See https://developers.facebook.com/blog/post/2011/05/13/how-to--handle-expired-access-tokens/

    Right now, the resulting token is a short-lived token (~2 hours). But it's
    possible that this is wrong and that it should be a long-term token
    instead.  See https://developers.facebook.com/bugs/341793929223330/

    Args:
        code: The code we get from their fb_signed_request

    Returns {
        'access_token': 'token-here-blarg',
        'expires': 6200,
    }
    """
    # Since we're exchanging a client-side token, redirect_uri should be ''
    params = {
        'client_id': rmc_settings.fb_app_id,
        'redirect_uri': '',
        'client_secret': rmc_settings.fb_app_secret,
        'code': code,
    }
    resp = requests.get('https://graph.facebook.com/oauth/access_token',
                        params=params)

    if resp.status_code != 200:
        err = util.json_loads(resp.text)
        if (err.get('error').get('message') == USED_AUTH_CODE_MSG
                and err.get('error').get('code') == 100):
            logging.info('code_for_token failed (%d) with text:\n%s' %
                         (resp.status_code, resp.text))
        else:
            logging.warn('code_for_token failed (%d) with text:\n%s' %
                         (resp.status_code, resp.text))

    result = dict(urlparse.parse_qsl(resp.text))

    if cmd_line_debug:
        print "result dict:"
        print result
        return resp

    return result
Example #4
0
def create_prof_comment():
    comment = util.json_loads(flask.request.data)
    current_user = view_helpers.get_current_user()
    if not current_user or comment['user_id'] != current_user.id:
        return flask.abort(400)
    if 'course_id' not in comment or 'professor_id' not in comment:
        return flask.abort(400)
    comment_obj = m.CourseProfessorComment(
        course_id=comment['course_id'],
        professor_id=comment['professor_id'],
        user_id=comment['user_id'])
    comment_obj.update_by_dict(comment)
    comment_obj.save()

    saved_comment_obj = comment_obj.to_mongo()

    if '_id' in saved_comment_obj:
        saved_comment_obj['id'] = str(saved_comment_obj['_id'])

    return util.json_dumps(saved_comment_obj)
Example #5
0
def get_friend_list(token):
    '''
    Return a list of fbids for the Facebook user associated with token
    '''
    params = {
        'access_token': token,
    }
    resp = requests.get('https://graph.facebook.com/me/friends', params=params)
    resp_dict = util.json_loads(resp.text)

    if 'error' in resp_dict:
        if resp_dict.get('error').get('type') == 'OAuthException':
            raise FacebookOAuthException()
        raise Exception(resp.text)

    fbid_list = []
    if 'data' in resp_dict:
        for entry in resp_dict['data']:
            fbid_list.append(entry['id'])
    else:
        raise Exception('"data" not in dict (%s)' % resp_dict)

    return fbid_list
Example #6
0
def parse_signed_request(signed_request, secret):
    """
    Returns a dict of the the Facebook signed request object
    See https://developers.facebook.com/docs/authentication/signed_request/
    """
    l = signed_request.split('.', 2)
    encoded_sig = l[0]
    payload = l[1]

    sig = base64_url_decode(encoded_sig)
    data = util.json_loads(base64_url_decode(payload))

    if data.get('algorithm').upper() != 'HMAC-SHA256':
        logging.error('Unknown algorithm during signed request decode')
        return None

    expected_sig = (hmac.new(secret, msg=payload,
                             digestmod=hashlib.sha256).digest())

    if sig != expected_sig:
        return None

    return data
Example #7
0
def save():
    comment = util.json_loads(flask.request.data)
    current_user_id = current_identity.id
    print comment, current_user_id
    if 'course_id' not in comment or 'course_id' not in comment:
        return flask.abort(400)
    if str(comment['user_id']) != current_user_id:
        return flask.abort(400)
    comment_obj = None
    if 'id' in comment:
        comment_obj = m.CourseComment.objects(id=comment['id']).first()
    if comment_obj is None:
        comment_obj = m.CourseComment(course_id=comment['course_id'],
                                      user_id=comment['user_id'])

    comment_obj.update_by_dict(comment)
    comment_obj.save()

    saved_comment_obj = comment_obj.to_mongo()

    if '_id' in saved_comment_obj:
        saved_comment_obj['id'] = str(saved_comment_obj['_id'])

    return util.json_dumps(saved_comment_obj)
Example #8
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,
    })