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 @@
+