示例#1
0
def test_private_event():
    from server.models.event import Event, EventAttendee
    from server.models.user import User

    with client() as c:
        user1 = User.find(key='test')
        user2 = User.find(key='test2')
        make_friends(c, user1, user2)

        event_id = create_event(c, user1, 'test event 1', privacy='private')

        assert 1 == Event.select().count()
        assert 0 == Event.select().group(user1.group).count()
        assert 1 == Event.select().user(user1).count()
        assert 0 == Event.select().user(user2).count()

        event = Event.find(event_id)

        resp = api_post(c, user1, '/api/events/{}/invites'.format(event_id),
                        {'invited_id': user2.id})

        assert resp.status_code == 200, 'oops {}'.format(resp.data)
        assert 1 == Event.select().user(user2).count()
        count, page, results = EventAttendee.select().event(event).user(
            user2).execute()
        assert count == 1
        assert results[0] == user1
示例#2
0
def test_create_event():
    from server.models.event import Event
    from server.models.user import User

    with client() as c:
        user1 = User.find(key='test')
        user2 = User.find(key='test2')

        create_event(c, user1, 'test event')

        resp = api_get(c, user1, '/api/events/')
        assert resp.status_code == 200, 'oops {}'.format(resp.data)
        data = ujson.loads(resp.data)
        assert data['objects'][0]['name'] == 'test event'
        assert data['objects'][0]['group'] == {'$ref': 'Group:1'}

        event_id = data['objects'][0]['id']
        event = Event.find(event_id)
        assert user1.is_attending(event), 'user is attending the new event'
        assert 1 == Event.select().count()

        event_id = create_event(c, user1, 'test event 2')
        user1 = User.find(key='test')
        assert user1.get_attending_id() == event_id
        assert 2 == Event.select().count(), '2 events total now'
        count, page, results = Event.select().group(user1.group).execute()
        assert 1 == count, 'only 1 in the group though, since the other has no attendees now'
        assert results[0].name == 'test event 2'
示例#3
0
def new_friend(user_id, friend_id):
    user = User.find(user_id)
    friend = User.find(friend_id)

    if not user.is_friend(friend):
        return

    min = epoch(datetime.utcnow() - timedelta(days=8))

    # tells each friend about the event history of the other
    def capture_history(u, f):
        # capture each of the users posted photos
        with wigo_db.transaction(commit_on_select=False):
            for message in EventMessage.select().key(skey(
                    u, 'event_messages')).min(min):
                if message.user and message.event:
                    message.record_for_user(f)

        # capture the events being attended
        for event in Event.select().user(u).min(min):
            if u.is_attending(event) and f.can_see_event(event):
                event.add_to_user_attending(f, u)

    capture_history(user, friend)
    capture_history(friend, user)
示例#4
0
def notify_on_friend(user_id, friend_id, accepted):
    user = User.find(user_id)
    friend = User.find(friend_id)

    if not accepted:
        message_text = '{} wants to be your friend on Wigo'.format(user.full_name.encode('utf-8'))
    else:
        message_text = '{} accepted your friend request'.format(user.full_name.encode('utf-8'))

    notification = Notification({
        'user_id': friend_id,
        'type': 'friend.request' if not accepted else 'friend.accept',
        'from_user_id': user.id,
        'navigate': '/users/{}'.format(user_id) if accepted else '/find/users/user/{}'.format(user_id),
        'badge': 1,
        'message': message_text
    })

    if accepted:
        notification.save()
        send_notification_push.delay(notification.to_primitive())
    else:
        __send_notification_push(notification)

        # for imported users from wigo1, send them a push saying their friend just joined wigo2
        if friend.status == 'imported':
            notification = Notification({
                'user_id': friend_id,
                'type': 'system',
                'message': '{} added you to {} Wigo Summer friend list. Update Wigo now!'.format(
                    user.full_name.encode('utf-8'), ('his' if user.gender == 'male' else
                                                     'her' if user.gender == 'female' else 'their'))
            })

            __send_notification_push(notification, api_version_num=1)
