Esempio n. 1
0
def do(megatron_user_id: int, serialized_request_data: dict,
       arguments: dict) -> dict:
    request_data = RequestData(**serialized_request_data)
    megatron_user = MegatronUser.objects.get(id=megatron_user_id)
    try:
        channel = MegatronChannel.objects.get(
            platform_channel_id=request_data.channel_id)
    except MegatronChannel.DoesNotExist:
        return {'ok': False, 'error': 'Channel is invalid.'}
    workspace = channel.workspace
    connection = WorkspaceService(workspace).get_connection(
        as_user=False)
    response = connection.open_im(channel.platform_user_id)
    channel_id = response['channel']['id']
    msg = {
        'megatron_verification_token': settings.MEGATRON_VERIFICATION_TOKEN,
        'command': 'push_message',
        'message': {'text': arguments['arguments']},
        'channel_id': channel_id,
        'platform_user_id': channel.platform_user_id,
        'platform_channel_id': request_data.channel_id
    }
    try:
        requests.post(megatron_user.command_url, json=msg, timeout=10)
    except requests.Timeout:
        LOGGER.error("Timeout on megatron do.")
    return {'ok': True}
Esempio n. 2
0
def do(megatron_user_id: int, serialized_request_data: dict, arguments: dict) -> dict:
    request_data = RequestData(**serialized_request_data)
    megatron_user = MegatronUser.objects.get(id=megatron_user_id)
    try:
        channel = MegatronChannel.objects.get(
            platform_channel_id=request_data.channel_id
        )
    except MegatronChannel.DoesNotExist:
        return {"ok": False, "error": "Channel is invalid."}
    workspace = channel.workspace
    connection = WorkspaceService(workspace).get_connection(as_user=False)
    response = connection.open_im(channel.platform_user_id)
    channel_id = response["channel"]["id"]
    msg = {
        "megatron_verification_token": settings.MEGATRON_VERIFICATION_TOKEN,
        "command": "push_message",
        "message": {"text": arguments["arguments"]},
        "channel_id": channel_id,
        "platform_user_id": channel.platform_user_id,
        "platform_channel_id": request_data.channel_id,
    }
    try:
        requests.post(megatron_user.command_url, json=msg, timeout=10)
    except requests.Timeout:
        LOGGER.error("Timeout on megatron do.")
    return {"ok": True}
Esempio n. 3
0
def incoming(msg: dict, channel: MegatronChannel):
    from megatron.services import WorkspaceService

    platform_user = PlatformUser.objects.get(platform_id=msg["user"])
    workspace_connection = WorkspaceService(
        channel.megatron_integration).get_connection(as_user=False)

    if msg.get("files", ""):
        msg = workspace_connection.build_img_attach(msg, platform_user)

    else:
        msg = {
            "username": platform_user.get_display_name(),
            "icon_url": platform_user.profile_image,
            "text": msg.get("text", None),
            "attachments": msg.get("attachments", None),
        }
    post_message_action = Action(
        ActionType.POST_MESSAGE,
        {
            "channel": channel.platform_channel_id,
            "message": msg
        },
    )
    response = workspace_connection.take_action(post_message_action)
    response.update({"watched_channel": True})
    return response
Esempio n. 4
0
def _change_pause_state(
    megatron_user: MegatronUser,
    platform_user: User,
    request_data: RequestData,
    pause=False,
) -> dict:
    workspace = platform_user.workspace
    if not getattr(megatron_user, "command_url", None):
        return {"ok": False, "error": "No command url provided for workspace."}

    customer_connection = WorkspaceService(workspace).get_connection(as_user=False)
    response = customer_connection.open_im(platform_user.platform_id)
    if not response["ok"]:
        return {
            "ok": False,
            "error": "Failed to open get im channel from "
            f"slack: {response['error']}",
        }
    channel_id = response["channel"]["id"]

    data = {
        "megatron_verification_token": settings.MEGATRON_VERIFICATION_TOKEN,
        "command": "pause",
        "channel_id": channel_id,
        "platform_user_id": platform_user.platform_id,
        "team_id": workspace.platform_id,
        "paused": pause,
    }
    response = requests.post(megatron_user.command_url, json=data)
    # TODO: This response is 200 even on failure to find user
    if not response.status_code == 200:
        return {"ok": False, "error": "Failed to pause bot for user."}

    megatron_channel = MegatronChannel.objects.get(
        workspace=workspace, platform_user_id=platform_user.platform_id
    )
    megatron_channel.is_paused = pause
    megatron_channel.save()

    # TODO: This is probably better suited to being part of the integration itself
    integration = megatron_user.megatronintegration_set.first()
    integration_connection = IntegrationService(integration).get_connection(
        as_user=False
    )
    paused_word = "paused" if pause else "unpaused"
    msg = {"text": f"Bot *{paused_word}* for user: {platform_user}."}
    channel = request_data.channel_id
    message_action = Action(
        ActionType.POST_MESSAGE, {"channel": channel, "message": msg}
    )
    integration_connection.take_action(message_action)
    return {"ok": True}
Esempio n. 5
0
def _change_pause_state(megatron_user: MegatronUser, platform_user: User,
                        request_data: RequestData, pause=False
                        ) -> dict:
    workspace = platform_user.workspace
    if not getattr(megatron_user, 'command_url', None):
        return {'ok': False, 'error': 'No command url provided for workspace.'}

    customer_connection = WorkspaceService(
        workspace).get_connection(as_user=False)
    response = customer_connection.open_im(platform_user.platform_id)
    if not response['ok']:
        return {
            'ok': False,
            'error': 'Failed to open get im channel from '
            f"slack: {response['error']}"
        }
    channel_id = response['channel']['id']

    data = {
        'megatron_verification_token': settings.MEGATRON_VERIFICATION_TOKEN,
        'command': 'pause',
        'channel_id': channel_id,
        'platform_user_id': platform_user.platform_id,
        'team_id': workspace.platform_id,
        'paused': pause,
    }
    response = requests.post(megatron_user.command_url, json=data)
    # TODO: This response is 200 even on failure to find user
    if not response.status_code == 200:
        return {'ok': False, 'error': 'Failed to pause bot for user.'}

    megatron_channel = MegatronChannel.objects.get(
        workspace=workspace, platform_user_id=platform_user.platform_id)
    megatron_channel.is_paused = pause
    megatron_channel.save()

    # TODO: This is probably better suited to being part of the integration itself
    integration = megatron_user.megatronintegration_set.first()
    integration_connection = IntegrationService(
        integration).get_connection(as_user=False)
    paused_word = 'paused' if pause else 'unpaused'
    msg = {
        "text": f"Bot *{paused_word}* for user: {platform_user}."
    }
    channel = request_data.channel_id
    message_action = Action(ActionType.POST_MESSAGE, {'channel': channel, 'message': msg})
    integration_connection.take_action(message_action)
    return {'ok': True}
Esempio n. 6
0
def open_channel(
    megatron_user_id: int, serialized_request_data: dict, arguments: dict
) -> dict:
    request_data = RequestData(**serialized_request_data)
    megatron_user = MegatronUser.objects.get(id=megatron_user_id)
    platform_user_id = arguments["targeted_platform_id"]
    integration = megatron_user.megatronintegration_set.first()
    connection = IntegrationService(integration).get_connection(as_user=False)

    # Ensure platform user exists
    if not PlatformUser.objects.filter(platform_id=platform_user_id).exists():
        user_info = connection._get_user_info(platform_user_id)
        try:
            workspace = CustomerWorkspace.objects.get(platform_id=user_info["user"]["team_id"])
        except (CustomerWorkspace.DoesNotExist, KeyError):
            return {"ok": False, "error": "Customer Workspace not found"}
        WorkspaceService(workspace).get_or_create_user_by_id(platform_user_id)

    new_msg = formatting.user_titled(platform_user_id, "Connecting...")
    response = connection.respond_to_url(request_data.response_url, new_msg)
    if not response.get("ok"):
        return response
    _update_channel_link.delay(
        megatron_user.id, platform_user_id, request_data.response_url
    )
    return {"ok": True}
