slackapi / bolt-python

A framework to build Slack apps using Python
https://tools.slack.dev/bolt-python/
MIT License
1.06k stars 245 forks source link

Passing a global dict object without channel prop can cause issues among requests #721

Closed gk-patel closed 2 years ago

gk-patel commented 2 years ago

I did try to answer as much as I though was relevant below, but I found the exact line which is leading to the bug.

https://github.com/slackapi/bolt-python/blob/main/slack_bolt/context/say/say.py#L51

I am passing a global dict to SAY function and that is getting modified here. Next time the SAY function is called with the same dictionary, it ignores the current channel and send the message to the very first user.

Please consider using ".copy()" or "copy.copy" method on this line, https://github.com/slackapi/bolt-python/blob/main/slack_bolt/context/say/say.py#L49

https://stackoverflow.com/questions/2465921/how-to-copy-a-dictionary-and-only-edit-the-copy

Reproducible in:

Pass a global dict as response to say().

The slack_bolt version

latest

Python runtime version

3.9

OS info

windows 10

Expected result:

Say should reply the global reply dict to the user who started conversation. Not, to the very fist user who used the service endpoint for the first time.

WilliamBergamin commented 2 years ago

Hi @gk-patel thanks for writing in 🥇

I think I understand what your issue is, just to be clear could you share an example of the dict you are passing to Say? I will try to reproduce this on my end

gk-patel commented 2 years ago

Hi @WilliamBergamin,

It should be very easy to reproduce, my setup is a bit complicated so I cannot paste my code here for sake of simplicity.

MESSAGE_ON_TRIGGER_X = { "text": "bla", "blocks": { --some-blocks-- } }

def triggerX(say): 
    say(MESSAGE_ON_TRIGGER_X) 

slackApp.action("trigger-id)(triggerX)

Now, the very first time triggerX is executed, MESSAGE_ON_TRIGGER_X will have an extra field "channel". And therefore, the second call to triggerX will send the message to the first first channel. Hence, action by the second user sends reaction to the first user.

Hope you can reproduce with this. Or simply adding a .copy() should solve it. In my code, I have done the following,

def triggerX(say): 
    say(MESSAGE_ON_TRIGGER_X.copy()) 

and it works fine.

seratch commented 2 years ago

@gk-patel Thanks for sharing the details. Indeed, this should be improved. We will resolve it in future versions.