Exemplo n.º 1
0
def setup_followup_history():
    """
    There are 4 users 1,2,3,4 but 4 doesn't have a social profile

    There are 2 chats:
    * chat 1 has participants 1,2,3,4 and followups from 2 outside of time range and 3,4 within time range
    * chat 2 has participants 1,2 and followups from 2 inside of time range

    Therefore
    * user 1 will get notifications from 3,4 for chat 1   and    from 2 for chat 2
    * user 2 will get notifications from 3,4 for chat 1
    * user 3 will get notifications from 4 for chat 1  <-- note: users don't receive notifications for their own updates
    * user 4 would get notifications from 3 for chat 1 BUT has no social profile, so no way to contact them

    :return:
    """
    user1 = UserFactory()
    soc_prof1 = SocialProfileFactory(user=user1)
    user2 = UserFactory()
    soc_prof2 = SocialProfileFactory(user=user2)
    user3 = UserFactory()
    soc_prof3 = SocialProfileFactory(user=user3)
    user4 = UserFactory()
    # NOTE! soc_prof4 is intentionally omitted because sometimes a User doesn't have a SocialProfile

    penny_chat1 = PennyChatFactory()
    Participant.objects.create(penny_chat=penny_chat1,
                               user=user1,
                               role=Participant.ORGANIZER)
    Participant.objects.create(penny_chat=penny_chat1,
                               user=user2,
                               role=Participant.ATTENDEE)
    Participant.objects.create(penny_chat=penny_chat1,
                               user=user3,
                               role=Participant.ATTENDEE)
    Participant.objects.create(penny_chat=penny_chat1,
                               user=user4,
                               role=Participant.ATTENDEE)
    FollowUpFactory(penny_chat=penny_chat1, user=user2, date=before_range_date)
    FollowUpFactory(penny_chat=penny_chat1, user=user3, date=within_range_date)
    FollowUpFactory(penny_chat=penny_chat1, user=user4, date=within_range_date)

    penny_chat2 = PennyChatFactory()
    Participant.objects.create(penny_chat=penny_chat2,
                               user=user2,
                               role=Participant.ORGANIZER)
    Participant.objects.create(penny_chat=penny_chat2,
                               user=user1,
                               role=Participant.ATTENDEE)
    FollowUpFactory(penny_chat=penny_chat2, user=user2, date=within_range_date)

    return {
        'penny_chats': [penny_chat1, penny_chat2],
        'users': [user1, user2, user3, user4],
        'social_profiles': [soc_prof1, soc_prof2, soc_prof3]
    }
Exemplo n.º 2
0
def test_make_matches(mocker):
    slack_team_id = 'sl123'
    slack_client = mocker.Mock()
    conversation = {'channel': {'id': 'FAKE123'}}
    slack_client.conversations_open.return_value = conversation

    profile1 = SocialProfileFactory(slack_team_id=slack_team_id)
    profile2 = SocialProfileFactory(slack_team_id=slack_team_id)
    profile3 = SocialProfileFactory(slack_team_id=slack_team_id)

    channel = TopicChannel.objects.create(
        channel_id='one',
        slack_team_id=slack_team_id,
        name='uno',
    )

    with mocker.patch('matchmaking.common.get_slack_client',
                      return_value=slack_client):
        make_matches(slack_team_id,
                     [profile1.email, profile2.email, profile3.email],
                     channel.name)

    expected_blocks = [
        {
            "type": "section",
            "text": {
                "type":
                "mrkdwn",
                "text":
                "Yahoo, you've been matched for a conversation about <#one>!\n\nWork together to find a time to meet and chat. Once you do, click the button below to schedule a Penny Chat.",  # noqa
            }
        },
        {
            "type":
            "actions",
            "elements": [{
                "type": "button",
                "action_id": "penny_chat_schedule_match",
                "text": {
                    "type": "plain_text",
                    "text": "Schedule Chat :calendar:",
                    "emoji": True,
                },
                "value": "FAKE123",
                "style": "primary",
            }]
        }
    ]

    slack_client.chat_postMessage.assert_called_once_with(
        channel='FAKE123', blocks=expected_blocks)
    match = Match.objects.get(conversation_id='FAKE123', topic_channel=channel)
    assert profile1 in match.profiles.all()
    assert profile2 in match.profiles.all()
    assert profile3 in match.profiles.all()
Exemplo n.º 3
0
def test_schedule_match_penny_chat(mocker):
    profile_1 = SocialProfileFactory()
    profile_2 = SocialProfileFactory()
    topic = TopicChannel.objects.create(slack_team_id=profile_1.slack_team_id,
                                        channel_id='FAKE_CHANNEL',
                                        name='testing')
    match = Match.objects.create(topic_channel=topic,
                                 conversation_id='FAKE_CONVERSATION')
    match.profiles.add(profile_1, profile_2)

    event = {
        'user': {
            'id': profile_1.slack_id,
            'team_id': profile_1.slack_team_id
        },
        'trigger_id':
        'fake_trigger',
        'actions': [{
            'action_id': 'penny_chat_schedule_match',
            'value': match.conversation_id
        }],
    }

    slack_client = mocker.Mock()
    response = mocker.Mock(data={'view': {'id': '12345'}})
    slack_client.configure_mock(**{'views_open.return_value': response})

    # The Actual Tests
    with mocker.patch(
            'bot.processors.pennychat.get_or_create_social_profile_from_slack_id',
            return_value=profile_1):
        PennyChatBotModule(slack_client).schedule_match(event)

    match.refresh_from_db()
    penny_chat = match.penny_chat
    assert penny_chat is not None
    invite = PennyChatSlackInvitation.objects.get(penny_chat=penny_chat)
    assert invite.invitees == profile_2.slack_id
    assert invite.title == f'{profile_1.real_name} + {profile_2.real_name} Discuss {match.topic_channel.name}'
    assert invite.organizer_slack_id == profile_1.slack_id
Exemplo n.º 4
0
def test_penny_chat_reminders_blocks(mocker):
    invite = PennyChatSlackInvitationFactory()
    organizer = UserFactory()
    organizer_profile = SocialProfileFactory()
    Participant.objects.create(user=organizer,
                               penny_chat=invite,
                               role=Participant.ORGANIZER)
    for i in range(12):
        user = UserFactory()
        Participant.objects.create(user=user,
                                   penny_chat=invite,
                                   role=Participant.ATTENDEE)

    with mocker.patch(
            'bot.tasks.pennychat.get_or_create_social_profile_from_slack_id',
            return_value=organizer_profile):
        reminder_blocks = _penny_chat_details_blocks(invite, 'remind')

    # Check that the correct number of blocks were created
    assert len(reminder_blocks[4]['elements']) == 10
    assert reminder_blocks[4]['elements'][-1]['text'] == '& 4 more attending'
Exemplo n.º 5
0
def test_get_unfulfilled_match_requests():
    now = datetime.now().astimezone(timezone.utc)
    since_date = now - timedelta(weeks=10)

    with freeze_time(now - timedelta(weeks=52), tz_offset=0):
        old_match_request_with_no_match = MatchRequestFactory(
            profile=SocialProfileFactory())

    with freeze_time(now - timedelta(weeks=5), tz_offset=0):
        match_request_with_successful_match = MatchRequestFactory(
            profile=SocialProfileFactory())
        MatchFactory(
            profiles=(match_request_with_successful_match.profile,
                      SocialProfileFactory()),
            # penny_chat is automatically supplied by MatchFactory
            date=now - timedelta(weeks=4),
        )

        match_request_with_unsuccessful_match = MatchRequestFactory(
            profile=SocialProfileFactory())
        MatchFactory(
            profiles=(match_request_with_unsuccessful_match.profile,
                      SocialProfileFactory()),
            penny_chat=None,
            date=now - timedelta(weeks=4),
        )

        match_request_with_no_match = MatchRequestFactory(
            profile=SocialProfileFactory())

    match_requests_profile_ids = set([
        mr['profile_id']
        for mr in MatchMaker._get_unfulfilled_match_requests(since_date)
    ])
    assert old_match_request_with_no_match.profile_id not in match_requests_profile_ids, \
        'this profile made a match request too long ago and should not be considered'
    assert match_request_with_successful_match.profile_id not in match_requests_profile_ids, \
        'this profile has had a successful match since their last match request and should not be considered'
    assert match_request_with_unsuccessful_match.profile_id in match_requests_profile_ids, \
        'this profile has had an unsuccessful match since their last match request (no chat) and should be considered'
    assert match_request_with_no_match.profile_id in match_requests_profile_ids, \
        'this profile has not had a match since their last match request and should be considered'
