diff --git a/COPYING.txt b/COPYING.txt new file mode 100755 index 0000000..ebb33d5 --- /dev/null +++ b/COPYING.txt @@ -0,0 +1,16 @@ +/** + * MageSpecialist + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to info@magespecialist.it so we can send you a copy immediately. + * + * @copyright Copyright (c) 2018 Skeeller srl (http://www.magespecialist.it) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ diff --git a/Command/Telegram/GetChatIds.php b/Command/Telegram/GetChatIds.php new file mode 100755 index 0000000..be35ee2 --- /dev/null +++ b/Command/Telegram/GetChatIds.php @@ -0,0 +1,72 @@ +getChatIds = $getChatIds; + + parent::__construct(); + } + + /** + * @inheritdoc + */ + protected function configure() + { + $this->setName('msp:notifier:telegram:chat_ids'); + $this->setDescription('Print chat IDs for a TelegramBot token'); + + $this->addArgument('token', InputArgument::REQUIRED, 'BOT Token'); + + parent::configure(); + } + + /** + * @inheritdoc + * @SuppressWarnings("PHPMD.UnusedFormalParameter") + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $token = $input->getArgument('token'); + $chatIds = $this->getChatIds->execute($token); + + // @codingStandardsIgnoreStart + $table = new Table($output); + // @codingStandardsIgnoreEnd + $table->setHeaders(['Chat ID', 'Name']); + + $tableRows = []; + foreach ($chatIds as $chatId => $title) { + $tableRows[] = [$chatId, $title]; + } + + $table->setRows($tableRows); + $table->render(); + } +} diff --git a/Model/AdapterEngine/Email.php b/Model/AdapterEngine/Email.php new file mode 100644 index 0000000..62d08f8 --- /dev/null +++ b/Model/AdapterEngine/Email.php @@ -0,0 +1,72 @@ +messageFactory = $messageFactory; + $this->transportFactory = $transportFactory; + } + + /** + * Execute engine and return true on success. Throw exception on failure. + * @param string $message + * @param array $params + * @return bool + * @throws \Magento\Framework\Exception\MailException + */ + public function execute(string $message, array $params = []): bool + { + $lines = explode("\n", $message); + + $emailMessage = $this->messageFactory->create(); + + $emailMessage->setFrom($params['from'], $params['from_name']); + $emailMessage->addTo($params['to']); + $emailMessage->setMessageType(MessageInterface::TYPE_TEXT); + $emailMessage->setBody($message); + $emailMessage->setSubject($lines[0]); + + $transport = $this->transportFactory->create(['message' => $emailMessage]); + $transport->sendMessage(); + + return true; + } +} diff --git a/Model/AdapterEngine/Slack.php b/Model/AdapterEngine/Slack.php new file mode 100755 index 0000000..02039d4 --- /dev/null +++ b/Model/AdapterEngine/Slack.php @@ -0,0 +1,85 @@ +scopeConfig = $scopeConfig; + } + + /** + * Execute engine and return true on success. Throw exception on failure. + * @param string $emailMessage + * @param array $params + * @return bool + */ + public function execute(string $emailMessage, array $params = []): bool + { + $client = $this->getClient($params); + + $client->attach([ + 'fallback' => $emailMessage, + 'text' => $emailMessage, + 'color' => $params[static::PARAM_COLOR] ?: static::DEFAULT_COLOR + ])->send(); + + return true; + } + + /** + * @param array $params + * @return array + */ + private function paramsToSettings(array $params): array + { + return [ + 'userName' => $this->scopeConfig->getValue('general/store_information/name'), + 'channel' => $params[static::PARAM_CHANNEL], + 'icon' => $params[static::PARAM_EMOJI] ?: static::DEFAULT_EMOJI + ]; + } + + /** + * @param array $params + * @return Client + */ + private function getClient(array $params): Client + { + $settings = $this->paramsToSettings($params); + // @codingStandardsIgnoreStart + return new Client($params[static::PARAM_WEBHOOK], $settings); + // @codingStandardsIgnoreEnd + } +} diff --git a/Model/AdapterEngine/Telegram.php b/Model/AdapterEngine/Telegram.php new file mode 100755 index 0000000..33aaf1d --- /dev/null +++ b/Model/AdapterEngine/Telegram.php @@ -0,0 +1,53 @@ +clientRepository = $clientRepository; + } + + /** + * Execute engine and return true on success. Throw exception on failure. + * @param string $emailMessage + * @param array $params + * @return bool + * @throws \Telegram\Bot\Exceptions\TelegramSDKException + */ + public function execute(string $emailMessage, array $params = []): bool + { + $client = $this->clientRepository->get($params[self::PARAM_TOKEN]); + $client->sendMessage([ + 'chat_id' => $params[self::PARAM_CHAT_ID], + 'text' => $emailMessage, + 'parse_mode' => 'HTML' + ]); + + return true; + } +} diff --git a/Model/AdapterEngine/Telegram/ClientRepository.php b/Model/AdapterEngine/Telegram/ClientRepository.php new file mode 100755 index 0000000..feee15e --- /dev/null +++ b/Model/AdapterEngine/Telegram/ClientRepository.php @@ -0,0 +1,33 @@ +clients[$token])) { + // @codingStandardsIgnoreStart + $this->clients[$token] = new Api($token); + // @codingStandardsIgnoreEnd + } + + return $this->clients[$token]; + } +} diff --git a/Model/AdapterEngine/Telegram/GetChatIds.php b/Model/AdapterEngine/Telegram/GetChatIds.php new file mode 100755 index 0000000..dc4cf1f --- /dev/null +++ b/Model/AdapterEngine/Telegram/GetChatIds.php @@ -0,0 +1,56 @@ +clientRepository = $clientRepository; + } + + /** + * Get a telegram client by token + * @param string $token + * @return array + * @throws \Telegram\Bot\Exceptions\TelegramSDKException + */ + public function execute(string $token): array + { + $bot = $this->clientRepository->get($token); + $updates = $bot->getUpdates(); + + $res = []; + foreach ($updates as $update) { + $message = $update->get('message'); + if ($message) { + $chat = $message->get('chat'); + $chatId = $chat->get('id'); + + if ($chat->get('title')) { + $res[$chatId] = $chat->get('title'); + } else { + $res[$chatId] = $chat->get('username'); + } + } + } + + return $res; + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..41955cc --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# notifier-core-adapters diff --git a/Test/Integration/Telegram/Validator/TelegramTest.php b/Test/Integration/Telegram/Validator/TelegramTest.php new file mode 100755 index 0000000..fe360c0 --- /dev/null +++ b/Test/Integration/Telegram/Validator/TelegramTest.php @@ -0,0 +1,73 @@ +adapterTelegram = Bootstrap::getObjectManager()->get( + 'MSP\NotifierCoreAdapters\Model\Adapter\Telegram' + ); + // @codingStandardsIgnoreEnd + } + + /** + * Test message validation + */ + public function testInvalidMessage() + { + $this->expectException(\InvalidArgumentException::class); + $this->adapterTelegram->validateMessage(''); + + $this->expectException(\InvalidArgumentException::class); + $this->adapterTelegram->validateMessage(' '); + } + + /** + * Test message validation + */ + public function testValidMessage() + { + $this->assertTrue($this->adapterTelegram->validateMessage('0')); + $this->assertTrue($this->adapterTelegram->validateMessage('Hello world!')); + } + + /** + * Test params validation + */ + public function testInvalidParams() + { + $this->setExpectedException(\InvalidArgumentException::class); + $this->adapterTelegram->validateParams([ + 'token' => null, + ]); + } + + /** + * Test params validation + */ + public function testValidParams() + { + $this->assertTrue($this->adapterTelegram->validateParams([ + 'token' => uniqid(), + 'chat_id' => 123, + ])); + } +} diff --git a/Ui/DataProvider/Form/Channel/Modifier/Email.php b/Ui/DataProvider/Form/Channel/Modifier/Email.php new file mode 100644 index 0000000..c0dc532 --- /dev/null +++ b/Ui/DataProvider/Form/Channel/Modifier/Email.php @@ -0,0 +1,111 @@ + [ + 'data' => [ + 'config' => [ + 'componentType' => Fieldset::NAME, + 'label' => __('Email Configuration'), + 'collapsible' => false, + ], + ], + ], + 'children' => [ + 'from' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'componentType' => Field::NAME, + 'label' => __('From'), + 'dataType' => 'text', + 'formElement' => 'input', + 'sortOrder' => 10, + 'dataScope' => 'general.configuration.from', + 'validation' => [ + 'required-entry' => true, + 'validate-email' => true, + ], + ], + ], + ], + ], + + 'from_name' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'componentType' => Field::NAME, + 'label' => __('From Name'), + 'dataType' => 'text', + 'formElement' => 'input', + 'sortOrder' => 20, + 'dataScope' => 'general.configuration.from_name', + 'validation' => [ + 'required-entry' => true, + ], + ], + ], + ], + ], + + 'to' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'componentType' => Field::NAME, + 'label' => __('Email'), + 'notice' => __('Write one recipient per line if multiple recipients are required'), + 'dataType' => 'text', + 'formElement' => 'textarea', + 'sortOrder' => 30, + 'dataScope' => 'general.configuration.to', + 'validation' => [ + 'required-entry' => true, + 'msp-validate-emails' => true, + ], + ], + ], + ], + ], + ], + ]; + + return $meta; + } + + /** + * @inheritdoc + */ + public function modifyData(array $data): array + { + return $data; + } + + /** + * @inheritdoc + */ + public function getAdapterCode(): string + { + return \MSP\NotifierCoreAdapters\Model\AdapterEngine\Email::ADAPTER_CODE; + } +} diff --git a/Ui/DataProvider/Form/Channel/Modifier/Slack.php b/Ui/DataProvider/Form/Channel/Modifier/Slack.php new file mode 100755 index 0000000..ac76ab8 --- /dev/null +++ b/Ui/DataProvider/Form/Channel/Modifier/Slack.php @@ -0,0 +1,117 @@ + [ + 'data' => [ + 'config' => [ + 'componentType' => Fieldset::NAME, + 'label' => __('Slack Configuration'), + 'collapsible' => false, + ], + ], + ], + 'children' => [ + 'webhook' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'componentType' => Field::NAME, + 'label' => __('Webhook'), + 'dataType' => 'text', + 'formElement' => 'input', + 'sortOrder' => 10, + 'dataScope' => 'general.configuration.webhook', + 'validation' => [ + 'required-entry' => true, + ], + ], + ], + ], + ], + 'channel' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'componentType' => Field::NAME, + 'label' => __('Channel'), + 'dataType' => 'text', + 'formElement' => 'input', + 'sortOrder' => 20, + 'dataScope' => 'general.configuration.channel', + 'validation' => [ + 'required-entry' => true, + ], + ], + ], + ], + ], + 'color' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'componentType' => Field::NAME, + 'label' => __('Color'), + 'dataType' => 'text', + 'formElement' => 'input', + 'sortOrder' => 30, + 'dataScope' => 'general.configuration.color', + ], + ], + ], + ], + 'emoji' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'componentType' => Field::NAME, + 'label' => __('Emoji code'), + 'dataType' => 'text', + 'formElement' => 'input', + 'sortOrder' => 40, + 'dataScope' => 'general.configuration.emoji', + ], + ], + ], + ], + ], + ]; + + return $meta; + } + + /** + * @inheritdoc + */ + public function modifyData(array $data): array + { + return $data; + } + + /** + * @inheritdoc + */ + public function getAdapterCode(): string + { + return \MSP\NotifierCoreAdapters\Model\AdapterEngine\Slack::ADAPTER_CODE; + } +} diff --git a/Ui/DataProvider/Form/Channel/Modifier/Telegram.php b/Ui/DataProvider/Form/Channel/Modifier/Telegram.php new file mode 100755 index 0000000..8bd7eab --- /dev/null +++ b/Ui/DataProvider/Form/Channel/Modifier/Telegram.php @@ -0,0 +1,89 @@ + [ + 'data' => [ + 'config' => [ + 'componentType' => Fieldset::NAME, + 'label' => __('Telegram Configuration'), + 'collapsible' => false, + ], + ], + ], + 'children' => [ + 'token' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'componentType' => Field::NAME, + 'label' => __('Bot Token'), + 'dataType' => 'text', + 'formElement' => 'input', + 'sortOrder' => 10, + 'dataScope' => 'general.configuration.token', + 'validation' => [ + 'required-entry' => true, + ], + ], + ], + ], + ], + 'chat_id' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'componentType' => Field::NAME, + 'label' => __('Chat ID'), + 'dataType' => 'text', + 'formElement' => 'input', + 'sortOrder' => 20, + 'dataScope' => 'general.configuration.chat_id', + 'validation' => [ + 'required-entry' => true, + ], + ], + ], + ], + ], + ], + ]; + + return $meta; + } + + /** + * @inheritdoc + */ + public function modifyData(array $data): array + { + return $data; + } + + /** + * @inheritdoc + */ + public function getAdapterCode(): string + { + return \MSP\NotifierCoreAdapters\Model\AdapterEngine\Telegram::ADAPTER_CODE; + } +} diff --git a/composer.json b/composer.json new file mode 100755 index 0000000..e5bc40e --- /dev/null +++ b/composer.json @@ -0,0 +1,40 @@ +{ + "name": "msp/module-notifier-core-adapters", + "description": "MSP_Notifier core adapters", + "require": { + "php": "^7.0|^7.1|^7.2", + "msp/module-notifier": "^0.1", + "magento/framework": "100.2.*|100.3.*", + "maknz/slack": "^1.7", + "irazasyed/telegram-bot-sdk": "^2.2" + }, + "support": { + "issues": "https://github.com/magespecialist/m2-MSP_Notifier/issues" + }, + "homepage": "https://github.com/magespecialist/m2-MSP_Notifier", + "keywords": [ + "telegram", + "slack", + "email" + ], + "authors": [ + { + "name": "Riccardo Tempesta", + "email": "riccardo.tempesta@magespecialist.it" + }, + { + "name": "Giacomo Mirabassi", + "email": "giacomo.mirabassi@magespecialist.it" + } + ], + "type": "magento2-module", + "license": "OSL-3.0", + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "MSP\\NotifierCoreAdapters\\": "" + } + } +} diff --git a/etc/adminhtml/di.xml b/etc/adminhtml/di.xml new file mode 100755 index 0000000..05a334c --- /dev/null +++ b/etc/adminhtml/di.xml @@ -0,0 +1,32 @@ + + + + + + + + + MSP\NotifierCoreAdapters\Ui\DataProvider\Form\Channel\Modifier\Telegram + 1000 + + + MSP\NotifierCoreAdapters\Ui\DataProvider\Form\Channel\Modifier\Slack + 1000 + + + MSP\NotifierCoreAdapters\Ui\DataProvider\Form\Channel\Modifier\Email + 1000 + + + + + diff --git a/etc/adminhtml/routes.xml b/etc/adminhtml/routes.xml new file mode 100644 index 0000000..dcb35eb --- /dev/null +++ b/etc/adminhtml/routes.xml @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file diff --git a/etc/di.xml b/etc/di.xml new file mode 100755 index 0000000..3bdd492 --- /dev/null +++ b/etc/di.xml @@ -0,0 +1,147 @@ + + + + + + + + MSP\NotifierCoreAdapters\Model\Adapter\Telegram + MSP\NotifierCoreAdapters\Model\Adapter\Slack + MSP\NotifierCoreAdapters\Model\Adapter\Email + + + + + + + + MSP\NotifierCoreAdapters\Command\Telegram\GetChatIds + + + + + + + + MSP\NotifierCoreAdapters\Model\AdapterEngine\Telegram + + MSP\NotifierCoreAdapters\Model\AdapterEngine\ValidatorChain\Telegram + + telegram + Telegram + Telegram Messenger + + + + + + + + chat_id + token + + + + + + + + + MSP\Notifier\Model\AdapterEngine\MessageValidator\Required + + + MSP\NotifierCoreAdapters\Model\AdapterEngine\ParamsValidator\Telegram\Required + + + + + + + + MSP\NotifierCoreAdapters\Model\AdapterEngine\Slack + MSP\NotifierCoreAdapters\Model\AdapterEngine\ValidatorChain\Slack + slack + Slack + Slack Messenger + + + + + + + + channel + webhook + + + + + + + + + MSP\Notifier\Model\AdapterEngine\MessageValidator\Required + + + + MSP\NotifierCoreAdapters\Model\AdapterEngine\ParamsValidator\Slack\Required + + + + + + + + + MSP\NotifierCoreAdapters\Model\AdapterEngine\Email + MSP\NotifierCoreAdapters\Model\AdapterEngine\ValidatorChain\Email + email + Email + Email + + + + + + + + to + from + from_name + + + + + + + + + MSP\Notifier\Model\AdapterEngine\MessageValidator\Required + + + + MSP\NotifierCoreAdapters\Model\AdapterEngine\ParamsValidator\Email\Required + + + + + diff --git a/etc/module.xml b/etc/module.xml new file mode 100755 index 0000000..8af5f0a --- /dev/null +++ b/etc/module.xml @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/registration.php b/registration.php new file mode 100755 index 0000000..5ddc506 --- /dev/null +++ b/registration.php @@ -0,0 +1,11 @@ +