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}
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}
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
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}
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}
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}
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
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
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
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}
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
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'')
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'))
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"")
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"))
def refresh_platform_user_data(): for workspace in CustomerWorkspace.objects.all(): WorkspaceService(workspace).refresh_user_data()