Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Slack Message Buttons #40

Open
ebpitts opened this issue Jun 22, 2016 · 13 comments
Open

Support Slack Message Buttons #40

ebpitts opened this issue Jun 22, 2016 · 13 comments

Comments

@ebpitts
Copy link

ebpitts commented Jun 22, 2016

Slack recently introduced the concept of message buttons.

Example Message Button

Blog post: https://slackhq.com/get-more-done-with-message-buttons-5fa5b283a59
Developer documentation: https://api.slack.com/docs/message-buttons

Here's their summary of the interaction model:

  1. Your application produces a message containing buttons. Maybe the message originated in response to an invoked slash command, or in response to a bot user's trigger phrase. Or maybe your app posted the message manually using an incoming webhook or chat.postMessage. In any case, your Slack app produced a message with buttons, offering users a chance to interact with it.
  2. Users encounter your message and, inspired by its call to action, clicks one of your buttons. This triggers an invocation of your application's associated Action URL.
  3. Slack sends a request to your Action URL, sending all the context needed to identify the originating message, the user that executed the action, and the specific values you've associated with the button. This request also contains a response_url you can use to continue interacting with the user or channel.
  4. Your application responds to the action. If you respond directly to the incoming invocation request, your provided message will replace the existing message. It's also possible to respond with an ephemeral message, visible only to the invoking user. Or you can just respond with HTTP 200 OK and wait to continue the interaction until later using the response_url provided as part of the action.
  5. Meanwhile: Your application does whatever it does as a result of the intended action to be taken: enqueue a process, save a database row, or continue interacting with users through additional message buttons.
  6. By using the response_url, your app can continue interacting with users up to 5 times within 30 minutes of the action invocation. Use this to continue through a workflow until it is complete.
  7. Messages can evolve. By using chat.update and your created message's message_ts field, you can modify the original interactive message (including all of its attachments) to add or remove buttons based on user interactions.

I opened this issue so there would be a place for conversation about if and how errbot could support message buttons.

@gbin
Copy link
Member

gbin commented Jul 11, 2016

We are considering this.
But we will have to emulate that for the other backends that don't support it probably like what we did for the cards with some markdown.

@ab9-er
Copy link

ab9-er commented Jun 20, 2017

Any idea when could this feature be implemented for Slack ?

@zoni
Copy link
Member

zoni commented Jun 20, 2017

Nothing concrete is currently being worked on (to the best of my knowledge) so don't get your hopes up too much.

@i-nikolov
Copy link

Any news or progress on this?

@ab9-er
Copy link

ab9-er commented Nov 8, 2017

@i-nikolov I am using Slack's API to make use of this feature instead of relying on any functions from errbot.

@eran-totango
Copy link

@ab9-er Will you be willing to share some code examples with us?

@ab9-er
Copy link

ab9-er commented Nov 13, 2017

@eran-totango check this out https://gist.github.com/ab9-er/e47695429262f8274d1b0a9b19114db0

(I have initiated a variable with a mutable value which is not the best of the practices but it was a dirty quick example) 😈

The function should also return something, which it doesn't in the basic example, best would be to return the result of the API call which should be a 200 OK along with the ts value of the message and other details as per Slack's API documentation.

@gbin-argo
Copy link

@ab9-er cool, I'd really love to integrate that to flows: they basically match this with button answers being fed to the context and unlocking steps. I don't have much time for myself at the moment but I can guide anyone willing to do that.

@ab9-er
Copy link

ab9-er commented Nov 15, 2017

@gbin-argo I could help chip in but sporadically.

@lingfish
Copy link

lingfish commented Aug 25, 2018

I'm a bit keen on this too, but I also see authentication being "fun" (not). @ab9-er how did you handle that?

@Buffer0x7cd
Copy link

@ab9-er @gbin-argo Is there any update regarding this feature? if not then I would like to take up the task of implementing this feature 😄

@sheluchin
Copy link

You guys may want to take a quick glance at https://api.slack.com/changelog/2018-12-a-bric-a-brac-of-broadcasts-built-with-blocks before starting any work. I don't know if it impacts buttons, but it might.

Blocks also introduce more interactive options for app developers. They provide visually cleaner ways to incorporate buttons or menus, as well as new interactive elements like date pickers or overflow menus.

@duhow
Copy link
Collaborator

duhow commented Dec 10, 2020

I guess this is more meant to be provided by Slack Events errbotio/errbot#1451 .
The way I implemented it in my custom Slack Event Backend was by parsing the button event (interactive message) as a text message with extra fields.

    def _interactive_message_event_handler(self, event):
        """
        Event handler for the 'interactive' event, used in attachments / buttons.
        """
        msg = Message(
            frm=SlackPerson(event['user']['id'], event['channel']['id'], bot=self),
            to=self.bot_identifier,
            extras={
                'actions': [{x['name']: x} for x in event['actions']],
                'url': event['response_url'],
                'trigger_id': event.get('trigger_id', None),
                'callback_id': event.get('callback_id', None),
                'slack_event': event
            }
        )

        flow, _ = self.flow_executor.check_inflight_flow_triggered(msg.extras['callback_id'], msg.frm)
        if flow:
            log.debug("Reattach context from flow %s to the message", flow._root.name)
            msg.ctx = flow.ctx

        self.callback_message(msg)

Then on callback_message of the plugin:

    def callback_message(self, msg):
        callback = msg.extras.get('callback_id', None)
        if (
            callback and callback in dir(self) and
            callable(getattr(self, callback))
        ):
            self.log.info(f'Calling function {callback}')
            return getattr(self, callback)(msg)

Finally on the command:

    @botcmd
    def approval_request(self, msg, args=None):
        """ Check response of a request. """
        if msg.extras.get('callback_id', None) == 'approval_request':
            answer = msg.extras.get('actions')[0]['question']['value']
            answer = True if answer == 'Approve' else False

@sijis sijis transferred this issue from errbotio/errbot Jul 23, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests