diff --git a/config/jsons/github-event.json b/config/jsons/github-events.json similarity index 100% rename from config/jsons/github-event.json rename to config/jsons/github-events.json diff --git a/config/jsons/gitlab-event.json b/config/jsons/gitlab-events.json similarity index 100% rename from config/jsons/gitlab-event.json rename to config/jsons/gitlab-events.json diff --git a/config/jsons/tg-setting.json b/config/jsons/tgn-settings.json similarity index 100% rename from config/jsons/tg-setting.json rename to config/jsons/tgn-settings.json diff --git a/config/tg-notifier.php b/config/tg-notifier.php index 1021753..9127043 100644 --- a/config/tg-notifier.php +++ b/config/tg-notifier.php @@ -4,26 +4,53 @@ 'telegram-git-notifier' => [ 'app' => [ 'name' => $_ENV['TGN_APP_NAME'] ?? 'Telegram Git Notifier', + + // Required for the bot to work properly 'url' => $_ENV['TGN_APP_URL'] ?? 'http://localhost:3000', + 'timezone' => $_ENV['TIMEZONE'] ?? 'Asia/Ho_Chi_Minh', ], 'bot' => [ 'token' => $_ENV['TELEGRAM_BOT_TOKEN'] ?? '', 'chat_id' => $_ENV['TELEGRAM_BOT_CHAT_ID'] ?? '', - 'notify_chat_ids' => explode( - ',', - $_ENV['TELEGRAM_NOTIFY_CHAT_IDS'] ?? '' - ), + + /** + * Set the chat ids that will receive notifications + * You can add the owner bot id, group id, ... + * ------------------------------------------------------- + * Note: + * Please use semicolon ";" to separate chat ids + * And use colon ":" to separate chat id and thread id + * And use comma "," if you want to add multiple thread ids + * ------------------------------------------------------- + * The environment variable is expected to be in the format: + * "chat_id1;chat_id2:thread_id2;chat_id3:thread_id3_1,thread_id3_2;..." + */ + 'notify_chat_ids' => $_ENV['TELEGRAM_NOTIFY_CHAT_IDS'] ?? '', ], 'author' => [ - 'discussion' => $_ENV['TGN_AUTHOR_DISCUSSION'] ?? + 'discussion' => $_ENV['TGN_AUTHOR_DISCUSSION'] ?? 'https://github.com/lbiltech/telegram-git-notifier/discussions', 'source_code' => $_ENV['TGN_AUTHOR_SOURCE_CODE'] ?? 'https://github.com/lbiltech/telegram-git-notifier', ], + /** Set the path to the data file */ + 'data_file' => [ + 'setting' => $_ENV['TGN_PATH_SETTING'] ?? + 'storage/json/tgn/tgn-settings.json', + + 'platform' => [ + 'gitlab' => $_ENV['TGN_PATH_PLATFORM_GITLAB'] ?? + 'storage/json/tgn/gitlab-events.json', + 'github' => $_ENV['TGN_PATH_PLATFORM_GITHUB'] ?? + 'storage/json/tgn/github-events.json', + ], + ], + + /** Set the path to the view file */ 'view' => [ 'path' => $_ENV['TGN_VIEW_PATH'] ?? 'resources/views', diff --git a/src/Bot.php b/src/Bot.php new file mode 100644 index 0000000..445c98a --- /dev/null +++ b/src/Bot.php @@ -0,0 +1,48 @@ +telegram = $telegram ?? new Telegram(config('telegram-git-notifier.bot.token')); + $this->setCurrentChatBotId($chatBotId); + $this->event = $event ?? new Event(); + $this->setPlatFormForEvent($platform, $platformFile); + + $this->setting = $setting ?? new Setting(); + $this->updateSetting($settingFile); + } +} diff --git a/src/Constants/EventConstant.php b/src/Constants/EventConstant.php index 67e5ebe..94a54a2 100644 --- a/src/Constants/EventConstant.php +++ b/src/Constants/EventConstant.php @@ -2,7 +2,7 @@ namespace LbilTech\TelegramGitNotifier\Constants; -class EventConstant +final class EventConstant { public const DEFAULT_PLATFORM = 'github'; diff --git a/src/Constants/NotificationConstant.php b/src/Constants/NotificationConstant.php new file mode 100644 index 0000000..27d6df5 --- /dev/null +++ b/src/Constants/NotificationConstant.php @@ -0,0 +1,15 @@ +platformFile = $platformFile; } + /** + * @return array + */ + public function getEventConfig(): array + { + return $this->eventConfig; + } + /** * Set event config * diff --git a/src/Models/Setting.php b/src/Models/Setting.php index bce7fe8..6c07913 100644 --- a/src/Models/Setting.php +++ b/src/Models/Setting.php @@ -62,6 +62,8 @@ public function isAllEventsNotification(): bool } /** + * Condition for checking the notification status + * * @return bool */ public function isNotified(): bool @@ -83,7 +85,7 @@ public function isNotified(): bool * * @return bool */ - public function updateSettingItem( + public function updateSetting( string $settingName, $settingValue = null ): bool { diff --git a/src/Notifier.php b/src/Notifier.php new file mode 100644 index 0000000..33d9a0c --- /dev/null +++ b/src/Notifier.php @@ -0,0 +1,61 @@ +telegram = $telegram ?? new Telegram(config('telegram-git-notifier.bot.token')); + $this->setCurrentChatBotId($chatBotId); + + $this->event = $event ?? new Event(); + $this->setPlatFormForEvent($platform, $platformFile); + + $this->client = $client ?? new Client(); + } + + public function parseNotifyChatIds(): array + { + $chatData = explode( + NotificationConstant::CHAT_ID_PAIRS_SEPARATOR, + config('telegram-git-notifier.bot.notify_chat_ids') + ); + $chatThreadMapping = []; + + foreach ($chatData as $data) { + [$chatId, $threadIds] = explode(NotificationConstant::CHAT_THREAD_ID_SEPARATOR, $data) + [null, null]; + $chatThreadMapping[$chatId] = $threadIds + ? explode(NotificationConstant::THREAD_ID_SEPARATOR, $threadIds) + : []; + } + return $chatThreadMapping; + } +} diff --git a/src/Services/EventService.php b/src/Objects/Validator.php similarity index 60% rename from src/Services/EventService.php rename to src/Objects/Validator.php index 50e5bcf..944529d 100644 --- a/src/Services/EventService.php +++ b/src/Objects/Validator.php @@ -1,29 +1,35 @@ setting = $setting; $this->event = $event; } - public function validateAccessEvent( + /** + * Validate is access event before send notify + * + * @param string $platform Source code platform (GitHub, GitLab) + * @param string $event Event name (push, pull_request) + * @param $payload + * + * @return bool + */ + public function isAccessEvent( string $platform, string $event, $payload @@ -35,11 +41,9 @@ public function validateAccessEvent( if ($this->setting->isAllEventsNotification()) { return true; } - $this->event->setEventConfig($platform); - $eventConfig = $this->event->eventConfig; - $eventConfig = $eventConfig[tgn_convert_event_name($event)] ?? false; + $eventConfig = $this->event->getEventConfig()[tgn_convert_event_name($event)] ?? false; $action = $this->getActionOfEvent($payload); if (!empty($action) && isset($eventConfig[$action])) { diff --git a/src/Services/SettingService.php b/src/Services/SettingService.php deleted file mode 100644 index 4a1684d..0000000 --- a/src/Services/SettingService.php +++ /dev/null @@ -1,36 +0,0 @@ -setting = $setting; - $this->event = $event; - - $this->setCurrentChatId($chatId); - } -} diff --git a/src/Services/TelegramService.php b/src/Services/TelegramService.php deleted file mode 100644 index 0b8d9c1..0000000 --- a/src/Services/TelegramService.php +++ /dev/null @@ -1,73 +0,0 @@ -setCurrentChatId($chatId); - - $this->telegram = $telegram; - } - - public function setMyCommands( - array $menuCommand, - ?string $view = null - ): void { - $this->telegram->setMyCommands([ - 'commands' => json_encode($menuCommand) - ]); - $this->sendMessage( - view( - $view ?? - config('telegram-git-notifier.view.tools.set_menu_cmd') - ) - ); - } - - public function isCallback(): bool - { - if ($this->telegram->getUpdateType() === Telegram::CALLBACK_QUERY) { - return true; - } - - return false; - } - - public function isMessage(): bool - { - if ($this->telegram->getUpdateType() === Telegram::MESSAGE) { - return true; - } - - return false; - } - - public function isOwner(): bool - { - if ($this->telegram->ChatID() == $this->chatId) { - return true; - } - - return false; - } - - public function isNotifyChat(): bool - { - $chatIds = config('telegram-git-notifier.bot.notify_chat_ids'); - if (in_array($this->telegram->ChatID(), $chatIds)) { - return true; - } - - return false; - } -} diff --git a/src/Services/AppService.php b/src/Structures/App.php similarity index 79% rename from src/Services/AppService.php rename to src/Structures/App.php index 6a7f4a0..f3bf8c1 100644 --- a/src/Services/AppService.php +++ b/src/Structures/App.php @@ -1,33 +1,27 @@ telegram = $telegram ?? new Telegram(config('telegram-git-notifier.bot.token')); + $this->chatBotId = $chatBotId ?? config('telegram-git-notifier.bot.chat_id'); } - public function setCurrentChatId(string $chatId = null): void - { - $this->chatId = $chatId ?? config('telegram-git-notifier.bot.chat_id'); - } - - private function createBaseContent(): array + private function createTelegramBaseContent(): array { return [ - 'chat_id' => $this->chatId, + 'chat_id' => $this->chatBotId, 'disable_web_page_preview' => true, 'parse_mode' => 'HTML' ]; @@ -39,15 +33,18 @@ public function sendMessage(string $message = '', array $options = []): void throw MessageIsEmptyException::create(); } - $content = $this->createBaseContent(); + $content = $this->createTelegramBaseContent(); $content['text'] = $message; if (!empty($options['reply_markup'])) { $content['reply_markup'] = $this->telegram->buildInlineKeyBoard( $options['reply_markup'] ); + unset($options['reply_markup']); } + $content = $content + $options; + $this->telegram->sendMessage($content); } @@ -57,25 +54,26 @@ public function sendPhoto(string $photo = '', string $caption = ''): void throw EntryNotFoundException::fileNotFound(); } - $content = $this->createBaseContent(); + $content = $this->createTelegramBaseContent(); $content['photo'] = curl_file_create($photo); $content['caption'] = $caption; $this->telegram->sendPhoto($content); } - public function answerCallbackQuery(string $text = null): void + public function answerCallbackQuery(string $text = null, array $options = []): void { if (empty($text)) { throw MessageIsEmptyException::create(); } try { - $this->telegram->answerCallbackQuery([ + $options = array_merge([ 'callback_query_id' => $this->telegram->Callback_ID(), 'text' => $text, 'show_alert' => true - ]); + ], $options); + $this->telegram->answerCallbackQuery($options); } catch (Exception $e) { error_log("Error answering callback query: " . $e->getMessage()); } diff --git a/src/Services/NotificationService.php b/src/Structures/Notification.php similarity index 54% rename from src/Services/NotificationService.php rename to src/Structures/Notification.php index dc85ef4..cfdbef3 100644 --- a/src/Services/NotificationService.php +++ b/src/Structures/Notification.php @@ -1,39 +1,24 @@ client = $client; - } - public function accessDenied( - TelegramService $telegramService, string $chatId = null, string $viewTemplate = null, ): void { - $telegramService->telegram->sendMessage([ - 'chat_id' => config('telegram-git-notifier.bot.chat_id'), + $this->telegram->sendMessage([ + 'chat_id' => $this->chatBotId, 'text' => view( $viewTemplate ?? config('telegram-git-notifier.view.globals.access_denied'), ['chatId' => $chatId] @@ -45,9 +30,9 @@ public function accessDenied( public function setPayload(Request $request, string $event) { - if ($this->platform === 'gitlab') { + if ($this->event->platform === 'gitlab') { $this->payload = json_decode($request->getContent()); - } elseif ($this->platform === EventConstant::DEFAULT_PLATFORM) { + } elseif ($this->event->platform === EventConstant::DEFAULT_PLATFORM) { $this->payload = json_decode($request->request->get('payload')); } $this->setMessage($event); @@ -68,8 +53,8 @@ private function setMessage(string $typeEvent): void $action = $this->getActionOfEvent($this->payload); $viewTemplate = empty($action) - ? "events.{$this->platform}.{$event}.default" - : "events.{$this->platform}.{$event}.{$action}"; + ? "events.{$this->event->platform}.{$event}.default" + : "events.{$this->event->platform}.{$event}.{$action}"; $this->message = view($viewTemplate, [ 'payload' => $this->payload, @@ -77,25 +62,18 @@ private function setMessage(string $typeEvent): void ]); } - public function sendNotify(string $chatId, string $message = null): bool + public function sendNotify(string $message = null, array $options = []): bool { - if (!is_null($message)) { - $this->message = $message; - } + $this->message = !empty($message) ? $message : $this->message; - $queryParams = [ - 'chat_id' => $chatId, - 'disable_web_page_preview' => 1, - 'parse_mode' => 'html', - 'text' => $this->message - ]; + $queryParams = array_merge($this->createTelegramBaseContent(), ['text' => $this->message], $options); - $url = 'https://api.telegram.org/bot' - . config('telegram-git-notifier.bot.token') . '/sendMessage' - . '?' . http_build_query($queryParams); + $url = 'https://api.telegram.org/bot' . config('telegram-git-notifier.bot.token') . '/sendMessage'; try { - $response = $this->client->request('GET', $url); + $response = $this->client->request('POST', $url, [ + 'form_params' => $queryParams + ]); if ($response->getStatusCode() === 200) { return true; diff --git a/src/Structures/TelegramBot.php b/src/Structures/TelegramBot.php new file mode 100644 index 0000000..af865dd --- /dev/null +++ b/src/Structures/TelegramBot.php @@ -0,0 +1,33 @@ +telegram->getUpdateType() === Telegram::CALLBACK_QUERY; + } + + public function isMessage(): bool + { + return $this->telegram->getUpdateType() === Telegram::MESSAGE; + } + + public function isOwner(): bool + { + return $this->telegram->ChatID() == $this->chatBotId; + } + + public function isNotifyChat(): bool + { + $chatIds = config('telegram-git-notifier.bot.notify_chat_ids'); + if (in_array($this->telegram->ChatID(), $chatIds)) { + return true; + } + + return false; + } +} diff --git a/src/Trait/BotSettingTrait.php b/src/Trait/BotSettingTrait.php index 3d2593f..ef0ad2d 100644 --- a/src/Trait/BotSettingTrait.php +++ b/src/Trait/BotSettingTrait.php @@ -6,6 +6,31 @@ trait BotSettingTrait { + public function updateSetting(?string $settingFile = null): void + { + if ($this->setting->getSettingFile()) { + return; + } + $settingFile = $settingFile ?? config('telegram-git-notifier.data_file.setting'); + $this->setting->setSettingFile($settingFile); + $this->setting->setSettingConfig(); + } + + public function setMyCommands( + array $menuCommand, + ?string $view = null + ): void { + $this->telegram->setMyCommands([ + 'commands' => json_encode($menuCommand) + ]); + $this->sendMessage( + view( + $view ?? + config('telegram-git-notifier.view.tools.set_menu_cmd') + ) + ); + } + public function settingHandle(?string $view = null): void { $this->sendMessage( diff --git a/src/Trait/EventSettingTrait.php b/src/Trait/EventSettingTrait.php index 369766d..7e4f7fa 100644 --- a/src/Trait/EventSettingTrait.php +++ b/src/Trait/EventSettingTrait.php @@ -14,8 +14,8 @@ public function eventMarkup( $replyMarkup = $replyMarkupItem = []; $this->event->setEventConfig($platform); - $events = $parentEvent === null ? $this->event->eventConfig - : $this->event->eventConfig[$parentEvent]; + $events = $parentEvent === null ? $this->event->getEventConfig() + : $this->event->getEventConfig()[$parentEvent]; foreach ($events as $key => $value) { if (count($replyMarkupItem) === SettingConstant::BTN_LINE_ITEM_COUNT) { diff --git a/src/Trait/EventTrait.php b/src/Trait/EventTrait.php new file mode 100644 index 0000000..b29c157 --- /dev/null +++ b/src/Trait/EventTrait.php @@ -0,0 +1,36 @@ +event->getPlatformFile()) { + /** @var array $platformFileDefaults */ + $platformFileDefaults = config('telegram-git-notifier.data_file.platform'); + $this->event->setPlatformFile($platformFile ?? $platformFileDefaults[$platform]); + } + $this->event->setEventConfig($platform); + } + + public function handleEventFromRequest(Request $request): ?string + { + foreach (EventConstant::WEBHOOK_EVENT_HEADER as $platform => $header) { + $event = $request->server->get($header); + if (!is_null($event)) { + $this->event->platform = $platform; + $this->setPlatFormForEvent($platform); + + return $event; + } + } + + return null; + } +} diff --git a/src/Services/WebhookService.php b/src/Webhook.php similarity index 60% rename from src/Services/WebhookService.php rename to src/Webhook.php index bc7d75f..1fa81a1 100644 --- a/src/Services/WebhookService.php +++ b/src/Webhook.php @@ -1,10 +1,10 @@ token}/getWebhookInfo"; + + return file_get_contents($url); + } + + public function getUpdates(): false|string + { + $url = "https://api.telegram.org/bot{$this->token}/getUpdates"; + + return file_get_contents($url); + } }