def custom_stream_factory(total_content_length, filename, content_type, content_length=None): if total_content_length > server.config['MAX_CONTENT_LENGTH_EDGELIST']: raise exceptions.RequestEntityTooLarge() if not allowed_edgelist(filename): raise exceptions.ImATeapot() tmpfile = NamedTemporaryFile('wb+', delete=False) # delete=False requires manual deletion using os.remove(tmpfile.name) return tmpfile
def __init__(self, limit): self.limit = limit # Set defaults self.code = 429 self.body = self.get_body() self.headers = self.get_headers() # Get the description if limit.error_message: self.description = limit.error_message if not callable( limit.error_message) else limit.error_message() else: self.description = text_type(limit.limit) # If error is given, get body & headers if self.limit.error_code: self.code = limit.error_code exception = exceptions.HTTPException(description=self.description) # Some common error codes, can add more here if self.code == 400: exception = exceptions.BadRequest() elif self.code == 401: exception = exceptions.Unauthorized() elif self.code == 403: exception = exceptions.Forbidden() elif self.code == 404: exception = exceptions.NotFound() elif self.code == 405: exception = exceptions.MethodNotAllowed() elif self.code == 406: exception = exceptions.NotAcceptable() elif self.code == 418: exception = exceptions.ImATeapot() # <3 elif self.code == 500: exception = exceptions.InternalServerError() elif self.code == 501: exception = exceptions.NotImplemented() # Update body & headers self.body = exception.get_body() self.headers = exception.get_headers() else: exception = exceptions.TooManyRequests( description=self.description) # Update body & headers self.body = exception.get_body() self.headers = exception.get_headers() super(RateLimitExceeded, self).__init__(description=self.description, response=Response(self.body, self.code, self.headers))
def renew_fb(): '''Renew the current user's Facebook access token. The client should make this call periodically (once every couple months, see User.should_renew_fb_token) to keep the access token up to date. Takes a Facebook signed request object from the post params in the form of: { 'fb_signed_request': obj } ''' req = flask.request current_user = view_helpers.get_current_user() rmclogger.log_event( rmclogger.LOG_CATEGORY_API, rmclogger.LOG_EVENT_RENEW_FB, { 'user_id': current_user.id, 'request_form': req.form, } ) fbsr = req.form.get('fb_signed_request') if fbsr is None: logging.warn('No fbsr set') raise exceptions.ImATeapot('No fbsr set') fb_data = facebook.get_fb_data(fbsr, app.config) access_token = fb_data['access_token'] expires_on = fb_data['expires_on'] is_invalid = fb_data['is_invalid'] if not is_invalid: current_user.fb_access_token_expiry_date = expires_on current_user.fb_access_token = access_token current_user.fb_access_token_invalid = is_invalid # Update the user's fb friend list, since it's likely outdated by now try: current_user.update_fb_friends( facebook.get_friend_list(access_token)) except: # Not sure why this would happen. Usually it's due to invalid # access_token, but we JUST got the token, so it should be valid logging.warn( "/api/renew-fb: get_friend_list failed with token (%s)" % access_token) current_user.save() return ''
def get_current_user(): """Get the current user using Flask sessions. Also allows admins to become another user based on oid or fbid. Returns a User object if the user is logged in, or None otherwise. """ req = flask.request if hasattr(req, 'current_user'): return req.current_user api_key = req.values.get('api_key') if api_key and is_api_request(): req.current_user = m.User.objects(api_key=api_key).first() if not req.current_user: # TODO(mack): change exceptions to not return html, but just the # error text raise exceptions.ImATeapot('Invalid api key %s' % api_key) elif SESSION_COOKIE_KEY_USER_ID in flask.session: user_id = flask.session[SESSION_COOKIE_KEY_USER_ID] req.current_user = m.User.objects.with_id(user_id) # req.current_user can be None if the client still has a cookie with # this user_id, but the corresponding User's account has been deleted. if req.current_user: req.current_user.update(set__last_visited=datetime.datetime.now()) else: req.current_user = None if req.current_user and req.current_user.is_admin: oid = req.values.get('as_oid', '') fbid = req.values.get('as_fbid', '') if oid: try: as_user = m.User.objects.with_id(oid) req.current_user = as_user req.as_user_override = True except me.base.ValidationError: logging.warn("Bad as_oid (%s) in get_current_user()" % oid) elif fbid: as_user = m.User.objects(fbid=fbid).first() if as_user is None: logging.warn("Bad as_fbid (%s) in get_current_user()" % fbid) else: req.current_user = as_user req.as_user_override = True return req.current_user
def login(): req = flask.request fbsr = req.form.get('fb_signed_request') # TODO(Sandy): Change log category because this isn't API? rmclogger.log_event( rmclogger.LOG_CATEGORY_API, rmclogger.LOG_EVENT_LOGIN, { 'fbsr': fbsr, 'request_form': req.form, }, ) if (fbsr is None): raise exceptions.ImATeapot('No fbsr set') fb_data = facebook.get_fb_data(fbsr, app.config) fbid = fb_data['fbid'] fb_access_token = fb_data['access_token'] fb_access_token_expiry_date = fb_data['expires_on'] is_invalid = fb_data['is_invalid'] user = m.User.objects(fbid=fbid).first() if user: # Existing user. Update with latest FB info user.fb_access_token = fb_access_token user.fb_access_token_expiry_date = fb_access_token_expiry_date user.fb_access_token_invalid = is_invalid user.save() view_helpers.login_as_user(user) rmclogger.log_event( rmclogger.LOG_CATEGORY_IMPRESSION, rmclogger.LOG_EVENT_LOGIN, { 'new_user': False, 'user_id': user.id, }, ) return '' # Sign up the new user friend_fbids = flask.json.loads(req.form.get('friend_fbids')) gender = req.form.get('gender') first_name = req.form.get('first_name') middle_name = req.form.get('middle_name') last_name = req.form.get('last_name') email = req.form.get('email') now = datetime.now() user_obj = { 'fbid': fbid, 'first_name': first_name, 'middle_name': middle_name, 'last_name': last_name, 'email': email, 'gender': gender, 'fb_access_token': fb_access_token, 'fb_access_token_expiry_date': fb_access_token_expiry_date, # TODO(Sandy): Count visits properly 'join_date': now, 'join_source': m.User.JoinSource.FACEBOOK, 'num_visits': 1, 'last_visited': now, 'friend_fbids': friend_fbids, # TODO(Sandy): Fetch from client side and pass here: name, email, # school, program, faculty } referrer_id = req.form.get('referrer_id') if referrer_id: try: user_obj['referrer_id'] = bson.ObjectId(referrer_id) except: pass user = m.User(**user_obj) user.save() view_helpers.login_as_user(user) rmclogger.log_event( rmclogger.LOG_CATEGORY_IMPRESSION, rmclogger.LOG_EVENT_LOGIN, { 'new_user': True, 'user_id': user.id, 'referrer_id': referrer_id, }, ) return ''
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, })
def login_with_facebook(): """Login or create an account using Facebook connect Upon successful login or account creation, returns a 'secure cookie' (provided by Flask) containing the session data. Takes a Facebook signed request in the form of: { 'fb_signed_request': obj } """ req = flask.request fbsr = req.form.get('fb_signed_request') rmclogger.log_event( rmclogger.LOG_CATEGORY_GENERIC, rmclogger.LOG_EVENT_LOGIN, { 'fbsr': fbsr, 'request_form': req.form, 'type': rmclogger.LOGIN_TYPE_STRING_FACEBOOK, }, ) if (fbsr is None): raise exceptions.ImATeapot('No fbsr set') fb_data = facebook.get_fb_data(fbsr, app.config) fbid = fb_data['fbid'] fb_access_token = fb_data['access_token'] fb_access_token_expiry_date = fb_data['expires_on'] is_invalid = fb_data['is_invalid'] user = m.User.objects(fbid=fbid).first() if user: # Existing user. Update with their latest Facebook info user.fb_access_token = fb_access_token user.fb_access_token_expiry_date = fb_access_token_expiry_date user.fb_access_token_invalid = is_invalid user.save() # Authenticate view_helpers.login_as_user(user) rmclogger.log_event( rmclogger.LOG_CATEGORY_IMPRESSION, rmclogger.LOG_EVENT_LOGIN, { 'new_user': False, 'user_id': user.id, 'type': rmclogger.LOGIN_TYPE_STRING_FACEBOOK, }, ) else: # New user, or existing email logins user. now = datetime.now() email = req.form.get('email') user_data = { 'fb_access_token': fb_access_token, 'fb_access_token_expiry_date': fb_access_token_expiry_date, 'fbid': fbid, 'friend_fbids': flask.json.loads(req.form.get('friend_fbids')), 'gender': req.form.get('gender'), 'last_visited': now, } user = m.User.objects(email=email).first() if email else None if user: # Update existing account with Facebook data referrer_id = None for k, v in user_data.iteritems(): user[k] = v user.save() else: # Create an account with their Facebook data user_data.update({ 'email': email, 'first_name': req.form.get('first_name'), 'join_date': now, 'join_source': m.User.JoinSource.FACEBOOK, 'last_name': req.form.get('last_name'), 'middle_name': req.form.get('middle_name'), }) referrer_id = req.form.get('referrer_id') if referrer_id: try: user_data['referrer_id'] = bson.ObjectId(referrer_id) except bson.errors.InvalidId: pass user = m.User(**user_data) user.save() # Authenticate view_helpers.login_as_user(user) rmclogger.log_event( rmclogger.LOG_CATEGORY_IMPRESSION, rmclogger.LOG_EVENT_LOGIN, { 'new_user': True, 'user_id': user.id, 'referrer_id': referrer_id, 'type': rmclogger.LOGIN_TYPE_STRING_FACEBOOK, }, ) return ''
def login_with_facebook(): req_json = flask.request.get_json() fbsr = req_json.get('fb_signed_request') if (fbsr is None): raise exceptions.ImATeapot('No fbsr set') fb_data = facebook.get_fb_data(fbsr, app.config) fbid = fb_data['fbid'] fb_access_token = fb_data['access_token'] fb_access_token_expiry_date = fb_data['expires_on'] is_invalid = fb_data['is_invalid'] user = User.objects(fbid=fbid).first() if user: # Existing user. Update with their latest Facebook info user.fb_access_token = fb_access_token user.fb_access_token_expiry_date = fb_access_token_expiry_date user.fb_access_token_invalid = is_invalid user.save() else: # New user, or existing email logins user. now = datetime.now() email = req_json.get('email') user_data = { 'fb_access_token': fb_access_token, 'fb_access_token_expiry_date': fb_access_token_expiry_date, 'fbid': fbid, 'friend_fbids': flask.json.loads(req_json.get('friend_fbids')), 'gender': req_json.get('gender'), 'last_visited': now, } user = User.objects(email=email).first() if email else None if user: for k, v in user_data.iteritems(): user[k] = v user.save() else: # Create an account with their Facebook data user_data.update({ 'email': email, 'first_name': req_json.get('first_name'), 'join_date': now, 'join_source': User.JoinSource.FACEBOOK, 'last_name': req_json.get('last_name'), 'middle_name': req_json.get('middle_name'), }) referrer_id = req_json.get('referrer_id') if referrer_id: try: user_data['referrer_id'] = bson.ObjectId(referrer_id) except bson.errors.InvalidId: pass user = User(**user_data) user.save() if user: identity = UserToken(str(user.pk), user.email or '') access_token = _jwt.jwt_encode_callback(identity) return util.json_dumps({'accessToken': access_token})