2021-08-06 12:22:22 +10:00
< ? php
namespace Slack ;
use Carbon\Carbon ;
use Carbon\CarbonInterface ;
use Illuminate\Database\Eloquent\Model ;
use Illuminate\Support\Facades\Log ;
2021-08-10 13:48:59 +10:00
use Slack\Blockkit\Blocks ;
use Slack\Exceptions\SlackException ;
2021-08-06 12:22:22 +10:00
use Slack\Jobs\DeleteChat ;
2021-08-10 13:48:59 +10:00
use Slack\Message\Attachments ;
2021-08-06 12:22:22 +10:00
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 13:48:59 +10:00
private Model $o ;
private Blocks $blocks ;
2021-08-13 12:51:57 +10:00
private ? Carbon $selfdestruct = NULL ;
2021-08-06 12:22:22 +10:00
/**
* Message constructor .
*
* @ param Model | null $o Who the message will be to - Channel or User
2021-08-10 13:48:59 +10:00
* @ throws SlackException
2021-08-06 12:22:22 +10:00
*/
public function __construct ( Model $o = NULL )
{
$this -> _data = collect ();
2021-08-10 13:48:59 +10:00
if ( $o ) {
// Message is to a channel
if ( $o instanceof Channel ) {
$this -> setChannel ( $o );
2021-08-06 12:22:22 +10:00
2021-08-10 13:48:59 +10:00
// Message is to a user
} elseif ( $o instanceof User ) {
$this -> setUser ( $o );
2021-08-06 12:22:22 +10:00
2021-08-10 13:48:59 +10:00
} else {
throw new SlackException ( 'Model not handled: ' . get_class ( $o ));
}
2021-08-06 12:22:22 +10:00
2021-08-10 13:48:59 +10:00
$this -> o = $o ;
}
2021-08-06 12:22:22 +10:00
2021-08-10 13:48:59 +10:00
$this -> blocks = new Blocks ;
2021-08-06 12:22:22 +10:00
}
/**
* Add a block to the message
*
2021-08-10 13:48:59 +10:00
* @ param Blocks $blocks
* @ return Message
* @ todo to test
2021-08-06 12:22:22 +10:00
*/
2021-08-10 13:48:59 +10:00
public function addBlock ( Blocks $blocks ) : self
2021-08-06 12:22:22 +10:00
{
2021-08-10 13:48:59 +10:00
$this -> blocks = $blocks ;
2021-08-06 12:22:22 +10:00
return $this ;
}
/**
* Empty the message
*
2021-08-10 13:48:59 +10:00
* @ return Message
2021-08-06 12:22:22 +10:00
*/
public function blank () : self
{
$this -> _data = collect ();
2021-08-10 13:48:59 +10:00
$this -> blocks = new Blocks ;
2021-08-06 12:22:22 +10:00
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 13:48:59 +10:00
if ( $this -> blocks -> count ())
2021-08-06 12:22:22 +10:00
$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
{
2021-08-13 12:51:57 +10:00
if ( ! $delete && $this -> selfdestruct )
$delete = $this -> selfdestruct ;
2021-08-06 12:22:22 +10:00
if ( $this -> _data -> has ( 'ephemeral' ))
abort ( '500' , 'Cannot post ephemeral messages.' );
2021-08-10 13:48:59 +10:00
if ( $this -> blocks -> count () && $this -> _data -> get ( 'attachments' ))
throw new SlackException ( 'Message cannot have blocks and attachments.' );
2021-08-06 12:22:22 +10:00
$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-12-08 14:21:57 +11:00
/**
* Schedule a message
*
* @ param Carbon $time
* @ return Generic
*/
public function schedule ( Carbon $time ) : Generic
{
$this -> _data -> put ( 'post_at' , $time -> timestamp );
$api = $this -> o -> team -> slackAPI ();
$response = $this -> _data -> has ( 'ts' ) ? $api -> updateMessage ( $this ) : $api -> scheduleMessage ( $this );
return $response ;
}
2021-08-10 13:48:59 +10: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-06 12:22:22 +10:00
{
2021-08-10 13:48:59 +10:00
$this -> _data -> put ( 'unfurl_links' , $unfurl ? 'true' : 'false' );
2021-08-06 12:22:22 +10:00
return $this ;
}
/**
* Post a message to slack using the respond_url
*
2021-08-10 13:48:59 +10:00
* @ note This URL can only be used 5 times in 30 minutes
2021-08-06 12:22:22 +10:00
* @ param string $url
2021-08-10 13:48:59 +10:00
* @ return string
* @ throws SlackException
2021-08-06 12:22:22 +10:00
*/
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
2021-08-13 12:51:57 +10:00
* @ return Message
2021-08-06 12:22:22 +10:00
*/
2021-08-13 12:51:57 +10:00
public function selfdestruct ( Carbon $time ) : self
2021-08-06 12:22:22 +10:00
{
2021-08-13 12:51:57 +10:00
$this -> blocks -> addContextElements ( collect ([
Blocks\Text :: item ( sprintf ( 'This message will self destruct in %s...' , $time -> diffForHumans ( Carbon :: now (),[ 'syntax' => CarbonInterface :: DIFF_RELATIVE_TO_NOW ])))
]));
2021-08-06 12:22:22 +10:00
2021-08-13 12:51:57 +10:00
$this -> selfdestruct = $time ;
return $this ;
2021-08-06 12:22:22 +10:00
}
2021-08-10 13:48:59 +10:00
/**
* Add an attachment to a message
*
2021-08-13 12:51:57 +10:00
* @ param Attachments $attachments
2021-08-10 13:48:59 +10:00
* @ 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 ;
}
2021-08-06 12:22:22 +10:00
/**
* Set our channel
*
* @ param Channel $o
* @ return Message
*/
2021-08-10 13:48:59 +10:00
public function setChannel ( Channel $o ) : self
2021-08-06 12:22:22 +10:00
{
2021-08-10 13:48:59 +10:00
$this -> _data -> put ( 'channel' , $o -> channel_id );
$this -> o = $o ;
2021-08-06 12:22:22 +10:00
return $this ;
}
/**
* Set the icon next to the message
*
* @ param string $icon
2021-08-10 13:48:59 +10:00
* @ return Message
2021-08-06 12:22:22 +10:00
* @ 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 13:48:59 +10:00
$this -> _data = collect (); // @todo Why are clearing our data?
2021-08-06 12:22:22 +10:00
$this -> _data -> put ( 'option_groups' , $array );
}
/**
* Message text
*
* @ param string $string
2021-08-10 13:48:59 +10:00
* @ return Message
2021-08-06 12:22:22 +10:00
*/
public function setText ( string $string ) : self
{
$this -> _data -> put ( 'text' , $string );
return $this ;
}
2021-08-10 13:48:59 +10:00
/**
* Set the timestamp , used when replacing messages
*
* @ param string $string
* @ return Message
*/
2021-08-06 12:22:22 +10:00
public function setTS ( string $string ) : self
{
$this -> _data -> put ( 'ts' , $string );
return $this ;
}
2021-08-10 13:48:59 +10:00
/**
* Set the thread timestamp , used when adding a threaded response
*
* @ param string $string
* @ return Message
*/
2021-08-06 12:22:22 +10:00
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 13:48:59 +10:00
public function setUser ( User $o ) : self
2021-08-06 12:22:22 +10:00
{
2021-08-10 13:48:59 +10:00
$this -> _data -> put ( 'channel' , $o -> user_id );
$this -> o = $o ;
2021-08-06 12:22:22 +10:00
return $this ;
}
2021-08-10 13:48:59 +10:00
public function setUserName ( string $user ) : self
2021-08-06 12:22:22 +10:00
{
2021-08-10 13:48:59 +10:00
$this -> _data -> put ( 'username' , $user );
2021-08-06 12:22:22 +10:00
return $this ;
}
}