diff --git a/src/Slack/SlackMessage.php b/src/Slack/SlackMessage.php index e1fda76..f190aef 100644 --- a/src/Slack/SlackMessage.php +++ b/src/Slack/SlackMessage.php @@ -13,6 +13,7 @@ use Illuminate\Notifications\Slack\Contracts\BlockContract; use Illuminate\Support\Arr; use Illuminate\Support\Traits\Conditionable; +use JsonException; use LogicException; class SlackMessage implements Arrayable @@ -32,7 +33,7 @@ class SlackMessage implements Arrayable /** * The message's blocks. * - * @var \Illuminate\Notifications\Slack\Contracts\BlockContract[] + * @var array<\Illuminate\Notifications\Slack\Contracts\BlockContract|array> */ protected array $blocks = []; @@ -268,6 +269,25 @@ public function broadcastReply(?bool $broadcastReply = true): self return $this; } + /** + * Specify a raw Block Kit Builder JSON payload for the message. + * + * @throws JsonException + * @throws LogicException + */ + public function usingBlockKitTemplate(string $template): self + { + $blocks = json_decode($template, true, flags: JSON_THROW_ON_ERROR); + + if (! array_key_exists('blocks', $blocks)) { + throw new LogicException('The blocks array key is missing.'); + } + + array_push($this->blocks, ...$blocks['blocks']); + + return $this; + } + /** * Get the instance as an array. */ @@ -283,7 +303,7 @@ public function toArray(): array $optionalFields = array_filter([ 'text' => $this->text, - 'blocks' => ! empty($this->blocks) ? array_map(fn (BlockContract $block) => $block->toArray(), $this->blocks) : null, + 'blocks' => ! empty($this->blocks) ? array_map(fn ($block) => $block instanceof BlockContract ? $block->toArray() : $block, $this->blocks) : null, 'icon_emoji' => $this->icon, 'icon_url' => $this->image, 'metadata' => $this->metaData?->toArray(), diff --git a/tests/Slack/Feature/SlackMessageTest.php b/tests/Slack/Feature/SlackMessageTest.php index 6af56e2..0b90c99 100644 --- a/tests/Slack/Feature/SlackMessageTest.php +++ b/tests/Slack/Feature/SlackMessageTest.php @@ -447,4 +447,130 @@ public function it_submits_blocks_in_the_order_they_were_defined(): void ], ]); } + + /** @test */ + public function it_can_use_copied_block_kit_template() + { + $this->sendNotification(function (SlackMessage $message) { + $message->usingBlockKitTemplate(<<<'JSON' + { + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "This is a header block", + "emoji": true + } + }, + { + "type": "context", + "elements": [ + { + "type": "image", + "image_url": "https://pbs.twimg.com/profile_images/625633822235693056/lNGUneLX_400x400.jpg", + "alt_text": "cute cat" + }, + { + "type": "mrkdwn", + "text": "*Cat* has approved this message." + } + ] + }, + { + "type": "image", + "image_url": "https://assets3.thrillist.com/v1/image/1682388/size/tl-horizontal_main.jpg", + "alt_text": "delicious tacos" + } + ] + } + JSON); + })->assertNotificationSent([ + 'channel' => '#ghost-talk', + 'blocks' => [ + [ + 'type' => 'header', + 'text' => [ + 'type' => 'plain_text', + 'text' => 'This is a header block', + 'emoji' => true, + ], + ], + [ + 'type' => 'context', + 'elements' => [ + [ + 'type' => 'image', + 'image_url' => 'https://pbs.twimg.com/profile_images/625633822235693056/lNGUneLX_400x400.jpg', + 'alt_text' => 'cute cat', + ], + [ + 'type' => 'mrkdwn', + 'text' => '*Cat* has approved this message.', + ], + ], + ], + [ + 'type' => 'image', + 'image_url' => 'https://assets3.thrillist.com/v1/image/1682388/size/tl-horizontal_main.jpg', + 'alt_text' => 'delicious tacos', + ], + ], + ]); + } + + /** @test */ + public function it_can_combined_block_kit_template_and_block_contract_in_order() + { + $this->sendNotification(function (SlackMessage $message) { + $message->usingBlockKitTemplate(<<<'JSON' + { + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "This is a header block", + "emoji": true + } + } + ] + } + JSON); + + $message->dividerBlock(); + + $message->usingBlockKitTemplate(<<<'JSON' + { + "blocks": [ + { + "type": "image", + "image_url": "https://assets3.thrillist.com/v1/image/1682388/size/tl-horizontal_main.jpg", + "alt_text": "delicious tacos" + } + ] + } + JSON); + })->assertNotificationSent([ + 'channel' => '#ghost-talk', + 'blocks' => [ + [ + 'type' => 'header', + 'text' => [ + 'type' => 'plain_text', + 'text' => 'This is a header block', + 'emoji' => true, + ], + ], + [ + 'type' => 'divider', + ], + [ + 'type' => 'image', + 'image_url' => 'https://assets3.thrillist.com/v1/image/1682388/size/tl-horizontal_main.jpg', + 'alt_text' => 'delicious tacos', + ], + ], + ]); + } }