Esempio n. 7
0
def outgoing(msg: dict, channel: MegatronChannel):
    from megatron.services import WorkspaceService
    cleaned_msg = remove_sensitive_data(msg)
    msg = {
        'username': BOTNAME,
        'icon_emoji': ':robot_face:',
        'text': cleaned_msg.get('text', None),
        'attachments': cleaned_msg.get('attachments', None)
    }
    workspace_connection = WorkspaceService(
        channel.megatron_integration).get_connection(as_user=False)
    channel_id = channel.platform_channel_id
    post_message_action = Action(ActionType.POST_MESSAGE, {
        'channel': channel_id,
        'message': msg
    })
    response = workspace_connection.take_action(post_message_action)
    response.update({'watched_channel': True})
    return response
Esempio n. 8
0
def outgoing(msg: dict, channel: MegatronChannel):
    from megatron.services import WorkspaceService

    cleaned_msg = remove_sensitive_data(msg)
    msg = {
        "username": BOTNAME,
        "icon_emoji": ":robot_face:",
        "text": cleaned_msg.get("text", None),
        "attachments": cleaned_msg.get("attachments", None),
    }
    workspace_connection = WorkspaceService(
        channel.megatron_integration).get_connection(as_user=False)
    channel_id = channel.platform_channel_id
    post_message_action = Action(ActionType.POST_MESSAGE, {
        "channel": channel_id,
        "message": msg
    })
    response = workspace_connection.take_action(post_message_action)
    response.update({"watched_channel": True})
    return response
Esempio n. 9
0
def _get_conversation_history(channel: MegatronChannel):
    connection = WorkspaceService(channel.workspace).get_connection()
    response = connection.open_im(channel.platform_user_id)
    channel_id = response['channel']['id']
    prev_messages = connection.im_history(channel_id, 10)
    integration_interpreter = IntegrationService(
        channel.megatron_integration).get_interpreter()
    messages = prev_messages['messages']
    messages.sort(key=lambda message: message['ts'])
    previous_ts = None
    for message in messages:
        timestamp = datetime.fromtimestamp(int(message['ts'].split('.')[0]))
        formatted_timestamp = _format_slack_timestamp(timestamp, previous_ts)
        message['text'] = f"{formatted_timestamp}{message['text']}"
        previous_ts = timestamp

        if message.get('bot_id'):
            integration_interpreter.outgoing(message, channel)
        else:
            integration_interpreter.incoming(message, channel)
    return prev_messages
Esempio n. 10
0
def forward_message(channel: str, msg: dict, from_user: dict = None) -> dict:
    engagement_channel = _check_channel(channel)
    if not engagement_channel:
        return {"ok": False, "error": f"Channel {channel} not found."}
    platform_user_id = engagement_channel.platform_user_id

    workspace = engagement_channel.workspace
    connection = WorkspaceService(workspace).get_connection()
    if from_user:
        msg = connection.add_forward_footer(msg, from_user)
    response = connection.dm_user(platform_user_id, msg)

    engagement_channel.last_message_sent = datetime.now(timezone.utc)
    engagement_channel.save()

    megatron_msg, _ = MegatronMessage.objects.update_or_create(
        integration_msg_id=msg["ts"],
        megatron_channel=engagement_channel,
        defaults={"customer_msg_id": response["ts"]},
    )

    return {"ok": True, "response": response}
Esempio n. 11
0
def incoming(msg: dict, channel: MegatronChannel):
    from megatron.services import WorkspaceService
    platform_user = PlatformUser.objects.get(platform_id=msg['user'])
    workspace_connection = WorkspaceService(
        channel.megatron_integration).get_connection(as_user=False)

    if msg.get('files', ''):
        msg = workspace_connection.build_img_attach(msg, platform_user)

    else:
        msg = {
            'username': platform_user.get_display_name(),
            'icon_url': platform_user.profile_image,
            'text': msg.get('text', None),
            'attachments': msg.get('attachments', None)
        }
    post_message_action = Action(ActionType.POST_MESSAGE, {
        'channel': channel.platform_channel_id,
        'message': msg
    })
    response = workspace_connection.take_action(post_message_action)
    response.update({'watched_channel': True})
    return response
