laravel/slack-notification-channel

Error using Illuminate\Notifications\Slack\SlackMessage buildJsonPayload

sts-ryan-holton opened this issue ยท 15 comments

Slack Notification Channel Version

3.1.0

Laravel Version

10.34.2

PHP Version

8.1.26

Database Driver & Version

MySQL 5.7

Description

I'm trying to send a Slack message via a notification toSlack. My user has a Slack incoming webhook URL that they wish to receive alerts with, but when sending a message, an error is thrown.

Illuminate\Notifications\Channels\SlackWebhookChannel::buildJsonPayload(): Argument #1 ($message) must be of type Illuminate\Notifications\Messages\SlackMessage, Illuminate\Notifications\Slack\SlackMessage given, called in /var/www/html/vendor/laravel/slack-notification-channel/src/Channels/SlackWebhookChannel.php on line 43

The docs say to use Illuminate\Notifications\Slack\SlackMessage which I'm using, put I get an error with that

Steps To Reproduce

  1. Create a notification
  2. Set the incoming webhook url on User model

Here's my routeNotificationForSlack function:

/**
 * Route notifications for the Slack channel.
 */
public function routeNotificationForSlack(Notification $notification): string|null
{
    return 'https://hooks.slack.com/services/XXXXXX';
}

Here's my toSlack function

/**
 * Get the array representation of the notification.
 *
 * @param  mixed  $notifiable
 */
public function toSlack($notifiable): SlackMessage
{
    $data = [
        'type' => 'monitor-down',
        'name' => $this->emailData['monitor_name'],
        'url' => $this->emailData['monitor_url'],
        'value' => 'down',
    ];

    try {
        $this->createHistoryEntry('slack', 'Monitor Down', $data, $notifiable);
    } catch (\Exception $e) {
    }

    $monitorName = $this->emailData['monitor_name'];
    $monitorURL = $this->emailData['monitor_url'];

    return (new SlackMessage)
        ->text('One of your invoices has been paid!')
        ->headerBlock('Invoice Paid')
        ->contextBlock(function (ContextBlock $block) {
            $block->text('Customer #1234');
        })
        ->sectionBlock(function (SectionBlock $block) {
            $block->text('An invoice has been paid.');
            $block->field("*Invoice No:*\n1000")->markdown();
            $block->field("*Invoice Recipient:*\ntaylor@laravel.com")->markdown();
        })
        ->dividerBlock()
        ->sectionBlock(function (SectionBlock $block) {
            $block->text('Congratulations!');
        });

    // return (new SlackMessage)
    //         ->from('Domain Monitor')
    //         ->image('https://domain-monitor.io/slack-logo.png')
    //         ->error()
    //         ->attachment(function ($attachment) use ($monitorName, $monitorURL) {
    //             $attachment->title('Monitor down')
    //                        ->content("Your monitor *$monitorName* -- _($monitorURL)_ -- has just gone *DOWN*")
    //                        ->markdown(['text']);
    //         });
}

I'm importing

use Illuminate\Notifications\Slack\BlockKit\Blocks\ContextBlock;
use Illuminate\Notifications\Slack\BlockKit\Blocks\SectionBlock;
use Illuminate\Notifications\Slack\BlockKit\Composites\ConfirmObject;
use Illuminate\Notifications\Slack\SlackMessage;

protected function determineChannel($route)
{
if ($route instanceof UriInterface) {
return $this->app->make(SlackWebhookChannel::class);
}
if (is_string($route) && Str::startsWith($route, ['http://', 'https://'])) {
return $this->app->make(SlackWebhookChannel::class);
}
return $this->app->make(SlackWebApiChannel::class);

It seems you are using SlackWebhookChannel instead SlackWebApiChannel which the documentation refers to.

@crynobone How can it be set up correctly to use the SlackWebApiChannel? not sure where this is being setup. Thanks in advance.

I hit this today! Recently upgraded from laravel 9 -> 10 and we use webhooks (not slack app).

  • Webhook notifications toSlack method wants Illuminate\Notifications\Messages\SlackMessage
  • While app notifications toSlack method wants Illuminate\Notifications\Slack\SlackMessage

The issue (for me) is that I set the webhook url via .env file, but have it commented out for local dev so phpunit doesn't spam slack. When it is commented out, routeNotificationForSlack was returning nothing... which caused return type errors because determineChannel used SlackWebApiChannel (instead of SlackWebhookChannel) and my toSlack methods return type is Illuminate\Notifications\Messages\SlackMessage and not Illuminate\Notifications\Slack\SlackMessage....

Long story short, to fix I set a default of https://hooks.slack.com/ to make sure determineChannel uses SlackWebhookChannel.

I spent more time on this than the entire Laravel 10 upgrade >.<

    // services.php
    'slack' => [
        // default needed to make laravel 10 still use webhooks for local dev and not slack api / apps
        'tech_notifications' => env('SLACK_TECH_WEBHOOK', 'https://hooks.slack.com/'),
        'custserv_notifications' => env('SLACK_CUSTSERV_WEBHOOK', 'https://hooks.slack.com/'),
    ],

I'm the other way around, I want to use Slack\SlackMessage instead of Webhook to use the new Builder but don't see where to specify that, the toSlack method asks for the Messages\SlackMessage, seems there's somewhere to specify this, just not sure where. Thanks man

I do not think you can use the new builder, webhooks seem to want Messages\SlackMessage, but if you do find a way to force Slack\SlackMessage for webhooks... post it here as I also would like the new formatting options.

@brandonburkett will do, man. Good luck and thanks again.

Here's something strange then that I need help with, so, my original setup of utilising Messages\SlackMessage, throws the following error:

Illuminate\Notifications\Slack\SlackChannel::buildJsonPayload(): Argument #1 ($message) must be of type Illuminate\Notifications\Slack\SlackMessage, Illuminate\Notifications\Messages\SlackMessage given, called in /var/www/domain-monitor-api/vendor/laravel/slack-notification-channel/src/Slack/SlackChannel.php on line 38

That's returning:

/**
 * Get the array representation of the notification.
 *
 * @param  mixed  $notifiable
 */
public function toSlack($notifiable)
{
    $data = [
        'type' => 'monitor-down',
        'name' => $this->emailData['monitor_name'],
        'url' => $this->emailData['monitor_url'],
        'value' => 'down',
    ];

    try {
        $this->createHistoryEntry('slack', 'Monitor Down', $data, $notifiable);
    } catch (\Exception $e) {
    }

    $monitorName = $this->emailData['monitor_name'];
    $monitorURL = $this->emailData['monitor_url'];

    return (new SlackMessage)
            ->from('Domain Monitor')
            ->image('https://domain-monitor.io/slack-logo.png')
            ->error()
            ->attachment(function ($attachment) use ($monitorName, $monitorURL) {
                $attachment->title('Monitor down')
                            ->content("Your monitor *$monitorName* -- _($monitorURL)_ -- has just gone *DOWN*")
                            ->markdown(['text']);
            });
}

Yep, that's the same error ๐Ÿค” will dive deep into this today if something comes up, I'll post it here.

@albertorsesc Appreciate it ๐Ÿ˜„ because my application is throwing lots of exception logs, for my environment I need to continue using the routeNotificationForSlack on my User model which needs to return a string with the user's webhook URL.

Just need to determine the correct set up for 3.1.0 of the package, maybe a 3.1.1 can be released for this?

Hopefully.

Found this Issue, will take a look at it today, but in case you want to try this, I'll leave it here. (Let us know if it worked for you), good luck.

#68

@albertorsesc The problem I've got, is my routeNotificationForSlack function on my User model is dynamic. A User in my application can setup a "Slack" integration to receive notifications on, they, I achieve this with a function that calls for their integration, which comes from a form which only has the option for a Slack webhook URL:

/**
 * Route notifications for the Slack channel.
 */
public function routeNotificationForSlack(Notification $notification): string|null
{
    try {
        $userIntegration = $this->getUserIntegration($this->id, 'slack');

        if (! $userIntegration) {
            return null;
        }

        return $userIntegration->schema->slack_webhook;
    } catch (\Exception $e) {
    }

    return null;
}

I have a few hundred users that are using this webhook URL method, and there's no channel option defined for them. How would I migrate this then?

They never needed a channel when they activated the integration.

Capture

Instead of returning null, try returning https://hooks.slack.com/ and see if that fixes your return type for toSlack.

Returning null will default to SlackWebApiChannel instead of SlackWebhookChannel

Fix was merged today. :)

Slack Notification Channel Version

3.1.0

Laravel Version

10.34.2

PHP Version

8.1.26

Database Driver & Version

MySQL 5.7

Description

I'm trying to send a Slack message via a notification toSlack. My user has a Slack incoming webhook URL that they wish to receive alerts with, but when sending a message, an error is thrown.

Illuminate\Notifications\Channels\SlackWebhookChannel::buildJsonPayload(): Argument #1 ($message) must be of type Illuminate\Notifications\Messages\SlackMessage, Illuminate\Notifications\Slack\SlackMessage given, called in /var/www/html/vendor/laravel/slack-notification-channel/src/Channels/SlackWebhookChannel.php on line 43

The docs say to use Illuminate\Notifications\Slack\SlackMessage which I'm using, put I get an error with that

Steps To Reproduce

  1. Create a notification

  2. Set the incoming webhook url on User model

Here's my routeNotificationForSlack function:

/**

 * Route notifications for the Slack channel.

 */

public function routeNotificationForSlack(Notification $notification): string|null

{

    return 'https://hooks.slack.com/services/XXXXXX';

}

Here's my toSlack function

/**

 * Get the array representation of the notification.

 *

 * @param  mixed  $notifiable

 */

public function toSlack($notifiable): SlackMessage

{

    $data = [

        'type' => 'monitor-down',

        'name' => $this->emailData['monitor_name'],

        'url' => $this->emailData['monitor_url'],

        'value' => 'down',

    ];



    try {

        $this->createHistoryEntry('slack', 'Monitor Down', $data, $notifiable);

    } catch (\Exception $e) {

    }



    $monitorName = $this->emailData['monitor_name'];

    $monitorURL = $this->emailData['monitor_url'];



    return (new SlackMessage)

        ->text('One of your invoices has been paid!')

        ->headerBlock('Invoice Paid')

        ->contextBlock(function (ContextBlock $block) {

            $block->text('Customer #1234');

        })

        ->sectionBlock(function (SectionBlock $block) {

            $block->text('An invoice has been paid.');

            $block->field("*Invoice No:*\n1000")->markdown();

            $block->field("*Invoice Recipient:*\ntaylor@laravel.com")->markdown();

        })

        ->dividerBlock()

        ->sectionBlock(function (SectionBlock $block) {

            $block->text('Congratulations!');

        });



    // return (new SlackMessage)

    //         ->from('Domain Monitor')

    //         ->image('https://domain-monitor.io/slack-logo.png')

    //         ->error()

    //         ->attachment(function ($attachment) use ($monitorName, $monitorURL) {

    //             $attachment->title('Monitor down')

    //                        ->content("Your monitor *$monitorName* -- _($monitorURL)_ -- has just gone *DOWN*")

    //                        ->markdown(['text']);

    //         });

}

I'm importing

use Illuminate\Notifications\Slack\BlockKit\Blocks\ContextBlock;

use Illuminate\Notifications\Slack\BlockKit\Blocks\SectionBlock;

use Illuminate\Notifications\Slack\BlockKit\Composites\ConfirmObject;

use Illuminate\Notifications\Slack\SlackMessage;

@Freebands22 did you ever figure this out? I'm dealing with the same issue.