Added in HTTP interactive messages and Controller

This commit is contained in:
Deon George 2022-02-24 09:02:29 +11:00
parent dbd355555b
commit 29d3591125
9 changed files with 128 additions and 49 deletions

View File

@ -0,0 +1,45 @@
<?php
namespace Slack\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Slack\Client\Payload;
use Slack\Message;
use Slack\Interactive\Factory as InteractiveMessageFactory;
use App\Http\Controllers\Controller;
class InteractiveMessageController extends Controller
{
private const LOGKEY = 'CIM';
/**
* Fire slack event
*
* @param Request $request
* @return \Illuminate\Http\Response|\Laravel\Lumen\Http\ResponseFactory
*/
public function fire(Request $request)
{
$event = InteractiveMessageFactory::make(new Payload(json_decode($request->payload,TRUE),TRUE));
Log::debug(sprintf('%s:Firing Event [%s] and responding [%s]',static::LOGKEY,get_class($event),$event->respondNow));
if ($event->respondNow) {
if (! method_exists($event,'respond')) {
Log::alert(sprintf('%s:Cant respond to Event [%s], no respond method',static::LOGKEY,get_class($event)));
} else {
$result = $event->respond();
return (($result instanceof Message) AND $result->isEmpty()) ? NULL : $result;
}
} else {
event($event);
Log::info(sprintf('%s:Dispatched Event [%s]',static::LOGKEY,get_class($event)));
return response('IM Event Processed',200);
}
}
}

View File