Esempio n. 12
0
def event(request):
    data = json.loads(request.body)

    if data.get('type') == 'url_verification':
        return HttpResponse((data['challenge']))
    if not data['type'] == 'event_callback':
        return HttpResponse(b'')

    event = data['event']
    if event['type'] == 'message':
        if event.get('bot_id'):
            return HttpResponse(b'')
        if event.get('message') and event['message'].get('bot_id'):
            return HttpResponse(b'')
        if event.get('message') and event['message'].get(
                'subtype') == 'bot_message':
            return HttpResponse(b'')

        user_id = event.get('user')
        channel_id = event.get('channel')
        tracked_channel = MegatronChannel.objects.filter(
            platform_channel_id=channel_id).first()
        if tracked_channel:
            front_integration.team_member_message.delay(
                user_id, tracked_channel.platform_user_id, data['event'])
            try:
                MegatronMessage.objects.create(
                    megatron_channel=tracked_channel,
                    integration_msg_id=event['event_ts'])
            except IntegrityError:
                LOGGER.warning("Discarding duplicate event.",
                               extra={'received_msg': data})
                return HttpResponse(b'')

            from_user = _get_slack_user_data(channel_id, user_id)
            subtype = event.get('subtype')
            if subtype:
                if subtype == 'file_share':
                    msg = _image_passthrough_message(event)
                    Command.get_command('forward').action.delay(
                        event['channel'], msg, from_user)

                elif subtype == 'message_changed':
                    user_id = event['message'].get('user')
                    from_user = _get_slack_user_data(channel_id, user_id)
                    # Was changed by bot
                    existing_message = MegatronMessage.objects.filter(
                        integration_msg_id=event['previous_message']['ts'],
                        megatron_channel=tracked_channel).first()

                    if not existing_message:
                        return HttpResponse(b'')

                    workspace_connection = WorkspaceService(
                        tracked_channel.workspace).get_connection(
                            as_user=False)

                    channel_id = workspace_connection.open_im(
                        tracked_channel.platform_user_id)['channel']['id']

                    customer_ts = existing_message.customer_msg_id
                    msg = {
                        'text': event['message'].get('text', ' '),
                        'attachments': event['message'].get('attachments', [])
                    }
                    msg = workspace_connection.add_forward_footer(
                        msg, from_user)
                    response = workspace_connection.update_msg(
                        customer_ts, channel_id, msg)

                    existing_message.integration_msg_id = event['message'][
                        'ts']
                    existing_message.customer_msg_id = response['ts']
                    existing_message.save()
                else:
                    return HttpResponse(b'')

            else:
                _check_and_send_paused_warning(tracked_channel, user_id)
                msg = {
                    'text': event.get('text'),
                    'attachments': event.get('attachments'),
                    'ts': event.get('ts')
                }
                Command.get_command('forward').action.delay(
                    event['channel'], msg, from_user)

    return HttpResponse(b'')