示例#5
0
def capture_interaction(user_id, with_user_id, t, action='view'):
    if not client:
        return

    logger.debug('capturing prediction event data between {} and {}'.format(
        user_id, with_user_id))

    user = User.find(user_id)
    with_user = User.find(with_user_id)

    tz = timezone(with_user.group.timezone)
    event_time = t.replace(tzinfo=UTC).astimezone(tz)

    r = client.set_user(
        user_id, event_time=user.created.replace(tzinfo=UTC).astimezone(tz))

    if r.status not in (200, 201):
        raise Exception('Error returned from prediction io')

    r = client.set_item(
        with_user_id, {'categories': [str(with_user.group_id)]},
        event_time=with_user.created.replace(tzinfo=UTC).astimezone(tz))

    if r.status not in (200, 201):
        raise Exception('Error returned from prediction io')

    r = client.record_user_action_on_item(action,
                                          user_id,
                                          with_user_id,
                                          event_time=event_time)
    if r.status not in (200, 201):
        raise Exception('Error returned from prediction io')
示例#6
0
def tell_friend_user_not_attending(user_id, event_id, friend_id):
    try:
        user = User.find(user_id)
        event = Event.find(event_id)
        friend = User.find(friend_id)
    except DoesNotExist:
        return

    if not user.is_attending(event):
        event.remove_from_user_attending(friend, user)
示例#7
0
def tell_friend_user_attending(user_id, event_id, friend_id, notify=True):
    try:
        user = User.find(user_id)
        event = Event.find(event_id)
        friend = User.find(friend_id)
    except DoesNotExist:
        return

    if user.is_attending(event):
        event.add_to_user_attending(friend, user)
        if notify:
            friend_attending.send(None, event=event, user=friend, friend=user)
示例#8
0
def user_invited(event_id, inviter_id, invited_id):
    try:
        event = Event.find(event_id)
        inviter = User.find(inviter_id)
        invited = User.find(invited_id)
    except DoesNotExist:
        return

    # make sure i am seeing all my friends attending now
    for friend in invited.friends_iter():
        if friend.is_attending(event):
            event.add_to_user_attending(invited, friend)
示例#9
0
def sendgrid_hook():
    data = request.get_data() or request.form.get('data') or ''
    if not data:
        abort(400, message='JSON post data invalid')

    try:
        data = ujson.loads(data)
    except ValueError:
        abort(400, message='JSON post data invalid')

    for record in data:
        event = record.get('event')
        user = None
        user_id = record.get('user_id')

        if user_id:
            try:
                user = User.find(user_id)
            except DoesNotExist:
                pass

        if not user:
            try:
                user = User.find(email=record.get('email'))
            except DoesNotExist:
                pass

        # only update the user if not validated already, since if they are validated
        # the email_validated_status will be set
        if user and not user.email_validated:
            event = record.get('event')
            existing_event = user.email_validated_status

            # make sure events progress forward, don't allow "delivered"->"processed"
            sg_evt_ord = [
                'processed', 'dropped', 'deferred', 'delivered', 'bounce',
                'open', 'click', 'unsubscribe', 'spamreport'
            ]

            if event in sg_evt_ord and existing_event in sg_evt_ord and \
                            sg_evt_ord.index(existing_event) >= sg_evt_ord.index(event):
                continue

            logger.info('updating email validation status for user "%s", %s' %
                        (user.email, event))
            user.email_validated_status = event
            user.save()

    return jsonify(success=True)
示例#10
0
def test_update_user():
    from server.models.user import User

    with client() as c:
        user = User.find(key='test')

        resp = api_post(c, user, '/api/users/me', {
            'key': '123',
            'bio': '321'
        })

        assert resp.status_code == 200, 'oops {}'.format(resp.data)
        user = User.find(key='test')
        assert user.bio == '321'
        assert user.key == 'test', 'key should not change, blacklisted'
示例#11
0
        def decorated(*args, **kw):
            headers = {}
            kw['headers'] = headers

            if context_var == 'user' and 'user_id' in kw:
                user_id = kw['user_id']
                if user_id == '(null)':
                    return f(*args, **kw)
                context = g.user if user_id == 'me' else User.find(int(user_id))
            else:
                context = getattr(g, context_var, None)

            if not context:
                return f(*args, **kw)

            last_change = wigo_db.get_redis().hget(skey(context, 'meta'), field)
            if last_change:
                last_change = datetime.utcfromtimestamp(float(last_change))
            else:
                return f(*args, **kw)

            if last_change > datetime.utcnow():
                # if last-change is set to the future, the intent is to disable if-modified-since
                # until that time. Last-Modified can't be set to the future or that doesn't work.
                headers['Last-Modified'] = http_date(datetime.utcnow())
            else:
                headers['Last-Modified'] = http_date(last_change)

            if max_age:
                headers['Cache-Control'] = 'max-age={}'.format(max_age)

            if last_change and not is_resource_modified(request.environ, last_modified=last_change):
                return 'Not modified', 304, headers

            return f(*args, **kw)
