Exemplo n.º 1
0
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}
Exemplo n.º 2
0
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}
Exemplo n.º 3
0
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}
Exemplo n.º 4
0
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
Exemplo n.º 5
0
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
Exemplo n.º 6
0
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}
Exemplo n.º 7
0
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
Exemplo n.º 8
0
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}
Exemplo n.º 9
0
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}
Exemplo n.º 10
0
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)