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())
def get(self, headers): user = g.user group = g.group query = self.select().group(group) query = query.min(epoch(group.get_day_end() - timedelta(days=8))) query = query.max(epoch(group.get_day_end() + timedelta(hours=4))) count, page, events = query.execute() if count == 0 and group.status == 'initializing': tries = int(request.args.get('tries', 0)) if tries < 5: sleep(1) # clients seem to not obey Retry-After, so artificially delay request_arguments = request.args.copy().to_dict() request_arguments['tries'] = tries response = redirect('%s?%s' % (request.path, url_encode(request_arguments))) response.headers.add('Retry-After', 1) return response else: # return without "headers" so this response isn't cached return self.serialize_list(self.model, events, count, page), 200 attending_id = g.user.get_attending_id() if attending_id: try: attending = Event.find(attending_id) if attending in events: events.remove(attending) if 'page' not in request.args: events.insert(0, attending) attending.current_user_attending = True except DoesNotExist: logger.warn('Event {} not found'.format(attending_id)) return self.serialize_list(self.model, events, count, page), 200, headers
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
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'
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())
def event(self): if self.event_id: from server.models.event import Event try: return Event.find(self.event_id) except DoesNotExist: logger.warn('event {} not found'.format(self.event_id)) return None
def get(self, event_id, message_id, headers): from server.models.user import User event = Event.find(event_id) if not g.user.can_see_event(event): abort(403, message='Can not see event') message = EventMessage.find(message_id) count, page, votes = self.select().eventmessage(message).execute() return self.serialize_list(User, votes, count, page), 200, headers
def get(self, user_id, event_id, headers): event = Event.find(event_id) if not g.user.can_see_event(event): abort(403, message='Can not see event') query = self.select().event(event).user(g.user).secure(g.user) # if event.is_expired: # query = query.by_votes() count, page, messages = query.execute() return self.serialize_list(self.model, messages, count, page), 200, headers
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)
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)
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)
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)
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)
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()
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
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)
def notify_on_invite(inviter_id, invited_id, event_id): rl_key = 'notify:invite:{}:{}:{}'.format(inviter_id, invited_id, event_id) with rate_limit(rl_key, timedelta(hours=2)) as limited: if not limited: inviter = User.find(inviter_id) invited = User.find(invited_id) event = Event.find(event_id) if event_id else None message_text = '{} invited you out to {}'.format(inviter.full_name.encode('utf-8'), event.name.encode('utf-8')) notification = Notification({ 'user_id': invited_id, 'type': 'invite', 'from_user_id': inviter_id, 'navigate': '/users/me/events/{}'.format(event_id), 'badge': 1, 'message': message_text }).save() send_notification_push.delay(notification.to_primitive())
def test_attending(): 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') create_event(c, user1, 'test event 1') event = Event.find(name='test event 1', group=user1.group) resp = api_post(c, user2, '/api/events/{}/attendees'.format(event.id), {}) assert resp.status_code == 200, 'oops {}'.format(resp.data) assert 2 == EventAttendee.select().event(event).count() assert 1 == EventAttendee.select().event(event).user(user1).count() assert 1 == EventAttendee.select().event(event).user(user2).count() make_friends(c, user1, user2) assert 2 == EventAttendee.select().event(event).user(user1).count()
def get(self, user_id, headers): user = g.user group = g.group query = self.select().user(user) query = query.min(epoch(group.get_day_end() - timedelta(days=8))) query = query.max(epoch(group.get_day_end() + timedelta(hours=4))) count, page, events = query.execute() attending_id = user.get_attending_id() if attending_id: try: attending = Event.find(attending_id) if attending in events: events.remove(attending) if 'page' not in request.args: events.insert(0, attending) attending.current_user_attending = True except DoesNotExist: logger.warn('Event {} not found'.format(attending_id)) return self.serialize_list(self.model, events, count, page), 200, headers
def send_friend_invites(user_id, event_id): try: user = User.find(user_id) event = Event.find(event_id) except DoesNotExist: return if event.is_expired or not user.is_attending(event): return groups = {} for friend in user.friends_iter(): if wigo_db.sorted_set_is_member( skey('event', event_id, user, 'invited'), friend.id): continue if friend.group_id: friend_group = groups.get(friend.group_id) if friend_group is None: friend_group = Group.find(friend.group_id) groups[friend.group_id] = friend_group distance = Location.getLatLonDistance( (user.group.latitude, user.group.longitude), (friend_group.latitude, friend_group.longitude)) if distance > 160: # > 160km, 100 miles continue try: invite = Invite() invite.user_id = user.id invite.invited_id = friend.id invite.event_id = event_id invite.save() except ValidationException, e: logger.warn('error creating invite, {}'.format(e.message))
def event_related_change(group_id, event_id, is_global=False, deleted=False): from server.db import redis lock = redis.lock('locks:group_event_change:{}:{}'.format( group_id, event_id), timeout=120) if lock.acquire(blocking=False): try: agent.add_custom_parameter('group_id', group_id) logger.debug('recording event change in group {}'.format(group_id)) if not deleted: try: event = Event.find(event_id) event.deleted = False except DoesNotExist: event = Event({'id': event_id, 'group_id': group_id}) event.deleted = True else: event = Event({'id': event_id, 'group_id': group_id}) event.deleted = True group = Group.find(group_id) with wigo_db.transaction(commit_on_select=False): # add to the time in case other changes come in while this lock is taken, # or in case the job queues get backed up group.track_meta('last_event_change', time() + EVENT_CHANGE_TIME_BUFFER) if is_global or event.is_global: groups_to_add_to = get_all_groups() else: radius = 100 population = group.population or 50000 if population < 60000: radius = 40 elif population < 100000: radius = 60 groups_to_add_to = get_close_groups( group.latitude, group.longitude, radius) num_visited = 0 for group_to_add_to in groups_to_add_to: if group_to_add_to.id == group.id: continue # index this event into the close group if event.deleted is False: event.update_global_events(group=group_to_add_to) else: event.remove_index(group=group_to_add_to) # track the change for the group group_to_add_to.track_meta( 'last_event_change', time() + EVENT_CHANGE_TIME_BUFFER) num_visited += 1 if (num_visited % 25) == 0: lock.extend(30) finally: lock.release()
def get(self, user_id, event_id, headers): event = Event.find(event_id) if not g.user.can_see_event(event): abort(403, message='Can not see event') count, page, instances = self.select().user(g.user).event(event).execute() return self.serialize_list(self.model, instances, count, page), 200, headers