示例#12
0
    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')
示例#13
0
def notify_on_attendee(event_id, user_id):
    try:
        event = Event.find(event_id)
        user = User.find(user_id)
        if event.owner is None:
            return
    except DoesNotExist:
        return

    if event.is_expired or not user.is_attending(event):
        return

    targets = [5, 10, 20, 30, 50, 75, 100, 150, 200, 250, 300, 350, 400, 450, 500]
    num_attending = get_num_attending(event_id)
    target = next(reversed([t for t in targets if t <= num_attending]), None)

    if target is None:
        return

    rl_key = 'notify:event_creators:{}:{}:{}'.format(event.id, event.owner_id, target)
    with rate_limit(rl_key, event.expires) as limited:
        if not limited:
            notification = Notification({
                'user_id': event.owner_id,
                'type': 'system',
                'navigate': '/events/{}'.format(event_id),
                'badge': 1,
                'message': '{} people are going to your event {}'.format(
                    num_attending, event.name.encode('utf-8'))
            }).save()

            send_notification_push.delay(notification.to_primitive())
示例#14
0
def new_user(user_id, score=None):
    user = User.find(user_id)

    if user.status != 'waiting':
        return

    user_queue_key = skey('user_queue')

    if score is None:
        if user_id < 130000:
            score = time() + randint(60, 60 * 30)
        else:
            last_waiting = wigo_db.sorted_set_range(user_queue_key, -1, -1,
                                                    True)
            if last_waiting:
                last_waiting_score = last_waiting[0][1]
                if last_waiting_score > (time() + (60 * 60 * 6)):
                    score = last_waiting_score + 10
                else:
                    score = last_waiting_score + randint(0, 60)
            else:
                score = time() + randint(120, 60 * 20)

    wigo_db.sorted_set_add(user_queue_key, user_id, score, replicate=False)

    scheduler.schedule(datetime.utcfromtimestamp(score),
                       process_waitlist,
                       result_ttl=0,
                       timeout=600)
示例#15
0
def notify_on_eventmessage_vote(voter_id, message_id):
    try:
        voter = User.find(voter_id)
        message = EventMessage.find(message_id)
    except DoesNotExist:
        return

    user = message.user
    type = 'video' if message.media_mime_type == 'video/mp4' else 'photo'

    # don't send to self or if not friend
    if (voter_id == message.user_id) or (not user.is_friend(voter_id)):
        return

    with rate_limit('notify:vote:%s:%s:%s' % (message.user_id, message_id, voter_id),
                    timedelta(hours=2)) as limited:
        if not limited:
            message_text = '{name} liked your {type} in {event}'.format(
                name=voter.full_name.encode('utf-8'),
                type=type,
                event=message.event.name.encode('utf-8'))

            notification = Notification({
                'user_id': message.user_id,
                'type': 'eventmessage.vote',
                'from_user_id': voter_id,
                'navigate': '/users/me/events/{}/messages/{}'.format(message.event_id, message.id),
                'message': message_text
            }).save()

            send_notification_push.delay(notification.to_primitive())
示例#16
0
def process_waitlist():
    from server.db import redis

    while True:
        lock = redis.lock('locks:process_waitlist', timeout=600)
        if lock.acquire(blocking=False):
            try:
                user_ids = wigo_db.sorted_set_range_by_score(
                    skey('user_queue'), 0, time(), 0, 50)
                if user_ids:
                    for user_id in user_ids:
                        logger.info('unlocking user id {}'.format(user_id))
                        user = User.find(user_id)
                        if user.is_waiting():
                            user.status = 'active'
                            user.save()

                        # remove from wait list
                        wigo_db.sorted_set_remove(skey('user_queue'),
                                                  user.id,
                                                  replicate=False)
                else:
                    break
            finally:
                lock.release()
示例#17
0
def notify_on_friend_attending(event_id, user_id, friend_id):
    num_attending = get_num_attending(event_id, user_id)
    if num_attending < 5:
        return

    try:
        event = Event.find(event_id)
        user = User.find(user_id)
    except DoesNotExist:
        return

    if event.is_expired:
        return

    rl_key = 'notify:nofa:{}:{}'.format(event_id, user_id)
    with rate_limit(rl_key, event.expires) as limited:
        if not limited:
            friends = list(islice(EventAttendee.select().event(event).user(user).limit(6), 5))
            if user in friends:
                friends.remove(user)
                num_attending -= 1

            logger.info('notifying user {} of {} friends attending event {}'.format(user_id, num_attending, event_id))
            if len(friends) >= 2:
                notification = Notification({
                    'user_id': user.id,
                    'type': 'system',
                    'navigate': '/users/me/events/{}'.format(event_id),
                    'badge': 1,
                    'message': '{}, {}, and {} others are going to {}'.format(
                        friends[0].full_name.encode('utf-8'), friends[1].full_name.encode('utf-8'),
                        num_attending - 2, event.name.encode('utf-8'))
                }).save()

                send_notification_push.delay(notification.to_primitive())
