def open_modal(trigger_id: str):
    try:
        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-1",
                                   label=PlainTextObject(text="Input label"),
                                   element=ConversationSelectElement(
                                       action_id="a",
                                       default_to_current_conversation=True,
                                   )),
                        InputBlock(block_id="b-id-2",
                                   label=PlainTextObject(text="Input label"),
                                   element=ConversationMultiSelectElement(
                                       action_id="a",
                                       max_selected_items=2,
                                       default_to_current_conversation=True,
                                   )),
                    ])
        api_response = client.views_open(trigger_id=trigger_id, view=view)
        return make_response("", 200)
    except SlackApiError as e:
        code = e.response["error"]
        return make_response(f"Failed to open a modal due to {code}", 200)
Exemplo n.º 2
0
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_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)
Exemplo n.º 4
0
    def from_view(cls, view):
        new_view = cls(type=view['type'],
                       title=PlainTextObject(text=view['title']['text']),
                       callback_id=view['callback_id'],
                       blocks=view['blocks'],
                       external_id=view['external_id'] or None,
                       clear_on_close=view['clear_on_close'] or None)

        if view['close']:
            new_view.close = PlainTextObject(text=view['close']['text'])

        if view['submit']:
            new_view.submit = PlainTextObject(text=view['submit']['text'])

        new_view.notify_on_close = view['notify_on_close']
        new_view.view_id = view['id']

        if view['private_metadata']:
            try:
                new_view.private_metadata = json.loads(
                    view['private_metadata'])
            except json.JSONDecodeError:
                new_view.private_metadata = view['private_metadata']

        new_view.state_values = view['state']['values']
        new_view.view_hash = view['hash']
        return new_view
def delayed_update_view(rqst: ViewRequest, view: View, delay: int):

    sleep(delay)

    modal = Modal(rqst=rqst, view=view, detached=True)

    # If the User clicks on Done, then the `done_booping` handler will be
    # invoked as a result of the view close.

    modal.notify_on_close = done_booping

    view = modal.view
    view.title = PlainTextObject(text='Booped!')
    view.close = PlainTextObject(text='Done')

    view.blocks[0] = SectionBlock(text=PlainTextObject(
        text=f'First boop after {delay} seconds'))

    button = view.add_block(
        SectionBlock(text=PlainTextObject(text='Click button to boop again.'),
                     block_id=cmd.prog + ".boop"))

    button.accessory = ButtonElement(text='Boop',
                                     action_id=button.block_id,
                                     value='boop')

    rqst.app.ic.block_action.on(button.block_id, on_boop_button)

    res = modal.update()
    if not res.get('ok'):
        rqst.app.log.error(f'failed to boop: {res}')
Exemplo n.º 6
0
 def setUp(self) -> None:
     self.elements = [
         ButtonElement(text=PlainTextObject(text="Click me"),
                       action_id="reg_button",
                       value="1"),
         LinkButtonElement(text=PlainTextObject(text="URL Button"),
                           url="http://google.com"),
     ]
Exemplo n.º 7
0
    def test_basic_json(self):
        self.assertDictEqual(
            {"text": "some text", "type": "plain_text"},
            PlainTextObject(text="some text").to_dict(),
        )

        self.assertDictEqual(
            {"text": "some text", "emoji": False, "type": "plain_text"},
            PlainTextObject(text="some text", emoji=False).to_dict(),
        )
    def test_text_length_with_object(self):
        with self.assertRaises(SlackObjectFormationError):
            plaintext = PlainTextObject(text=STRING_301_CHARS)
            ConfirmObject(title=PlainTextObject(text="title"),
                          text=plaintext).to_dict()

        with self.assertRaises(SlackObjectFormationError):
            markdown = MarkdownTextObject(text=STRING_301_CHARS)
            ConfirmObject(title=PlainTextObject(text="title"),
                          text=markdown).to_dict()
Exemplo n.º 9
0
 def test_invalid_type_value(self):
     modal_view = View(
         type="modallll",
         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")),
         ])
     with self.assertRaises(SlackObjectFormationError):
         modal_view.validate_json()
