slackapi / bolt-js

A framework to build Slack apps using JavaScript
https://slack.dev/bolt-js
MIT License
2.74k stars 394 forks source link

Cannot post a message as a user via an application/bot #2092

Closed jpventura closed 3 months ago

jpventura commented 5 months ago

(Filling out the following with as much detail as you can provide will help us solve your issue sooner.)

Reproducible in:

 "@slack/bolt": "^3.17.1"

The Slack SDK version

(Paste the output of)

Not relevant

or refer to your package.json

Node.js runtime version

node v20.11.1

OS info

Ubuntu macOS
Ubuntu 22.04.4 LTS v13.6.4

(Paste the output of sw_vers && uname -v on macOS/Linux or ver on Windows OS)

Steps to reproduce:

Same issue was reported at bolt-python when trying to use Bolt to post a channel message an specific user:

const result = await app.client.chat.postMessage({
      token: process.env.SLACK_BOT_TOKEN,
      channel: channel_id,
      text: "All your bases are belong to us", 
      as_user: true,
      username: 'username',
      icon_url: "https://i.pinimg.com/736x/b5/13/5f/b5135f5280b8ccb7b48c0bb9eaedc158.jpg"
});

Expected result:

Bolt Slack bot should post a message by the specified username and with a different profile picture,

Actual result

As reported at bolt-python, this feature is not working at their framework, neither bolt-js.

What the chat:write.customize scope enables developers is to customize the message appearance (icon, name) while the message is still by a bot user.

If your situation here is that the username argument for a customized bot message does not work as you expect, please let us know. We'll try to reproduce the situation on our end.

I also does not work at chat.postMessage test page.

I would recommend modify the API to use the user_id instead of username, considering the last one may be changed.

seratch commented 5 months ago

Hi @jpventura, thanks for asking the question! What "chat:write.customize" scope gives to your app might be confusing, but as mentioned at https://github.com/slackapi/bolt-python/issues/611, this bot scope allows your app to send a "bot" message with a personalized icon and username. This feature is supposed to be used for visualizing bot and various user interactions within a Slack thread conversation.

For your use case, your app needs to serve the OAuth flow for app installation and ask each your end user to grant your app to post a message on behalf of them. More specifically, chat:write in user_scope in the OAuth flow is necessary. Behaving as a human user is so critical that your app needs to receive approval from each user to do so.

I hope this helps.

jpventura commented 5 months ago

@seratch I tried exactly this call and the icon and name change does not happen. The permission was added to the bot, but it does not seems to work on new apps.

seratch commented 5 months ago

Just in case, I verified there is no such issue with a newly created app. I create a new app and confirmed the app works for me without any issues. To narrow your issue down, I'd suggest making sure the following:

I hope this helps.

jpventura commented 5 months ago

@seratch Thank you for your attention.

We discovered the problem. According to the documentation, as_user parameter is required only for legacy apps. Including it into new apps causes the unexpected behavior.

The following code works as expected:

const result = await app.client.chat.postMessage({
      channel: channel_id,
      icon_url: 'https://i.pinimg.com/736x/b5/13/5f/b5135f5280b8ccb7b48c0bb9eaedc158.jpg',
      text: 'All your bases are belong to us', 
      token: process.env.SLACK_BOT_TOKEN,
      username: 'CATS',
});

However it does not seem to work with app.client.files.upload function. Is it an API restriction or should it work as well?

jpventura commented 5 months ago

I just checked the code and compared the app.client.files.upload arguments:

export interface FilesUploadArguments extends FileUpload, WebAPICallOptions, TokenOverridable {
}

interface FileUpload {
    channels?: string;
    content?: string;
    file?: Buffer | Stream | string;
    filename?: string;
    filetype?: string;
    initial_comment?: string;
    thread_ts?: string;
    title?: string;
}

and app.client.chat.postMessage

export interface ChatPostMessageArguments extends WebAPICallOptions, TokenOverridable {
      channel: string;
      text?: string;
      as_user?: boolean;
      attachments?: MessageAttachment[];
      blocks?: (KnownBlock | Block)[];
      icon_emoji?: string;
      icon_url?: string;
      metadata?: MessageMetadata;
      link_names?: boolean;
      mrkdwn?: boolean;
      parse?: 'full' | 'none';
      reply_broadcast?: boolean;
      thread_ts?: string;
      unfurl_links?: boolean;
      unfurl_media?: boolean;
      username?: string;
}

So I would guess that this feature is unsupported and it would require a patch into the library.

seratch commented 5 months ago

Hi @jpventura, I overlooked you were trying to use as_user option, but you're right that the option should not be used along with username and icon for the latest permission. As for files.upload API, it does not support the parameters. However, you can do the following instead:

I hope this helps.

github-actions[bot] commented 4 months ago

👋 It looks like this issue has been open for 30 days with no activity. We'll mark this as stale for now, and wait 10 days for an update or for further comment before closing this issue out. If you think this issue needs to be prioritized, please comment to get the thread going again! Maintainers also review issues marked as stale on a regular basis and comment or adjust status if the issue needs to be reprioritized.

