def test_basic_json(self): self.assertDictEqual( {"text": "some text", "type": "mrkdwn"}, MarkdownTextObject(text="some text").to_dict(), ) self.assertDictEqual( {"text": "some text", "verbatim": True, "type": "mrkdwn"}, MarkdownTextObject(text="some text", verbatim=True).to_dict(), )
def build_slack_block_native(cls, msg1, msg2, data): blocks: List[SectionBlock] = [ SectionBlock(text=MarkdownTextObject.parse(f"*{msg1}*:\n{msg2}")), SectionBlock(fields=[]), ] names: List[str] = list(set(data.keys()) - set("user_comments")) fields = [ MarkdownTextObject.parse(f"*{name}*:\n{data[name]}") for name in names ] blocks[1].fields = fields return list(b.to_dict() for b in blocks)
def test_basic_json(self): expected = { "confirm": { "emoji": True, "text": "Yes", "type": "plain_text" }, "deny": { "emoji": True, "text": "No", "type": "plain_text" }, "text": { "text": "are you sure?", "type": "mrkdwn", "verbatim": False }, "title": { "emoji": True, "text": "some title", "type": "plain_text" }, } simple_object = ConfirmObject( title=PlainTextObject(text="some title"), text=MarkdownTextObject(text="are you sure?")).to_dict() self.assertDictEqual(simple_object, expected)
def test_confirm_overrides(self): confirm = ConfirmObject( title=PlainTextObject(text="some title"), text=MarkdownTextObject(text="are you sure?"), confirm=PlainTextObject(text="I'm really sure"), deny=PlainTextObject(text="Nevermind"), ) expected = { "confirm": { "emoji": True, "text": "I'm really sure", "type": "plain_text" }, "deny": { "emoji": True, "text": "Nevermind", "type": "plain_text" }, "text": { "text": "are you sure?", "type": "mrkdwn", "verbatim": False }, "title": { "emoji": True, "text": "some title", "type": "plain_text" }, } self.assertDictEqual(confirm.to_dict(), expected)
def on_401_unauthorized(exc): try: msg = exc.args[0] code = exc.args[1] rqst: AnyRequest = exc.args[2] except Exception as exc: errmsg = "App error called with exception: {}".format(str(exc)) slackapp.log.error(errmsg) err = dict(blocks=[SectionBlock(text=MarkdownTextObject(text=f"```{errmsg}```")).to_dict()]) return jsonify(err) errmsg = f"I'm sorry <@{rqst.user_id}>, I'm not authorized do to that." msg = dict(blocks=[SectionBlock(text=MarkdownTextObject(text=f"```{errmsg}```")).to_dict()]) return jsonify(msg)
def on_main_modal_submit(rqst: ViewRequest, input_values: Dict): params = session[SESSION_KEY]['params'] # The input_values is a dictionary of key=action_id and value=user-input # since all action_id are formulated with dots (.), just use the # last token as the variable name when form results = {k.rpartition('.')[-1]: v for k, v in input_values.items()} results.update(dict(clicks=params['clicks'])) modal = Modal( rqst, view=View(type="modal", title=PlainTextObject(text='Modal Results'), close=PlainTextObject(text='Done'), clear_on_close=True, blocks=[ SectionBlock(text=PlainTextObject( text="Input results in raw JSON")), SectionBlock(text=MarkdownTextObject( text="```" + json.dumps(results, indent=3) + "```")) ])) return modal.push()
def test_home_tab_construction(self): home_tab_view = View( type="home", blocks=[ SectionBlock(text=MarkdownTextObject( text="*Here's what you can do with Project Tracker:*"), ), ActionsBlock(elements=[ ButtonElement( text=PlainTextObject(text="Create New Task", emoji=True), style="primary", value="create_task", ), ButtonElement( text=PlainTextObject(text="Create New Project", emoji=True), value="create_project", ), ButtonElement( text=PlainTextObject(text="Help", emoji=True), value="help", ), ], ), ContextBlock(elements=[ ImageElement( image_url= "https://api.slack.com/img/blocks/bkb_template_images/placeholder.png", alt_text="placeholder", ), ], ), SectionBlock( text=MarkdownTextObject(text="*Your Configurations*"), ), DividerBlock(), SectionBlock( text=MarkdownTextObject( text= "*#public-relations*\n<fakelink.toUrl.com|PR Strategy 2019> posts new tasks, comments, and project updates to <fakelink.toChannel.com|#public-relations>" ), accessory=ButtonElement( text=PlainTextObject(text="Edit", emoji=True), value="public-relations", ), ), ], ) home_tab_view.validate_json()
def test_text_length_with_object(self): with self.assertRaises(SlackObjectFormationError): plaintext = PlainTextObject(text=STRING_301_CHARS) ConfirmObject(title="title", text=plaintext).to_dict() with self.assertRaises(SlackObjectFormationError): markdown = MarkdownTextObject(text=STRING_301_CHARS) ConfirmObject(title="title", text=markdown).to_dict()
def update_message(self, request: GladosRequest, **kwargs): message = Message( text=request.json.message, blocks=[ ContextBlock(elements=[ MarkdownTextObject( text= f"Message Updated: {datetime.now().isoformat(sep=' ', timespec='minutes')}" ) ]), SectionBlock(text=MarkdownTextObject( text=request.json.message)), ], ) return self.bot.update_message(channel=request.json.channel, ts=request.json.ts, message=message)
def on_slack_apierror(exc): errmsg = f"Error with call to api.slack.com: {str(exc)}" slackapp.log.error(errmsg) msg = dict(blocks=[ SectionBlock(text=MarkdownTextObject( text=f"```{errmsg}```")).to_dict() ]) return jsonify(msg)
def test_json_with_fields(self): self.assertDictEqual( SectionBlock(text=MarkdownTextObject(text="some text"), fields=[ MarkdownTextObject(text=f"field{i}") for i in range(5) ]).to_dict(), { "text": { "text": "some text", "type": "mrkdwn", "verbatim": False }, "fields": [ { "text": "field0", "type": "mrkdwn", "verbatim": False }, { "text": "field1", "type": "mrkdwn", "verbatim": False }, { "text": "field2", "type": "mrkdwn", "verbatim": False }, { "text": "field3", "type": "mrkdwn", "verbatim": False }, { "text": "field4", "type": "mrkdwn", "verbatim": False }, ], "type": "section", }, )
def on_general_exception(exc): exc_info = sys.exc_info() tb_content = json.dumps(traceback.format_tb(exc_info[2]), indent=3) errmsg = f"Unexpected error: {str(exc)}:\n{tb_content}" slackapp.log.critical(errmsg) msg = dict(blocks=[ SectionBlock(text=MarkdownTextObject( text=f"```{errmsg}```")).to_dict() ]) return jsonify(msg)
def test_passing_text_objects(self): direct_construction = ConfirmObject( title=PlainTextObject(text="title"), text=MarkdownTextObject(text="Are you sure?")) mrkdwn = MarkdownTextObject(text="Are you sure?") preconstructed = ConfirmObject(title=PlainTextObject(text="title"), text=mrkdwn) self.assertDictEqual(direct_construction.to_dict(), preconstructed.to_dict()) plaintext = PlainTextObject(text="Are you sure?", emoji=False) passed_plaintext = ConfirmObject(title=PlainTextObject(text="title"), text=plaintext) self.assertDictEqual( passed_plaintext.to_dict(), { "confirm": { "emoji": True, "text": "Yes", "type": "plain_text" }, "deny": { "emoji": True, "text": "No", "type": "plain_text" }, "text": { "emoji": False, "text": "Are you sure?", "type": "plain_text" }, "title": { "emoji": True, "text": "title", "type": "plain_text" }, }, )
def send_message(self, request: GladosRequest, **kwargs): message = Message( text=request.json.message, blocks=[ SectionBlock(text=MarkdownTextObject( text=request.json.message)) ], ) return self.bot.send_message(channel=request.json.channel, message=message)
def test_from_list_of_json_objects(self): json_objects = [ PlainTextObject(text="foo"), MarkdownTextObject(text="bar"), ] output = extract_json(json_objects) expected = {"result": [ {"type": "plain_text", "text": "foo", "emoji": True}, {"type": "mrkdwn", "text": "bar", "verbatim": False}, ]} self.assertDictEqual(expected, {"result": output})
def main(rqst: Union[InteractiveMessageRequest, CommandRequest]) -> None: block_id = cmd.prog + '.main.button' # create a Slack message that will be used to respond to the User's # interaction which was the invocation of the /demo command. resp = Response(rqst) # ------------------------------------------------------------------------- # define the button callback handler to send a response back to the # User telling the time when they pressed the button # ------------------------------------------------------------------------- @rqst.app.ic.block_action.on(block_id) def on_button(btn_rqst: BlockActionRequest, btn_action: ActionEvent): btn_resp = Response(btn_rqst) btn_resp.send_response(text=( f"At timestamp `{btn_action.data['action_ts']}`, " f"you pressed: *{btn_action.value.title()}*") ) # ------------------------------------------------------------------------- # create a message to send to the User that has two buttons; and when # they click either one, the above callback will be executed. # ------------------------------------------------------------------------- user_id = rqst.user_id resp['blocks'] = extract_json([ SectionBlock(text=MarkdownTextObject(text=f'Hi there <@{user_id}>!')), DividerBlock(), ActionsBlock( block_id=block_id, elements=[ ButtonElement( text='Press for Bad', style='danger', action_id=f'{block_id}.bad', value='bad'), ButtonElement( text='Press for Good', style="primary", action_id=f'{block_id}.good', value='good') ] ), DividerBlock() ]) resp.send()
def test_json_simple(self): section = SectionBlock(text=MarkdownTextObject(text="some text"), block_id="a_block").to_dict() json = { "text": { "text": "some text", "type": "mrkdwn", "verbatim": False }, "block_id": "a_block", "type": "section", } self.assertDictEqual(section, json)
async def test_with_blocks(self): url = os.environ[SLACK_SDK_TEST_INCOMING_WEBHOOK_URL] webhook = AsyncWebhookClient(url) response = await webhook.send( text="fallback", blocks=[ SectionBlock( block_id="sb-id", text=MarkdownTextObject( text="This is a mrkdwn text section block."), fields=[ PlainTextObject(text="*this is plain_text text*", emoji=True), MarkdownTextObject(text="*this is mrkdwn text*"), PlainTextObject(text="*this is plain_text text*", emoji=True), ]), DividerBlock(), ActionsBlock(elements=[ ButtonElement( text=PlainTextObject(text="Create New Task", emoji=True), style="primary", value="create_task", ), ButtonElement( text=PlainTextObject(text="Create New Project", emoji=True), value="create_project", ), ButtonElement( text=PlainTextObject(text="Help", emoji=True), value="help", ), ], ), ]) self.assertEqual(200, response.status_code) self.assertEqual("ok", response.body)
def on_view2_submit(rqst: ViewRequest): # same technique as on_main_modal_submit; in this case disable the submit # button only allow the User to click the "Done" (close) button. modal = Modal(rqst) view = modal.view view.title = PlainTextObject(text='Final Modal View') view.close = PlainTextObject(text='Done') view.submit = None view.add_block(SectionBlock(text=MarkdownTextObject(text='Final bit.'))) return modal.update()
def test_json_with_accessory(self): button = LinkButtonElement(text=PlainTextObject(text="Click me!"), url="http://google.com") section = SectionBlock(text=MarkdownTextObject(text="some text"), accessory=button).to_dict() coded = { "text": { "text": "some text", "type": "mrkdwn", "verbatim": False }, "accessory": button.to_dict(), "type": "section", } self.assertDictEqual(section, coded)
def on_dialog_submit(rqst: DialogRequest, submit): # when the User clicks submit from the dialog, this function is called and # a response message is send to the User showing their inputs; as well as a # state variable that was hardcoded. resp = Response(rqst) resp['blocks'] = [ blocks.SectionBlock(text=MarkdownTextObject(text=f""" Your selections:\n *message*: {submit['message']} *signature*: {submit['signature']}\n *state* `value`: {rqst.state['value']} (hardcoded in demo) """)).to_dict() ] res = resp.send_response()
def main(rqst: AnyRequest): # create a Modal and view, setting the callback so that when the User # clicks the "Next" button the code in on_main_modal_submit will be used as # the handler. Modal(rqst, callback=on_main_modal_submit, view=View(type="modal", title='First Modal View', callback_id=cmd.prog + ".view1", close='Cancel', submit='Next', blocks=[ SectionBlock(text=MarkdownTextObject( text="This is the *first* modal view.")) ])).open()
def on_main_modal_submit(rqst: ViewRequest): # define the modal and view based on the received view request from # api.slack.com as a result of this instance, the code can then "update" # the view by returning the update payload as a resposse message. modal = Modal(rqst) view = modal.view view.title = PlainTextObject(text=('Second Modal View')) view.callback_id = cmd.prog + ".view2" modal.callback = on_view2_submit view.add_block( SectionBlock(text=MarkdownTextObject( text="This is the *second* modal view."))) return modal.update()
def test_json_with_confirm(self): confirm = ConfirmObject(title=PlainTextObject(text="confirm_title"), text=MarkdownTextObject(text="confirm_text")) button = ActionButton( name="button_1", text="Click me!", value="btn_1", confirm=confirm, style="danger", ).to_dict() coded = { "name": "button_1", "text": "Click me!", "value": "btn_1", "type": "button", "confirm": confirm.to_dict("action"), "style": "danger", } self.assertDictEqual(button, coded)
from slack.web.classes.blocks import ContextBlock, SectionBlock, DividerBlock from slack.web.classes.messages import Message from slack.web.classes.objects import ( MarkdownTextObject, PlainTextObject, OptionGroup, Option, ) from slack.web.classes.elements import ButtonElement, ExternalDataSelectElement from slack.web.classes.actions import ActionButton from glados.slack_classes.views import Home HOME_VIEW = Home(blocks=[ SectionBlock(text=MarkdownTextObject(text="*Welcome to GLaDOS!*")), DividerBlock(), SectionBlock( text="*Security Events*", fields=["*New Alerts*\n20", "*Open Cases*\n5"], accessory=ButtonElement(text="Go To Security Alerts", action_id="gotoSecurityAlerts", value="go"), ), DividerBlock(), SectionBlock( text="*Service Tickets*", fields=["*Total Tickets*\n23"], accessory=ButtonElement(text="Go To Service Desk", action_id="gotoServiceDesk", value="go"), ),
def test_valid_construction(self): modal_view = View( type="modal", callback_id="modal-id", title=PlainTextObject(text="Awesome Modal"), submit=PlainTextObject(text="Submit"), close=PlainTextObject(text="Cancel"), blocks=[ InputBlock( block_id="b-id", label=PlainTextObject(text="Input label"), element=PlainTextInputElement(action_id="a-id"), ), InputBlock( block_id="cb-id", label=PlainTextObject(text="Label"), element=CheckboxesElement( action_id="a-cb-id", options=[ Option( text=PlainTextObject( text="*this is plain_text text*"), value="v1", ), Option( text=MarkdownTextObject( text="*this is mrkdwn text*"), value="v2", ), ], ), ), SectionBlock( block_id="sb-id", text=MarkdownTextObject( text="This is a mrkdwn text section block."), fields=[ PlainTextObject(text="*this is plain_text text*", emoji=True), MarkdownTextObject(text="*this is mrkdwn text*"), PlainTextObject(text="*this is plain_text text*", emoji=True), ], ), DividerBlock(), SectionBlock( block_id="rb-id", text=MarkdownTextObject( text= "This is a section block with radio button accessory"), accessory=RadioButtonsElement( initial_option=Option( text=PlainTextObject(text="Option 1"), value="option 1", description=PlainTextObject( text="Description for option 1"), ), options=[ Option( text=PlainTextObject(text="Option 1"), value="option 1", description=PlainTextObject( text="Description for option 1"), ), Option( text=PlainTextObject(text="Option 2"), value="option 2", description=PlainTextObject( text="Description for option 2"), ), ], ), ), ], ) modal_view.validate_json()
def test_deny_length(self): with self.assertRaises(SlackObjectFormationError): ConfirmObject( title=PlainTextObject(text="title"), text=MarkdownTextObject(text="Are you sure?"), deny=PlainTextObject(text=STRING_51_CHARS)).to_dict()
def test_fields_length(self): with self.assertRaises(SlackObjectFormationError): SectionBlock(fields=[ MarkdownTextObject(text=f"field{i}") for i in range(11) ]).to_dict()
def test_from_string(self): markdown = MarkdownTextObject(text="some text") self.assertDictEqual( markdown.to_dict(), MarkdownTextObject.direct_from_string("some text"))
from slack.web.classes.blocks import DividerBlock, SectionBlock from slack.web.classes.elements import ButtonElement, ExternalDataSelectElement from slack.web.classes.messages import Message from slack.web.classes.objects import MarkdownTextObject from glados import EventRoutes, GladosBot, GladosPlugin, GladosRequest, RouteType from glados.slack_classes.views import Home HOME_VIEW = Home(blocks=[ SectionBlock(text=MarkdownTextObject( text="*Welcome to GLaDOS From Lambda!*")), DividerBlock(), SectionBlock( text="*Security Events*", fields=["*New Alerts*\n20", "*Open Cases*\n5"], accessory=ButtonElement(text="Go To Security Alerts", action_id="gotoSecurityAlerts", value="go"), ), DividerBlock(), SectionBlock( text="*Service Tickets*", fields=["*Total Tickets*\n23"], accessory=ButtonElement(text="Go To Service Desk", action_id="gotoServiceDesk", value="go"), ), DividerBlock(), SectionBlock( text="Test External Menu", accessory=ExternalDataSelectElement(placeholder="Loading",