示例#18
0
 def owner(self):
     if hasattr(self, 'owner_id') and self.owner_id:
         from server.models.user import User
         try:
             return User.find(self.owner_id)
         except DoesNotExist:
             logger.warn('user {} not found'.format(self.owner_id))
     return None
示例#19
0
def tell_friend_event_message(message_id, friend_id):
    try:
        message = EventMessage.find(message_id)
        friend = User.find(friend_id)
    except DoesNotExist:
        return

    message.record_for_user(friend)
示例#20
0
    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
示例#21
0
 def iterate_facebook(next=None):
     for facebook_id in facebook.get_friend_ids(next):
         try:
             friend = User.find(facebook_id=facebook_id)
             if should_suggest(friend.id):
                 yield friend.id
         except DoesNotExist:
             pass
示例#22
0
def send_email_verification(user_id, resend=False):
    if not Configuration.PUSH_ENABLED:
        return

    sendgrid = create_sendgrid()

    user = User.find(user_id)

    verify_code = wigo_db.get_new_code({
        'type': 'verify_email',
        'user_id': user_id,
        'email': user.email
    })

    verify_link = '{}://{}/c/{}'.format(
        'https' if Configuration.ENVIRONMENT != 'dev' else 'http',
        Configuration.WEB_HOST, verify_code)

    logger.info('generated verify code for user "%s", "%s"' %
                (user.email, verify_code))

    first_name = user.first_name
    if not first_name:
        first_name = user.email

    msg = Mail()

    if resend:
        msg.set_subject('Everyone deserves a second chance')
    else:
        msg.set_subject('Welcome to Wigo')

    msg.set_from('Wigo <*****@*****.**>')

    if user.first_name and user.last_name:
        msg.add_to('%s <%s>' % (user.full_name, user.email))
    else:
        msg.add_to(user.email)

    msg.set_text(
        "Hi %s\n\nPlease click the following link to verify your email address:\n\n%s\n\n"
        % (first_name, verify_link))

    msg.set_html(
        render_template('confirmation_email.html',
                        name=first_name,
                        confirmation_link=verify_link,
                        resend=resend))

    msg.add_unique_arg('user_id', user.id)
    msg.add_category('verify')
    msg.add_filter('opentrack', 'enable', 0)
    msg.add_filter('subscriptiontrack', 'enable', 1)
    msg.add_filter('subscriptiontrack', 'replace', '-UNSUB-')

    sendgrid.send(msg)
    logger.info('sent verification email to "%s"' % user.email)
示例#23
0
def test_event_messages():
    from server.models.event import Event
    from server.models.user import User

    with client() as c:
        user1 = User.find(key='test')
        user2 = User.find(key='test2')
        event_id = create_event(c, user1, 'e1')
        event = Event.find(event_id)

        create_event_message(c, user1, event, 'test.jpg')
        assert 1 == EventMessage.select().event(event).count()
        assert 1 == EventMessage.select().event(event).user(user1).count()
        assert 0 == EventMessage.select().event(event).user(user2).count()

        make_friends(c, user1, user2)

        assert 1 == EventMessage.select().event(event).user(user2).count()
示例#24
0
    def get(self):
        user_ids = request.args.get('ids')
        text = request.args.get('text')
        if text:
            text = text.strip()

        if user_ids:
            user_ids = [
                int(user_id.strip()) for user_id in user_ids.split(',')
            ]
            users = User.find(user_ids)
            return self.serialize_list(self.model, users, len(users), 1)
        elif text and len(text) > 1:
            sql = "SELECT id FROM users WHERE "
            text = text.encode('utf-8')

            params = []
            split = [('{}%%'.format(part))
                     for part in re.split(r'\s+',
                                          text.strip().lower())]
            for index, s in enumerate(split):
                if index != 0:
                    sql += ' AND '
                sql += "((LOWER(first_name) LIKE %s) or (LOWER(last_name) LIKE %s))"
                params.append(s)
                params.append(s)

            sql += """
                ORDER BY earth_distance(
                    ll_to_earth({},{}),
                    ll_to_earth(latitude, longitude)
                ), first_name, last_name LIMIT 50
            """.format(g.user.group.latitude, g.user.group.longitude)

            with slave.execution_context(False) as ctx:
                results = list(slave.execute_sql(sql, params))

            users = User.find([id[0] for id in results])
            return self.serialize_list(self.model, users)

        else:
            count, page, instances = self.setup_query(
                self.model.select().group(g.group)).execute()
            return self.serialize_list(self.model, instances, count, page)
