Switch API to use Http::class instead of curl directly

This commit is contained in:
Deon George 2022-09-05 13:56:47 +10:00
parent 15a6933026
commit 905c207956

View File

@ -4,6 +4,7 @@ namespace Slack;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Slack\Blockkit\Modal; use Slack\Blockkit\Modal;
@ -77,7 +78,7 @@ final class API
* @param string $channel * @param string $channel
* @param string $timestamp * @param string $timestamp
* @return Generic * @return Generic
* @throws \Exception * @throws SlackException
*/ */
public function deleteChat(string $channel,string $timestamp): Generic public function deleteChat(string $channel,string $timestamp): Generic
{ {
@ -92,13 +93,13 @@ final class API
* @param string $trigger * @param string $trigger
* @param string $dialog * @param string $dialog
* @return Generic * @return Generic
* @throws \Exception * @throws SlackException
*/ */
public function dialogOpen(string $trigger,string $dialog): Generic public function dialogOpen(string $trigger,string $dialog): Generic
{ {
Log::debug(sprintf('%s:Open a Dialog',static::LOGKEY),['m'=>__METHOD__,'d'=>$dialog,'t'=>$trigger]); Log::debug(sprintf('%s:Open a Dialog',static::LOGKEY),['m'=>__METHOD__,'d'=>$dialog,'t'=>$trigger]);
return new Generic($this->execute('dialog.open',json_encode(['dialog'=>$dialog,'trigger_id'=>$trigger]))); return new Generic($this->execute('dialog.open',['dialog'=>$dialog,'trigger_id'=>$trigger]));
} }
/** /**
@ -108,13 +109,13 @@ final class API
* @param string $timestamp * @param string $timestamp
* @param int $limit * @param int $limit
* @return Generic * @return Generic
* @throws \Exception * @throws SlackException
*/ */
public function getChannelHistory(string $channel,string $timestamp,int $limit=20): Generic public function getChannelHistory(string $channel,string $timestamp,int $limit=20): Generic
{ {
Log::debug(sprintf('%s:Message History for Channel [%s] from Timestamp [%s]',static::LOGKEY,$channel,$timestamp),['m'=>__METHOD__]); Log::debug(sprintf('%s:Message History for Channel [%s] from Timestamp [%s]',static::LOGKEY,$channel,$timestamp),['m'=>__METHOD__]);
return new Generic($this->execute('conversations.history',['channel'=>$channel,'oldest'=>$timestamp,'limit'=>$limit])); return new Generic($this->execute('conversations.history',['channel'=>$channel,'oldest'=>$timestamp,'limit'=>$limit],TRUE));
} }
/** /**
@ -122,13 +123,13 @@ final class API
* *
* @param string $channel * @param string $channel
* @return Generic * @return Generic
* @throws \Exception * @throws SlackException
*/ */
public function getChannelInfo(string $channel): Generic public function getChannelInfo(string $channel): Generic
{ {
Log::debug(sprintf('%s:Channel Information [%s]',static::LOGKEY,$channel),['m'=>__METHOD__]); Log::debug(sprintf('%s:Channel Information [%s]',static::LOGKEY,$channel),['m'=>__METHOD__]);
return new Generic($this->execute('conversations.info',['channel'=>$channel])); return new Generic($this->execute('conversations.info',['channel'=>$channel],TRUE));
} }
/** /**
@ -136,13 +137,13 @@ final class API
* *
* @param int $limit * @param int $limit
* @return Generic * @return Generic
* @throws \Exception * @throws SlackException
*/ */
public function getChannelList(int $limit=100): Generic public function getChannelList(int $limit=100): Generic
{ {
Log::debug(sprintf('%s:Channel List',static::LOGKEY),['m'=>__METHOD__]); Log::debug(sprintf('%s:Channel List',static::LOGKEY),['m'=>__METHOD__]);
return new Generic($this->execute('conversations.list',['limit'=>$limit])); return new Generic($this->execute('conversations.list',['limit'=>$limit],TRUE));
} }
/** /**
@ -151,13 +152,13 @@ final class API
* @param string $channel * @param string $channel
* @param string $thread_ts * @param string $thread_ts
* @return Chat * @return Chat
* @throws \Exception * @throws SlackException
*/ */
public function getMessageHistory(string $channel,string $thread_ts): Chat public function getMessageHistory(string $channel,string $thread_ts): Chat
{ {
Log::debug(sprintf('%s:Get Message Threads for Message [%s] on Channel [%s]',static::LOGKEY,$thread_ts,$channel),['m'=>__METHOD__]); Log::debug(sprintf('%s:Get Message Threads for Message [%s] on Channel [%s]',static::LOGKEY,$thread_ts,$channel),['m'=>__METHOD__]);
return new Chat($this->execute('conversations.replies',['channel'=>$channel,'ts'=>$thread_ts])); return new Chat($this->execute('conversations.replies',['channel'=>$channel,'ts'=>$thread_ts],TRUE));
} }
/** /**
@ -165,13 +166,13 @@ final class API
* *
* @param string $team_id * @param string $team_id
* @return ResponseTeam * @return ResponseTeam
* @throws \Exception * @throws SlackException
*/ */
public function getTeam(string $team_id): ResponseTeam public function getTeam(string $team_id): ResponseTeam
{ {
Log::debug(sprintf('%s:Team Info [%s]',static::LOGKEY,$team_id),['m'=>__METHOD__]); Log::debug(sprintf('%s:Team Info [%s]',static::LOGKEY,$team_id),['m'=>__METHOD__]);
return new ResponseTeam($this->execute('team.info',['team'=>$team_id])); return new ResponseTeam($this->execute('team.info',['team'=>$team_id],TRUE));
} }
/** /**
@ -179,13 +180,13 @@ final class API
* *
* @param string $user_id * @param string $user_id
* @return ResponseUser * @return ResponseUser
* @throws \Exception * @throws SlackException
*/ */
public function getUser(string $user_id): ResponseUser public function getUser(string $user_id): ResponseUser
{ {
Log::debug(sprintf('%s:User Info [%s]',static::LOGKEY,$user_id),['m'=>__METHOD__]); Log::debug(sprintf('%s:User Info [%s]',static::LOGKEY,$user_id),['m'=>__METHOD__]);
return new ResponseUser($this->execute('users.info',['user'=>$user_id])); return new ResponseUser($this->execute('users.info',['user'=>$user_id],TRUE));
} }
/** /**
@ -195,7 +196,7 @@ final class API
* @param int $limit * @param int $limit
* @param string|null $cursor * @param string|null $cursor
* @return ChannelList * @return ChannelList
* @throws \Exception * @throws SlackException
*/ */
public function getUserChannels(User $uo,int $limit=100,string $cursor=NULL): ChannelList public function getUserChannels(User $uo,int $limit=100,string $cursor=NULL): ChannelList
{ {
@ -211,7 +212,7 @@ final class API
if ($cursor) if ($cursor)
$args->put('cursor',$cursor); $args->put('cursor',$cursor);
return new ChannelList($this->execute('users.conversations',$args->toArray())); return new ChannelList($this->execute('users.conversations',$args->toArray(),TRUE));
} }
/** /**
@ -219,13 +220,13 @@ final class API
* *
* @param array $users * @param array $users
* @return Generic * @return Generic
* @throws \Exception * @throws SlackException
*/ */
public function migrationExchange(array $users): Generic public function migrationExchange(array $users): Generic
{ {
Log::debug(sprintf('%s:Migrate Exchange [%s] users',static::LOGKEY,count($users)),['m'=>__METHOD__]); Log::debug(sprintf('%s:Migrate Exchange [%s] users',static::LOGKEY,count($users)),['m'=>__METHOD__]);
return new Generic($this->execute('migration.exchange',['users'=>join(',',$users)])); return new Generic($this->execute('migration.exchange',['users'=>join(',',$users)],TRUE));
} }
/** /**
@ -234,13 +235,13 @@ final class API
* @param string $channel * @param string $channel
* @param string $timestamp * @param string $timestamp
* @return Generic * @return Generic
* @throws \Exception * @throws SlackException
*/ */
public function pinMessage(string $channel,string $timestamp): Generic public function pinMessage(string $channel,string $timestamp): Generic
{ {
Log::debug(sprintf('%s:Pin Message [%s|%s]',static::LOGKEY,$channel,$timestamp),['m'=>__METHOD__]); Log::debug(sprintf('%s:Pin Message [%s|%s]',static::LOGKEY,$channel,$timestamp),['m'=>__METHOD__]);
return new Generic($this->execute('pins.add',json_encode(['channel'=>$channel,'timestamp'=>$timestamp]))); return new Generic($this->execute('pins.add',['channel'=>$channel,'timestamp'=>$timestamp]));
} }
/** /**
@ -248,13 +249,13 @@ final class API
* *
* @param Message $request * @param Message $request
* @return Generic * @return Generic
* @throws \Exception * @throws SlackException
*/ */
public function postEphemeral(Message $request): Generic public function postEphemeral(Message $request): Generic
{ {
Log::debug(sprintf('%s:Post a Slack Ephemeral Message',static::LOGKEY),['m'=>__METHOD__,'r'=>$request]); Log::debug(sprintf('%s:Post a Slack Ephemeral Message',static::LOGKEY),['m'=>__METHOD__,'r'=>$request]);
return new Generic($this->execute('chat.postEphemeral',json_encode($request))); return new Generic($this->execute('chat.postEphemeral',$request));
} }
/** /**
@ -262,13 +263,13 @@ final class API
* *
* @param Message $request * @param Message $request
* @return Generic * @return Generic
* @throws \Exception * @throws SlackException
*/ */
public function postMessage(Message $request): Generic public function postMessage(Message $request): Generic
{ {
Log::debug(sprintf('%s:Post a Slack Message',static::LOGKEY),['m'=>__METHOD__,'r'=>$request]); Log::debug(sprintf('%s:Post a Slack Message',static::LOGKEY),['m'=>__METHOD__,'r'=>$request]);
return new Generic($this->execute('chat.postMessage',json_encode($request))); return new Generic($this->execute('chat.postMessage',$request));
} }
/** /**
@ -276,13 +277,13 @@ final class API
* *
* @param Message $request * @param Message $request
* @return Generic * @return Generic
* @throws \Exception * @throws SlackException
*/ */
public function scheduleMessage(Message $request): Generic public function scheduleMessage(Message $request): Generic
{ {
Log::debug(sprintf('%s:Scheduling a Slack Message',static::LOGKEY),['m'=>__METHOD__,'r'=>$request]); Log::debug(sprintf('%s:Scheduling a Slack Message',static::LOGKEY),['m'=>__METHOD__,'r'=>$request]);
return new Generic($this->execute('chat.scheduleMessage',json_encode($request))); return new Generic($this->execute('chat.scheduleMessage',$request));
} }
/** /**
@ -290,7 +291,7 @@ final class API
* *
* @param string|null $request * @param string|null $request
* @return Generic * @return Generic
* @throws \Exception * @throws SlackException
*/ */
public function scheduleMessagesList(string $request=NULL): Generic public function scheduleMessagesList(string $request=NULL): Generic
{ {
@ -305,13 +306,13 @@ final class API
* @param string $channel * @param string $channel
* @param string $timestamp * @param string $timestamp
* @return Generic * @return Generic
* @throws \Exception * @throws SlackException
*/ */
public function unpinMessage(string $channel,string $timestamp): Generic public function unpinMessage(string $channel,string $timestamp): Generic
{ {
Log::debug(sprintf('%s:Remove Pin from Message [%s|%s]',static::LOGKEY,$channel,$timestamp),['m'=>__METHOD__]); Log::debug(sprintf('%s:Remove Pin from Message [%s|%s]',static::LOGKEY,$channel,$timestamp),['m'=>__METHOD__]);
return new Generic($this->execute('pins.remove',json_encode(['channel'=>$channel,'timestamp'=>$timestamp]))); return new Generic($this->execute('pins.remove',['channel'=>$channel,'timestamp'=>$timestamp]));
} }
/** /**
@ -319,20 +320,20 @@ final class API
* *
* @param Message $request * @param Message $request
* @return Generic * @return Generic
* @throws \Exception * @throws SlackException
*/ */
public function updateMessage(Message $request): Generic public function updateMessage(Message $request): Generic
{ {
Log::debug(sprintf('%s:Update a Slack Message',static::LOGKEY),['m'=>__METHOD__,'r'=>$request]); Log::debug(sprintf('%s:Update a Slack Message',static::LOGKEY),['m'=>__METHOD__,'r'=>$request]);
return new Generic($this->execute('chat.update',json_encode($request))); return new Generic($this->execute('chat.update',$request));
} }
public function viewOpen(string $trigger,Modal $view): Generic public function viewOpen(string $trigger,Modal $view): Generic
{ {
Log::debug(sprintf('%s:Open a view',static::LOGKEY),['m'=>__METHOD__,'t'=>$trigger]); Log::debug(sprintf('%s:Open a view',static::LOGKEY),['m'=>__METHOD__,'t'=>$trigger]);
return new Generic($this->execute('views.open',json_encode(['trigger_id'=>$trigger,'view'=>$view]))); return new Generic($this->execute('views.open',['trigger_id'=>$trigger,'view'=>$view]));
} }
/** /**
@ -342,49 +343,41 @@ final class API
* @param Modal $view * @param Modal $view
* @param string $hash * @param string $hash
* @return Generic * @return Generic
* @throws \Exception * @throws SlackException
* @todo Add some smarts to detect if the new view is the same as the current view, and thus no need to post. * @todo Add some smarts to detect if the new view is the same as the current view, and thus no need to post.
*/ */
public function viewPublish(string $user,Modal $view,string $hash=''): Generic public function viewPublish(string $user,Modal $view,string $hash=''): Generic
{ {
Log::debug(sprintf('%s:Publish a view',static::LOGKEY),['m'=>__METHOD__,'u'=>$user,'h'=>$hash]); Log::debug(sprintf('%s:Publish a view',static::LOGKEY),['m'=>__METHOD__,'u'=>$user,'h'=>$hash]);
return new Generic($this->execute('views.publish',json_encode($hash ? ['user_id'=>$user,'view'=>$view,'hash'=>$hash] : ['user_id'=>$user,'view'=>$view]))); return new Generic($this->execute('views.publish',$hash ? ['user_id'=>$user,'view'=>$view,'hash'=>$hash] : ['user_id'=>$user,'view'=>$view]));
} }
public function viewPush(string $trigger,Modal $view): Generic public function viewPush(string $trigger,Modal $view): Generic
{ {
Log::debug(sprintf('%s:Push a view',static::LOGKEY),['m'=>__METHOD__,'t'=>$trigger]); Log::debug(sprintf('%s:Push a view',static::LOGKEY),['m'=>__METHOD__,'t'=>$trigger]);
return new Generic($this->execute('views.push',json_encode(['trigger_id'=>$trigger,'view'=>$view]))); return new Generic($this->execute('views.push',['trigger_id'=>$trigger,'view'=>$view]));
} }
public function viewUpdate(string $view_id,Modal $view): Generic public function viewUpdate(string $view_id,Modal $view): Generic
{ {
Log::debug(sprintf('%s:Update a view',static::LOGKEY),['m'=>__METHOD__,'id'=>$view_id]); Log::debug(sprintf('%s:Update a view',static::LOGKEY),['m'=>__METHOD__,'id'=>$view_id]);
return new Generic($this->execute('views.update',json_encode(['view_id'=>$view_id,'view'=>$view]))); return new Generic($this->execute('views.update',['view_id'=>$view_id,'view'=>$view]));
} }
/** /**
* Call the Slack API * Call the Slack API
* *
* @param string $method * @param string $method
* @param null $parameters * @param mixed $parameters
* @param bool $asForm
* @return object * @return object
* @throws SlackAlreadyPinnedException * @throws \Exception
* @throws SlackChannelNotFoundException
* @throws SlackException * @throws SlackException
* @throws SlackHashConflictException
* @throws SlackMessageNotFoundException
* @throws SlackNoAuthException
* @throws SlackNoPinException
* @throws SlackNotFoundException
* @throws SlackNotInChannelException
* @throws SlackThreadNotFoundException
* @throws SlackTokenScopeException
*/ */
private function execute(string $method,$parameters=NULL): object private function execute(string $method,mixed $parameters,bool $asForm=FALSE): object
{ {
switch (config('app.env')) { switch (config('app.env')) {
case 'steno': $url = 'http://steno:3000'; case 'steno': $url = 'http://steno:3000';
@ -395,43 +388,29 @@ final class API
$url = 'https://slack.com'; $url = 'https://slack.com';
} }
$url .= '/api/'.$method;
// If we dont have a scope definition, or if the scope definition is not in the token // If we dont have a scope definition, or if the scope definition is not in the token
if (is_null($x=Arr::get(self::scopes,$method)) OR (($x !== '') AND ! $this->_token->hasScope($x))) { if (is_null($x=Arr::get(self::scopes,$method)) OR (($x !== '') AND ! $this->_token->hasScope($x))) {
throw new SlackTokenScopeException(sprintf('Token [%d:%s] doesnt have the required scope: [%s] for [%s]',$this->_token->id,$this->_token->token_hidden,serialize($x),$method)); throw new SlackTokenScopeException(sprintf('Token [%d:%s] doesnt have the required scope: [%s] for [%s]',$this->_token->id,$this->_token->token_hidden,serialize($x),$method));
} }
// If we are passed an array, we'll do a normal post. $http = Http::baseUrl($url);
if (is_array($parameters)) { $http
$parameters['token'] = $this->_token->token; ->withToken($this->_token->token)
$request = $this->prepareRequest( ->acceptJson();
$url,
json_encode($parameters)
);
// If we are json, then we'll do an application/json post if ($asForm) {
} elseif (is_json($parameters)) { if (! is_array($parameters))
$request = $this->prepareRequest( throw new SlackException('Parameters are not an array for a form submission');
$url,
$parameters,
[
'Content-Type: application/json; charset=utf-8',
'Content-Length: '.strlen($parameters),
'Authorization: Bearer '.$this->_token->token,
]
);
} else { $http->asForm();
throw new SlackException('Parameters unknown');
} elseif ($parameters) {
$http->withBody((is_array($parameters) || ($parameters instanceof BlockKit)) ? json_encode($parameters) : $parameters,'application/json');
} }
try { try {
$response = curl_exec($request); $request = $http->post(sprintf('/api/%s',$method),$asForm ? $parameters : NULL)->throw();
if (! $response) $response = $request->object();
throw new \Exception('CURL exec returned an empty response: '.serialize(curl_getinfo($request)));
$result = json_decode($response);
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error(sprintf('%s:Got an error while posting to [%s] (%s)',static::LOGKEY,$url,$e->getMessage()),['m'=>__METHOD__]); Log::error(sprintf('%s:Got an error while posting to [%s] (%s)',static::LOGKEY,$url,$e->getMessage()),['m'=>__METHOD__]);
@ -439,73 +418,47 @@ final class API
throw new \Exception($e->getMessage()); throw new \Exception($e->getMessage());
} }
if (! $result) { if ($response->ok)
Log::error(sprintf('%s:Our result shouldnt be empty',static::LOGKEY),['m'=>__METHOD__,'r'=>$request,'R'=>$response]); return $response;
throw new SlackException('Slack Result is Empty'); else
} switch ($response->error) {
if (! $result->ok) {
switch ($result->error) {
case 'already_pinned': case 'already_pinned':
throw new SlackAlreadyPinnedException('Already Pinned',curl_getinfo($request,CURLINFO_HTTP_CODE)); throw new SlackAlreadyPinnedException('Already Pinned',$request->status());
case 'not_authed':
throw new SlackNoAuthException('No Auth Token',curl_getinfo($request,CURLINFO_HTTP_CODE));
case 'channel_not_found': case 'channel_not_found':
throw new SlackChannelNotFoundException('Channel Not Found',curl_getinfo($request,CURLINFO_HTTP_CODE)); throw new SlackChannelNotFoundException('Channel Not Found',$request->status());
case 'hash_conflict': case 'hash_conflict':
if (App::environment() == 'local') if (App::environment() == 'local')
file_put_contents('/tmp/hash_conflict.'.$method,print_r(json_decode(json_decode($parameters)->view),TRUE)); file_put_contents('/tmp/hash_conflict.'.$method,print_r(json_decode(json_decode($parameters)->view),TRUE));
throw new SlackHashConflictException('Hash Conflict',curl_getinfo($request,CURLINFO_HTTP_CODE)); throw new SlackHashConflictException('Hash Conflict',$request->status());
case 'invalid_auth':
throw new SlackNoAuthException('Invalid Auth Token',$request->status());
case 'message_not_found': case 'message_not_found':
throw new SlackMessageNotFoundException('Message Not Found',curl_getinfo($request,CURLINFO_HTTP_CODE)); throw new SlackMessageNotFoundException('Message Not Found',$request->status());
case 'no_pin': case 'no_pin':
throw new SlackNoPinException('No Pin',curl_getinfo($request,CURLINFO_HTTP_CODE)); throw new SlackNoPinException('No Pin',$request->status());
case 'not_in_channel': case 'not_authed':
throw new SlackNotInChannelException('Not In Channel',curl_getinfo($request,CURLINFO_HTTP_CODE)); throw new SlackNoAuthException('No Auth Token',$request->status());
case 'not_found': case 'not_found':
file_put_contents('/tmp/method.'.$method,print_r(['request'=>is_json($parameters) ? json_decode($parameters,TRUE) : $parameters,'response'=>$result],TRUE)); file_put_contents('/tmp/method.'.$method,print_r(['request'=>is_json($parameters) ? json_decode($parameters,TRUE) : $parameters,'response'=>$response],TRUE));
throw new SlackNotFoundException('Not Found',curl_getinfo($request,CURLINFO_HTTP_CODE)); throw new SlackNotFoundException('Not Found',$request->status());
case 'not_in_channel':
throw new SlackNotInChannelException('Not In Channel',$request->status());
case 'thread_not_found': case 'thread_not_found':
throw new SlackThreadNotFoundException('Thread Not Found',curl_getinfo($request,CURLINFO_HTTP_CODE)); throw new SlackThreadNotFoundException('Thread Not Found',$request->status());
default: default:
Log::error(sprintf('%s:Generic Error',static::LOGKEY),['m'=>__METHOD__,'t'=>$this->_token->team_id,'r'=>$result]); Log::error(sprintf('%s:Generic Error',static::LOGKEY),['m'=>__METHOD__,'t'=>$this->_token->team_id,'r'=>$response]);
throw new SlackException($result->error,curl_getinfo($request,CURLINFO_HTTP_CODE)); throw new SlackException($response->error,$request->status());
} }
}
curl_close($request);
return $result;
}
/**
* Setup the API call
*
* @param string $url
* @param string $parameters
* @param array $headers
* @return \CurlHandle
*/
private function prepareRequest(string $url,string $parameters='',array $headers=[]): \CurlHandle
{
$request = curl_init();
curl_setopt($request,CURLOPT_URL,$url);
curl_setopt($request,CURLOPT_RETURNTRANSFER,TRUE);
curl_setopt($request,CURLOPT_HTTPHEADER,$headers);
curl_setopt($request,CURLINFO_HEADER_OUT,TRUE);
curl_setopt($request,CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($request,CURLOPT_POSTFIELDS,$parameters);
return $request;
} }
} }