diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -363,6 +363,8 @@ 'PhutilSimpleOptionsLexerTestCase' => 'lexer/__tests__/PhutilSimpleOptionsLexerTestCase.php', 'PhutilSimpleOptionsTestCase' => 'parser/__tests__/PhutilSimpleOptionsTestCase.php', 'PhutilSimplifiedChineseLocale' => 'internationalization/locales/PhutilSimplifiedChineseLocale.php', + 'PhutilSlackAuthAdapter' => 'auth/PhutilSlackAuthAdapter.php', + 'PhutilSlackFuture' => 'future/slack/PhutilSlackFuture.php', 'PhutilSocketChannel' => 'channel/PhutilSocketChannel.php', 'PhutilSortVector' => 'utils/PhutilSortVector.php', 'PhutilSpanishSpainLocale' => 'internationalization/locales/PhutilSpanishSpainLocale.php', @@ -933,6 +935,8 @@ 'PhutilSimpleOptionsLexerTestCase' => 'PhutilTestCase', 'PhutilSimpleOptionsTestCase' => 'PhutilTestCase', 'PhutilSimplifiedChineseLocale' => 'PhutilLocale', + 'PhutilSlackAuthAdapter' => 'PhutilOAuthAuthAdapter', + 'PhutilSlackFuture' => 'FutureProxy', 'PhutilSocketChannel' => 'PhutilChannel', 'PhutilSortVector' => 'Phobject', 'PhutilSpanishSpainLocale' => 'PhutilLocale', diff --git a/src/auth/PhutilSlackAuthAdapter.php b/src/auth/PhutilSlackAuthAdapter.php new file mode 100644 --- /dev/null +++ b/src/auth/PhutilSlackAuthAdapter.php @@ -0,0 +1,61 @@ +getOAuthAccountData('user'); + return idx($user, 'id'); + } + + public function getAccountEmail() { + $user = $this->getOAuthAccountData('user'); + return idx($user, 'email'); + } + + public function getAccountImageURI() { + $user = $this->getOAuthAccountData('user'); + return idx($user, 'image_512'); + } + + public function getAccountRealName() { + $user = $this->getOAuthAccountData('user'); + return idx($user, 'name'); + } + + protected function getAuthenticateBaseURI() { + return 'https://slack.com/oauth/authorize'; + } + + protected function getTokenBaseURI() { + return 'https://slack.com/api/oauth.access'; + } + + public function getScope() { + return 'identity.basic,identity.team,identity.avatar'; + } + + public function getExtraAuthenticateParameters() { + return array( + 'response_type' => 'code', + ); + } + + protected function loadOAuthAccountData() { + return id(new PhutilSlackFuture()) + ->setAccessToken($this->getAccessToken()) + ->setRawSlackQuery('users.identity') + ->resolve(); + } + +} diff --git a/src/future/slack/PhutilSlackFuture.php b/src/future/slack/PhutilSlackFuture.php new file mode 100644 --- /dev/null +++ b/src/future/slack/PhutilSlackFuture.php @@ -0,0 +1,87 @@ +accessToken = $token; + return $this; + } + + public function setClientID($client_id) { + $this->clientID = $client_id; + return $this; + } + + public function setRawSlackQuery($action, array $params = array()) { + $this->action = $action; + $this->params = $params; + return $this; + } + + public function setMethod($method) { + $this->method = $method; + return $this; + } + + protected function getProxiedFuture() { + if (!$this->future) { + $params = $this->params; + + if (!$this->action) { + throw new Exception(pht('You must %s!', 'setRawSlackQuery()')); + } + + if (!$this->accessToken) { + throw new Exception(pht('You must %s!', 'setAccessToken()')); + } + + $uri = new PhutilURI('https://slack.com/'); + $uri->setPath('/api/'.$this->action); + $uri->setQueryParam('token', $this->accessToken); + + $future = new HTTPSFuture($uri); + $future->setData($this->params); + $future->setMethod($this->method); + + $this->future = $future; + } + + return $this->future; + } + + protected function didReceiveResult($result) { + list($status, $body, $headers) = $result; + + if ($status->isError()) { + throw $status; + } + + $data = null; + try { + $data = phutil_json_decode($body); + } catch (PhutilJSONParserException $ex) { + throw new PhutilProxyException( + pht('Expected JSON response from Slack.'), + $ex); + } + + if (idx($data, 'error')) { + $error = $data['error']; + throw new Exception(pht('Received error from Slack: %s', $error)); + } + + return $data; + } + +}