示例#25
0
def test_update_user_group():
    from server.models.group import Group
    from server.models.user import User

    with client() as c:
        user = User.find(key='test')
        g = user.group

        user.group_id = Group.find(code='san_diego').id
        user.save()

        assert User.find(key='test').group.name == 'San Diego'

        # posting with geo should change the users group
        resp = api_post(c, user, '/api/users/me', {
            'bio': '321'
        }, lat=42.3584, lon=-71.0598)

        assert User.find(key='test').group.name == 'Boston'
示例#26
0
def test_event_message_votes():
    from server.models.event import Event
    from server.models.user import User
    from server.db import wigo_db

    with client() as c:
        user1 = User.find(key='test')
        user2 = User.find(key='test2')
        user3 = User.find(key='test3')

        make_friends(c, user2, user3)

        event_id = create_event(c, user1, 'e1')
        event = Event.find(event_id)

        message_id_1 = create_event_message(c, user1, event, 'test.jpg')
        message_id_2 = create_event_message(c, user1, event, 'test.jpg')

        message_1 = EventMessage.find(message_id_1)
        message_2 = EventMessage.find(message_id_2)

        resp = create_event_message_vote(c, user1, event, message_1)
        resp = create_event_message_vote(c, user2, event, message_2)
        resp = create_event_message_vote(c, user3, event, message_2)

        assert wigo_db.get_sorted_set_size(skey(message_1, 'votes')) == 1
        assert wigo_db.get_sorted_set_size(skey(message_2, 'votes')) == 2

        assert EventMessage.select().event(event).by_votes().get() == message_2

        resp = api_get(c, user1,
                       '/api/events/{}/messages/meta'.format(event_id))
        data = ujson.loads(resp.data)
        assert 1 == data[str(message_id_1)]['num_votes']

        make_friends(c, user1, user2)

        make_friends(c, user1, user3)

        resp = create_event_message_vote(c, user2, event, message_1)
        resp = create_event_message_vote(c, user3, event, message_1)

        assert EventMessage.select().event(event).by_votes().get() == message_1
示例#27
0
def tell_friends_user_not_attending(user_id, event_id):
    try:
        user = User.find(user_id)
        event = Event.find(event_id)
    except DoesNotExist:
        return

    if not user.is_attending(event):
        for friend_id, score in wigo_db.sorted_set_iter(skey(user, 'friends')):
            tell_friend_user_not_attending.delay(user_id, event_id, friend_id)
示例#28
0
def privacy_changed(user_id):
    # tell all friends about the privacy change
    user = User.find(user_id)

    with wigo_db.transaction(commit_on_select=False):
        for friend in user.friends_iter():
            if user.privacy == 'public':
                wigo_db.set_remove(skey(friend, 'friends', 'private'), user_id)
            else:
                wigo_db.set_add(skey(friend, 'friends', 'private'), user_id)
示例#29
0
def tell_friends_user_attending(user_id, event_id, notify=True):
    try:
        user = User.find(user_id)
        event = Event.find(event_id)
    except DoesNotExist:
        return

    if user.is_attending(event):
        for friend in user.friends_iter():
            if friend.can_see_event(event):
                tell_friend_user_attending.delay(user_id, event_id, friend.id,
                                                 notify)
示例#30
0
def delete_friend(user_id, friend_id):
    user = User.find(user_id)
    friend = User.find(friend_id)

    if user.is_friend(friend):
        return

    def delete_history(u, f):
        with wigo_db.transaction(commit_on_select=False):
            for message in EventMessage.select().key(skey(u,
                                                          'event_messages')):
                if message.user and message.event:
                    message.remove_for_user(f)

        for event in Event.select().user(u):
            if wigo_db.sorted_set_is_member(user_attendees_key(f, event),
                                            u.id):
                event.remove_from_user_attending(f, u)

    delete_history(user, friend)
    delete_history(friend, user)