Example #1
0
def command(request):
    event = request.POST
    logging.info(f'COMMAND> {request.POST}')
    command = event['text'].split(' ', 1)[0]
    if command == 'chat':
        PennyChatBotModule.create_penny_chat(slack_client, event)
    elif command == 'set-topic':
        MatchMakingBotModule.set_topic_channel(slack_client, event)
    else:
        blocks = [
            {
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": "I can help you make a new Penny Chat! Type `/penny chat` to get started.\n"
                            "_More features coming soon..._"
                }
            }
        ]
        chat_postEphemeral_with_fallback(
            slack_client,
            channel=event['channel_id'],
            user=event['user_id'],
            blocks=blocks,
        )

    return HttpResponse('')
Example #2
0
def test_visibility_select(mocker):
    slack_client = mocker.Mock()
    bot_module = PennyChatBotModule(slack_client)

    penny_chat = PennyChatSlackInvitationFactory()

    event = {
        'type':
        'block_actions',
        'trigger_id':
        'trigger',
        'view': {
            'id': 'view'
        },
        'actions': [{
            'action_id': penny_chat_constants.PENNY_CHAT_VISIBILITY,
            'selected_option': {
                'value': str(PennyChat.PRIVATE)
            }
        }],
        'user': {
            'id': 'user'
        }
    }

    bot_module(event)

    chat_id = PennyChatSlackInvitation.objects.get(id=penny_chat.id)
    assert chat_id.visibility == PennyChat.PRIVATE
Example #3
0
def test_date_select(mocker):
    slack_client = mocker.Mock()
    bot_module = PennyChatBotModule(slack_client)

    chat_id = create_penny_chat()

    event = {
        'type':
        'block_actions',
        'trigger_id':
        'trigger',
        'view': {
            'id': 'view'
        },
        'actions': [{
            'action_id': penny_chat_constants.PENNY_CHAT_DATE,
            'selected_date': '2019-01-01'
        }],
        'user': {
            'id': 'user'
        }
    }

    bot_module(event)

    penny_chat = PennyChatSlackInvitation.objects.get(id=chat_id)
    assert penny_chat.date.astimezone(TIMEZONE).date() == datetime(2019, 1,
                                                                   1).date()
Example #4
0
def test_time_select(mocker):
    slack_client = mocker.Mock()
    bot_module = PennyChatBotModule(slack_client)

    chat_id = create_penny_chat()

    event = {
        'type':
        'block_actions',
        'trigger_id':
        'trigger',
        'view': {
            'id': 'view'
        },
        'actions': [{
            'action_id': penny_chat_constants.PENNY_CHAT_TIME,
            'selected_option': {
                'value': '12:00 PM'
            }
        }],
        'user': {
            'id': 'user'
        }
    }

    bot_module(event)
    penny_chat = PennyChatSlackInvitation.objects.get(id=chat_id)
    test_time = datetime.now().replace(hour=12,
                                       minute=0,
                                       second=0,
                                       microsecond=0).time()
    assert penny_chat.date.astimezone(TIMEZONE).time() == test_time
Example #5
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
Example #6
0
    JsonResponse,
)
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.clickjacking import xframe_options_exempt

from bot.processors.greeting import GreetingBotModule
from bot.processors.pennychat import PennyChatBotModule
from bot.processors.matchmaking import MatchMakingBotModule
from bot.processors.base import Bot
from bot.utils import chat_postEphemeral_with_fallback
from common.utils import get_slack_client

slack_client = get_slack_client()
bot = Bot(event_processors=[
    GreetingBotModule(slack_client),
    PennyChatBotModule(slack_client),
    MatchMakingBotModule(slack_client),
])


def index(request):
    # We've come a long way haven't we?
    return HttpResponse("At least something works!!!!")


@xframe_options_exempt
@csrf_exempt
def hook(request):
    blob = json.loads(request.body)
    logging.info(f'HOOK> {request.body.decode("utf-8")}')