Exemplo n.º 10
0
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()
Exemplo n.º 11
0
 def test_close_in_home_tab(self):
     modal_view = View(type="home",
                       callback_id="home-tab-id",
                       close=PlainTextObject(text="Cancel"),
                       blocks=[DividerBlock()])
     with self.assertRaises(SlackObjectFormationError):
         modal_view.validate_json()
Exemplo n.º 12
0
    def test_basic_json(self):
        self.elements = [
            ImageElement(
                image_url=
                "https://api.slack.com/img/blocks/bkb_template_images/palmtree.png",
                alt_text="palmtree"),
            PlainTextObject(text="Just text"),
        ]
        e = {
            "elements": [
                {
                    "type": "image",
                    "image_url":
                    "https://api.slack.com/img/blocks/bkb_template_images/palmtree.png",
                    "alt_text": "palmtree"
                },
                {
                    "type": "plain_text",
                    "text": "Just text"
                },
            ],
            "type":
            "context",
        }
        d = ContextBlock(elements=self.elements).to_dict()
        self.assertDictEqual(e, d)

        with self.assertRaises(SlackObjectFormationError):
            ContextBlock(elements=self.elements * 6).to_dict()
Exemplo n.º 13
0
 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)
Exemplo n.º 14
0
 def test_from_single_value(self):
     option = Option(text=PlainTextObject(text="option_1"),
                     value="option_1")
     self.assertDictEqual(
         option.to_dict("text"),
         option.from_single_value("option_1").to_dict("text"),
     )
Exemplo n.º 15
0
 def test_options_length(self):
     with self.assertRaises(SlackObjectFormationError):
         StaticSelectElement(
             placeholder=PlainTextObject(text="select"),
             action_id="selector",
             options=[self.option_one] * 101,
         ).to_dict()
Exemplo n.º 16
0
 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()
Exemplo n.º 17
0
 def test_json_simple(self):
     button = ButtonElement(text=PlainTextObject(text="button text"), action_id="some_button",
                            value="button_123").to_dict()
     coded = {
         "text": {"emoji": True, "text": "button text", "type": "plain_text"},
         "action_id": "some_button",
         "value": "button_123",
         "type": "button",
     }
     self.assertDictEqual(button, coded)
Exemplo n.º 18
0
    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"
                },
            },
        )
Exemplo n.º 19
0
 def test_json_with_confirm(self):
     confirm = ConfirmObject(title=PlainTextObject(text="really?"),
                             text=PlainTextObject(text="are you sure?"))
     button = ButtonElement(
         text=PlainTextObject(text="button text"),
         action_id="some_button",
         value="button_123",
         style="primary",
         confirm=confirm,
     ).to_dict()
     coded = {
         "text": {"emoji": True, "text": "button text", "type": "plain_text"},
         "action_id": "some_button",
         "value": "button_123",
         "type": "button",
         "style": "primary",
         "confirm": confirm.to_dict(),
     }
     self.assertDictEqual(button, coded)
Exemplo n.º 20
0
 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})
Exemplo n.º 21
0
 def test_json_with_confirm(self):
     confirm = ConfirmObject(title=PlainTextObject(text="title"), text=PlainTextObject(text="text"))
     select = StaticSelectElement(
         placeholder=PlainTextObject(text="selectedValue"),
         action_id="dropdown",
         options=self.options,
         confirm=confirm,
     ).to_dict()
     coded = {
         "placeholder": {
             "emoji": True,
             "text": "selectedValue",
             "type": "plain_text",
         },
         "action_id": "dropdown",
         "options": [o.to_dict() for o in self.options],
         "confirm": confirm.to_dict(),
         "type": "static_select",
     }
     self.assertDictEqual(select, coded)
Exemplo n.º 22
0
 def test_input_blocks_in_home_tab(self):
     modal_view = View(
         type="home",
         callback_id="home-tab-id",
         blocks=[
             InputBlock(block_id="b-id",
                        label=PlainTextObject(text="Input label"),
                        element=PlainTextInputElement(action_id="a-id")),
         ])
     with self.assertRaises(SlackObjectFormationError):
         modal_view.validate_json()