Esempio n. 13
0
def interactive_message(request):
    payload = json.loads(request.POST['payload'])
    megatron_user = MegatronIntegration.objects.get(
        platform_id=payload['team']['id']).megatron_user
    callback_id = payload['callback_id']
    action_type = payload['actions'][0]['type']
    command_str = callback_id.split('|')[0]
    command = Command.get_command(command_str)
    response_channel = payload['channel']['id']
    response_url = payload['response_url']
    response_user = payload['user']['id']

    request_data = RequestData(channel_id=response_channel,
                               user_id=response_user,
                               response_url=response_url)

    # TODO: Make all command.action calls async, at which point this is unneeded
    request_data = kombu_json.loads(kombu_json.dumps(request_data))

    if action_type == 'select':
        workspace_id, platform_user_id = payload['actions'][0][
            'selected_options'][0]['value'].split('-')
        workspace = CustomerWorkspace.objects.get(platform_id=workspace_id)
        platform_user = WorkspaceService(workspace).get_or_create_user_by_id(
            platform_user_id)
    elif action_type == 'button':
        workspace_id, platform_user_id = payload['actions'][0]['value'].split(
            '-')
        workspace = CustomerWorkspace.objects.get(platform_id=workspace_id)
        platform_user = WorkspaceService(workspace).get_or_create_user_by_id(
            platform_user_id)
    else:
        return MegatronResponse('Received unknown action type', 400)

    if not platform_user:
        LOGGER.error("Could not identify platform user to act on.",
                     extra={'platform_user_id': user_id})
        return

    arguments = {
        'targeted_user_id': platform_user.id,
        'targeted_platform_id': platform_user_id
    }

    if command_str == 'open':
        response = command.action(megatron_user.id, request_data, arguments)
        if response.get('ok'):
            return HttpResponse(b'')

    elif command_str == 'close':
        response = command.action(megatron_user.id, request_data, arguments)
        if response.get('ok'):
            msg = formatting.user_titled(platform_user, "Got it!")
        else:
            msg = formatting.user_titled(platform_user,
                                         "Couldn't find an open channel.")
        return JsonResponse(msg)

    elif command_str == 'pause':
        command.action(megatron_user.id, request_data, arguments)
        msg = formatting.get_pause_warning(workspace_id, platform_user_id)
        return JsonResponse(msg)

    elif command_str == 'unpause':
        command.action(megatron_user.id, request_data, arguments)
        msg = formatting.get_unpaused_warning(workspace_id, platform_user_id)
        return JsonResponse(msg)

    elif command_str == 'clear-context':
        response = command.action(megatron_user.id, request_data, arguments)
        if response['ok']:
            return HttpResponse(b'')

    else:
        return MegatronResponse('Unknown command', 400)

    return MegatronResponse(response.get('error'), response.get('status'))
Esempio n. 14
0
def event(request):
    data = json.loads(request.body)

    if data.get("type") == "url_verification":
        return HttpResponse((data["challenge"]))
    if not data["type"] == "event_callback":
        return HttpResponse(b"")

    event = data["event"]
    if event["type"] == "message":
        if event.get("bot_id"):
            return HttpResponse(b"")
        if event.get("message") and event["message"].get("bot_id"):
            return HttpResponse(b"")
        if event.get("message") and event["message"].get(
                "subtype") == "bot_message":
            return HttpResponse(b"")

        user_id = event.get("user")
        channel_id = event.get("channel")
        tracked_channel = MegatronChannel.objects.filter(
            platform_channel_id=channel_id).first()
        if tracked_channel:
            front_integration.team_member_message.delay(
                user_id, tracked_channel.platform_user_id, data["event"])
            try:
                MegatronMessage.objects.create(
                    megatron_channel=tracked_channel,
                    integration_msg_id=event["event_ts"],
                )
            except IntegrityError:
                LOGGER.warning("Discarding duplicate event.",
                               extra={"received_msg": data})
                return HttpResponse(b"")

            from_user = _get_slack_user_data(channel_id, user_id)
            subtype = event.get("subtype")
            if subtype:
                if subtype == "file_share":
                    msg = _image_passthrough_message(event)
                    Command.get_command("forward").action.delay(
                        event["channel"], msg, from_user)

                elif subtype == "message_changed":
                    user_id = event["message"].get("user")
                    from_user = _get_slack_user_data(channel_id, user_id)
                    # Was changed by bot
                    existing_message = MegatronMessage.objects.filter(
                        integration_msg_id=event["previous_message"]["ts"],
                        megatron_channel=tracked_channel,
                    ).first()

                    if not existing_message:
                        return HttpResponse(b"")

                    workspace_connection = WorkspaceService(
                        tracked_channel.workspace).get_connection(
                            as_user=False)

                    channel_id = workspace_connection.open_im(
                        tracked_channel.platform_user_id)["channel"]["id"]

                    customer_ts = existing_message.customer_msg_id
                    msg = {
                        "text": event["message"].get("text", " "),
                        "attachments": event["message"].get("attachments", []),
                    }
                    msg = workspace_connection.add_forward_footer(
                        msg, from_user)
                    response = workspace_connection.update_msg(
                        customer_ts, channel_id, msg)

                    existing_message.integration_msg_id = event["message"][
                        "ts"]
                    existing_message.customer_msg_id = response["ts"]
                    existing_message.save()
                else:
                    return HttpResponse(b"")

            else:
                _check_and_send_paused_warning(tracked_channel, user_id)
                msg = {
                    "text": event.get("text"),
                    "attachments": event.get("attachments"),
                    "ts": event.get("ts"),
                }
                Command.get_command("forward").action.delay(
                    event["channel"], msg, from_user)

    return HttpResponse(b"")