@ -2,16 +2,16 @@
namespace Slack\Http\Controllers; namespace Slack\Http\Controllers;
use App\Http\Controllers\Controller;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\Redirect;
use Slack\Jobs\TeamUpdate; use Slack\Jobs\TeamUpdate;
use Slack\Models\{Enterprise,Team,Token,User}; use Slack\Models\{Enterprise,Team,Token,User};
use App\Http\Controllers\Controller;
class SlackAppController extends Controller class SlackAppController extends Controller
{ {
protected const LOGKEY = 'CSA'; protected const LOGKEY = 'CSA';

View File

@ -7,8 +7,8 @@ use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Slack\Client\Payload; use Slack\Client\Payload;
use Slack\Event\Factory as EventFactory; use Slack\Event\Factory as EventFactory;
use Slack\Interactive\Factory as InteractiveFactory;
use App\Slack\Interactive\Factory as InteractiveFactory;
use App\Slack\Options\Factory as OptionsFactory; use App\Slack\Options\Factory as OptionsFactory;
class CheckRequest class CheckRequest
@ -51,7 +51,7 @@ class CheckRequest
break; break;
case 'api/imsg': case 'api/imsg':
$event = InteractiveFactory::make($request); $event = InteractiveFactory::make(new Payload(json_decode($request->payload,TRUE),TRUE));
break; break;
default: default:

View File

@ -8,6 +8,8 @@ use Slack\Base as SlackBase;
abstract class Base extends SlackBase abstract class Base extends SlackBase
{ {
// Does the event respond with a reply to the HTTP request, or via a post with a trigger // Does the event respond with a reply to the HTTP request, or via a post with a trigger
// Child class should have a respond() function.
// (There should be a local implementation of the child class should respondNow = TRUE)
public $respondNow = FALSE; public $respondNow = FALSE;
// When retrieving multiple action values, this is the index we are retrieving. // When retrieving multiple action values, this is the index we are retrieving.

View File

@ -60,9 +60,6 @@ class BlockActions extends Base
public function __get($key) public function __get($key)
{ {
switch ($key) { switch ($key) {
case 'actions':
return object_get($this->_data,$key);
case 'action_id': case 'action_id':
return object_get(Arr::get(object_get($this->_data,'actions'),$this->index),$key); return object_get(Arr::get(object_get($this->_data,'actions'),$this->index),$key);
@ -73,9 +70,15 @@ class BlockActions extends Base
case 'action_value': case 'action_value':
return $this->action('value'); return $this->action('value');
case 'actions':
return object_get($this->_data,$key);
case 'callback_id': case 'callback_id':
return object_get($this->_data,'view.callback_id'); return object_get($this->_data,'view.callback_id');
case 'channel_id':
return object_get($this->_data,'channel.id') ?: Channel::findOrFail($this->action('value'))->channel_id;
case 'keys': case 'keys':
return collect(object_get($this->_data,'view.blocks'))->pluck('accessory.action_id'); return collect(object_get($this->_data,'view.blocks'))->pluck('accessory.action_id');
@ -83,9 +86,6 @@ class BlockActions extends Base
case 'message_ts': case 'message_ts':
return object_get($this->_data,'message.ts'); return object_get($this->_data,'message.ts');
case 'channel_id':
return object_get($this->_data,'channel.id') ?: Channel::findOrFail($this->action('value'))->channel_id;
case 'team_id': // view.team_id represent workspace publishing view case 'team_id': // view.team_id represent workspace publishing view
return object_get($this->_data,'user.team_id'); return object_get($this->_data,'user.team_id');
@ -166,4 +166,20 @@ class BlockActions extends Base
{ {
return object_get($this->_data,'message') ? TRUE : FALSE; return object_get($this->_data,'message') ? TRUE : FALSE;
} }
/**
* Get the selected options from a block action actions array
*
* @return Collection
*/
public function selected_options(): Collection
{
$result = collect();
foreach (Arr::get(object_get($this->_data,'actions'),'0')->selected_options as $option) {
$result->push($option->value);
}
return $result;
}
} }

View File

@ -15,11 +15,11 @@ class Factory {
* @var array event type to event class mapping * @var array event type to event class mapping
*/ */
public const map = [ public const map = [
'block_actions'=>BlockActions::class, 'block_actions' => BlockActions::class,
'interactive_message'=>InteractiveMessage::class, //'interactive_message' => InteractiveMessage::class,
'shortcut'=>Shortcut::class, 'shortcut' => Shortcut::class,
'view_closed'=>ViewClosed::class, 'view_closed' => ViewClosed::class,
'view_submission'=>ViewSubmission::class, //'view_submission' => ViewSubmission::class,
]; ];
/** /**
@ -31,7 +31,7 @@ class Factory {
*/ */
public static function create(string $type,array $request): Base public static function create(string $type,array $request): Base
{ {
$class = Arr::get(self::map,$type,Unknown::class); $class = Arr::get(config('slack.interactive',self::map),$type,Unknown::class);
Log::debug(sprintf('%s:Working out Interactive Message Event Class for [%s] as [%s]',static::LOGKEY,$type,$class),['m'=>__METHOD__]); Log::debug(sprintf('%s:Working out Interactive Message Event Class for [%s] as [%s]',static::LOGKEY,$type,$class),['m'=>__METHOD__]);
if (App::environment() == 'local') if (App::environment() == 'local')

View File

@ -57,7 +57,7 @@ use Slack\Message;
*/ */
class InteractiveMessage extends Base class InteractiveMessage extends Base
{ {
private const LOGKEY = 'IIM'; protected const LOGKEY = 'IIM';
// Does the event respond with a reply to the HTTP request, or via a post with a trigger // Does the event respond with a reply to the HTTP request, or via a post with a trigger
public $respondNow = TRUE; public $respondNow = TRUE;
@ -90,6 +90,11 @@ class InteractiveMessage extends Base
} }
} }
/**
* This method should be overridden by a local implementation
*
* @return Message
*/
public function respond(): Message public function respond(): Message
{ {
Log::info(sprintf('%s:Interactive Message - Callback [%s] Name [%s] Type [%s]',static::LOGKEY,$this->callback_id,$this->name,$this->type),['m'=>__METHOD__]); Log::info(sprintf('%s:Interactive Message - Callback [%s] Name [%s] Type [%s]',static::LOGKEY,$this->callback_id,$this->name,$this->type),['m'=>__METHOD__]);
@ -112,7 +117,7 @@ class InteractiveMessage extends Base
switch ($action) { switch ($action) {
default: default:
Log::notice(sprintf('%s:Unhandled ACTION [%s]',static::LOGKEY,$action),['m'=>__METHOD__]); Log::notice(sprintf('%s:Unhandled ACTION [%s]',static::LOGKEY,$action),['m'=>__METHOD__]);
return (new Message)->setText('That didnt work, I didnt know what to do with your button - you might like to tell '.$this->team()->owner->slack_user); return (new Message)->text('That didnt work, I didnt know what to do with your button - you might like to tell '.$this->team()->owner->slack_user);
} }
} }
} }

View File

@ -5,6 +5,7 @@ namespace Slack\Interactive;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Slack\Message;
use Slack\Models\Team; use Slack\Models\Team;
use Slack\Blockkit\Modal; use Slack\Blockkit\Modal;
@ -15,7 +16,7 @@ use Slack\Blockkit\Modal;
*/ */
class ViewSubmission extends Base class ViewSubmission extends Base
{ {
private const LOGKEY = 'IVS'; protected const LOGKEY = 'IVS';
// View Submissions must respond with via a trigger or inline // View Submissions must respond with via a trigger or inline
public $respondNow = TRUE; public $respondNow = TRUE;
@ -37,33 +38,11 @@ class ViewSubmission extends Base
} }
} }
private function blocks(): Collection /**
{ * This method should be overridden by a local implementation
$result = collect(); *
* @return Message
foreach (object_get($this->_data,'view.blocks',[]) as $id=>$block) { */
switch (object_get($block,'type')) {
case 'input':
$result->put($block->element->action_id,$block->block_id);
break;
case 'section':
$result->put($block->block_id,$id);
break;
}
}
return $result;
}
public function value(string $block_id): ?string
{
$key = Arr::get($this->blocks(),$block_id);
// Return the state value, or the original block value
return object_get($this->_data,'view.state.values.'.$key.'.'.$block_id.'.value') ?: object_get(Arr::get(object_get($this->_data,'view.blocks'),$key),'text.text','');
}
public function respond(): Modal public function respond(): Modal
{ {
// Do some magic with event data // Do some magic with event data
@ -90,4 +69,31 @@ class ViewSubmission extends Base
return new Modal(new Team); return new Modal(new Team);
} }
protected function blocks(): Collection
{
$result = collect();
foreach (object_get($this->_data,'view.blocks',[]) as $id=>$block) {
switch (object_get($block,'type')) {
case 'input':
$result->put($block->element->action_id,$block->block_id);
break;
case 'section':
$result->put($block->block_id,$id);
break;
}
}
return $result;
}
public function value(string $block_id): ?string
{
$key = Arr::get($this->blocks(),$block_id);
// Return the state value, or the original block value
return object_get($this->_data,'view.state.values.'.$key.'.'.$block_id.'.value') ?: object_get(Arr::get(object_get($this->_data,'view.blocks'),$key),'text.text','');
}
} }

View File

@ -28,4 +28,9 @@ app('router')
'uses' => 'EventsController@fire', 'uses' => 'EventsController@fire',
'as' => 'event', 'as' => 'event',
]); ]);
$router->post('imsg', [
'uses' => 'InteractiveMessageController@fire',
'as' => 'imsg',
]);
}); });