def _get_nodes_and_edges(graph_data, nodes=None, edges=None, text_field='Key', append_key_to_text=False): if nodes is None: nodes = [] if edges is None: edges = [] if graph_data: for key, issue in graph_data.get('nodes').items(): if issue and issue.get('Summary'): text = issue.get(text_field) if append_key_to_text: text += " | {0}".format(key) else: text = key nodes.append({ 'key': key, 'text': text, 'color': Misc.get_random_color() }) for edge in graph_data.get('edges'): if edge[0] and edge[2]: edges.append({ 'from': edge[0], 'text': edge[1], 'to': edge[2], 'color': Misc.get_random_color() }) else: print(edge) return nodes, edges
def milestone(team_id=None, channel=None, params=None): Misc.array_pop(params) # original slack event object if not params or len(params) < 2: return send_message( ':red_circle: You must provide the following params: `Server Id` and `jira ID`', channel, team_id) short_id = str(Misc.array_pop(params, 0)) source = str(Misc.array_pop(params, 0)).upper() source_notebook = "icap/gwbot-reporting/TEST-milestones-TEST.ipynb" target_notebook = f"icap/gwbot-reporting/{source}.ipynb" send_message(f":python: creating milestone view for `{source}`", channel, team_id) # need to double check exec_params = [ short_id, f"!papermill ../../{source_notebook} ../../{target_notebook} -p source {source}", {} ] preview_params = [short_id, f"{target_notebook}", {}] Jupyter_Web_Commands.exec(channel=channel, params=exec_params) Jupyter_Web_Commands.preview(channel=channel, params=preview_params)
def group_by_field(self, root_node, field_name): graph = self.graph issues = graph.get_nodes_issues() # resolve current node's issues nodes = graph.nodes # save current nodes edges = graph.edges # save current edges graph.nodes = [] # reset nodes graph.edges = [] # reset edges graph.add_node(root_node) if field_name == 'Issue Links': for edge in edges: link_type = edge[1] to_key = edge[2] to_issue = Misc.get_value(issues, to_key, {}) to_key = Misc.get_value(to_issue, 'Key') graph.add_node(link_type) graph.add_node(to_key) graph.add_edge(root_node, '', link_type) graph.add_edge(link_type, '', to_key) else: for node in nodes: issue = issues.get(node) if issue: value = issue.get(field_name) graph.add_node(value) graph.add_node(node) graph.add_edge(root_node, field_name, value) graph.add_edge(value, '', node) return self
def cmd_screenshot(self, params, team_id=None, channel=None): attachments = [] if len(params) < 2: text = ":exclamation: you must provide an issue id " else: params.pop(0) # remove 'issue' command issue_id = params.pop(0).upper() width = to_int(Misc.array_pop(params), None) height = to_int(Misc.array_pop(params), None) delay = to_int(Misc.array_pop(params), None) text = ':point_right: Getting screenshot for issue `{0}`'.format( issue_id) if width: text += ' with width `{0}`'.format(width) if height: text += ' and height `{0}`'.format(height) if delay: text += ' and delay `{0}`'.format(delay) payload = { 'issue_id': issue_id, 'channel': channel, 'team_id': team_id, 'width': width, 'height': height, 'delay': delay } Lambda('osbot_browser.lambdas.jira_web').invoke_async(payload) return {"text": text, "attachments": attachments}
def test_message_send(self): message_1 = Misc.random_string_and_numbers(prefix='Hello_') message_2 = Misc.random_string_and_numbers(prefix='World_') self.queue.add(body=message_1).add(body=message_2) messages = [self.queue.get_message(), self.queue.get_message()] assert message_1 in messages assert message_2 in messages assert self.queue.get_message() is None
def test_array_find(self): array = ['1', 2, '3'] self.assertEqual(Misc.array_find(array, '1'), 0) self.assertEqual(Misc.array_find(array, 2), 1) self.assertEqual(Misc.array_find(array, '3'), 2) self.assertEqual(Misc.array_find(array, 'a'), -1) self.assertEqual(Misc.array_find(array, None), -1) self.assertRaises(Exception, Misc.array_find, None, None) self.assertRaises(Exception, Misc.array_find, 'a', None)
def slack(team_id=None, channel=None, params=None): target = Misc.array_pop(params, 0) height = Misc.to_int(Misc.array_pop(params, 0)) width = Misc.to_int(Misc.array_pop(params, 0)) scroll_by = Misc.to_int(Misc.array_pop(params, 0)) delay = Misc.to_int(Misc.array_pop(params, 0)) if target is None: target = 'general' if width is None: width = 800 if height is None: height = 1000 if scroll_by is None: scroll_by = 0 if delay is None: delay = 0 target_url = '/messages/{0}'.format(target) slack_message( ":point_right: Taking screenshot of slack channel: `{0}` with height `{1}`, width `{2}`, scroll_by `{3}` and delay `{4}`" .format(target, height, width, scroll_by, delay), [], channel, team_id) payload = { 'target': target_url, 'channel': channel, 'team_id': team_id, 'width': width, 'height': height, 'scroll_by': scroll_by, 'delay': delay } aws_lambda = Lambda('osbot_browser.lambdas.slack_web') aws_lambda.invoke_async(payload)
def handle_action(self, event): action = Misc.get_value(Misc.array_pop(event.get('actions'), 0), 'value') try: target = getattr(self, action) except: return self.message_not_supported_action(action) try: return target(event) except Exception as error: return self.message_execution_error(error)
def test_array_pop(self): array = ['1', 2, '3'] assert Misc.array_pop(array) == '3' assert Misc.array_pop(array) == 2 assert Misc.array_pop(array) == '1' assert Misc.array_pop(array) is None assert Misc.array_pop(None) is None array = ['1', 2, '3'] assert Misc.array_pop(array, 1) == 2 assert Misc.array_pop(array, 1) == '3' assert Misc.array_pop(array, 1) is None assert Misc.array_pop(array, 0) == '1' assert Misc.array_pop(array, 0) is None
def test_is_number(self): assert is_number(42) is True assert is_number(4.2) is True assert is_number(-1) is True assert is_number(True) is False assert is_number('42') is False assert is_number(None) is False assert Misc.is_number(123) is True assert Misc.is_number('123') is False assert Misc.is_number('abc') is False assert Misc.is_number(None) is False assert Misc.is_number([]) is False
def view_exec_file(team_id=None, channel=None, params=None): #event = Misc.array_pop(params) # original slack event object if not params or len(params) < 2: build_id = 'gscs' # for now default to this one #return send_message(':red_circle: You must provide the following params: `Server Id`', channel, team_id) else: build_id = str(Misc.array_pop(params, 0)) notebook = Live_Notebook() if notebook.set_build_from_short_id(build_id) is None: return ':red_circle: Could not find Jupyter server with id `{0}`. Please use `jupyter servers` to see the current list of live servers'.format( build_id) (target_notebook, created) = notebook.get_python_invoke_file() send_message( ":point_right: Today's python execution file in server `{0}` is `{1}`, here is what it looks like:" .format(build_id, target_notebook), channel, team_id) width = 1200 height = 1200 delay = 2 png_data = notebook.screenshot(path=target_notebook, width=width, height=height, delay=delay, apply_ui_fixes=False) return send_png_to_slack(png_data, channel, team_id)
def transition_to(self, action): value_split = action.get('value').split('::') issue_id = Misc.array_pop(value_split, 0) transition_to = Misc.array_pop(value_split, 0) transition_name = Misc.array_pop(value_split, 0) try: self.api_jira.issue_transition_to_id(issue_id, transition_to) self.send_message( ':white_check_mark: Changed `{0}` status to: *{1}*. Here are the new transitions available ' .format(issue_id, transition_name)) self.create_ui_actions_with_transitions(issue_id, transition_name, show_intro=False) except Exception as error: self.send_message( ':red_circle: Error in transition_to: {0}'.format(error))
def _create_table_with_headers(team_id, channel, graph_name, headers, columns_defs=[], table_width='1200px'): graph_data = DataTable_Js_Views._get_data(graph_name) if graph_data: nodes = graph_data.get('nodes') rows = [] for index, node in enumerate(nodes.values()): row = [index + 1] for header in headers: value = node.get(header) if type(value).__name__ == 'dict': value = json.dumps(value) else: value = Misc.remove_html_tags(value) row.append(value) rows.append(row) headers.insert(0, '#') return DataTable_Js_Views._create_table( headers, rows, team_id, channel, table_width=table_width, columns_defs=columns_defs, table_title= "<b>{0}</b> <small><small><i>(data from graph)</i></small></small>" .format(graph_name))
def test_update_to_json_string(self): data = { 'the answer is': 42, 'random_string': Misc.random_string_and_numbers() } self.secrets.update_to_json_string(data) assert self.secrets.value_from_json_string() == data
def run(event, context): try: load_dependencies('requests,syncer,pyppeteer,websocket-client') from osbot_jupyter.osbot.Jupyter_Commands import Jupyter_Commands params = Misc.get_value(event, 'params', []) if not params: params = [''] data = event.get('data') channel = Misc.get_value(data, 'channel') team_id = Misc.get_value(data, 'team_id') params.append({"data": data}) return Slack_Commands_Helper(Jupyter_Commands).invoke( team_id, channel, params) except Exception as error: message = "[lambda_osbot] Error: {0}".format(error) #log_to_elk(message, level='error') return message
def node_label(team_id=None, channel=None, params=None, headless=True): if len(params) < 2: return "':red_circle: Hi, for the `node_label` view, you need to provide the label field name. Try: `Key`, `Summary`, `Rating`, `Status`" label_key = ' '.join(params[1:]) (graph_name, nodes, edges, graph_data, vis_js) = Vis_Js_Views.default(params=params, no_render=True, headless=headless) graph_name += ' | node_label | ' + label_key if graph_data: issues = graph_data.get('nodes') for node in nodes: issue = issues.get(node['label']) if issue: value = str(issue.get(label_key)) node['label'] = Misc.word_wrap(value, 40) for edge in edges: del edge['label'] options = {'nodes': {'shape': 'box'}, 'edges': {'arrows': 'to'}} options = None return vis_js.create_graph_and_send_screenshot_to_slack( graph_name, nodes, edges, options, team_id, channel)
def format_node(node): issue = graph_data.get('nodes').get(node.get('id')) if issue: node['label'] = Misc.word_wrap(issue.get('Summary'), 20) #node['label'] = issue.get('Rating') labels = issue.get('Labels') if 'R0' in labels: #node['label'] = issue.get('Summary') node['color'] = '#FF0000' node['font'] = {'color': 'white', 'size': 25} node['mass'] = 2 return node if 'R1' in labels: node['color'] = '#FF6666' node['font'] = {'size': 20} node['mass'] = 3 return node if 'R2' in labels: node['color'] = '#FFAAAA' node['font'] = {'size': 15} #node['mass'] = 1 return node if 'R3' in labels: node['color'] = '#FFDDDD' return node if 'R4' in labels: node['color'] = '#00DDDD' return node
def __init__(self, web_root=None): self.src_tmp = '/tmp/temp_web_server' self.python_path = 'python3' if web_root: self.web_root = web_root else: self.web_root = self.src_tmp + '/html' self.html_file = Files.path_combine(self.web_root, 'index.html') self.port = Misc.random_number(10000, 60000) self.server_proc = None
def __init__(self, blocks, action_id=None, block_id=None): self.action_id = action_id self.block_id = block_id self.blocks = blocks self.text = None self.fields = [] self.accessory = {} if block_id is None: self.block_id = Misc.random_string_and_numbers(4, 'block_')
def render(self): if self.block_id is None: self.block_id = Misc.random_string_and_numbers(4, 'block_') self.blocks.append({ "type": "actions", "block_id": self.block_id, "elements": self.elements }) return self
def _test_lambda_write_cloud_watch__with_asserts(self): group_name = '/unit-tests/test_log_group' stream_name = Misc.random_string_and_numbers(prefix='tmp_stream_') message = 'this is a message sent from an lambda function' lambda_name = 'osbot_aws.lambdas.dev.write_cloud_watch_log' log_group_arn = 'arn:aws:logs:eu-west-2:244560807427:log-group:{0}*'.format( group_name) policy_name = 'temp_policy_for_lambda_write_cloud_watch' role_name = 'temp_role_for_lambda_invocation' policy_actions = ['logs:PutLogEvents'] logs = Logs(group_name=group_name, stream_name=stream_name) logs.group_create() logs.stream_create() iam_role = IAM(role_name=role_name) iam_policy = IAM_Policy(policy_name=policy_name) iam_policy.add_statement_allow(policy_actions, [log_group_arn]) policy_arn = iam_policy.create( delete_before_create=True).get('policy_arn') assert iam_policy.exists() is True assert iam_role.role_exists() is True assert logs.group_exists() is True assert logs.stream_exists() is True assert set(iam_role.role_policies()) == { 'AWSXrayWriteOnlyAccess', 'policy_temp_role_for_lambda_invocation' } iam_role.role_policy_attach(policy_arn) assert set(iam_role.role_policies()) == { 'AWSXrayWriteOnlyAccess', 'policy_temp_role_for_lambda_invocation', 'temp_policy_for_lambda_write_cloud_watch' } sleep(10) # wait for AWS to propagate role update payload = { 'group_name': group_name, 'stream_name': stream_name, 'message': message } lambda_obj = Lambda_Package(lambda_name) #.update_with_root_folder() result = lambda_obj.invoke(payload) sleep(1) # wait for Cloudwatch to update assert result.get('status') == 'ok' assert logs.messages() == [message] assert iam_policy.delete() is True assert logs.group_delete() is True assert logs.group_exists() is False assert set(iam_role.role_policies()) == { 'AWSXrayWriteOnlyAccess', 'policy_temp_role_for_lambda_invocation' }
def __init__(self, file_ids=None, sheet_name=None): self.gsuite_secret_id = 'gsuite_gsbot_user' self.file_id = Misc.array_get(file_ids, 0) self.other_files = file_ids self.sheet_name = sheet_name self.gsheets = GSheets(self.gsuite_secret_id) self.gsheets_sync = API_Jira_Sheets_Sync(self.file_id, self.gsuite_secret_id) self.jira_api_rest = API_Jira_Rest() self.gsheets_create = API_Jira_Sheets_Create(self.file_id)
def files(team_id=None, channel=None, params=None): event = params.pop() # needed due to injection of event param short_id = Misc.array_pop(params,0) target = " ".join(params) if short_id is None: return send_message(":red_circle: missing `short id`. The syntax for this method is `contents {short_id} [{path}]`", channel, team_id) notebook = Live_Notebook(short_id=short_id) text_title, text_body = notebook.files(target) attachments = [{'text':text_body, 'color':'good'}] slack_message(text_title, attachments,channel,team_id)
def __init__(self): self.require_js = { "paths": { "vis": "https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min" } } self.div_id = Misc.random_string_and_numbers(prefix='network_') #self.test = 42 self.setup_code = """
def test_log_group_create_delete_exists_info(self): tmp_log_group = Misc.random_string_and_numbers( prefix='/unit-tests/test_log_group_') temp_logs = Logs(tmp_log_group, '') assert temp_logs.group_exists() is False assert temp_logs.group_create() is True assert temp_logs.group_exists() is True assert temp_logs.group_info().get('logGroupName') == tmp_log_group assert temp_logs.group_delete() == True assert temp_logs.group_exists() is False
def _get_graph_data(params,layout=None, headless=True): load_dependencies('syncer,requests,pyppeteer,websocket-client'); from osbot_browser.view_helpers.Am_Charts import Am_Charts am_charts = Am_Charts(headless=headless,layout=layout) graph_name = Misc.array_pop(params,0) if graph_name: graph_data = am_charts.get_graph_data(graph_name) return am_charts, graph_data return am_charts,None
def test_array_get(self): array = ['1', 2, '3'] assert Misc.array_get(array, 0) == '1' assert Misc.array_get(array, 1) == 2 assert Misc.array_get(array, 2) == '3' assert Misc.array_get(array, -1) is None assert Misc.array_get(array, 3) is None assert Misc.array_get(array, None) is None assert Misc.array_get(None, None) is None
def exec(team_id=None, channel=None, params=None): try: event = Misc.array_pop(params) # original slack event object if not params or len(params) < 2: return send_message( ':red_circle: You must provide the following params: `Server Id` and `code` (to execute)', channel, team_id) short_id = str(Misc.array_pop(params, 0)) code = ' '.join(params).replace('“', '"').replace('”', '"').replace( '‘', "'").replace('’', "'") notebook = Live_Notebook() if notebook.set_build_from_short_id(short_id) is None: return ':red_circle: Could not find Jupyter server with id `{0}`. Please use `jupyter servers` to see the current list of live servers'.format( short_id) (target_notebook, created) = notebook.get_python_invoke_file() if created: send_message( ':point_right: Created temp file for dynamic execution: `{0}`' .format(target_notebook), channel, team_id) send_message( ':point_right: Running code with size `{0}` on server `{1}` (on file `{2}`)' .format(len(code), short_id, target_notebook), channel, team_id) result = notebook.execute_python_in_notebook( target_notebook, code, event) if channel: return send_message( ':point_right: Code executed, here is the output:\n ```{0}```' .format(result), channel, team_id) else: return result except Exception as error: return send_message(':red_circle: Error: {0}'.format(error), channel, team_id)
def render(team_id=None, channel=None, params=None, no_render=False, headless=True): page = Misc.array_pop(params, 0) if page is None: return ':red_circle: you need to provide a map to render, try `cup-of-tea`' maps = Maps(headless, page) maps.load_page(True) return maps.send_screenshot_to_slack('not-used', channel)
def __init__(self, width="100%", height=800): self.frame_id = Misc.random_string_and_numbers(prefix='go_view_') self.frame_id = 'go_view_12345' self.src = '/view/html/go-js/incremental-tree.html' self.nodes = [] # keep track of nodes added self.edges = [] self.link_types = [] self.width = width self.height = height self.verbose = False pass