Esempio n. 15
0
def interactive_message(request):
    payload = json.loads(request.POST["payload"])
    megatron_user = MegatronIntegration.objects.get(
        platform_id=payload["team"]["id"]).megatron_user
    callback_id = payload["callback_id"]
    action_type = payload["actions"][0]["type"]
    command_str = callback_id.split("|")[0]
    command = Command.get_command(command_str)
    response_channel = payload["channel"]["id"]
    response_url = payload["response_url"]
    response_user = payload["user"]["id"]

    request_data = RequestData(channel_id=response_channel,
                               user_id=response_user,
                               response_url=response_url)

    # TODO: Make all command.action calls async, at which point this is unneeded
    request_data = kombu_json.loads(kombu_json.dumps(request_data))

    if action_type == "select":
        workspace_id, platform_user_id = payload["actions"][0][
            "selected_options"][0]["value"].split("-")
        workspace = CustomerWorkspace.objects.get(platform_id=workspace_id)
        platform_user = WorkspaceService(workspace).get_or_create_user_by_id(
            platform_user_id)
    elif action_type == "button":
        workspace_id, platform_user_id = payload["actions"][0]["value"].split(
            "-")
        workspace = CustomerWorkspace.objects.get(platform_id=workspace_id)
        platform_user = WorkspaceService(workspace).get_or_create_user_by_id(
            platform_user_id)
    else:
        return MegatronResponse("Received unknown action type", 400)

    if not platform_user:
        LOGGER.error(
            "Could not identify platform user to act on.",
            extra={"platform_user_id": platform_user_id},
        )
        return

    arguments = {
        "targeted_user_id": platform_user.id,
        "targeted_platform_id": platform_user_id,
    }

    if command_str == "open":
        response = command.action(megatron_user.id, request_data, arguments)
        if response.get("ok"):
            return HttpResponse(b"")

    elif command_str == "close":
        response = command.action(megatron_user.id, request_data, arguments)
        if response.get("ok"):
            msg = formatting.user_titled(platform_user, "Got it!")
        else:
            msg = formatting.user_titled(platform_user,
                                         "Couldn't find an open channel.")
        return JsonResponse(msg)

    elif command_str == "pause":
        command.action(megatron_user.id, request_data, arguments)
        msg = formatting.get_pause_warning(workspace_id, platform_user_id)
        return JsonResponse(msg)

    elif command_str == "unpause":
        command.action(megatron_user.id, request_data, arguments)
        msg = formatting.get_unpaused_warning(workspace_id, platform_user_id)
        return JsonResponse(msg)

    elif command_str == "clear-context":
        response = command.action(megatron_user.id, request_data, arguments)
        if response["ok"]:
            return HttpResponse(b"")

    else:
        return MegatronResponse("Unknown command", 400)

    return MegatronResponse(response.get("error"), response.get("status"))
Esempio n. 16
0
def refresh_platform_user_data():
    for workspace in CustomerWorkspace.objects.all():
        WorkspaceService(workspace).refresh_user_data()