Exemplo n.º 23
0
 def test_from_single_json_object(self):
     single_json_object = PlainTextObject.from_str("foo")
     output = extract_json(single_json_object)
     expected = {
         "result": {
             "type": "plain_text",
             "text": "foo",
             "emoji": True
         }
     }
     self.assertDictEqual(expected, {"result": output})
Exemplo n.º 24
0
def slack_app():
    if not signature_verifier.is_valid_request(request.get_data(), request.headers):
        return make_response("invalid request", 403)

    if "payload" in request.form:
        payload = json.loads(request.form["payload"])
        if payload["type"] == "shortcut" \
            and payload["callback_id"] == "open-modal-shortcut":
            # Open a new modal by a global shortcut
            try:
                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")
                        )
                    ]
                )
                api_response = client.views_open(
                    trigger_id=payload["trigger_id"],
                    view=view,
                )
                return make_response("", 200)
            except SlackApiError as e:
                code = e.response["error"]
                return make_response(f"Failed to open a modal due to {code}", 200)

        if payload["type"] == "view_submission" \
            and payload["view"]["callback_id"] == "modal-id":
            # Handle a data submission request from the modal
            submitted_data = payload["view"]["state"]["values"]
            print(submitted_data)  # {'b-id': {'a-id': {'type': 'plain_text_input', 'value': 'your input'}}}
            return make_response("", 200)

    return make_response("", 404)
Exemplo n.º 25
0
 def test_json(self):
     button = LinkButtonElement(text=PlainTextObject(text="button text"), url="http://google.com")
     self.assertDictEqual(
         button.to_dict(),
         {
             "text": {"emoji": True, "text": "button text", "type": "plain_text"},
             "url": "http://google.com",
             "type": "button",
             "value": "",
             "action_id": button.action_id,
         },
     )
Exemplo n.º 26
0
    def test_json(self):
        self.assertDictEqual(
            ExternalDataSelectElement(
                placeholder=PlainTextObject(text="selectedValue"), action_id="dropdown", min_query_length=5
            ).to_dict(),
            {
                "placeholder": {
                    "emoji": True,
                    "text": "selectedValue",
                    "type": "plain_text",
                },
                "action_id": "dropdown",
                "min_query_length": 5,
                "type": "external_select",
            },
        )

        self.assertDictEqual(
            ExternalDataSelectElement(
                placeholder=PlainTextObject(text="selectedValue"),
                action_id="dropdown",
                confirm=ConfirmObject(title=PlainTextObject(text="title"), text=PlainTextObject(text="text")),
            ).to_dict(),
            {
                "placeholder": {
                    "emoji": True,
                    "text": "selectedValue",
                    "type": "plain_text",
                },
                "action_id": "dropdown",
                "confirm": ConfirmObject(title=PlainTextObject(text="title"),
                                         text=PlainTextObject(text="text")).to_dict("block"),
                "type": "external_select",
            },
        )
 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)
Exemplo n.º 28
0
 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_main_modal_submit(rqst):
    modal = Modal(rqst)
    view = modal.view
    view.callback_id = cmd.prog + ".view2"
    view.title = PlainTextObject(text='Awaiting Boop')

    params = session[SESSION_KEY]['params']
    delay = params['delay']

    view.blocks[0] = SectionBlock(text=PlainTextObject(
        text=f"Launching async task for {delay} sec update"))

    view.submit = None

    rqst.app.log.debug(modal.view.hash)

    Thread(target=delayed_update_view,
           kwargs={
               'rqst': rqst,
               'view': modal.view,
               'delay': delay
           }).start()

    return modal.update()
def on_boop_button(rqst):

    params = session[SESSION_KEY]['params']

    params['boops'] += 1
    boops = params['boops']

    modal = Modal(rqst)

    view = modal.view
    view.blocks.pop(0)
    view.blocks.insert(
        0, SectionBlock(text=PlainTextObject(text=f'Boop {boops}')))

    res = modal.update()
    if not res.get('ok'):
        rqst.app.log.error(f'failed to boop: {res}')