├── .gitattributes ├── .gitignore ├── CHANGELOG ├── Command ├── BotMessagingCommand.php ├── ChangeChannelsTopicCommand.php ├── DebugCommand.php ├── MessageCommand.php └── UsersCommand.php ├── DZunkeSlackBundle.php ├── DependencyInjection ├── Configuration.php └── DZunkeSlackExtension.php ├── Event.php ├── Events └── MessageEvent.php ├── LICENSE ├── Monolog └── Handler │ └── SlackHandler.php ├── README.md ├── Resources ├── config │ └── services.yml └── doc │ ├── actions-list.md │ ├── basic-usage.md │ ├── commands.md │ ├── configuration.md │ ├── index.md │ ├── installation.md │ ├── monolog.md │ ├── roadmap.md │ ├── services.md │ ├── silex.md │ ├── slack.md │ └── symfony-usage.md ├── Silex └── Provider │ └── SlackServiceProvider.php ├── Slack ├── Channels.php ├── Client.php ├── Client │ ├── Actions.php │ ├── Actions │ │ ├── ActionsInterface.php │ │ ├── ApiTest.php │ │ ├── AuthTest.php │ │ ├── ChannelsCreate.php │ │ ├── ChannelsHistory.php │ │ ├── ChannelsInfo.php │ │ ├── ChannelsInvite.php │ │ ├── ChannelsList.php │ │ ├── ChannelsSetTopic.php │ │ ├── ChatPostMessage.php │ │ ├── FilesUpload.php │ │ └── UsersList.php │ ├── Connection.php │ └── Response.php ├── Entity │ ├── Message.php │ └── MessageAttachment.php ├── Messaging.php ├── Messaging │ ├── Identity.php │ └── IdentityBag.php └── Users.php └── composer.json /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | composer.phar 3 | vendor 4 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | SlackBundle v2.6.0 2 | ================== 3 | - Feature: Support file upload api with multipart form data (by @pmishev) 4 | - Feature: Add support for threads in file upload api (by @pmishev) 5 | 6 | SlackBundle v2.5.0 7 | ================== 8 | - Feature: Removed symfony/symfony as required package by splitting requirements (by @makasim) 9 | - FIX: Symfony 4 Warnings when calling public services (by @syunta) 10 | 11 | SlackBundle v2.4.1 12 | ================== 13 | - FIX: Symfony 2.8 support was defect by removed classes in services.yml 14 | 15 | SlackBundle v2.4.0 16 | ================== 17 | - Feature: Commands compatible to Symfony 3.4 (by @alister) 18 | - (NOT BC) Feature: Remove old command prefixes (see v1.3) (by @alister) 19 | - Patch: removed different typos (by @alister) 20 | - Feature: Support for more fields in attachments and additional client options for Messaging::message() (by @pmishev) 21 | - Support for Symfony 4.0 22 | 23 | SlackBundle v2.3.0 24 | ================== 25 | - Feature: Add channel.create action 26 | - Bug: Fixed dumb error with post requesting 27 | 28 | SlackBundle v2.2.0 29 | ================== 30 | - Feature: Add Support to send Requests as POST instead of GET 31 | - Patch: Fix UsersList-Action, users email could be empty (by @mediafigaro) 32 | - Patch: Fix channel history (found in fork by @elmpp) 33 | 34 | SlackBundle v2.1.0 35 | ================== 36 | - Add Support to disable SSL Verification at Guzzle Client 37 | 38 | SlackBundle v2.0.0 39 | ================== 40 | - (NOT BC) Feature: Upgrade to Guzzle 6 (thanks for Support @alister) 41 | 42 | SlackBundle v1.4.0 43 | ================== 44 | - Feature: Monolog-Logger uses colored attachments based on the log level (by @jdecoster) 45 | - Patch: Quoting Services to Support Symfony > 2.8 (by @carlosmasip) 46 | - Patch: Fix deprecation in configuration 47 | - Patch: Enable Symfony 3.0 and PHP 7 48 | 49 | SlackBundle v1.3.0 50 | ================== 51 | - Feature: File upload service now accepts an array of channels, string usage is deprecated 52 | - Feature: Implement action to invite users to a channel 53 | - Feature: Implement action and service to get details about users on the team 54 | - Feature: Implement console command to read userdata from api 55 | - Patch: File upload no longer need to lookup channel id due to api changes 56 | - Patch: Set aliases for command names - old names with dzunke: prefix will be removed in the future! 57 | 58 | SlackBundle v1.2.2 59 | ================== 60 | - Patch: MessageAttachment support complete attachment-api (by @shimmi) 61 | 62 | SlackBundle v1.2.1 63 | ================== 64 | - Patch Feature: Customize icon_url and icon_emoji on single message-action (by @tobiassjosten) 65 | 66 | SlackBundle v1.2.0 67 | ================== 68 | - Feature: Added FileUploads 69 | - Feature: Added Basic Implementation for Event-Driven Bots 70 | 71 | SlackBundle v1.1.1 72 | ================== 73 | - Feature: Downgraded requirement for GuzzleClient Version to 3.7.0 (by @toooni) 74 | 75 | SlackBundle v1.1.0 76 | ================== 77 | - Feature: Added Provider for Silex-Integration 78 | - Feature: Added Attachments to the Messaging-Methods 79 | - (NOT BC) Refactor: Identities are only needed for Chat, so no general use is needed 80 | 81 | SlackBundle v1.0.0 82 | ================== 83 | - Initial Release 84 | -------------------------------------------------------------------------------- /Command/BotMessagingCommand.php: -------------------------------------------------------------------------------- 1 | channels = $channels; 37 | $this->eventDispatcher = $eventDispatcher; 38 | parent::__construct(); 39 | } 40 | 41 | protected function configure() 42 | { 43 | $this 44 | ->setName(static::$defaultName) 45 | ->setDescription('Running the Bot-User to a Channel') 46 | ->addArgument( 47 | 'channel', 48 | InputArgument::REQUIRED, 49 | 'Channel to Watch over' 50 | ); 51 | } 52 | 53 | protected function execute(InputInterface $input, OutputInterface $output) 54 | { 55 | $logger = new Logger(new StreamHandler('php://output')); 56 | 57 | $channel = $this->channels->getId($input->getArgument('channel')); 58 | if (empty($channel)) { 59 | $logger->error('channel "' . $channel . '" does not exists'); 60 | return; 61 | } 62 | 63 | $lastTimestamp = time(); 64 | while (true) { 65 | 66 | try { 67 | $latestMessages = $this->channels->history($channel, $lastTimestamp); 68 | 69 | foreach ($latestMessages as $message) { 70 | if ($message->isBot() === true) { 71 | continue; 72 | } 73 | 74 | $logger->debug('Handling Message of Type : "' . $message->getType() . '"'); 75 | 76 | $event = Event::MESSAGE; 77 | switch ($message->getType()) { 78 | case Message::TYPE_MESSAGE : 79 | $event = Event::MESSAGE; 80 | break; 81 | case Message::TYPE_CHANNEL_JOIN: 82 | $event = Event::JOIN; 83 | break; 84 | case Message::TYPE_CHANNEL_LEAVE: 85 | $event = Event::LEAVE; 86 | break; 87 | } 88 | 89 | $logger->debug('Dispatching "' . $event . '"'); 90 | 91 | $this->eventDispatcher->dispatch( 92 | $event, 93 | new Events\MessageEvent($channel, $message) 94 | ); 95 | 96 | $lastTimestamp = $message->getId(); 97 | } 98 | 99 | $logger->debug('Handled ' . count($latestMessages) . ' Messages'); 100 | 101 | } catch (\Exception $e) { 102 | $logger->error($e->getMessage()); 103 | $logger->error($e->getTraceAsString()); 104 | } 105 | 106 | sleep(self::PROCESS_ITERATION_SLEEP); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Command/ChangeChannelsTopicCommand.php: -------------------------------------------------------------------------------- 1 | channels = $channels; 25 | parent::__construct(); 26 | } 27 | 28 | protected function configure() 29 | { 30 | $this 31 | ->setName(static::$defaultName) 32 | ->setDescription('Changing the Topic of a Channel') 33 | ->addOption('discover', 'd', InputOption::VALUE_NONE, 'channel name is given, so discover the id') 34 | ->addArgument('channel', InputArgument::REQUIRED, 'an existing channel in your team to change the topic') 35 | ->addArgument('topic', InputArgument::REQUIRED, 'the topic you want to set in the channel'); 36 | } 37 | 38 | protected function execute(InputInterface $input, OutputInterface $output) 39 | { 40 | try { 41 | if ($input->getOption('discover')) { 42 | $channelId = $this->channels->getId($input->getArgument('channel')); 43 | } else { 44 | $channelId = $input->getArgument('channel'); 45 | } 46 | 47 | $response = $this->channels->setTopic( 48 | $channelId, 49 | $input->getArgument('topic') 50 | ); 51 | 52 | if ($response->getStatus() === false) { 53 | $output->writeln('✘ request got an error from slack: "' . $response->getError() . '"'); 54 | 55 | return; 56 | } 57 | 58 | $output->writeln('✔ changed topic'); 59 | 60 | if ($output->getVerbosity() == OutputInterface::VERBOSITY_VERBOSE) { 61 | $output->writeln('Old Topic: ' . $response->getData()['old_topic']); 62 | $output->writeln('New Topic: ' . $response->getData()['new_topic']); 63 | } 64 | 65 | } catch (\Exception $e) { 66 | $output->writeln('✘ there was an error while changing topic: "' . $e->getMessage() . '"'); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Command/DebugCommand.php: -------------------------------------------------------------------------------- 1 | client = $client; 34 | parent::__construct(); 35 | } 36 | 37 | protected function configure() 38 | { 39 | $this 40 | ->setName(static::$defaultName) 41 | ->setDescription('Gives some Debug Informations about the SlackBundle'); 42 | } 43 | 44 | 45 | protected function execute(InputInterface $input, OutputInterface $output) 46 | { 47 | $this->input = $input; 48 | $this->output = $output; 49 | 50 | $config = $this->getContainer()->getParameter('d_zunke_slack.config'); 51 | 52 | $this->renderConnection($config); 53 | $this->output->writeln(''); 54 | $this->renderIdentities($config); 55 | $this->output->writeln(''); 56 | $this->renderSlackChannels($config); 57 | } 58 | 59 | protected function renderSlackChannels() 60 | { 61 | $this->output->writeln('Available Channels'); 62 | 63 | $channels = $this->client->send( 64 | Client\Actions::ACTION_CHANNELS_LIST, 65 | [], 66 | null 67 | ); 68 | 69 | if ($channels->getStatus() === false) { 70 | $this->output->writeln('' . $channels->getError() . ''); 71 | 72 | return; 73 | } 74 | 75 | $table = new Table($this->output); 76 | 77 | $index = 0; 78 | foreach ($channels->getData() as $name => $channel) { 79 | 80 | if ($index > 0) { 81 | $table->addRow(new TableSeparator()); 82 | } 83 | 84 | $table->addRow(['' . $name . '']); 85 | $table->addRow( 86 | [ 87 | ' id', 88 | $channel['id'] 89 | ] 90 | ); 91 | 92 | $index++; 93 | } 94 | 95 | $table->render(); 96 | } 97 | 98 | protected function renderIdentities(array $config) 99 | { 100 | $this->output->writeln('Identities'); 101 | 102 | $table = new Table($this->output); 103 | 104 | $index = 0; 105 | foreach ($config['identities'] as $username => $userConfig) { 106 | 107 | if ($index > 0) { 108 | $table->addRow(new TableSeparator()); 109 | } 110 | 111 | $table->addRow(['' . $username . '']); 112 | 113 | foreach ($userConfig as $configName => $configValue) { 114 | $table->addRow( 115 | [ 116 | " " . $configName, 117 | is_null($configValue) ? 'null' : $configValue 118 | ] 119 | ); 120 | } 121 | 122 | $index++; 123 | } 124 | 125 | $table->render(); 126 | } 127 | 128 | protected function renderConnection(array $config) 129 | { 130 | $this->output->writeln('Connection'); 131 | 132 | $table = new Table($this->output); 133 | 134 | $table->addRow(['endpoint', $config['endpoint']]); 135 | $table->addRow(['token', $config['token']]); 136 | 137 | $table->addRow(new TableSeparator()); 138 | $table->addRow(['ConnectionStatus', $this->connectionTest()]); 139 | $table->addRow(['Authorization', $this->authTest()]); 140 | 141 | $table->render(); 142 | } 143 | 144 | protected function connectionTest() 145 | { 146 | $connectionTest = $this->client->send( 147 | Client\Actions::ACTION_API_TEST, 148 | [], 149 | null 150 | ); 151 | 152 | if ($connectionTest->getStatus()) { 153 | $statusMessage = 'Ok'; 154 | } else { 155 | $statusMessage = '' . $connectionTest->getError() . ''; 156 | } 157 | 158 | return $statusMessage; 159 | } 160 | 161 | protected function authTest() 162 | { 163 | $authTest = $this->client->send( 164 | Client\Actions::ACTION_AUTH_TEST, 165 | [], 166 | null 167 | ); 168 | 169 | if ($authTest->getStatus()) { 170 | $statusMessage = 'Ok - User: ' . $authTest->getData()['user'] . ''; 171 | } else { 172 | $statusMessage = '' . $authTest->getError() . ''; 173 | } 174 | 175 | return $statusMessage; 176 | } 177 | 178 | } 179 | -------------------------------------------------------------------------------- /Command/MessageCommand.php: -------------------------------------------------------------------------------- 1 | messenger = $messenger; 19 | parent::__construct(); 20 | } 21 | 22 | protected function configure() 23 | { 24 | $this 25 | ->setName(static::$defaultName) 26 | ->setDescription('Sending a Message to a Channel or User') 27 | ->addArgument('channel', InputArgument::REQUIRED, 'an existing channel in your team to send to') 28 | ->addArgument('username', InputArgument::REQUIRED, 'an username from configured identities to send with') 29 | ->addArgument('message', InputArgument::REQUIRED, 'the message to send'); 30 | } 31 | 32 | protected function execute(InputInterface $input, OutputInterface $output) 33 | { 34 | try { 35 | $response = $this->messenger->message( 36 | $input->getArgument('channel'), 37 | $input->getArgument('message'), 38 | $input->getArgument('username') 39 | ); 40 | 41 | if ($response->getStatus() === false) { 42 | $output->writeln('✘ request got an error from slack: "' . $response->getError() . '"'); 43 | return; 44 | } 45 | 46 | $output->writeln('✔ message was sent to ' . $input->getArgument('channel') . ''); 47 | } catch (\Exception $e) { 48 | $output->writeln('✘ there was an error while sending message: "' . $e->getMessage() . '"'); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Command/UsersCommand.php: -------------------------------------------------------------------------------- 1 | api = $users; 24 | parent::__construct(); 25 | } 26 | 27 | protected function configure() 28 | { 29 | $this 30 | ->setName(static::$defaultName) 31 | ->setDescription('work with the users of your team') 32 | ->addOption('only-active', 'a', InputOption::VALUE_NONE, 'lists only active users') 33 | ->addOption('only-deleted', 'd', InputOption::VALUE_NONE, 'lists only deleted users') 34 | ->addOption('user', 'u', InputOption::VALUE_REQUIRED, 'get a single user'); 35 | } 36 | 37 | protected function execute(InputInterface $input, OutputInterface $output) 38 | { 39 | $formatter = $this->getHelper('formatter'); 40 | 41 | try { 42 | if ($input->getOption('only-active')) { 43 | $response = $this->api->getActiveUsers(); 44 | } elseif ($input->getOption('only-deleted')) { 45 | $response = $this->api->getDeletedUsers(); 46 | } elseif ($input->getOption('user')) { 47 | $response = $this->api->getUser($input->getOption('user')); 48 | 49 | if (is_array($response)) { 50 | $response = [$response['name'] => $response]; 51 | } 52 | } else { 53 | $response = $this->api->getUsers(); 54 | } 55 | 56 | if (empty($response)) { 57 | $output->writeln($formatter->formatBlock('✘ no data found', 'error')); 58 | return; 59 | } 60 | 61 | array_walk( 62 | $response, 63 | function (&$row) { 64 | foreach ($row as &$col) { 65 | if (is_bool($col)) { 66 | $col = $col ? 'true' : 'false'; 67 | } 68 | } 69 | } 70 | ); 71 | 72 | $table = new Table($output); 73 | $table->setHeaders(array_keys(reset($response)))->setRows($response); 74 | $table->render($output); 75 | 76 | } catch (\Exception $e) { 77 | $output->writeln( 78 | $formatter->formatBlock( 79 | sprintf('✘ there was an error with your request: "%s"', $e->getMessage()), 80 | 'error' 81 | ) 82 | ); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /DZunkeSlackBundle.php: -------------------------------------------------------------------------------- 1 | root('d_zunke_slack'); 19 | $rootNode->children() 20 | ->scalarNode('endpoint') 21 | ->defaultValue('https://slack.com/api') 22 | ->end() 23 | ->scalarNode('token') 24 | ->isRequired() 25 | ->defaultNull() 26 | ->cannotBeEmpty() 27 | ->end() 28 | ->integerNode('limit_retries') 29 | ->defaultValue(3) 30 | ->min(1) 31 | ->info('The amount of retries for the connection if the Rate Limits of Slack are reached') 32 | ->end() 33 | ->booleanNode('verify_ssl') 34 | ->defaultTrue() 35 | ->end() 36 | ->booleanNode('use_http_post') 37 | ->defaultFalse() 38 | ->end() 39 | ->end(); 40 | 41 | $rootNode->append($this->addIdentities()); 42 | 43 | return $treeBuilder; 44 | } 45 | 46 | /** 47 | * @return ArrayNodeDefinition|\Symfony\Component\Config\Definition\Builder\NodeDefinition 48 | */ 49 | private function addIdentities() 50 | { 51 | $treeBuilder = new TreeBuilder(); 52 | $node = $treeBuilder->root('identities'); 53 | 54 | /** @var $connectionNode ArrayNodeDefinition */ 55 | $microservicesNode = $node->requiresAtLeastOneElement() 56 | ->useAttributeAsKey('username') 57 | ->info('Usernames to use for Communication inside the Messaging') 58 | ->prototype('array'); 59 | 60 | 61 | $microservicesNode 62 | ->children() 63 | ->scalarNode('icon_url') 64 | ->defaultNull() 65 | ->info('An Url to a specific picture to use as Icon, be sure no emoji is set') 66 | ->end() 67 | ->scalarNode('icon_emoji') 68 | ->defaultNull() 69 | ->info('The Icon to use from an emoji like :smile:') 70 | ->end() 71 | ->end(); 72 | 73 | return $node; 74 | } 75 | 76 | 77 | } 78 | -------------------------------------------------------------------------------- /DependencyInjection/DZunkeSlackExtension.php: -------------------------------------------------------------------------------- 1 | getConfiguration($configs, $container); 20 | $config = $this->processConfiguration($configuration, $configs); 21 | 22 | $container->setParameter('d_zunke_slack.config', $config); 23 | 24 | $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); 25 | $loader->load('services.yml'); 26 | 27 | $this->configureSlackIdentityBag($config, $container); 28 | $this->configureSlackConnection($config, $container); 29 | } 30 | 31 | /** 32 | * @param array $config 33 | * @param ContainerBuilder $container 34 | */ 35 | protected function configureSlackIdentityBag(array $config, ContainerBuilder $container) 36 | { 37 | $definition = $container->getDefinition('dz.slack.identity_bag'); 38 | 39 | $definition->addMethodCall('createIdentities', [$config['identities']]); 40 | } 41 | 42 | /** 43 | * @param array $config 44 | * @param ContainerBuilder $container 45 | */ 46 | protected function configureSlackConnection(array $config, ContainerBuilder $container) 47 | { 48 | $definition = $container->getDefinition('dz.slack.connection'); 49 | 50 | $definition->addMethodCall('setEndpoint', [$config['endpoint']]); 51 | $definition->addMethodCall('setToken', [$config['token']]); 52 | $definition->addMethodCall('setLimitRetries', [$config['limit_retries']]); 53 | $definition->addMethodCall('setVerifySsl', [$config['verify_ssl']]); 54 | 55 | if ($config['use_http_post'] === true) { 56 | $definition->addMethodCall('isHttpPostMethod'); 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /Event.php: -------------------------------------------------------------------------------- 1 | message = $message; 22 | } 23 | 24 | /** 25 | * @return Message 26 | */ 27 | public function getMessage() 28 | { 29 | return $this->message; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Denis Zunke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Monolog/Handler/SlackHandler.php: -------------------------------------------------------------------------------- 1 | messagingClient = $messaging; 39 | $this->channel = $channel; 40 | $this->username = $username; 41 | 42 | if (!$this->messagingClient->getIdentityBag()->has($username)) { 43 | throw new \InvalidArgumentException('Invalid Username given'); 44 | } 45 | 46 | parent::__construct($level, $bubble); 47 | } 48 | 49 | protected function write(array $record) 50 | { 51 | $attachment = new MessageAttachment(); 52 | 53 | switch($record['level']) { 54 | case Logger::DEBUG: 55 | case Logger::INFO: 56 | $attachment->setColor('good'); 57 | break; 58 | case Logger::NOTICE: 59 | case Logger::WARNING: 60 | $attachment->setColor('warning'); 61 | break; 62 | case Logger::ERROR: 63 | case Logger::CRITICAL: 64 | case Logger::ALERT: 65 | case Logger::EMERGENCY: 66 | $attachment->setColor('danger'); 67 | break; 68 | } 69 | 70 | $attachment->addField($record['level_name'], $record['formatted']); 71 | 72 | $this->messagingClient->message($this->channel, '', $this->username, [$attachment]); 73 | } 74 | 75 | /** 76 | * {@inheritDoc} 77 | */ 78 | protected function getDefaultFormatter() 79 | { 80 | return new LineFormatter(); 81 | } 82 | } 83 | 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## PROJECT ARCHIVED 2 | 3 | You may want to use the symfony notifier component which can also send messages to slack -> More Information here: https://symfony.com/doc/current/notifier.html 4 | 5 | 6 | --- 7 | 8 | ## Symfony SlackBundle [![License](https://poser.pugx.org/dzunke/slack-bundle/license.svg)](https://packagist.org/packages/dzunke/slack-bundle) 9 | 10 | [![Dependency Status](https://www.versioneye.com/user/projects/53f7cb30e09da3d0bf00047b/badge.svg)](https://www.versioneye.com/user/projects/53f7cb30e09da3d0bf00047b) [![SensioLabsInsight](https://insight.sensiolabs.com/projects/12c02e49-a1a8-42f7-a213-71d4288fc75d/mini.png)](https://insight.sensiolabs.com/projects/12c02e49-a1a8-42f7-a213-71d4288fc75d) [![Latest Unstable Version](https://poser.pugx.org/dzunke/slack-bundle/v/unstable.svg)](https://packagist.org/packages/dzunke/slack-bundle) [![Latest Stable Version](https://poser.pugx.org/dzunke/slack-bundle/v/stable.svg)](https://packagist.org/packages/dzunke/slack-bundle) 11 | 12 | The Bundle will integrate [Slack](https://slack.com/) Team-Communication-Software into your Symfony2 Project and in the future will deliver a set of Project-Management-Tools to use between your Symfony-Project and Slack. 13 | 14 | ## Documentation 15 | 16 | Please check the [Documentation](Resources/doc/index.md) for Help and Informations about the Usage of the Bundle. There is also a [Roadmap](Resources/doc/roadmap.md) available. 17 | 18 | ## License 19 | 20 | SlackBundle is licensed under the MIT license. 21 | -------------------------------------------------------------------------------- /Resources/config/services.yml: -------------------------------------------------------------------------------- 1 | services: 2 | 3 | dz.slack.identity_bag: 4 | class: DZunke\SlackBundle\Slack\Messaging\IdentityBag 5 | public: true 6 | 7 | dz.slack.connection: 8 | class: DZunke\SlackBundle\Slack\Client\Connection 9 | public: true 10 | 11 | dz.slack.client: 12 | class: DZunke\SlackBundle\Slack\Client 13 | public: true 14 | arguments: ["@dz.slack.connection"] 15 | 16 | dz.slack.messaging: 17 | class: DZunke\SlackBundle\Slack\Messaging 18 | public: true 19 | arguments: ["@dz.slack.client", "@dz.slack.identity_bag"] 20 | 21 | dz.slack.channels: 22 | class: DZunke\SlackBundle\Slack\Channels 23 | public: true 24 | arguments: ["@dz.slack.client"] 25 | 26 | dz.slack.users: 27 | class: DZunke\SlackBundle\Slack\Users 28 | public: true 29 | arguments: ["@dz.slack.client"] 30 | 31 | DZunke\SlackBundle\Slack\Messaging\IdentityBag: '@dz.slack.identity_bag' 32 | 33 | DZunke\SlackBundle\Slack\Client\Connection: '@dz.slack.connection' 34 | 35 | DZunke\SlackBundle\Slack\Client: '@dz.slack.client' 36 | 37 | DZunke\SlackBundle\Slack\Messaging: '@dz.slack.messaging' 38 | 39 | DZunke\SlackBundle\Slack\Channels: '@dz.slack.channels' 40 | 41 | DZunke\SlackBundle\Slack\Users: '@dz.slack.users' 42 | 43 | DZunke\SlackBundle\Command\BotMessagingCommand: 44 | class: DZunke\SlackBundle\Command\BotMessagingCommand 45 | arguments: ["@dz.slack.channels", "@event_dispatcher"] 46 | tags: 47 | - { name: console.command, command: slack:run-bot } 48 | 49 | DZunke\SlackBundle\Command\ChangeChannelsTopicCommand: 50 | class: DZunke\SlackBundle\Command\ChangeChannelsTopicCommand 51 | arguments: ["@dz.slack.channels"] 52 | tags: 53 | - { name: console.command, command: slack:channels:topic } 54 | 55 | DZunke\SlackBundle\Command\DebugCommand: 56 | class: DZunke\SlackBundle\Command\DebugCommand 57 | arguments: ["@dz.slack.client"] 58 | tags: 59 | - { name: console.command, command: slack:debug } 60 | 61 | DZunke\SlackBundle\Command\MessageCommand: 62 | class: DZunke\SlackBundle\Command\MessageCommand 63 | arguments: ["@dz.slack.messaging"] 64 | tags: 65 | - { name: console.command, command: slack:message } 66 | 67 | DZunke\SlackBundle\Command\UsersCommand: 68 | class: DZunke\SlackBundle\Command\UsersCommand 69 | arguments: ["@dz.slack.users"] 70 | tags: 71 | - { name: console.command, command: slack:users } 72 | -------------------------------------------------------------------------------- /Resources/doc/actions-list.md: -------------------------------------------------------------------------------- 1 | # Available Actions for Basic Usage 2 | 3 | ## api.test 4 | 5 | [Slack Documentation](https://api.slack.com/methods/api.test) 6 | 7 | Constant: \DZunke\SlackBundle\Slack\Client::ACTION_API_TEST 8 | 9 | Available Parameters: 10 | 11 | ``` php 12 | protected $parameter = []; 13 | ``` 14 | 15 | ## auth.test 16 | 17 | [Slack Documentation](https://api.slack.com/methods/auth.test) 18 | 19 | Constant: \DZunke\SlackBundle\Slack\Client::ACTION_AUTH_TEST 20 | 21 | Available Parameters: 22 | 23 | ``` php 24 | protected $parameter = []; 25 | ``` 26 | 27 | ## channels.create 28 | 29 | [Slack Documentation](https://api.slack.com/methods/channels.create) 30 | 31 | Constant: \DZunke\SlackBundle\Slack\Client::ACTION_CHANNELS_CREATE 32 | 33 | Available Parameters: 34 | 35 | ``` php 36 | protected $parameter = [ 37 | 'name' => null 38 | ]; 39 | ``` 40 | 41 | ## channels.info 42 | 43 | [Slack Documentation](https://api.slack.com/methods/channels.info) 44 | 45 | Constant: \DZunke\SlackBundle\Slack\Client::ACTION_CHANNELS_INFO 46 | 47 | Available Parameters: 48 | 49 | ``` php 50 | protected $parameter = [ 51 | 'channel' => null 52 | ]; 53 | ``` 54 | 55 | ## channels.invite 56 | 57 | [Slack Documentation](https://api.slack.com/methods/channels.invite) 58 | 59 | Constant: \DZunke\SlackBundle\Slack\Client::ACTION_CHANNELS_INVITE 60 | 61 | Available Parameters: 62 | 63 | Both Parameters have to be the if of the entity and not the raw name 64 | 65 | ``` php 66 | protected $parameter = [ 67 | 'channel' => null, 68 | 'user' => null, 69 | ]; 70 | ``` 71 | 72 | ## channels.list 73 | 74 | [Slack Documentation](https://api.slack.com/methods/channels.list) 75 | 76 | Constant: \DZunke\SlackBundle\Slack\Client::ACTION_CHANNELS_LIST 77 | 78 | Available Parameters: 79 | 80 | ``` php 81 | protected $parameter = [ 82 | 'exclude_archived' => 1 83 | ]; 84 | ``` 85 | 86 | ## channels.setTopic 87 | 88 | [Slack Documentation](https://api.slack.com/methods/channels.setTopic) 89 | 90 | Constant: \DZunke\SlackBundle\Slack\Client::ACTION_CHANNELS_SET_TOPIC 91 | 92 | Available Parameters: 93 | 94 | ``` php 95 | protected $parameter = [ 96 | 'channel' => null, 97 | 'topic' => null 98 | ]; 99 | ``` 100 | 101 | ## chat.postMessage 102 | 103 | [Slack Documentation](https://api.slack.com/methods/chat.postMessage) 104 | 105 | Constant: \DZunke\SlackBundle\Slack\Client::ACTION_POST_MESSAGE 106 | 107 | Available Parameters: 108 | 109 | ``` php 110 | protected $parameter = [ 111 | 'identity' => null, # Object of Class \DZunke\SlackBundle\Slack\Messaging\Identity 112 | 'channel' => null, 113 | 'text' => null, 114 | 'icon_url' => null, # only one of icon_url or icon_emoji could be used 115 | 'icon_emoji' => null, 116 | 'parse' => 'full', 117 | 'link_names' => 1, 118 | 'unfurl_links' => 1, 119 | 'attachments' => [] 120 | ]; 121 | ``` 122 | 123 | ## files.upload 124 | 125 | [Slack Documentation](https://api.slack.com/methods/files.upload) 126 | 127 | Constant: \DZunke\SlackBundle\Slack\Client::ACTION_FILES_UPLOAD 128 | 129 | ``` php 130 | protected $parameter = [ 131 | 'content' => null, 132 | 'filetype' => null, 133 | 'filename' => null, 134 | 'title' => null, 135 | 'initial_comment' => null, 136 | 'channels' => null # If no Channel is given the File will be private to the API-User 137 | ]; 138 | ``` 139 | 140 | ## users.list 141 | 142 | [Slack Documentation](https://api.slack.com/methods/users.list) 143 | 144 | Constant: \DZunke\SlackBundle\Slack\Client::ACTION_USERS_LIST 145 | 146 | ``` php 147 | protected $parameter = [ 148 | 'presence' => 1 149 | ]; 150 | ``` 151 | -------------------------------------------------------------------------------- /Resources/doc/basic-usage.md: -------------------------------------------------------------------------------- 1 | # Basic Usage without Symfony Integration 2 | 3 | The Basic-Integration of Slack in this Bundle is usable without Symfony. 4 | 5 | ``` php 6 | $identity = new \DZunke\SlackBundle\Slack\Messaging\Identity(); 7 | $identity->setUsername('CoffeeBrewer'); 8 | $identity->setIconEmoji(':coffee:'); 9 | 10 | $connection = new \DZunke\SlackBundle\Slack\Client\Connection(); 11 | $connection->setEndpoint('slack.com/api/'); 12 | $connection->setToken('YOUR API TOKEN'); 13 | 14 | # Switch from GET to POST Method 15 | # $connection->isHttpPostMethod(); 16 | 17 | $client = new \DZunke\SlackBundle\Slack\Client($connection); 18 | 19 | $response = $client->send( 20 | \DZunke\SlackBundle\Slack\Client\Actions::ACTION_POST_MESSAGE, 21 | [ 22 | 'identity' => $identity, 23 | 'channel' => '#slack-testing', 24 | 'text' => 'Good Morning, please make sure u got a coffee before working!' 25 | ] 26 | ); 27 | ``` 28 | -------------------------------------------------------------------------------- /Resources/doc/commands.md: -------------------------------------------------------------------------------- 1 | # Commands 2 | 3 | ## Debugging 4 | 5 | Output of Debug Informations like Connection, Identities, Channels etc. 6 | 7 | ``` bash 8 | php app/console slack:debug 9 | ``` 10 | 11 | ## Messaging 12 | 13 | Sending a Message directly from Console 14 | 15 | ``` bash 16 | php app/console slack:message @fooUser BazUser "Lorem ipsum dolor sit amet .." 17 | php app/console slack:message "#FooChannel" BazUser "Lorem ipsum dolor sit amet .." 18 | ``` 19 | 20 | ## Switch Topic of a Channel 21 | 22 | You can switch the Topic of a Channel 23 | 24 | ``` bash 25 | php app/console slack:channels:topic "C02GABTDT" "Lorem ipsum dolor sit amet .." 26 | 27 | # If you don't have the ChannelId it must be discovered while processing 28 | php app/console slack:channels:topic "#foo-channel" "Lorem ipsum dolor sit amet .." -d 29 | ``` 30 | 31 | ## Read userdata from api 32 | 33 | you will get a table of userdata. 34 | 35 | ``` bash 36 | # Read all users from your team 37 | php app/console slack:users 38 | 39 | # Read a single user 40 | php app/console slack:users --user=nameOfTheUser 41 | ``` 42 | -------------------------------------------------------------------------------- /Resources/doc/configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration Reference 2 | 3 | ``` yaml 4 | d_zunke_slack: 5 | endpoint: slack.com/api/ 6 | token: null # Required 7 | verify_ssl: true # ssl verification at guzzle client 8 | use_http_post: false # give the ability to send request as HTTP POST 9 | 10 | # The amount of retries for the connection if the Rate Limits of Slack are reached 11 | limit_retries: 3 12 | 13 | # Usernames to use for Communication inside the Messaging 14 | identities: 15 | 16 | # Prototype 17 | username: 18 | 19 | # An Url to a specific picture to use as Icon 20 | icon_url: null 21 | 22 | # The Icon to use from an emoji like :smile: 23 | icon_emoji: null 24 | 25 | ``` 26 | -------------------------------------------------------------------------------- /Resources/doc/index.md: -------------------------------------------------------------------------------- 1 | # SlackBundle Documentation 2 | 3 | 1. [Installation](installation.md) 4 | 5 | 2. [Configuration Reference](configuration.md) 6 | 7 | 3. [Basic Usage without Symfony Integration](basic-usage.md) 8 | 4. [Basic Usage in Symfony](symfony-usage.md) 9 | 5. [Available Actions for Basic Usage](actions-list.md) 10 | 11 | 6. [Services](services.md) 12 | 7. [Commands](commands.md) 13 | 8. [Monolog Integration](monolog.md) 14 | 15 | 9. [Silex Integration](silex.md) 16 | 17 | 10. [Help for Slack](slack.md) 18 | -------------------------------------------------------------------------------- /Resources/doc/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## 1. Install the Bundle 4 | 5 | You can add the Bundle by running [Composer](http://getcomposer.org) on your shell or adding it directly to your composer.json 6 | 7 | ``` bash 8 | php composer.phar require dzunke/slack-bundle:dev-master 9 | ``` 10 | 11 | ``` json 12 | "require" : { 13 | "dzunke/slack-bundle": "dev-master" 14 | } 15 | ``` 16 | 17 | ## 2. Register the Bundle to Symfony 18 | 19 | The Namespace will be registered by autoloading with Composer but to use the integrated features for symfony you have to register the Bundle. 20 | 21 | ``` php 22 | # app/AppKernel.php 23 | public function registerBundles() 24 | { 25 | $bundles = [ 26 | // [..] 27 | new DZunke\SlackBundle\DZunkeSlackBundle(), 28 | ]; 29 | } 30 | ``` 31 | 32 | ## 3. Add the Configuration for the Bundle 33 | 34 | To use the Bundle without an Error you have to add the Connection-Data and finally one Identity to use with the Methods like MonologHandler or Messaging. 35 | 36 | ``` yaml 37 | # app/config/config.yml 38 | d_zunke_slack: 39 | token: "YOUR AUTH-TOKEN" 40 | identities: 41 | CoffeeBrewer: ~ 42 | ``` 43 | 44 | -------------------------------------------------------------------------------- /Resources/doc/monolog.md: -------------------------------------------------------------------------------- 1 | # Monolog Integration 2 | 3 | **Please only use this Log-Handler for Errors or Criticals** 4 | 5 | In a first step you have to create a custom service for the Handler. In this Service you can define Channel and Username to work with. The Username must be registered in the [Configuration](configuration.md) to be usable otherwise you'll get an Exception. 6 | 7 | ``` yaml 8 | # app/config.yml 9 | services: 10 | my_custom_handler: 11 | class: DZunke\SlackBundle\Monolog\Handler\SlackHandler 12 | # 400 = ERROR, see Monolog::Logger for the values of log levels 13 | arguments: [@dz.slack.messaging, "#foo-channel", "bazuser", 400] 14 | ``` 15 | 16 | You can create a bunch of Handlers. To Register the Handler to the Main-Logging of Symfony you'll have to add the new Service to the Monolog Configuration. 17 | 18 | ``` yaml 19 | # app/config.yml 20 | monolog: 21 | handlers: 22 | slack: 23 | type: service 24 | id: my_custom_handler 25 | ``` 26 | -------------------------------------------------------------------------------- /Resources/doc/roadmap.md: -------------------------------------------------------------------------------- 1 | # Roadmap 2 | 3 | To view a bit into the future there are some ideas for features and the will to implement them. The long term Target is to create a Set of Project-Management Features to make the daily work easier and use the full capacity of the gorgeous Slack-System. 4 | 5 | * Upload Files 6 | * Connectors for extern Tools to fetch Data and post them (maybe with a cache to only get updated content) 7 | * "iDoneThis" for Slack-Chat (Checking if it is possible with the API) 8 | 9 | 10 | The following Features could not be implemented yet because of problems with the API of Slack. 11 | 12 | * Update ChatMessage for ProgressBars etc. 13 | -------------------------------------------------------------------------------- /Resources/doc/services.md: -------------------------------------------------------------------------------- 1 | # Services 2 | 3 | ## Messaging 4 | 5 | Sending Messages to Channel, Group or User without the need of knowing the Client 6 | 7 | ``` php 8 | $response = $container->get('dz.slack.messaging')->message( 9 | '#foo-channel', 10 | 'Good Morning, please make sure u got a coffee before working!', 11 | 'CoffeeBrewer' 12 | ); 13 | ``` 14 | 15 | There is also a way to use the "Attachment"-Feature of Slack. In this Case there will be a multi-column part below the Message. 16 | For this you must create deliver an Array of Attachments to the Message-Method. 17 | 18 | ``` php 19 | $attachment = new DZunke\SlackBundle\Slack\Entity\MessageAttachment(); 20 | $attachment->setColor('danger'); 21 | $attachment->addField('Test1', 'Test works'); 22 | 23 | $response = $container->get('dz.slack.messaging')->message( 24 | '#foo-channel', 25 | 'Good Morning, please make sure u got a coffee before working!', 26 | 'CoffeeBrewer', 27 | [$attachment] 28 | ); 29 | ``` 30 | 31 | ### File Uploads 32 | 33 | The Messaging does include File Uploads. So the Service has an "upload"-Method to publish Reports or other Files to a Channel. 34 | You must note that every uploaded File will be associated with the API-Key-User configured for your Slack-Client. 35 | 36 | ``` php 37 | $response = $container->get('dz.slack.messaging')->upload( 38 | '#foo-channel', 39 | 'Title for this File', 40 | '/Path/to/the/file', 41 | 'Optional Comment' 42 | ); 43 | ``` 44 | 45 | ## Channels 46 | 47 | There are some operations you can do for a Channel. It is necessary to get the ChannelId from the Slack-API before you 48 | can do the Actions. If you do not have the Channel Ids you can execute the Debug-Command or simply execute getId() of 49 | this Service. 50 | 51 | 52 | ``` php 53 | $service = $container->get('dz.slack.channels'); 54 | 55 | # get the specific id of a channel 56 | $service->getId($channelName); 57 | 58 | # list all available channels in your team 59 | $service->listAll(); 60 | 61 | # creates a channel 62 | $service->create($name); 63 | 64 | # get information about just a single channel 65 | $service->info($channelId); 66 | 67 | # set the topic of a channel 68 | $service->setTopic($channelId, $newTopic); 69 | ``` 70 | 71 | ## Users 72 | 73 | To get more information about the users in your team there is a service to read user specific things. In lack of an 74 | api method to load single users every method of the service will load the complete list of users in your team. Beware 75 | of using this service without caching informations you often need. 76 | 77 | ``` php 78 | $service = $container->get('dz.slack.users'); 79 | 80 | # get the list of all users in your team 81 | $service->getUsers(); 82 | 83 | # get all users that are not deleted 84 | $service->getActiveUsers(); 85 | 86 | # get all deleted users 87 | $service->getDeletedUsers(); 88 | 89 | # get the id of a single user - needed for some actions 90 | $service->getId($username); 91 | 92 | ``` 93 | -------------------------------------------------------------------------------- /Resources/doc/silex.md: -------------------------------------------------------------------------------- 1 | # Silex Integration 2 | 3 | In the Bundle there is a SilexProvider you can use with your Silex-Application. There is no need to get an extra Package. The Provider delivers the following Extensions: 4 | 5 | $app['dz.slack.connection'] # Slack/Client/Connection.php 6 | $app['dz.slack.client'] # Slack/Client.php 7 | $app['dz.slack.identity_bag'] # Slack/Messaging/IdentityBag.php 8 | $app['dz.slack.messaging'] # Slack/Messaging.php 9 | 10 | To configure the SlackBundle in Silex there is the need to set some Configuration-Values 11 | 12 | ``` php 13 | $app['dz.slack.options'] = [ 14 | 'token' => 'YOUR TOKEN HERE, 15 | 'identities' => [ 16 | 'YOUR IDENTITIY' => [] 17 | ], 18 | 'logging' => [ 19 | 'enabled' => true, 20 | 'channel' => 'YOUR CHANNEL TO LOG TO', 21 | 'identity' => 'THE IDENTITY TO LOG WITH' 22 | ] 23 | ]; 24 | ``` 25 | 26 | Wit these Options set you can load the Provider in your index 27 | 28 | ``` php 29 | $app->register(new DZunke\SlackBundle\Silex\Provider\SlackServiceProvider()); 30 | ``` 31 | 32 | ## Monolog Integration 33 | 34 | If you want to integrate the SlackHandler to an Instance of Monolog be sure the logging is enabled in the config. In that case the Provider will try to add the Handler to the default Logger ```$app['monolog']```. It will use the same LogLevel as the default Logger. 35 | 36 | Be sure that the MonologProvider is handled before! 37 | -------------------------------------------------------------------------------- /Resources/doc/slack.md: -------------------------------------------------------------------------------- 1 | # Help for Slack 2 | 3 | ## Token 4 | 5 | To get your Token you need to be logged in into the Slack-System and visit the [API-Page](https://api.slack.com/). 6 | There is a headline "Authentication" where your Team should be listet with the possibility to get a Token. 7 | 8 | **Note:** The API-Token is linked to the user who redeems it. Maybe there should be a "System"-User in your Team for this purposes. 9 | 10 | ## Formatting Messages 11 | 12 | There are some useful help for how you can format messages. 13 | 14 | * [Enabled Markdown](https://slack.zendesk.com/hc/en-us/articles/202288908-How-can-I-add-formatting-to-my-messages-) 15 | * [Emoji Cheat Sheet](http://www.emoji-cheat-sheet.com/) 16 | 17 | ## Notifications 18 | 19 | To call Notifications for a User. First it must be enabled for the User. There are some Ways to notify: 20 | 21 | * Message: _"Foo @everyone Bar"_, will notify everyone in at the Network. Must be Used on the #general Channel 22 | * Message: _"Foo @channel Bar"_, will notify everyone in a Channel 23 | * Message: _"Foo @Bazuser Bar"_, will notify the named User 24 | 25 | ## Rate-Limit 26 | 27 | Officially the Slack-API has a [Rate Limit](https://api.slack.com/docs/rate-limits) for Requests. The API only allows 28 | one Request per Second. For short times the API will ignore if you get over this limit but maybe there comes a time 29 | the API will give an Error for this. In this Case the Client will automatically try it for two more times. If you want 30 | to raise this loop of tries you can change it in the [Configuration](configuration.md). 31 | -------------------------------------------------------------------------------- /Resources/doc/symfony-usage.md: -------------------------------------------------------------------------------- 1 | # Basic Usage in Symfony 2 | 3 | If you followed the Setup you will have a bunch of services registered. For the Basic-Usage you only need the Client to execute all the Actions the Client has implemented. 4 | 5 | ``` php 6 | # AcmeBundle/IndexController.php 7 | public function messageAction() 8 | { 9 | $client = $this->get('dz.slack.client'); 10 | $response = $client->send( 11 | \DZunke\SlackBundle\Slack\Client\Actions::ACTION_POST_MESSAGE, 12 | [ 13 | 'identity' => $this->get('dz.slack.identity_bag')->get('CoffeeBrewer'), 14 | 'channel' => '#slack-testing', 15 | 'text' => 'Good Morning, please make sure u got a coffee before working!' 16 | ] 17 | ); 18 | } 19 | ``` 20 | -------------------------------------------------------------------------------- /Silex/Provider/SlackServiceProvider.php: -------------------------------------------------------------------------------- 1 | 'slack.com/api/', 19 | 'token' => null, 20 | 'limit_retries' => 5, 21 | 'identities' => [ 22 | 'Silex' => [] 23 | ], 24 | 'logging' => [ 25 | 'enabled' => false, 26 | 'channel' => '', 27 | 'identity' => '' 28 | ] 29 | ]; 30 | 31 | if (isset($app['dz.slack.options'])) { 32 | $app['dz.slack.options'] = array_merge($default_options, $app['dz.slack.options']); 33 | } else { 34 | $app['dz.slack.options'] = $default_options; 35 | } 36 | 37 | $app['dz.slack.identity_bag'] = $app->share( 38 | function ($app) { 39 | $identityBag = new Messaging\IdentityBag(); 40 | $identityBag->createIdentities($app['dz.slack.options']['identities']); 41 | 42 | return $identityBag; 43 | } 44 | ); 45 | 46 | $app['dz.slack.connection'] = $app->share( 47 | function ($app) { 48 | $connection = new Client\Connection(); 49 | $connection->setEndpoint($app['dz.slack.options']['endpoint']); 50 | $connection->setLimitRetries($app['dz.slack.options']['limit_retries']); 51 | $connection->setToken($app['dz.slack.options']['token']); 52 | 53 | return $connection; 54 | } 55 | ); 56 | 57 | $app['dz.slack.client'] = $app->share( 58 | function ($app) { 59 | return new Client($app['dz.slack.connection']); 60 | } 61 | ); 62 | 63 | $app['dz.slack.messaging'] = $app->share( 64 | function ($app) { 65 | return new Messaging($app['dz.slack.client'], $app['dz.slack.identity_bag']); 66 | } 67 | ); 68 | 69 | if ($app['dz.slack.options']['logging']['enabled']) { 70 | 71 | $app['monolog.handler.slack'] = $app->share( 72 | function ($app) { 73 | $level = MonologServiceProvider::translateLevel($app['monolog.level']); 74 | 75 | return new SlackHandler( 76 | $app['dz.slack.messaging'], 77 | $app['dz.slack.options']['logging']['channel'], 78 | $app['dz.slack.options']['logging']['identity'], 79 | $level 80 | ); 81 | } 82 | ); 83 | 84 | $app['monolog']->pushHandler($app['monolog.handler.slack']); 85 | 86 | } 87 | } 88 | 89 | public function boot(Application $app) 90 | { 91 | 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /Slack/Channels.php: -------------------------------------------------------------------------------- 1 | client = $client; 23 | } 24 | 25 | /** 26 | * @return Client 27 | */ 28 | public function getClient() 29 | { 30 | return $this->client; 31 | } 32 | 33 | /** 34 | * @param string $channelName 35 | * @return string 36 | */ 37 | public function getId($channelName) 38 | { 39 | if ($channelName[0] === 'C') { 40 | return $channelName; 41 | } 42 | 43 | if (strpos($channelName, '#') !== false) { 44 | $channelName = str_replace('#', '', $channelName); 45 | } 46 | 47 | foreach ((array)$this->listAll()->getData() as $name => $data) { 48 | if ($name == $channelName) { 49 | return $data['id']; 50 | } 51 | } 52 | 53 | return ''; 54 | } 55 | 56 | /** 57 | * @return Client\Response|bool 58 | */ 59 | public function listAll() 60 | { 61 | return $this->client->send( 62 | Actions::ACTION_CHANNELS_LIST, 63 | [] 64 | ); 65 | } 66 | 67 | /** 68 | * @param string $channel The Id of the Channel - NOT the Name. self::getId() if needed 69 | * @return Client\Response|bool 70 | */ 71 | public function info($channel) 72 | { 73 | return $this->client->send( 74 | Actions::ACTION_CHANNELS_INFO, 75 | [ 76 | 'channel' => (string)$channel 77 | ] 78 | ); 79 | } 80 | 81 | /** 82 | * @param string $name 83 | * 84 | * @return bool|Client\Response 85 | */ 86 | public function create($name) 87 | { 88 | return $this->client->send( 89 | Actions::ACTION_CHANNELS_CREATE, 90 | [ 91 | 'name' => trim($name) 92 | ] 93 | ); 94 | } 95 | 96 | /** 97 | * @param string $channel The Id of the Channel - NOT the Name. self::getId() if needed 98 | * @param string $topic 99 | * @return $this|Client\Response|bool 100 | */ 101 | public function setTopic($channel, $topic) 102 | { 103 | $channelInfo = $this->info($channel)->getData(); 104 | 105 | $response = $this->client->send( 106 | Actions::ACTION_CHANNELS_SET_TOPIC, 107 | [ 108 | 'channel' => (string)$channel, 109 | 'topic' => (string)$topic 110 | ] 111 | ); 112 | 113 | if (!$response->getStatus()) { 114 | return $response; 115 | } 116 | 117 | $data = $response->getData(); 118 | $data['old_topic'] = $channelInfo['topic']; 119 | $data['new_topic'] = (string)$topic; 120 | 121 | return $response->setData($data); 122 | } 123 | 124 | /** 125 | * @param string $channel 126 | * @param int $from 127 | * @param int $count 128 | * @return Message[] 129 | */ 130 | public function history($channel, $from = null, $count = 10) 131 | { 132 | $messages = $this->client->send( 133 | Client\Actions::ACTION_CHANNELS_HISTORY, 134 | [ 135 | 'channel' => $this->getId($channel), 136 | 'oldest' => is_null($from) ? time() : $from, 137 | 'count' => $count 138 | ] 139 | ); 140 | 141 | $repository = []; 142 | if (!empty($messages->getData()['messages'])) { 143 | $messages = $messages->getData()['messages']; 144 | foreach (array_reverse($messages) as $message) { 145 | $objMsg = new Message(); 146 | $objMsg->setId($message['ts']); 147 | $objMsg->setChannel($channel); 148 | $objMsg->setType(isset($message['subtype']) ? $message['subtype'] : $message['type']); 149 | $objMsg->setUserId(isset($message['user']) ? $message['user'] : null); 150 | $objMsg->setUsername(isset($message['username']) ? $message['username'] : null); 151 | $objMsg->setContent($message['text']); 152 | 153 | $repository[] = $objMsg; 154 | } 155 | } 156 | 157 | return $repository; 158 | } 159 | 160 | } 161 | -------------------------------------------------------------------------------- /Slack/Client.php: -------------------------------------------------------------------------------- 1 | connection = $connection; 26 | } 27 | 28 | /** 29 | * @param string $action 30 | * @param array $parameter 31 | * @param bool $multipart Whether to use multipart/form-data or the default application/x-www-form-urlencoded 32 | * 33 | * @return Response|bool 34 | */ 35 | public function send($action, array $parameter = [], $multipart = false) 36 | { 37 | if (!$this->connection->isValid()) { 38 | return false; 39 | } 40 | 41 | $action = Actions::loadClass($action); 42 | $action->setParameter($parameter); 43 | 44 | $parsedRequestParams = array_merge( 45 | ['token' => $this->connection->getToken()], 46 | $action->getRenderedRequestParams() 47 | ); 48 | 49 | $url = $this->buildUri($action, $parsedRequestParams); 50 | 51 | $tries = 1; 52 | do { 53 | $response = $this->executeRequest( 54 | $url, 55 | $this->connection->getHttpMethod() === Request::METHOD_POST ? $parsedRequestParams : null, 56 | $multipart 57 | ); 58 | $response = Response::parseGuzzleResponse($response, $action); 59 | 60 | if ( 61 | $response->getStatus() === true || 62 | ($response->getStatus() === false && $response->getError() != Response::ERROR_RATE_LIMITED) 63 | ) { 64 | break; 65 | } 66 | 67 | ++$tries; 68 | 69 | } while ($tries <= $this->connection->getLimitRetries()); 70 | 71 | 72 | return $response; 73 | } 74 | 75 | /** 76 | * @param Actions\ActionsInterface $action 77 | * @param array $requestParams 78 | * 79 | * @return Uri 80 | */ 81 | protected function buildUri(Actions\ActionsInterface $action, array $requestParams) 82 | { 83 | $uri = $this->connection->getEndpoint() . '/' . $action->getAction(); 84 | 85 | if ($this->connection->getHttpMethod() === Request::METHOD_GET) { 86 | $uri .= '?' . http_build_query($requestParams); 87 | } 88 | 89 | return new Uri($uri); 90 | } 91 | 92 | /** 93 | * @param Uri $uri 94 | * @param array $params form post values 95 | * @param bool $multipart Whether to use multipart/form-data or the default application/x-www-form-urlencoded 96 | * 97 | * @return \GuzzleHttp\Psr7\Response 98 | */ 99 | protected function executeRequest(Uri $uri, array $params = null, $multipart = false) 100 | { 101 | $guzzle = new GuzzleClient(['verify' => $this->connection->getVerifySsl()]); 102 | 103 | if (null !== $params) { 104 | if ($multipart) { 105 | $multipartParams = []; 106 | foreach ($params as $paramName => $paramValue) { 107 | $multipartParams[] = [ 108 | 'name' => $paramName, 109 | 'contents' => $paramValue, 110 | ]; 111 | } 112 | $postParams = ['multipart' => $multipartParams]; 113 | } else { 114 | $postParams = ['form_params' => $params]; 115 | } 116 | } else { 117 | $postParams = []; 118 | } 119 | 120 | return $guzzle->request( 121 | $this->connection->getHttpMethod(), 122 | $uri, 123 | $postParams 124 | ); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /Slack/Client/Actions.php: -------------------------------------------------------------------------------- 1 | 'ChatPostMessage', 26 | self::ACTION_CHANNELS_LIST => 'ChannelsList', 27 | self::ACTION_API_TEST => 'ApiTest', 28 | self::ACTION_AUTH_TEST => 'AuthTest', 29 | self::ACTION_CHANNELS_SET_TOPIC => 'ChannelsSetTopic', 30 | self::ACTION_CHANNELS_INFO => 'ChannelsInfo', 31 | self::ACTION_CHANNELS_INVITE => 'ChannelsInvite', 32 | self::ACTION_CHANNELS_HISTORY => 'ChannelsHistory', 33 | self::ACTION_CHANNELS_CREATE => 'ChannelsCreate', 34 | self::ACTION_FILES_UPLOAD => 'FilesUpload', 35 | self::ACTION_USERS_LIST => 'UsersList' 36 | ]; 37 | 38 | /** 39 | * @param string $action 40 | * @return ActionsInterface 41 | * @throws \Exception 42 | */ 43 | public static function loadClass($action) 44 | { 45 | if (!array_key_exists($action, self::$classes)) { 46 | throw new \Exception('the called action "' . $action . '" does not exist'); 47 | } 48 | 49 | $classname = '\\DZunke\\SlackBundle\\Slack\\Client\\Actions\\' . self::$classes[$action]; 50 | 51 | return new $classname; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Slack/Client/Actions/ActionsInterface.php: -------------------------------------------------------------------------------- 1 | parameter; 24 | } 25 | 26 | /** 27 | * @param array $parameter 28 | * @return $this 29 | */ 30 | public function setParameter(array $parameter) 31 | { 32 | return $this; 33 | } 34 | 35 | /** 36 | * @return string 37 | */ 38 | public function getAction() 39 | { 40 | return Actions::ACTION_API_TEST; 41 | } 42 | 43 | /** 44 | * @param array $response 45 | * @return array 46 | */ 47 | public function parseResponse(array $response) 48 | { 49 | return []; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Slack/Client/Actions/AuthTest.php: -------------------------------------------------------------------------------- 1 | parameter; 24 | } 25 | 26 | /** 27 | * @param array $parameter 28 | * @return $this 29 | */ 30 | public function setParameter(array $parameter) 31 | { 32 | return $this; 33 | } 34 | 35 | /** 36 | * @return string 37 | */ 38 | public function getAction() 39 | { 40 | return Actions::ACTION_AUTH_TEST; 41 | } 42 | 43 | /** 44 | * @param array $response 45 | * @return array 46 | */ 47 | public function parseResponse(array $response) 48 | { 49 | return [ 50 | 'user' => $response['user'] 51 | ]; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Slack/Client/Actions/ChannelsCreate.php: -------------------------------------------------------------------------------- 1 | null 18 | ]; 19 | 20 | /** 21 | * @return array 22 | * @throws \Exception 23 | */ 24 | public function getRenderedRequestParams() 25 | { 26 | if (is_null($this->parameter['name'])) { 27 | throw new \Exception('the channel name must be given'); 28 | } 29 | 30 | return $this->parameter; 31 | } 32 | 33 | /** 34 | * @param array $parameter 35 | * @return $this 36 | */ 37 | public function setParameter(array $parameter) 38 | { 39 | foreach ($parameter as $key => $value) { 40 | if (array_key_exists($key, $this->parameter)) { 41 | $this->parameter[$key] = $value; 42 | } 43 | } 44 | 45 | return $this; 46 | } 47 | 48 | /** 49 | * @return string 50 | */ 51 | public function getAction() 52 | { 53 | return Actions::ACTION_CHANNELS_CREATE; 54 | } 55 | 56 | /** 57 | * @param array $response 58 | * @return array 59 | */ 60 | public function parseResponse(array $response) 61 | { 62 | return $response['channel']; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Slack/Client/Actions/ChannelsHistory.php: -------------------------------------------------------------------------------- 1 | null, 18 | 'oldest' => null, 19 | 'count' => 10 20 | ]; 21 | 22 | /** 23 | * @return array 24 | */ 25 | public function getRenderedRequestParams() 26 | { 27 | return $this->parameter; 28 | } 29 | 30 | /** 31 | * @param array $parameter 32 | * @return $this 33 | */ 34 | public function setParameter(array $parameter) 35 | { 36 | foreach ($parameter as $key => $value) { 37 | if (array_key_exists($key, $this->parameter)) { 38 | $this->parameter[$key] = $value; 39 | } 40 | } 41 | 42 | return $this; 43 | } 44 | 45 | /** 46 | * @return string 47 | */ 48 | public function getAction() 49 | { 50 | return Actions::ACTION_CHANNELS_HISTORY; 51 | } 52 | 53 | /** 54 | * @param array $response 55 | * @return array 56 | */ 57 | public function parseResponse(array $response) 58 | { 59 | return $response; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Slack/Client/Actions/ChannelsInfo.php: -------------------------------------------------------------------------------- 1 | null 18 | ]; 19 | 20 | /** 21 | * @return array 22 | */ 23 | public function getRenderedRequestParams() 24 | { 25 | return $this->parameter; 26 | } 27 | 28 | /** 29 | * @param array $parameter 30 | * @return $this 31 | */ 32 | public function setParameter(array $parameter) 33 | { 34 | foreach ($parameter as $key => $value) { 35 | if (array_key_exists($key, $this->parameter)) { 36 | $this->parameter[$key] = $value; 37 | } 38 | } 39 | 40 | return $this; 41 | } 42 | 43 | /** 44 | * @return string 45 | */ 46 | public function getAction() 47 | { 48 | return Actions::ACTION_CHANNELS_INFO; 49 | } 50 | 51 | /** 52 | * @param array $response 53 | * @return array 54 | */ 55 | public function parseResponse(array $response) 56 | { 57 | return [ 58 | 'id' => $response['channel']['id'], 59 | 'name' => $response['channel']['name'], 60 | 'active' => $response['channel']['is_archived'], 61 | 'topic' => $response['channel']['topic']['value'], 62 | ]; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Slack/Client/Actions/ChannelsInvite.php: -------------------------------------------------------------------------------- 1 | null, 18 | 'user' => null 19 | ]; 20 | 21 | /** 22 | * @return array 23 | * @throws \Exception 24 | */ 25 | public function getRenderedRequestParams() 26 | { 27 | if (is_null($this->parameter['channel']) || is_null($this->parameter['user'])) { 28 | throw new \Exception('both parameters channel and user must be given'); 29 | } 30 | 31 | return $this->parameter; 32 | } 33 | 34 | /** 35 | * @param array $parameter 36 | * @return $this 37 | */ 38 | public function setParameter(array $parameter) 39 | { 40 | foreach ($parameter as $key => $value) { 41 | if (array_key_exists($key, $this->parameter)) { 42 | $this->parameter[$key] = $value; 43 | } 44 | } 45 | 46 | return $this; 47 | } 48 | 49 | /** 50 | * @return string 51 | */ 52 | public function getAction() 53 | { 54 | return Actions::ACTION_CHANNELS_INVITE; 55 | } 56 | 57 | /** 58 | * @param array $response 59 | * @return array 60 | */ 61 | public function parseResponse(array $response) 62 | { 63 | return []; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Slack/Client/Actions/ChannelsList.php: -------------------------------------------------------------------------------- 1 | 1 18 | ]; 19 | 20 | /** 21 | * @return array 22 | */ 23 | public function getRenderedRequestParams() 24 | { 25 | return $this->parameter; 26 | } 27 | 28 | /** 29 | * @param array $parameter 30 | * @return $this 31 | */ 32 | public function setParameter(array $parameter) 33 | { 34 | foreach ($parameter as $key => $value) { 35 | if (array_key_exists($key, $this->parameter)) { 36 | $this->parameter[$key] = $value; 37 | } 38 | } 39 | 40 | return $this; 41 | } 42 | 43 | /** 44 | * @return string 45 | */ 46 | public function getAction() 47 | { 48 | return Actions::ACTION_CHANNELS_LIST; 49 | } 50 | 51 | /** 52 | * @param array $response 53 | * @return array 54 | */ 55 | public function parseResponse(array $response) 56 | { 57 | $channels = []; 58 | foreach ($response['channels'] as $channel) { 59 | $channels[$channel['name']] = [ 60 | 'id' => $channel['id'], 61 | 'active' => $channel['is_archived'], 62 | 'topic' => $channel['topic']['value'], 63 | ]; 64 | } 65 | 66 | return $channels; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Slack/Client/Actions/ChannelsSetTopic.php: -------------------------------------------------------------------------------- 1 | null, 18 | 'topic' => null 19 | ]; 20 | 21 | /** 22 | * @return array 23 | */ 24 | public function getRenderedRequestParams() 25 | { 26 | return $this->parameter; 27 | } 28 | 29 | /** 30 | * @param array $parameter 31 | * @return $this 32 | */ 33 | public function setParameter(array $parameter) 34 | { 35 | foreach ($parameter as $key => $value) { 36 | if (array_key_exists($key, $this->parameter)) { 37 | $this->parameter[$key] = $value; 38 | } 39 | } 40 | 41 | return $this; 42 | } 43 | 44 | /** 45 | * @return string 46 | */ 47 | public function getAction() 48 | { 49 | return Actions::ACTION_CHANNELS_SET_TOPIC; 50 | } 51 | 52 | /** 53 | * @param array $response 54 | * @return array 55 | */ 56 | public function parseResponse(array $response) 57 | { 58 | return []; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Slack/Client/Actions/ChatPostMessage.php: -------------------------------------------------------------------------------- 1 | null, 19 | 'channel' => null, 20 | 'text' => null, 21 | 'icon_url' => null, 22 | 'icon_emoji' => null, 23 | 'parse' => 'full', 24 | 'link_names' => 1, 25 | 'unfurl_links' => 1, 26 | 'attachments' => [], 27 | ]; 28 | 29 | /** 30 | * @return array 31 | * @throws \Exception 32 | */ 33 | public function getRenderedRequestParams() 34 | { 35 | if (is_null($this->parameter['identity']) || !$this->parameter['identity'] instanceof Identity) { 36 | throw new \Exception('no identity given'); 37 | } 38 | 39 | $this->parseIdentity(); 40 | $this->parseAttachments(); 41 | 42 | return $this->parameter; 43 | } 44 | 45 | private function parseAttachments() 46 | { 47 | if (empty($this->parameter['attachments'])) { 48 | return; 49 | } 50 | 51 | $attachments = []; 52 | foreach ($this->parameter['attachments'] as $attachmentObj) { 53 | if (!$attachmentObj instanceof Attachment) { 54 | throw new \Exception('atachments must be instance of \DZunke\SlackBundle\Slack\Entity\MessageAttachment'); 55 | } 56 | 57 | $attachments[] = $attachmentObj->toArray(); 58 | } 59 | $this->parameter['attachments'] = json_encode($attachments); 60 | } 61 | 62 | private function parseIdentity() 63 | { 64 | $this->parameter['username'] = $this->parameter['identity']->getUsername(); 65 | if (empty($this->parameter['icon_url']) && $iconUrl = $this->parameter['identity']->getIconUrl()) { 66 | $this->parameter['icon_url'] = $iconUrl; 67 | } 68 | if (empty($this->parameter['icon_emoji']) && $iconEmoji = $this->parameter['identity']->getIconEmoji()) { 69 | $this->parameter['icon_emoji'] = $iconEmoji; 70 | } 71 | unset($this->parameter['identity']); 72 | } 73 | 74 | /** 75 | * @param array $parameter 76 | * @return $this 77 | */ 78 | public function setParameter(array $parameter) 79 | { 80 | foreach ($parameter as $key => $value) { 81 | if (array_key_exists($key, $this->parameter)) { 82 | $this->parameter[$key] = $value; 83 | } 84 | } 85 | 86 | return $this; 87 | } 88 | 89 | /** 90 | * @return string 91 | */ 92 | public function getAction() 93 | { 94 | return Actions::ACTION_POST_MESSAGE; 95 | } 96 | 97 | /** 98 | * @param array $response 99 | * @return array 100 | */ 101 | public function parseResponse(array $response) 102 | { 103 | return [ 104 | 'timestamp' => $response['ts'] 105 | ]; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /Slack/Client/Actions/FilesUpload.php: -------------------------------------------------------------------------------- 1 | null, 18 | 'filetype' => null, 19 | 'filename' => null, 20 | 'title' => null, 21 | 'initial_comment' => null, 22 | 'channels' => null 23 | ]; 24 | 25 | /** 26 | * @return array 27 | */ 28 | public function getRenderedRequestParams() 29 | { 30 | return $this->parameter; 31 | } 32 | 33 | /** 34 | * @param array $parameter 35 | * @return $this 36 | */ 37 | public function setParameter(array $parameter) 38 | { 39 | foreach ($parameter as $key => $value) { 40 | if (array_key_exists($key, $this->parameter)) { 41 | $this->parameter[$key] = $value; 42 | } 43 | } 44 | 45 | return $this; 46 | } 47 | 48 | /** 49 | * @return string 50 | */ 51 | public function getAction() 52 | { 53 | return Actions::ACTION_FILES_UPLOAD; 54 | } 55 | 56 | /** 57 | * @param array $response 58 | * @return array 59 | */ 60 | public function parseResponse(array $response) 61 | { 62 | if (isset($response['ok']) && $response['ok'] === true) { 63 | return $response['file']; 64 | } 65 | 66 | return $response; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Slack/Client/Actions/UsersList.php: -------------------------------------------------------------------------------- 1 | 1 18 | ]; 19 | 20 | /** 21 | * @return array 22 | */ 23 | public function getRenderedRequestParams() 24 | { 25 | return $this->parameter; 26 | } 27 | 28 | /** 29 | * @param array $parameter 30 | * @return $this 31 | */ 32 | public function setParameter(array $parameter) 33 | { 34 | foreach ($parameter as $key => $value) { 35 | if (array_key_exists($key, $this->parameter)) { 36 | $this->parameter[$key] = $value; 37 | } 38 | } 39 | 40 | return $this; 41 | } 42 | 43 | /** 44 | * @return string 45 | */ 46 | public function getAction() 47 | { 48 | return Actions::ACTION_USERS_LIST; 49 | } 50 | 51 | /** 52 | * @param array $response 53 | * @return array 54 | */ 55 | public function parseResponse(array $response) 56 | { 57 | $users = []; 58 | foreach ($response['members'] as $user) { 59 | $users[$user['name']] = [ 60 | 'id' => $user['id'], 61 | 'name' => $user['name'], 62 | 'deleted' => (bool)$user['deleted'], 63 | 'real_name' => $user['profile']['real_name'], 64 | 'email' => isset($user['profile']['email']) ? $user['profile']['email'] : null, 65 | 'is_bot' => (bool)$user['is_bot'], 66 | 'presence' => isset($user['presence']) ? $user['presence'] : null 67 | ]; 68 | } 69 | 70 | return $users; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Slack/Client/Connection.php: -------------------------------------------------------------------------------- 1 | endpoint; 40 | } 41 | 42 | /** 43 | * @param string $endpoint 44 | * 45 | * @return $this 46 | */ 47 | public function setEndpoint($endpoint) 48 | { 49 | $this->endpoint = (string)$endpoint; 50 | 51 | return $this; 52 | } 53 | 54 | /** 55 | * @return string 56 | */ 57 | public function getToken() 58 | { 59 | return $this->token; 60 | } 61 | 62 | /** 63 | * @param string $token 64 | * 65 | * @return $this 66 | */ 67 | public function setToken($token) 68 | { 69 | $this->token = (string)$token; 70 | 71 | return $this; 72 | } 73 | 74 | /** 75 | * @return int 76 | */ 77 | public function getLimitRetries() 78 | { 79 | return $this->limitRetries; 80 | } 81 | 82 | /** 83 | * @param int $retries 84 | * 85 | * @return $this 86 | */ 87 | public function setLimitRetries($retries) 88 | { 89 | $this->limitRetries = (int)$retries; 90 | 91 | return $this; 92 | } 93 | 94 | /** 95 | * @return bool 96 | */ 97 | public function getVerifySsl() 98 | { 99 | return $this->verifySsl; 100 | } 101 | 102 | /** 103 | * @param bool $verifySsl 104 | * 105 | * @return $this 106 | */ 107 | public function setVerifySsl($verifySsl) 108 | { 109 | $this->verifySsl = (bool)$verifySsl; 110 | 111 | return $this; 112 | } 113 | 114 | /** 115 | * @return string 116 | */ 117 | public function getHttpMethod() 118 | { 119 | return $this->httpMethod; 120 | } 121 | 122 | /** 123 | * @return $this 124 | */ 125 | public function isHttpGetMethod() 126 | { 127 | $this->httpMethod = Request::METHOD_GET; 128 | 129 | return $this; 130 | } 131 | 132 | /** 133 | * @return $this 134 | */ 135 | public function isHttpPostMethod() 136 | { 137 | $this->httpMethod = Request::METHOD_POST; 138 | 139 | return $this; 140 | } 141 | 142 | /** 143 | * @return bool 144 | */ 145 | public function isValid() 146 | { 147 | return (!empty($this->endpoint) && !empty($this->token)); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /Slack/Client/Response.php: -------------------------------------------------------------------------------- 1 | status = (bool)$status; 42 | 43 | return $this; 44 | } 45 | 46 | /** 47 | * @return bool 48 | */ 49 | public function getStatus() 50 | { 51 | return $this->status; 52 | } 53 | 54 | /** 55 | * @param string $error 56 | * @return $this 57 | */ 58 | public function setError($error) 59 | { 60 | $this->error = $error; 61 | 62 | return $this; 63 | } 64 | 65 | /** 66 | * @return string 67 | */ 68 | public function getError() 69 | { 70 | return $this->error; 71 | } 72 | 73 | /** 74 | * @param array $data 75 | * @return $this 76 | */ 77 | public function setData(array $data) 78 | { 79 | $this->data = $data; 80 | 81 | return $this; 82 | } 83 | 84 | /** 85 | * @return array 86 | */ 87 | public function getData() 88 | { 89 | return $this->data; 90 | } 91 | 92 | /** 93 | * @param \GuzzleHttp\Psr7\Response $guzzleResponse 94 | * @param ActionsInterface $action 95 | * @return Response 96 | */ 97 | public static function parseGuzzleResponse(\GuzzleHttp\Psr7\Response $guzzleResponse, ActionsInterface $action) 98 | { 99 | $response = new self(); 100 | 101 | if ($guzzleResponse->getStatusCode() != 200) { 102 | $response->setStatus(false); 103 | $response->setError($response::ERROR_REQUEST_ERROR); 104 | 105 | return $response; 106 | } 107 | 108 | $responseArray = json_decode($guzzleResponse->getBody()->getContents(), true); 109 | 110 | $response->setStatus($responseArray['ok']); 111 | 112 | if ($response->getStatus() === false) { 113 | $response->setError($responseArray['error']); 114 | 115 | return $response; 116 | } 117 | 118 | $response->setData($action->parseResponse($responseArray)); 119 | 120 | return $response; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Slack/Entity/Message.php: -------------------------------------------------------------------------------- 1 | id; 55 | } 56 | 57 | /** 58 | * @param string $id 59 | * @return $this 60 | */ 61 | public function setId($id) 62 | { 63 | $this->id = $id; 64 | 65 | return $this; 66 | } 67 | 68 | /** 69 | * @return string 70 | */ 71 | public function getChannel() 72 | { 73 | return $this->channel; 74 | } 75 | 76 | /** 77 | * @param string $channel 78 | * @return $this 79 | */ 80 | public function setChannel($channel) 81 | { 82 | $this->channel = $channel; 83 | 84 | return $this; 85 | } 86 | 87 | /** 88 | * @return string 89 | */ 90 | public function getType() 91 | { 92 | return $this->type; 93 | } 94 | 95 | /** 96 | * @param string $type 97 | * @return $this 98 | */ 99 | public function setType($type) 100 | { 101 | $this->type = $type; 102 | 103 | return $this; 104 | } 105 | 106 | /** 107 | * @return string 108 | */ 109 | public function getUserId() 110 | { 111 | return $this->userId; 112 | } 113 | 114 | /** 115 | * @param string $userId 116 | * @return $this 117 | */ 118 | public function setUserId($userId) 119 | { 120 | $this->userId = $userId; 121 | 122 | return $this; 123 | } 124 | 125 | /** 126 | * @return string 127 | */ 128 | public function getUsername() 129 | { 130 | return $this->username; 131 | } 132 | 133 | /** 134 | * @param string $username 135 | * @return $this 136 | */ 137 | public function setUsername($username) 138 | { 139 | $this->username = $username; 140 | 141 | return $this; 142 | } 143 | 144 | /** 145 | * @return bool 146 | */ 147 | public function isBot() 148 | { 149 | return !empty($this->id) && empty($this->userId) && !empty($this->username); 150 | } 151 | 152 | /** 153 | * @return string 154 | */ 155 | public function getContent() 156 | { 157 | return $this->content; 158 | } 159 | 160 | /** 161 | * @param string $content 162 | * @return $this 163 | */ 164 | public function setContent($content) 165 | { 166 | $this->content = $content; 167 | 168 | return $this; 169 | } 170 | 171 | /** 172 | * @return MessageAttachment[] 173 | */ 174 | public function getAttachments() 175 | { 176 | return $this->attachments; 177 | } 178 | 179 | /** 180 | * @param MessageAttachment $attachment 181 | * @return $this 182 | */ 183 | public function addAttachment(MessageAttachment $attachment) 184 | { 185 | $this->attachments[] = $attachment; 186 | 187 | return $this; 188 | } 189 | 190 | /** 191 | * @param MessageAttachment[] $attachments 192 | * @return $this 193 | */ 194 | public function setAttachments($attachments) 195 | { 196 | $this->attachments = $attachments; 197 | 198 | return $this; 199 | } 200 | 201 | } 202 | -------------------------------------------------------------------------------- /Slack/Entity/MessageAttachment.php: -------------------------------------------------------------------------------- 1 | authorIcon; 136 | } 137 | 138 | /** 139 | * @param string $authorIcon 140 | * 141 | * @return $this 142 | */ 143 | public function setAuthorIcon($authorIcon) 144 | { 145 | $this->authorIcon = $authorIcon; 146 | 147 | return $this; 148 | } 149 | 150 | /** 151 | * @return string 152 | */ 153 | public function getAuthorLink() 154 | { 155 | return $this->authorLink; 156 | } 157 | 158 | /** 159 | * @param string $authorLink 160 | * 161 | * @return $this 162 | */ 163 | public function setAuthorLink($authorLink) 164 | { 165 | $this->authorLink = $authorLink; 166 | 167 | return $this; 168 | } 169 | 170 | /** 171 | * @return string 172 | */ 173 | public function getAuthorName() 174 | { 175 | return $this->authorName; 176 | } 177 | 178 | /** 179 | * @param string $authorName 180 | * 181 | * @return $this 182 | */ 183 | public function setAuthorName($authorName) 184 | { 185 | $this->authorName = $authorName; 186 | 187 | return $this; 188 | } 189 | 190 | /** 191 | * @param string $color 192 | * 193 | * @return $this 194 | */ 195 | public function setColor($color) 196 | { 197 | $this->color = $color; 198 | 199 | return $this; 200 | } 201 | 202 | /** 203 | * @return string 204 | */ 205 | public function getColor() 206 | { 207 | return $this->color; 208 | } 209 | 210 | /** 211 | * @param string $fallback 212 | * 213 | * @return $this 214 | */ 215 | public function setFallback($fallback) 216 | { 217 | $this->fallback = $fallback; 218 | 219 | return $this; 220 | } 221 | 222 | /** 223 | * @return string 224 | */ 225 | public function getFallback() 226 | { 227 | return $this->fallback; 228 | } 229 | 230 | /** 231 | * @return string 232 | */ 233 | public function getImageUrl() 234 | { 235 | return $this->imageUrl; 236 | } 237 | 238 | /** 239 | * @param string $imageUrl 240 | * 241 | * @return $this 242 | */ 243 | public function setImageUrl($imageUrl) 244 | { 245 | $this->imageUrl = $imageUrl; 246 | 247 | return $this; 248 | } 249 | 250 | /** 251 | * @param array $fields 252 | * 253 | * @return $this 254 | */ 255 | public function setFields(array $fields) 256 | { 257 | $this->fields = $fields; 258 | 259 | return $this; 260 | } 261 | 262 | /** 263 | * @param string $title 264 | * @param string $text 265 | * @param bool $scale 266 | * 267 | * @return $this 268 | */ 269 | public function addField($title, $text, $scale = false) 270 | { 271 | $this->fields[] = [ 272 | 'title' => (string) $title, 273 | 'value' => (string) $text, 274 | 'short' => $scale, 275 | ]; 276 | 277 | return $this; 278 | } 279 | 280 | /** 281 | * @return array 282 | */ 283 | public function getFields() 284 | { 285 | return $this->fields; 286 | } 287 | 288 | /** 289 | * @param array $actions 290 | * 291 | * @return $this 292 | */ 293 | public function setActions(array $actions) 294 | { 295 | $this->actions = $actions; 296 | 297 | return $this; 298 | } 299 | 300 | /** 301 | * @param string $text 302 | * @param string $url 303 | * @param string $style 304 | * 305 | * @return $this 306 | */ 307 | public function addAction($text, $url, $style = null) 308 | { 309 | $this->actions[] = [ 310 | 'type' => 'button', 311 | 'text' => (string) $text, 312 | 'url' => (string) $url, 313 | 'style' => (string) $style, 314 | ]; 315 | 316 | return $this; 317 | } 318 | 319 | /** 320 | * @return array 321 | */ 322 | public function getActions() 323 | { 324 | return $this->actions; 325 | } 326 | 327 | /** 328 | * @param string $pretext 329 | * 330 | * @return $this 331 | */ 332 | public function setPretext($pretext) 333 | { 334 | $this->pretext = $pretext; 335 | 336 | return $this; 337 | } 338 | 339 | /** 340 | * @return string 341 | */ 342 | public function getPretext() 343 | { 344 | return $this->pretext; 345 | } 346 | 347 | /** 348 | * @param string $text 349 | * 350 | * @return $this 351 | */ 352 | public function setText($text) 353 | { 354 | $this->text = $text; 355 | 356 | return $this; 357 | } 358 | 359 | /** 360 | * @return string 361 | */ 362 | public function getText() 363 | { 364 | return $this->text; 365 | } 366 | 367 | /** 368 | * @return string 369 | */ 370 | public function getTitle() 371 | { 372 | return $this->title; 373 | } 374 | 375 | /** 376 | * @param string $title 377 | * 378 | * @return $this 379 | */ 380 | public function setTitle($title) 381 | { 382 | $this->title = $title; 383 | 384 | return $this; 385 | } 386 | 387 | /** 388 | * @return string 389 | */ 390 | public function getTitleLink() 391 | { 392 | return $this->titleLink; 393 | } 394 | 395 | /** 396 | * @param string $titleLink 397 | * 398 | * @return $this 399 | */ 400 | public function setTitleLink($titleLink) 401 | { 402 | $this->titleLink = $titleLink; 403 | 404 | return $this; 405 | } 406 | 407 | /** 408 | * @return string 409 | */ 410 | public function getThumbUrl() 411 | { 412 | return $this->thumbUrl; 413 | } 414 | 415 | /** 416 | * @param string $thumbUrl 417 | * 418 | * @return $this 419 | */ 420 | public function setThumbUrl($thumbUrl) 421 | { 422 | $this->thumbUrl = $thumbUrl; 423 | 424 | return $this; 425 | } 426 | 427 | /** 428 | * @return string 429 | */ 430 | public function getFooter() 431 | { 432 | return $this->footer; 433 | } 434 | 435 | /** 436 | * @param string $footer 437 | */ 438 | public function setFooter($footer) 439 | { 440 | $this->footer = $footer; 441 | } 442 | 443 | /** 444 | * @return string 445 | */ 446 | public function getFooterIcon() 447 | { 448 | return $this->footerIcon; 449 | } 450 | 451 | /** 452 | * @param string $footerIcon 453 | */ 454 | public function setFooterIcon($footerIcon) 455 | { 456 | $this->footerIcon = $footerIcon; 457 | } 458 | 459 | /** 460 | * @return int 461 | */ 462 | public function getTs() 463 | { 464 | return $this->ts; 465 | } 466 | 467 | /** 468 | * @param int $ts 469 | */ 470 | public function setTs($ts) 471 | { 472 | $this->ts = $ts; 473 | } 474 | 475 | /** 476 | * @return array 477 | */ 478 | public function toArray() 479 | { 480 | return [ 481 | 'fallback' => $this->getFallback(), 482 | 'color' => $this->getColor(), 483 | 'pretext' => $this->getPretext(), 484 | 'author_name' => $this->getAuthorName(), 485 | 'author_link' => $this->getAuthorLink(), 486 | 'author_icon' => $this->getAuthorIcon(), 487 | 'title' => $this->getTitle(), 488 | 'title_link' => $this->getTitleLink(), 489 | 'text' => $this->getText(), 490 | 'fields' => $this->getFields(), 491 | 'image_url' => $this->getImageUrl(), 492 | 'thumb_url' => $this->getThumbUrl(), 493 | 'footer' => $this->getFooter(), 494 | 'footer_icon' => $this->getFooterIcon(), 495 | 'ts' => $this->getTs(), 496 | 'actions' => $this->getActions(), 497 | ]; 498 | } 499 | } 500 | -------------------------------------------------------------------------------- /Slack/Messaging.php: -------------------------------------------------------------------------------- 1 | client = $client; 28 | $this->identityBag = $identityBag; 29 | } 30 | 31 | /** 32 | * @return IdentityBag 33 | */ 34 | public function getIdentityBag() 35 | { 36 | return $this->identityBag; 37 | } 38 | 39 | /** 40 | * @return Client 41 | */ 42 | public function getClient() 43 | { 44 | return $this->client; 45 | } 46 | 47 | /** 48 | * @param string $channel 49 | * @param string $message 50 | * @param string $identity 51 | * @param Attachment[] $attachments 52 | * @param array $clientOptions 53 | * 54 | * @return Client\Response|bool 55 | * 56 | * @throws \InvalidArgumentException 57 | */ 58 | public function message($channel, $message, $identity, array $attachments = [], array $clientOptions = []) 59 | { 60 | if (!$this->identityBag->has($identity)) { 61 | throw new \InvalidArgumentException(sprintf('identity "%s" is not registered', $identity)); 62 | } 63 | 64 | return $this->client->send( 65 | Actions::ACTION_POST_MESSAGE, 66 | array_merge([ 67 | 'identity' => $this->identityBag->get($identity), 68 | 'channel' => $channel, 69 | 'text' => $message, 70 | 'attachments' => $attachments, 71 | ], $clientOptions) 72 | ); 73 | } 74 | 75 | /** 76 | * @param string|array $channel # String is DEPRECATED scince v1.3 - Deliver Array 77 | * @param string $title 78 | * @param string $file 79 | * @param string|null $comment 80 | * @param string|null $threadTs 81 | * 82 | * @return Client\Response|false 83 | */ 84 | public function upload($channel, $title, $file, $comment = null, $threadTs = null) 85 | { 86 | if (!file_exists($file)) { 87 | return false; 88 | } 89 | 90 | if (!is_array($channel)) { 91 | @trigger_error('Channel as String is deprecated scince v1.3, please deliver an Array of Channels', E_USER_DEPRECATED); 92 | $channel = [$channel]; 93 | } 94 | 95 | $params = []; 96 | $params['title'] = $title; 97 | $params['initial_comment'] = $comment; 98 | $params['channels'] = implode(',', $channel); 99 | $params['filename'] = basename($file); 100 | $params['file'] = fopen($file, 'r'); 101 | $params['thread_ts'] = $threadTs; 102 | 103 | return $this->client->send( 104 | Actions::ACTION_FILES_UPLOAD, 105 | $params, 106 | true 107 | ); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Slack/Messaging/Identity.php: -------------------------------------------------------------------------------- 1 | username = (string)$username; 31 | 32 | return $this; 33 | } 34 | 35 | /** 36 | * @return string 37 | */ 38 | public function getUsername() 39 | { 40 | return $this->username; 41 | } 42 | 43 | /** 44 | * @param string $iconUrl 45 | * @return $this 46 | */ 47 | public function setIconUrl($iconUrl) 48 | { 49 | $this->iconUrl = (string)$iconUrl; 50 | 51 | return $this; 52 | } 53 | 54 | /** 55 | * @return string 56 | */ 57 | public function getIconUrl() 58 | { 59 | return $this->iconUrl; 60 | } 61 | 62 | /** 63 | * @param string $iconEmoji 64 | * @return mixed 65 | */ 66 | public function setIconEmoji($iconEmoji) 67 | { 68 | $this->iconEmoji = $iconEmoji; 69 | 70 | return $this->iconEmoji; 71 | } 72 | 73 | /** 74 | * @return string 75 | */ 76 | public function getIconEmoji() 77 | { 78 | return $this->iconEmoji; 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /Slack/Messaging/IdentityBag.php: -------------------------------------------------------------------------------- 1 | $config) { 25 | $identObj = new Identity(); 26 | $identObj->setUsername($username); 27 | $identObj->setIconEmoji((isset($config['icon_emoji']) ? $config['icon_emoji'] : null)); 28 | $identObj->setIconUrl((isset($config['icon_url']) ? $config['icon_url'] : null)); 29 | 30 | $this->add($identObj); 31 | } 32 | 33 | return $this; 34 | } 35 | 36 | /** 37 | * @param string $username 38 | * @return bool 39 | */ 40 | public function has($username) 41 | { 42 | if (array_key_exists($username, $this->identities)) { 43 | return true; 44 | } 45 | 46 | return false; 47 | } 48 | 49 | /** 50 | * @param Identity $identity 51 | * @return $this 52 | */ 53 | public function add(Identity $identity) 54 | { 55 | $this->identities[$identity->getUsername()] = $identity; 56 | 57 | return $this; 58 | } 59 | 60 | /** 61 | * @param string $username 62 | * @return Identity 63 | * @throws \Exception 64 | */ 65 | public function get($username) 66 | { 67 | if (!isset($this->identities[$username])) { 68 | throw new \Exception('identity "' . $username . '" does not exists'); 69 | } 70 | 71 | return $this->identities[$username]; 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /Slack/Users.php: -------------------------------------------------------------------------------- 1 | client = $client; 20 | } 21 | 22 | /** 23 | * @return Client 24 | */ 25 | public function getClient() 26 | { 27 | return $this->client; 28 | } 29 | 30 | /** 31 | * @return array 32 | */ 33 | public function getUsers() 34 | { 35 | return $this->client->send(Actions::ACTION_USERS_LIST)->getData(); 36 | } 37 | 38 | /** 39 | * @return array 40 | */ 41 | public function getActiveUsers() 42 | { 43 | return array_filter( 44 | $this->getUsers(), 45 | function ($user) { 46 | return $user['deleted'] === false; 47 | } 48 | ); 49 | } 50 | 51 | /** 52 | * @return array 53 | */ 54 | public function getDeletedUsers() 55 | { 56 | return array_filter( 57 | $this->getUsers(), 58 | function ($user) { 59 | return $user['deleted'] === true; 60 | } 61 | ); 62 | } 63 | 64 | /** 65 | * @param string $name 66 | * @return null|array 67 | */ 68 | public function getUser($name) 69 | { 70 | $users = $this->getUsers(); 71 | 72 | return array_key_exists($name, $users) ? $users[$name] : null; 73 | } 74 | 75 | /** 76 | * @param string $name 77 | * @return null|array 78 | */ 79 | public function getId($name) 80 | { 81 | $user = $this->getUser($name); 82 | 83 | return !is_null($user) ? $user['id'] : null; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dzunke/slack-bundle", 3 | "description": "Symfony2 Integration for Slack - supporting Monolog", 4 | "keywords": ["symfony", "api", "bundle", "slack", "monolog", "logger", "messaging"], 5 | "homepage": "https://github.com/DZunke/SlackBundle", 6 | "license": "MIT", 7 | "minimum-stability": "dev", 8 | "authors": [ 9 | { 10 | "name": "Denis Zunke", 11 | "email": "denis.zunke@gmail.com" 12 | } 13 | ], 14 | "archive": { 15 | "exclude": ["/Tests"] 16 | }, 17 | "require": { 18 | "php": ">=5.6", 19 | "symfony/console": "~2.8|~3.0|~4.0", 20 | "symfony/config": "~2.8|~3.0|~4.0", 21 | "symfony/dependency-injection": "~2.8|~3.0|~4.0", 22 | "symfony/http-foundation": "~2.8|~3.0|~4.0", 23 | "symfony/event-dispatcher": "~2.8|~3.0|~4.0", 24 | "monolog/monolog": "^1", 25 | "guzzlehttp/guzzle": "^6.2.1" 26 | }, 27 | "autoload": { 28 | "psr-0": { "DZunke\\SlackBundle": "" } 29 | }, 30 | "target-dir": "DZunke/SlackBundle", 31 | "extra": { 32 | "branch-alias": { 33 | "dev-dev": "2.0-dev" 34 | } 35 | } 36 | } 37 | --------------------------------------------------------------------------------