class UserReferredResource(WigoResource): model = User @user_token_required @api.expect( api.model( 'Referred', { 'referred_by_id': fields.Integer(description='User who referred user_id', required=True) })) @api.response(200, 'Success') def post(self, user_id): referred_by_id = self.get_id_field('referred_by_id') referred_by = User.find(referred_by_id) referred_key = skey(referred_by, 'referred') # record into the referrers list of users they referred if not wigo_db.sorted_set_is_member(referred_key, g.user.id): wigo_db.sorted_set_add(referred_key, g.user.id, time()) # record into the referrers rankings for the month now = datetime.now(Configuration.ANALYTICS_TIMEZONE) wigo_db.sorted_set_incr_score( skey('referrers', now.month, now.year), referred_by.id) wigo_db.sorted_set_incr_score(skey('referrers'), referred_by.id) return {'success': True}
class LayerTokenResource(WigoResource): @user_token_required @api.expect(api.model('Nonce', { 'nonce': fields.String(description='Nonce', required=True) })) def post(self): user_id = g.user.id nonce = request.get_json().get('nonce') if not nonce: abort(400, message='Nonce missing') # Create identity token # Make sure you have PyJWT and PyCrypto libraries installed and imported id_token = jwt.encode( payload={ 'iss': PROVIDER_ID, # String - The Provider ID found in the Layer Dashboard 'prn': str(user_id), # String - Provider's internal ID for the authenticating user 'iat': datetime.now(), # Integer - Time of Token Issuance in RFC 3339 seconds 'exp': datetime.utcnow() + timedelta(seconds=30), # Integer - Arbitrary Token Expiration in RFC 3339 seconds 'nce': nonce # The nonce obtained via the Layer client SDK. }, key=RSA_KEY, headers={ 'typ': 'JWT', # String - Expresses a MIME Type of application/JWT 'alg': 'RS256', # String - Expresses the type of algorithm used to sign the token, must be RS256 'cty': 'layer-eit;v=1', # String - Express a Content Type of Layer External Identity Token, version 1 'kid': KEY_ID # String - Private Key associated with 'layer.pem', found in the Layer Dashboard }, algorithm='RS256' ) return {'token': id_token}
class BlockListResource(WigoResource): model = Block @user_token_required @check_last_modified('user', 'last_block_change') @api.response(200, 'Success') def get(self, user_id, headers): return g.user.get_blocked_ids(), 200, headers @user_token_required @api.expect( api.model( 'NewBlock', { 'blocked_id': fields.Integer(description='User to block', required=True), 'type': fields.String( description= 'The block type, "abusive" is only supported value') })) @api.response(200, 'Success') def post(self, user_id): block = Block() block.user_id = g.user.id block.blocked_id = self.get_id_field('blocked_id') block.type = request.get_json().get('type') block.save() return {'success': True}
class UserMetaResource(WigoResource): model = User @user_token_required @api.response(200, 'Success', model=api.model( 'UserMeta', { 'last_message_received': fields.DateTime(), 'last_friend_request': fields.DateTime(), 'last_notification': fields.DateTime(), 'is_tapped': fields.Boolean(), 'is_friend': fields.Boolean(), 'is_blocked': fields.Boolean(), 'attending_event_id': fields.Integer(), 'friend_request': fields.String(), 'num_friends_in_common': fields.Integer() })) def get(self, user_id): user_id = self.get_id(user_id) meta = {} if user_id == g.user.id: user_meta = wigo_db.get_redis().hgetall( skey('user', user_id, 'meta')) if user_meta: def format_date(field): return datetime.utcfromtimestamp(float( user_meta[field])).isoformat() if 'last_message_received' in user_meta: meta['last_message_received'] = format_date( 'last_message_received') if 'last_friend_request' in user_meta: meta['last_friend_request'] = format_date( 'last_friend_request') if 'last_notification' in user_meta: meta['last_notification'] = format_date( 'last_notification') meta['attending_event_id'] = g.user.get_attending_id() else: meta['is_tapped'] = g.user.is_tapped(user_id) meta['is_friend'] = g.user.is_friend(user_id) meta['is_blocked'] = g.user.is_blocked(user_id) if g.user.is_friend_request_sent(user_id): meta['friend_request'] = 'sent' elif g.user.is_friend_request_received(user_id): meta['friend_request'] = 'received' if request.args.get('num_friends_in_common') == 'true': meta['num_friends_in_common'] = len( g.user.get_friend_ids_in_common(user_id)) meta['num_friends'] = wigo_db.get_sorted_set_size( skey('user', user_id, 'friends')) return meta
class LoginResource(WigoResource): @api.expect(api.model('LoginUser', { 'facebook_id': fields.String, 'facebook_access_token': fields.String, 'facebook_access_token_expires': fields.Integer, 'email': fields.String })) @api.response(200, 'Success', model=User.to_doc_list_model(api)) @api.response(400, 'Bad post data, or account already exists') @api.response(403, 'Security error') def post(self): data = request.get_json() facebook_id = data.get('facebook_id') facebook_token = data.get('facebook_access_token') facebook_token_expires = datetime.utcnow() + timedelta( seconds=data.get('facebook_access_token_expires') or 1728000) birthdate = data.get('birthdate') education = data.get('education') work = data.get('work') properties = data.get('properties') if not facebook_id or not facebook_token: abort(400, message='Missing facebook id or token') user = User.find(facebook_id=facebook_id) if user.facebook_token != facebook_token: # hit the facebook api. if this fails, the token is invalid try: facebook = Facebook(facebook_token, facebook_token_expires) fb_user_info = facebook.get('me') if fb_user_info.get('id') != facebook_id: abort(403, message='Facebook token user id does not match passed in user id') facebook_token_expires = facebook.get_token_expiration() except FacebookTimeoutException, e: logger.error('timeout validating facebook token for user "%s"' % user.email) raise except FacebookTokenExpiredException, e: logger.warning('access token expired for user "%s"' % user.email) abort(400, message='Facebook token expired') except Exception, e: logger.error('error validating facebook token for user "%s", %s' % (user.email, e.message)) raise
class TapListResource(WigoResource): model = Tap @user_token_required @check_last_modified('user', 'last_tap_change') @api.response(200, 'Success') def get(self, user_id, headers): return g.user.get_tapped_ids(), 200, headers @user_token_required @api.expect( api.model('NewTap', { 'tapped_id': fields.Integer(description='User to tap', required=True) })) @api.response(200, 'Success') @api.response(403, 'Not friends') def post(self, user_id): tap = Tap() tap.user_id = g.user.id tap.tapped_id = self.get_id_field('tapped_id') tap.save() return {'success': True}
class RegisterResource(WigoResource): @api.expect( api.model( 'RegisterUser', { 'facebook_id': fields.String, 'facebook_access_token': fields.String, 'facebook_access_token_expires': fields.Integer, 'email': fields.String, 'timezone': fields.String })) @api.response(200, 'Success', model=User.to_doc_list_model(api)) @api.response(400, 'Bad post data, or account already exists') def post(self): data = request.get_json() if not data: abort(400, message='No data posted') timezone = pytz.timezone(data.get('timezone', 'US/Eastern')) facebook_id = data.get('facebook_id') facebook_token = data.get('facebook_access_token') facebook_token_expires = datetime.utcnow() + timedelta( seconds=data.get('facebook_access_token_expires') or 1728000) birthdate = data.get('birthdate') education = data.get('education') work = data.get('work') properties = data.get('properties') if not facebook_id or not facebook_token: abort(400, message='Missing facebook id or token') with redis.lock('locks:register:{}'.format(facebook_id), timeout=30): try: User.find(facebook_id=facebook_id) abort(400, message='Account already exists') except DoesNotExist: pass if not facebook_id.startswith('xxx'): facebook = Facebook(facebook_token, facebook_token_expires) user_info = self.get_me(facebook, facebook_id, facebook_token, facebook_token_expires) facebook_token_expires = facebook.get_token_expiration() else: user_info = {} logger.info('creating new user account for facebook_id {}'.format( facebook_id)) user = User() user.key = uuid4().hex user.facebook_id = facebook_id user.facebook_token = facebook_token user.facebook_token_expires = facebook_token_expires user.email = user_info.get('email') if user.email: user.email_validated = True user.email_validated_date = datetime.utcnow() user.email_validated_status = 'validated' user.timezone = timezone.zone user.first_name = user_info.get('first_name') or user_info.get( 'given_name') user.last_name = user_info.get('last_name') or user_info.get( 'family_name') user.username = get_username(user.email or user.full_name) user.gender = user_info.get('gender') if not birthdate: birthdate = user_info.get('birthday') if birthdate: try: user.birthdate = parse(birthdate) except: logger.info('error parsing birthdate {}'.format(birthdate)) if education: user.education = education if work: user.work = work if g.group: user.group_id = g.group.id if properties: for key, value in properties.items(): user.set_custom_property(key, value) user.set_custom_property('events', {'triggers': ['find_referrer']}) platform = request.headers.get('X-Wigo-Device') if not platform: platform = request.user_agent.platform if platform: platform = platform.lower() if platform in ('android', 'iphone', 'ipad'): user.set_custom_property('platforms', [platform]) enterprise = request.headers.get('X-Wigo-Client-Enterprise') if enterprise == 'true': user.enterprise = True user.save() g.user = user # if not user.email_validated and Configuration.PUSH_ENABLED: # send_email_verification.delay(user.id) logger.info( 'registered new account for user {} for facebook_id {}'.format( user.id, facebook_id)) return self.serialize_list(User, [user]) def get_me(self, facebook, facebook_id, facebook_token, facebook_token_expires): # fetch user information from facebook def get_me(): fb_user_info = facebook.get('me') if fb_user_info.get('id') != facebook_id: abort( 403, message= 'Facebook token user id does not match passed in user id') return fb_user_info try: return get_me() except FacebookTimeoutException: logger.warn( 'register timed out waiting for facebook response, ' 'trying one more time, facebook_id {}'.format(facebook_id)) try: return get_me() except FacebookTimeoutException: logger.error( 'AGAIN register timed out waiting for facebook response, ' 'aborting, facebook_id {}'.format(facebook_id)) raise
class InviteListResource(WigoResource): model = Invite @user_token_required @api.response(200, 'Success', model=User.to_doc_list_model(api)) def get(self, event_id): event = Event.find(event_id) page = self.get_page() limit = self.get_limit() start = (page - 1) * limit num_friends = wigo_db.get_sorted_set_size(skey(g.user, 'friends')) # find the users top 5 friends. this is users with > 3 interactions top_5 = wigo_db.sorted_set_rrange_by_score(skey( g.user, 'friends', 'top'), 'inf', 3, limit=5) if not top_5: top_5 = wigo_db.sorted_set_rrange_by_score(skey(g.user, 'friends'), 'inf', 3, limit=5) friend_ids = wigo_db.sorted_set_range(skey(g.user, 'friends', 'alpha'), start, start + (limit - 1)) for top_friend_id in top_5: if top_friend_id in friend_ids: friend_ids.remove(top_friend_id) if page == 1 and top_5: friend_ids = top_5 + friend_ids users = User.find(friend_ids) p = wigo_db.redis.pipeline() for user in users: p.zscore(skey(event, g.user, 'invited'), user.id if user else -1) scores = p.execute() for index, user in enumerate(users): if user: user.invited = scores[index] is not None return self.serialize_list(self.model, users, num_friends, page) @user_token_required @api.expect( api.model( 'NewInvite', { 'invited_id': fields.Integer(description='User to invite', required=True), })) @api.response(200, 'Success') @api.response(403, 'Not friends or not attending') def post(self, event_id): user = g.user if 'friends' in request.get_json(): from server.tasks.data import send_friend_invites num_friends = wigo_db.get_sorted_set_size(skey(user, 'friends')) if num_friends < 25: send_friend_invites(user.id, event_id) else: send_friend_invites.delay(user.id, event_id) else: invite = Invite() invite.user_id = user.id invite.invited_id = self.get_id_field('invited_id') invite.event_id = event_id invite.save() return {'success': True}
class FriendsListResource(WigoResource): model = Friend @user_token_required @check_last_modified('user', 'last_friend_change') @api.response(200, 'Success', model=User.to_doc_list_model(api)) def get(self, user_id, headers): user = User.find(self.get_id(user_id)) text = request.args.get('text') if text: sql = """ select users.id from data_int_sorted_sets inner join users on users.key = format('{{user:%%s}}', data_int_sorted_sets.value) where data_int_sorted_sets.key = '{{user:{}}}:friends' """.format(user.id) params = [] split = [('{}%%'.format(part)) for part in re.split(r'\s+', text.strip().lower())] for s in split: sql += "AND ((LOWER(first_name) LIKE %s) or " \ "(LOWER(last_name) LIKE %s))" params.append(s) params.append(s) sql += "ORDER BY first_name, last_name" with slave.execution_context(False) as ctx: results = list(slave.execute_sql(sql, params)) users = User.find([id[0] for id in results]) if g.user == user: for friend in users: friend.friend = True else: for friend, is_friend in g.user.are_friends(users).items(): friend.friend = is_friend return self.serialize_list(self.model, users), 200, headers else: query = self.select(User).user(user).friends() count, page, users = query.execute() if g.user == user: for friend in users: friend.friend = True else: for friend, is_friend in g.user.are_friends(users).items(): friend.friend = is_friend return self.serialize_list(User, users, count, page), 200, headers @user_token_required @api.expect( api.model( 'NewFriend', { 'friend_id': fields.Integer(description='User to connect with', required=True) })) @api.response(200, 'Success') def post(self, user_id): friend_id = self.get_id_field('friend_id') # check if already friends, or friend request already sent if g.user.is_friend(friend_id) or g.user.is_friend_request_sent( friend_id): return {'success': True, 'status': 'already_friends'} friend = Friend() friend.user_id = g.user.id friend.friend_id = friend_id friend.save() return {'success': True} @user_token_required @api.expect( api.model( 'DeleteFriend', { 'friend_id': fields.Integer(description='User to remove connection with', required=True) })) @api.response(200, 'Success') def delete(self, user_id): Friend({ 'user_id': g.user.id, 'friend_id': self.get_id_field('friend_id') }).delete() return {'success': True}
from urlparse import urlparse, urljoin from uuid import uuid4 from boto.s3.connection import S3Connection from flask.ext.restful import abort from flask.ext.restplus import fields from werkzeug.utils import secure_filename from flask import g, request, jsonify from config import Configuration from server.models.event import EventMessage from server.rest import api_blueprint, WigoResource, api from server.security import user_token_required logger = logging.getLogger('wigo.web.uploads') param = api.model('UploadParam', { 'key': fields.String(required=True), 'value': fields.String(required=True) }) params = api.model('UploadParams', { 'action': fields.String(description='Form action', required=True), 'fields': fields.Nested(param, as_list=True, required=True) }) class UploadResource(WigoResource): @user_token_required def post(self): multipart_file = request.files.get('file') filename = secure_filename(multipart_file.filename) tmp_filepath = os.path.join(Configuration.UPLOAD_FOLDER, filename) multipart_file.save(tmp_filepath)