github-actions[bot] commented 3 months ago

As this issue has been inactive for more than one month, we will be closing it. Thank you to all the participants! If you would like to raise a related issue, please create a new issue which includes your specific details and references this issue number.

jpventura commented 1 month ago

@seratch Now I am just trying to change the bot name when a text message, audio, file, or gif is sent. Adding username is working perfectly for text messages, but no to file upload.

FileUpload seems to have been removed and replaced by UploadedFile, I just checked latest Bolt JS v3.21.0 and here is how UploadedFile interface looks now:

export interface UploadedFile {
    id: string;
    created: number;
    timestamp: number;
    name: string;
    title: string;
    filetype: string;
    mimetype: string;
    permalink: string;
    url_private: string;
    url_private_download: string;
    user: string;
    user_team: string;
    username?: string;
    access?: string;
    alt_txt?: string;
    app_id?: string;
    app_name?: string;
    bot_id?: string;
    channel_actions_count?: number;
    channel_actions_ts?: string;
    channels?: string[];
    comments_count?: number;
    converted_pdf?: string;
    deanimate?: string;
    deanimate_gif?: string;
    display_as_bot?: boolean;
    duration_ms?: number;
    edit_link?: string;
    editable?: boolean;
    editor?: string;
    external_id?: string;
    external_type?: string;
    external_url?: string;
    file_access?: string;
    groups?: string[];
    has_more?: boolean;
    has_more_shares?: boolean;
    has_rich_preview?: boolean;
    hls?: string;
    hls_embed?: string;
    image_exif_rotation?: number;
    ims?: string[];
    is_channel_space?: boolean;
    is_external?: boolean;
    is_public?: boolean;
    is_starred?: boolean;
    last_editor?: string;
    last_read?: number;
    lines?: number;
    lines_more?: number;
    linked_channel_id?: string;
    media_display_type?: string;
    mode?: string;
    mp4?: string;
    mp4_low?: string;
    non_owner_editable?: boolean;
    num_stars?: number;
    org_or_workspace_access?: string;
    original_attachment_count?: number;
    original_h?: string;
    original_w?: string;
    permalink_public?: string;
    pinned_to?: string[];
    pjpeg?: string;
    plain_text?: string;
    pretty_type?: string;
    preview?: string;
    preview_highlight?: string;
    preview_is_truncated?: boolean;
    preview_plain_text?: string;
    private_channels_with_file_access_count?: number;
    public_url_shared?: boolean;
    simplified_html?: string;
    size?: number;
    source_team?: string;
    subject?: string;
    subtype?: string;
    thumb_1024?: string;
    thumb_1024_gif?: string;
    thumb_1024_h?: string;
    thumb_1024_w?: string;
    thumb_160?: string;
    thumb_160_gif?: string;
    thumb_160_h?: string;
    thumb_160_w?: string;
    thumb_360?: string;
    thumb_360_gif?: string;
    thumb_360_h?: string;
    thumb_360_w?: string;
    thumb_480?: string;
    thumb_480_gif?: string;
    thumb_480_h?: string;
    thumb_480_w?: string;
    thumb_64?: string;
    thumb_64_gif?: string;
    thumb_64_h?: string;
    thumb_64_w?: string;
    thumb_720?: string;
    thumb_720_gif?: string;
    thumb_720_h?: string;
    thumb_720_w?: string;
    thumb_80?: string;
    thumb_800?: string;
    thumb_800_gif?: string;
    thumb_800_h?: string;
    thumb_800_w?: string;
    thumb_80_gif?: string;
    thumb_80_h?: string;
    thumb_80_w?: string;
    thumb_960?: string;
    thumb_960_gif?: string;
    thumb_960_h?: string;
    thumb_960_w?: string;
    thumb_gif?: string;
    thumb_pdf?: string;
    thumb_pdf_h?: string;
    thumb_pdf_w?: string;
    thumb_tiny?: string;
    thumb_video?: string;
    thumb_video_h?: number;
    thumb_video_w?: number;
    updated?: number;
    url_static_preview?: string;
    vtt?: string;
}

The optional username is now present, however the bot name remains the same. Is the parameter been ignored?

jpventura commented 1 month ago

I just checked at api.slack.com and files.completeUploadExternal does not handle username as an optional parameter.

So, even if I modified node-slack-sdk, it will not matter because it is just a client to a REST API web server that will ignore the additional parameter.

How this feature can be requested to Slack API engineering team?

filmaj commented 1 month ago

@jpventura please see @seratch's comment here - he suggested:

  1. Upload the file without sharing first. That is, without providing the channel_id and initial_comment parameters. This would upload the file but not share it, meaning the file exists within Slack but only the uploading user (the bot, in this case) has access to it.
  2. In a separate API call, call chat.postMessage and share the file's permalink in the message. chat.postMessage allows you to set username and so on. Once the file's permalink is shared, the file becomes visible to others.