Example #7
0
def test_PennyChatBotModule_attendance_selection(
    msg,  # pytest prints this out when the test errors  # noqa
    starting_role,
    can_attend,
    expected_final_role,
    expected_organizer_notified,
    mocker,
):
    user_1 = User.objects.create_user(username='******')
    user_2 = User.objects.create_user(username='******')
    user_3 = User.objects.create_user(username='******')

    organizer = SocialProfile.objects.create(slack_id='organizer_id',
                                             slack_team_id=SLACK_TEAM_ID,
                                             user=user_1)

    if starting_role == Participant.ORGANIZER:
        profile = organizer
    else:
        profile = SocialProfile.objects.create(slack_id=str(time.time_ns()),
                                               user=user_2)

    some_other_attendee = SocialProfile.objects.create(slack_id=str(
        time.time_ns()),
                                                       user=user_3)

    fake_title = 'Fake Title'
    fake_year = 2054
    fake_channel = 'fake_chan'
    penny_chat = PennyChat.objects.create(
        date=timezone("America/Los_Angeles").localize(
            datetime(fake_year, 10, 12)),
        title=fake_title,
        created_from_slack_team_id=SLACK_TEAM_ID,
    )
    penny_chat_id_dict = json.dumps(
        {penny_chat_constants.PENNY_CHAT_ID: penny_chat.id})

    Participant.objects.create(penny_chat=penny_chat,
                               user=organizer.user,
                               role=Participant.ORGANIZER)
    Participant.objects.create(penny_chat=penny_chat,
                               user=some_other_attendee.user,
                               role=Participant.ATTENDEE)
    if starting_role not in [None, Participant.ORGANIZER]:
        Participant.objects.create(penny_chat=penny_chat,
                                   user=profile.user,
                                   role=starting_role)

    def user_attendance_event(user, can_attend):
        if can_attend:
            attendance = penny_chat_constants.PENNY_CHAT_CAN_ATTEND
        else:
            attendance = penny_chat_constants.PENNY_CHAT_CAN_NOT_ATTEND
        return {
            'user': {
                'id': user.slack_id
            },
            'channel': {
                'id': fake_channel
            },
            'trigger_id': '(used for @is_block_interaction_event decorator)',
            'actions': [{
                'action_id': attendance,
                'value': penny_chat_id_dict
            }],
        }

    event = user_attendance_event(profile, can_attend)

    slack_client = mocker.Mock()

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

    # Evaluation
    actual_final_role = None
    try:
        actual_final_role = Participant.objects.get(penny_chat=penny_chat,
                                                    user=profile.user).role
    except Participant.DoesNotExist as e:
        capture_exception(e)
        # presumably we weren't supposed to make a participant. this will be tested below
        pass

    assert expected_final_role == actual_final_role, \
        f"expected and final roles do not match (roles: {Participant.ROLE_CHOICES})"

    if expected_organizer_notified:
        # organizer notification
        slack_client.chat_postMessage.assert_called_once()
        notification = slack_client.chat_postMessage.call_args[1]
        assert notification[
            'channel'] == 'organizer_id', 'notified the wrong person'
        assert f'<@{profile.slack_id}>' in notification[
            'text'], 'forgot to list the (non)attendees name'
        assert fake_title in notification[
            'text'], 'forgot to mention which penny chat'
        assert str(fake_year) in notification['text'], 'forgot to mention date'
        if can_attend:
            assert 'not' not in notification['text'].lower(
            ), 'did we say they could NOT attend?'
        else:
            assert 'not' in notification['text'].lower(
            ), 'did we say they COULD attend?'

        # RSVPer "thanks" notification
        slack_client.chat_postEphemeral.assert_called_once()
        thanks = slack_client.chat_postEphemeral.call_args[1]
        assert thanks['channel'] == fake_channel
        assert thanks['user'] == profile.slack_id
        assert 'will notify' in thanks['text'].lower()
    else:
        slack_client.chat_postMessage.assert_not_called()

    # Make sure the other attendee wasn't affected
    assert Participant.objects.get(
        penny_chat=penny_chat,
        user=some_other_attendee.user).role == Participant.ATTENDEE
Example #8
0
def test_PennyChatBotModule_share(mocker):
    user_1 = User.objects.create_user(username='******')
    user_2 = User.objects.create_user(username='******')
    organizer = SocialProfile.objects.create(slack_id='organizer', user=user_1)
    invitee_1 = SocialProfile.objects.create(slack_id='invitee', user=user_2)
    # make sure that things don't break if for some reason a user attempts to invite themselves
    invitee_2 = organizer

    view_id = 'some_silly_view_id'
    penny_chat_invitation = PennyChatSlackInvitation.objects.create(
        invitees=','.join([invitee_1.slack_id, invitee_2.slack_id]),
        organizer_slack_id=organizer.slack_id,
        date=timezone("America/Los_Angeles").localize(datetime(1979, 10, 12)),
        title='fake title',
        view=view_id,
        description='fake description',
        created_from_slack_team_id=SLACK_TEAM_ID,
    )

    def id_mock(user_id, slack_client=None, ignore_user_not_found=True):
        lookup = {
            organizer.slack_id: organizer,
            invitee_1.slack_id: invitee_1,
        }
        return lookup[user_id]

    event = {
        'user': {
            'id': organizer.slack_id
        },
        'view': {
            'id': view_id,
            'state': {
                'values': {
                    'penny_chat_title': {
                        'penny_chat_title': {
                            'value': 'new_title',
                        }
                    },
                    'penny_chat_description': {
                        'penny_chat_description': {
                            'value': 'new_description',
                        }
                    }
                }
            },
        },
        'actions': [{
            'action_id': penny_chat_constants.PENNY_CHAT_SHARE
        }],
        'response_url': 'http://some_website.com',
        'type': penny_chat_constants.VIEW_CLOSED,
        'callback_id': penny_chat_constants.PENNY_CHAT_DETAILS,
    }

    share_penny_chat_invitation = mocker.patch(
        'bot.processors.pennychat.share_penny_chat_invitation')
    post_organizer_edit_after_share_blocks = mocker.patch(
        'bot.processors.pennychat.post_organizer_edit_after_share_blocks')

    # The Actual Test (premature close)
    with mocker.patch(
            'pennychat.models.get_or_create_social_profile_from_slack_id',
            side_effect=id_mock
    ), post_organizer_edit_after_share_blocks:  # noqa
        PennyChatBotModule(mocker.Mock()).submit_details_and_share(event)

    assert share_penny_chat_invitation.call_count == 0

    # The Actual Test (actual submission)
    event['type'] = penny_chat_constants.VIEW_SUBMISSION
    with mocker.patch(
            'pennychat.models.get_or_create_social_profile_from_slack_id',
            side_effect=id_mock
    ), post_organizer_edit_after_share_blocks:  # noqa
        PennyChatBotModule(mocker.Mock()).submit_details_and_share(event)

    assert share_penny_chat_invitation.call_args == call(
        penny_chat_invitation.id)
    assert post_organizer_edit_after_share_blocks.now.call_args == call(
        view_id)

    penny_chat_invitation.refresh_from_db()
    penny_chat = penny_chat_invitation.penny_chat
    assert penny_chat is not None
    assert penny_chat.title == 'new_title'
    assert penny_chat.description == 'new_description'
    assert penny_chat.date == penny_chat_invitation.date
    assert penny_chat.status == PennyChat.SHARED
    assert organizer.user in penny_chat_invitation.get_organizers()
    assert penny_chat_invitation.status == PennyChatSlackInvitation.SHARED
Example #9
0
def test_PennyChatBotModule_share(mocker):
    organizer = UserProfile.objects.create(slack_id='organizer')
    user_invitee_1 = UserProfile.objects.create(slack_id='invitee')
    # make sure that things don't break if for some reason a user attempts to invite themselves
    user_invitee_2 = organizer

    view_id = 'some_silly_view_id'
    penny_chat_invitation = PennyChatInvitation.objects.create(
        invitees=','.join([user_invitee_1.slack_id, user_invitee_2.slack_id]),
        organizer_slack_id=organizer.slack_id,
        date=timezone("America/Los_Angeles").localize(datetime(1979, 10, 12)),
        title='fake title',
        view=view_id,
        description='fake description',
    )

    def ids_mock(user_ids, slack_client):
        lookup = {
            organizer.slack_id: organizer,
            user_invitee_1.slack_id: user_invitee_1,
        }
        return {user_id: lookup[user_id] for user_id in user_ids}

    def id_mock(user_id, slack_client):
        return ids_mock([user_id], slack_client).get(user_id)

    event = {
        'user': {
            'id': organizer.slack_id
        },
        'view': {
            'id': view_id,
            'state': {
                'values': {
                    'penny_chat_title': {
                        'penny_chat_title': {
                            'value': 'new_title',
                        }
                    },
                    'penny_chat_description': {
                        'penny_chat_description': {
                            'value': 'new_description',
                        }
                    }
                }
            },
        },
        'actions': [{
            'action_id': penny_chat_constants.PENNY_CHAT_SHARE
        }],
        'response_url': 'http://some_website.com',
        'type': penny_chat_constants.VIEW_SUBMISSION,
        'callback_id': penny_chat_constants.PENNY_CHAT_DETAILS,
    }

    slack_client = mocker.Mock()
    slack_client.chat_postMessage().data = {
        'channel': 'share_chan',
        'ts': 'share_ts'
    }

    with mocker.patch('bot.processors.pennychat.get_or_create_user_profile_from_slack_ids', side_effect=ids_mock), \
            mocker.patch('bot.processors.pennychat.get_or_create_user_profile_from_slack_id', side_effect=id_mock), \
            mocker.patch('bot.processors.pennychat.requests'):

        # The Actual Test
        PennyChatBotModule(slack_client).submit_details_and_share(event)

    message_to_slack = str(
        slack_client.chat_postMessage.call_args[1]['blocks'])
    assert "new_title" in message_to_slack
    assert "new_description" in message_to_slack

    penny_chat_invitation.refresh_from_db()
    penny_chat = penny_chat_invitation.penny_chat
    assert penny_chat is not None
    assert penny_chat.title == 'new_title'
    assert penny_chat.description == 'new_description'
    assert penny_chat.date == penny_chat_invitation.date
    assert penny_chat.status == PennyChat.SHARED
    assert penny_chat_invitation.shares == '{"share_chan": "share_ts"}'

    organizer_participant = Participant.objects.get(
        penny_chat=penny_chat,
        user=organizer,
    )
    assert organizer_participant.role == Participant.ORGANIZER

    assert penny_chat_invitation.status == PennyChatInvitation.SHARED