slack/src/Message.php

357 lines
7.3 KiB
PHP
Raw Normal View History

<?php
namespace Slack;
use Carbon\Carbon;
use Carbon\CarbonInterface;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;
2021-08-10 03:48:59 +00:00
use Slack\Blockkit\Blocks;
use Slack\Exceptions\SlackException;
use Slack\Jobs\DeleteChat;
2021-08-10 03:48:59 +00:00
use Slack\Message\Attachments;
use Slack\Models\{Channel,User};
use Slack\Response\Generic;
/**
* This class is used when composing a message to send to Slack.
*/
class Message implements \JsonSerializable
{
protected const LOGKEY = 'SM-';
2021-08-10 03:48:59 +00:00
private Model $o;
private Blocks $blocks;
/**
* Message constructor.
*
* @param Model|null $o Who the message will be to - Channel or User
2021-08-10 03:48:59 +00:00
* @throws SlackException
*/
public function __construct(Model $o=NULL)
{
$this->_data = collect();
2021-08-10 03:48:59 +00:00
if ($o) {
// Message is to a channel
if ($o instanceof Channel) {
$this->setChannel($o);
2021-08-10 03:48:59 +00:00
// Message is to a user
} elseif ($o instanceof User) {
$this->setUser($o);
2021-08-10 03:48:59 +00:00
} else {
throw new SlackException('Model not handled: '.get_class($o));
}
2021-08-10 03:48:59 +00:00
$this->o = $o;
}
2021-08-10 03:48:59 +00:00
$this->blocks = new Blocks;
}
/**
* Add a block to the message
*
2021-08-10 03:48:59 +00:00
* @param Blocks $blocks
* @return Message
* @todo to test
*/
2021-08-10 03:48:59 +00:00
public function addBlock(Blocks $blocks): self
{
2021-08-10 03:48:59 +00:00
$this->blocks = $blocks;
return $this;
}
/**
* Empty the message
*
2021-08-10 03:48:59 +00:00
* @return Message
*/
public function blank(): self
{
$this->_data = collect();
2021-08-10 03:48:59 +00:00
$this->blocks = new Blocks;
return $this;
}
/*
* @todo This doesnt appear to work
public function ephemeral(): self
{
$this->_data->put('ephemeral',TRUE);
return $this;
}
*/
public function forgetTS(): self
{
$this->_data->forget('ts');
return $this;
}
/**
* Return if this is an empty message
*
* @return bool
*/
public function isEmpty(): bool
{
return $this->jsonSerialize() ? FALSE : TRUE;
}
/**
* When we json_encode this object, this is the data that will be returned
*/
public function jsonSerialize()
{
2021-08-10 03:48:59 +00:00
if ($this->blocks->count())
$this->_data->put('blocks',$this->blocks);
// For interactive messages that generate a dialog, we need to return NULL
return $this->_data->count() ? $this->_data : NULL;
}
/**
* Post this message to slack
*
* @param Carbon|null $delete
* @return Generic
* @throws \Exception
*/
public function post(Carbon $delete=NULL): Generic
{
if ($this->_data->has('ephemeral'))
abort('500','Cannot post ephemeral messages.');
2021-08-10 03:48:59 +00:00
if ($this->blocks->count() && $this->_data->get('attachments'))
throw new SlackException('Message cannot have blocks and attachments.');
$api = $this->o->team->slackAPI();
$response = $this->_data->has('ts') ? $api->updateMessage($this) : $api->postMessage($this);
if ($delete) {
Log::debug(sprintf('%s:Scheduling Delete of [%s:%s] on [%s]',static::LOGKEY,object_get($this->o,'channel_id',$this->o->id),$response->ts,$delete->format('Y-m-d')),['m'=>__METHOD__]);
// Queue the delete of the message if requested
dispatch((new DeleteChat($this->o,$response->ts))->onQueue('low')->delay($delete));
}
return $response;
}
2021-08-10 03:48:59 +00:00
public function setReplace(bool $replace=TRUE): self
{
$this->_data->put('replace_original',$replace ? 'true' : 'false');
return $this;
}
/**
* To slack from rendering URLs in the message
*
* @param bool $unfurl
* @return $this
*/
public function setUnfurlLinks(bool $unfurl): self
{
2021-08-10 03:48:59 +00:00
$this->_data->put('unfurl_links',$unfurl ? 'true' : 'false');
return $this;
}
/**
* Post a message to slack using the respond_url
*
2021-08-10 03:48:59 +00:00
* @note This URL can only be used 5 times in 30 minutes
* @param string $url
2021-08-10 03:48:59 +00:00
* @return string
* @throws SlackException
*/
public function respond(string $url)
{
$request = curl_init();
curl_setopt($request,CURLOPT_URL,$url);
curl_setopt($request,CURLOPT_RETURNTRANSFER,TRUE);
curl_setopt($request,CURLINFO_HEADER_OUT,TRUE);
curl_setopt($request,CURLOPT_HTTPHEADER,['Content-Type: application/json; charset=utf-8']);
curl_setopt($request,CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($request,CURLOPT_POSTFIELDS,json_encode($this));
try {
$result = curl_exec($request);
if (! $result)
throw new \Exception('CURL exec returned an empty response: '.serialize(curl_getinfo($request)));
} catch (\Exception $e) {
Log::error(sprintf('%s:Got an error while posting to [%s] (%s)',static::LOGKEY,$url,$e->getMessage()),['m'=>__METHOD__]);
throw new \Exception($e->getMessage());
}
if ($result !== 'ok') {
switch ($result) {
default:
Log::critical(sprintf('%s:Generic Error',static::LOGKEY),['m'=>__METHOD__,'r'=>$result]);
throw new SlackException($result,curl_getinfo($request,CURLINFO_HTTP_CODE));
}
}
curl_close($request);
return $result;
}
/**
* Make the message self destruct
*
* @param Carbon $time
* @return Generic
* @throws \Exception
*/
public function selfdestruct(Carbon $time): Generic
{
2021-08-10 03:48:59 +00:00
$this->blocks->addContextElements(
collect()
2021-08-10 03:48:59 +00:00
->push(Blocks\Text::item(sprintf('This message will self destruct in %s...',$time->diffForHumans(Carbon::now(),['syntax' => CarbonInterface::DIFF_RELATIVE_TO_NOW])))));
return $this->post($time);
}
2021-08-10 03:48:59 +00:00
/**
* Add an attachment to a message
*
* @param Attachment $attachments
* @return Message
*/
public function setAttachments(Attachments $attachments): self
{
$this->_data->put('attachments',[$attachments]);
return $this;
}
/**
* Add blocks to the message
*
* @param Blocks $blocks
* @return Message
* @throws \Exception
*/
public function setBlocks(Blocks $blocks): self
{
if ($this->blocks->count())
throw new \Exception('Blocks already defined');
$this->blocks = $blocks;
return $this;
}
/**
* Set our channel
*
* @param Channel $o
* @return Message
*/
2021-08-10 03:48:59 +00:00
public function setChannel(Channel $o): self
{
2021-08-10 03:48:59 +00:00
$this->_data->put('channel',$o->channel_id);
$this->o = $o;
return $this;
}
/**
* Set the icon next to the message
*
* @param string $icon
2021-08-10 03:48:59 +00:00
* @return Message
* @deprecated
*/
public function setIcon(string $icon): self
{
$this->_data->put('icon_emoji',$icon);
return $this;
}
/**
* Option groups are used by the interactive Options controller and hold no other attributes
*
* @param array $array
* @return void
*/
public function setOptionGroup(array $array): void
{
2021-08-10 03:48:59 +00:00
$this->_data = collect(); // @todo Why are clearing our data?
$this->_data->put('option_groups',$array);
}
/**
* Message text
*
* @param string $string
2021-08-10 03:48:59 +00:00
* @return Message
*/
public function setText(string $string): self
{
$this->_data->put('text',$string);
return $this;
}
2021-08-10 03:48:59 +00:00
/**
* Set the timestamp, used when replacing messages
*
* @param string $string
* @return Message
*/
public function setTS(string $string): self
{
$this->_data->put('ts',$string);
return $this;
}
2021-08-10 03:48:59 +00:00
/**
* Set the thread timestamp, used when adding a threaded response
*
* @param string $string
* @return Message
*/
public function setThreadTS(string $string): self
{
$this->_data->put('thread_ts',$string);
return $this;
}
/**
* Set our channel
*
* @param User $o
* @return Message
*/
2021-08-10 03:48:59 +00:00
public function setUser(User $o): self
{
2021-08-10 03:48:59 +00:00
$this->_data->put('channel',$o->user_id);
$this->o = $o;
return $this;
}
2021-08-10 03:48:59 +00:00
public function setUserName(string $user): self
{
2021-08-10 03:48:59 +00:00
$this->_data->put('username',$user);
return $this;
}
}