Exemplo n.º 6
0
def test_gather_data():
    now = datetime.now().astimezone(timezone.utc)
    prof1, prof2, prof3, prof4, prof5, prof6, prof_too_old = [
        SocialProfileFactory(email=f'prof{i+1}@email.com') for i in range(7)
    ]
    prof_too_old.email = '*****@*****.**'
    prof_too_old.save()

    topic_channel_science = TopicChannelFactory(name='science')
    topic_channel_art = TopicChannelFactory(name='art')

    with freeze_time(now - timedelta(weeks=52), tz_offset=0):
        MatchRequestFactory(profile=prof_too_old)

    with freeze_time(now - timedelta(weeks=1), tz_offset=0):
        MatchRequestFactory(
            profile=prof1,
            topic_channel=topic_channel_art,
        )
        MatchRequestFactory(
            profile=prof1,
            topic_channel=topic_channel_science,
        )
        MatchRequestFactory(profile=prof2, topic_channel=topic_channel_art)
        MatchRequestFactory(profile=prof3, topic_channel=topic_channel_science)
        MatchRequestFactory(profile=prof4, topic_channel=topic_channel_science)

    with freeze_time(now - timedelta(weeks=3), tz_offset=0):
        MatchFactory(
            topic_channel=topic_channel_art,
            profiles=(prof1, prof2, prof3),
        )
        MatchFactory(
            topic_channel=topic_channel_science,
            profiles=(prof4, prof5),
        )
        MatchFactory(
            topic_channel=topic_channel_science,
            profiles=(prof6, prof_too_old),
        )

    match_maker = MatchMaker(match_request_since_date=now - timedelta(weeks=2))
    match_maker._gather_data()

    # _recent_match_by_profile_pair, _recent_match_by_profile_pair, and _recent_match_by_profile_pair_and_topic
    # are used to look up information useful in creating a score
    assert 'prof_too_old' not in set(
        chain(*set(match_maker._recent_match_by_profile_pair.keys())))
    assert set(match_maker._recent_match_by_profile_pair.keys()) == {
        key('*****@*****.**', '*****@*****.**'),
        # note that the meeting with 3 people got turned into 3 pairs here
        key('*****@*****.**', '*****@*****.**'),
        key('*****@*****.**', '*****@*****.**'),
        key('*****@*****.**', '*****@*****.**'),
    }
    assert match_maker._recent_match_by_profile_pair[key(
        '*****@*****.**', '*****@*****.**')]['num_attending'] == 3

    assert set(match_maker._recent_match_by_profile_topic) == {
        key('*****@*****.**', 'art'),
        key('*****@*****.**', 'art'),
        key('*****@*****.**', 'art'),
        key('*****@*****.**', 'science'),
        key('*****@*****.**', 'science'),
    }

    assert set(match_maker._recent_match_by_profile_pair_and_topic.keys()) == {
        key('*****@*****.**', '*****@*****.**', 'art'),
        key('*****@*****.**', '*****@*****.**', 'art'),
        key('*****@*****.**', '*****@*****.**', 'art'),
        key('*****@*****.**', '*****@*****.**', 'science'),
    }

    # _match_requests_profile_to_topic, _match_requests_topic_to_profile, and _possible_matches
    # are used largely as filters to quickly find topics for people, people for topics, and people that share a topic
    # respectively
    assert match_maker._match_requests_profile_to_topic == {
        '*****@*****.**': {'science', 'art'},
        '*****@*****.**': {'art'},
        '*****@*****.**': {'science'},
        '*****@*****.**': {'science'},
    }
    assert match_maker._match_requests_topic_to_profile == {
        'art': {'*****@*****.**', '*****@*****.**'},
        'science': {'*****@*****.**', '*****@*****.**', '*****@*****.**'},
    }
    assert match_maker._possible_matches == {
        '*****@*****.**':
        {'*****@*****.**', '*****@*****.**', '*****@*****.**'},
        '*****@*****.**': {'*****@*****.**'},
        '*****@*****.**': {'*****@*****.**', '*****@*****.**'},
        '*****@*****.**': {'*****@*****.**', '*****@*****.**'},
    }
Exemplo n.º 7
0
def test_review_match_requests():
    profile1 = SocialProfileFactory()
    profile2 = SocialProfileFactory()
    profile3 = SocialProfileFactory()

    chan1 = TopicChannel.objects.create(
        channel_id='one',
        slack_team_id='sl123',
        name='uno',
    )
    chan2 = TopicChannel.objects.create(
        channel_id='two',
        slack_team_id='sl123',
        name='dos',
    )

    # recent
    with freeze_time(timezone.now() - timedelta(days=3), tz_offset=0):
        MatchRequest.objects.create(
            topic_channel=chan1,
            profile=profile1,
        )
        MatchRequest.objects.create(
            topic_channel=chan2,
            profile=profile1,
        )
        MatchRequest.objects.create(
            topic_channel=chan1,
            profile=profile2,
        )

    # old - this one better not show up
    with freeze_time(timezone.now() - timedelta(days=30), tz_offset=0):
        MatchRequest.objects.create(
            topic_channel=chan1,
            profile=profile3,
        )

    actual = get_recent_matches(since_days_ago=7)
    expected = f"""PROFILE TO TOPICS
{profile1.email} ({profile1.real_name}) requested a match for:
	topic {chan1.name} in channel {chan1.channel_id}
	topic {chan2.name} in channel {chan2.channel_id}


{profile2.email} ({profile2.real_name}) requested a match for:
	topic {chan1.name} in channel {chan1.channel_id}




TOPIC TO PROFILES
Channel {chan1.channel_id} with topic {chan1.name} has interested people:
	topic {profile1.email} ({profile1.real_name})
	topic {profile2.email} ({profile2.real_name})


Channel two with topic dos has interested people:
	topic {profile1.email} ({profile1.real_name})

"""  # noqa

    assert actual == expected  # noqa