From 37a51ba07026e2a571e65f5f964912a55b0ff63a Mon Sep 17 00:00:00 2001 From: nevrfl Date: Mon, 2 Sep 2024 14:01:21 +0300 Subject: [PATCH 1/2] add new client auth step --- .../redmine_telegram_setup_controller.rb | 10 +++++++++ .../redmine_telegram_setup/step_1.html.erb | 2 +- .../redmine_telegram_setup/step_2.html.erb | 4 ++-- .../redmine_telegram_setup/step_3.html.erb | 19 ++++++++++++++++ config/locales/en.yml | 5 ++++- config/locales/ru.yml | 5 ++++- config/locales/zh-TW.yml | 5 ++++- config/routes.rb | 1 + lib/redmine_bots/telegram.rb | 22 ++++++++++++++----- .../telegram/tdlib/authenticate.rb | 4 ++-- 10 files changed, 64 insertions(+), 13 deletions(-) create mode 100644 app/views/redmine_telegram_setup/step_3.html.erb diff --git a/app/controllers/redmine_telegram_setup_controller.rb b/app/controllers/redmine_telegram_setup_controller.rb index 7a5f74e..eaa9486 100644 --- a/app/controllers/redmine_telegram_setup_controller.rb +++ b/app/controllers/redmine_telegram_setup_controller.rb @@ -14,6 +14,16 @@ def step_2 end end + def step_3 + RedmineBots::Telegram::Tdlib.wrap do + promise = RedmineBots::Telegram::Tdlib::Authenticate.(params).rescue do |error| + redirect_to plugin_settings_path('redmine_bots'), alert: error.message + end + + RedmineBots::Telegram::Tdlib.permit_concurrent_loads { promise.wait! } + end + end + def authorize RedmineBots::Telegram::Tdlib.wrap do promise = RedmineBots::Telegram::Tdlib::Authenticate.(params).then do diff --git a/app/views/redmine_telegram_setup/step_1.html.erb b/app/views/redmine_telegram_setup/step_1.html.erb index f622038..7ac406f 100644 --- a/app/views/redmine_telegram_setup/step_1.html.erb +++ b/app/views/redmine_telegram_setup/step_1.html.erb @@ -1,6 +1,6 @@

<%= t 'redmine_bots.settings.telegram.authorize_client' %>


-

1. <%= t 'redmine_bots.settings.telegram.auth_step_1' %> — 2. <%= t 'redmine_bots.settings.telegram.auth_step_2' %>

+

1. <%= t 'redmine_bots.settings.telegram.auth_step_1' %> — 2. <%= t 'redmine_bots.settings.telegram.auth_step_2' %> — 3. <%= t 'redmine_bots.settings.telegram.auth_step_3' %>


<%= form_tag telegram_setup_2_path, method: :post do %> diff --git a/app/views/redmine_telegram_setup/step_2.html.erb b/app/views/redmine_telegram_setup/step_2.html.erb index c3f41e3..c4cc3ee 100644 --- a/app/views/redmine_telegram_setup/step_2.html.erb +++ b/app/views/redmine_telegram_setup/step_2.html.erb @@ -1,9 +1,9 @@

<%= t 'redmine_bots.settings.telegram.authorize_client' %>


-

<%= link_to telegram_setup_1_path do %>1. <%= t 'redmine_bots.settings.telegram.auth_step_1' %><% end %> — 2. <%= t 'redmine_bots.settings.telegram.auth_step_2' %>

+

<%= link_to telegram_setup_1_path do %>1. <%= t 'redmine_bots.settings.telegram.auth_step_1' %><% end %> — 2. <%= t 'redmine_bots.settings.telegram.auth_step_2' %> — 3. <%= t 'redmine_bots.settings.telegram.auth_step_3' %>


-<%= form_tag telegram_setup_authorize_path, method: :post do %> +<%= form_tag telegram_setup_3_path, method: :post do %>

<%= t 'redmine_bots.settings.telegram.authorize_client' %>

+
+

<%= link_to telegram_setup_1_path do %>1. <%= t 'redmine_bots.settings.telegram.auth_step_1' %><% end %> — 2. <%= t 'redmine_bots.settings.telegram.auth_step_2' %> — 3. <%= t 'redmine_bots.settings.telegram.auth_step_3' %>

+
+ +<%= form_tag telegram_setup_authorize_path, method: :post do %> +

+ + <%= text_field_tag 'password' %> + <%= t 'redmine_bots.settings.telegram.password_hint' %> +

+ + + + + +<% end %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 8d59320..c7a3418 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -14,13 +14,16 @@ en: phone_number: "Phone Number" phone_number_hint: "Format: 78005553535" phone_code: "Telegram code" + password: "Telegram password" + password_hint: "If you do not have two-factor authentication enabled in the Telegram application, click the «Authorize» button." authorize_button_code: "Receive code" authorize_button: "Authorize" authorize_client: "Authorize Telegram client" authorize_hint: "To authorize Telegram, press the button below. Current authorization will be drop." plugin_link: "Back to the plugin settings" auth_step_1: "Receiving Telegram code" - auth_step_2: "Authorization" + auth_step_2: "Code authorization" + auth_step_3: "Password authorization" reset: "Reset cache and authorization" bot_init: Initialize bot bot_deinit: Deinitialize bot diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 1d17862..5462f5c 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -15,13 +15,16 @@ ru: phone_number: "Номер телефона" phone_number_hint: "В формате: 78005553535" phone_code: "Код из Telegram" + password: "Пароль из Telegram" + password_hint: "Если у вас не включена двухфакторная аутентификация в приложении Telegram, нажмите кнопку «Авторизовать»." authorize_button_code: "Получить код авторизации" authorize_client: "Авторизовать клиент Telegram" authorize_hint: "Чтобы авторизировать Telegram, нажмите кнопку ниже. Текущая авторизация сбросится." authorize_button: "Авторизовать" plugin_link: "К настройкам плагина" auth_step_1: "Получение кода авторизации" - auth_step_2: "Авторизация" + auth_step_2: "Авторизация кода" + auth_step_3: "Авторизация пароля" reset: "Сбросить кеш и авторизацию" bot_init: Инициализировать бота bot_deinit: Деинициализировать бота diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index d08cda1..ea1e160 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -14,13 +14,16 @@ zh-TW: phone_number: "電話號碼" phone_number_hint: "以台灣手機 0912-345-678 為例,需輸入:886912345678" phone_code: "Telegram 代碼" + password: "Telegram 密碼" + password_hint: "如果您沒有在 Telegram 應用程式中啟用雙重認證,請按一下「授權」按鈕。" authorize_button_code: "接收代碼" authorize_button: "授權" authorize_client: "授權給 Telegram 用戶端" authorize_hint: "請按下面的按鈕授權給 Telegram。目前的授權則會被清除。" plugin_link: "回到外掛設定" auth_step_1: "接收 Telegram 代碼" - auth_step_2: "授權" + auth_step_2: "代碼授權" + auth_step_3: "密碼授權" reset: "重設快取及授權" bot_init: 初始化機器人 bot_deinit: 停用機器人 diff --git a/config/routes.rb b/config/routes.rb index 2e20e9b..b25a47a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -9,6 +9,7 @@ scope :setup do get 'step_1' => 'redmine_telegram_setup#step_1', as: :telegram_setup_1 post 'step_2' => 'redmine_telegram_setup#step_2', as: :telegram_setup_2 + post 'step_3' => 'redmine_telegram_setup#step_3', as: :telegram_setup_3 post 'authorize' => 'redmine_telegram_setup#authorize', as: :telegram_setup_authorize delete 'reset' => 'redmine_telegram_setup#reset', as: :telegram_setup_reset end diff --git a/lib/redmine_bots/telegram.rb b/lib/redmine_bots/telegram.rb index cba34bc..143dc7b 100644 --- a/lib/redmine_bots/telegram.rb +++ b/lib/redmine_bots/telegram.rb @@ -39,13 +39,25 @@ def self.tdlib_client settings = Setting.find_by_name(:plugin_redmine_bots).value TD::Api.set_log_file_path(Rails.root.join('log', 'redmine_bots', 'tdlib.log').to_s) config = { - api_id: settings['telegram_api_id'], - api_hash: settings['telegram_api_hash'], - database_directory: Rails.root.join('tmp', 'redmine_bots', 'tdlib', 'db').to_s, - files_directory: Rails.root.join('tmp', 'redmine_bots', 'tdlib', 'files').to_s, + api_id: settings['telegram_api_id'], + api_hash: settings['telegram_api_hash'], + use_test_dc: false, + database_directory: Rails.root.join('tmp', 'redmine_bots', 'tdlib', 'db').to_s, + files_directory: Rails.root.join('tmp', 'redmine_bots', 'tdlib', 'files').to_s, + use_file_database: true, + use_chat_info_database: true, + use_secret_chats: true, + use_message_database: true, + system_language_code: 'en', + device_model: 'Ruby TD client', + system_version: 'Unknown', + application_version: '1.0', } - TD::Client.new(timeout: 300, **config) + client = TD::Client.new(timeout: 300, **config) + client.set_tdlib_parameters(**config) + + client end def self.init_bot diff --git a/lib/redmine_bots/telegram/tdlib/authenticate.rb b/lib/redmine_bots/telegram/tdlib/authenticate.rb index ba0ba4a..73d53fb 100644 --- a/lib/redmine_bots/telegram/tdlib/authenticate.rb +++ b/lib/redmine_bots/telegram/tdlib/authenticate.rb @@ -19,11 +19,11 @@ def call(params) promise = client.set_authentication_phone_number(phone_number: params[:phone_number], settings: nil) when AuthorizationState::WaitCode promise = client.check_authentication_code(code: params[:phone_code]) if params[:phone_code] + when AuthorizationState::WaitPassword + promise = client.check_authentication_password(password: params[:password]) if params[:password] when AuthorizationState::Ready - puts 'lok' promise = Promises.fulfilled_future(true) else - puts update.authorization_state next end From eea1570ff1bb7e24d62da121305f984079a8ea7c Mon Sep 17 00:00:00 2001 From: nevrfl Date: Mon, 2 Sep 2024 14:02:23 +0300 Subject: [PATCH 2/2] update tdlib methods --- Gemfile | 4 +- lib/redmine_bots/telegram/tdlib/add_bot.rb | 4 +- lib/redmine_bots/telegram/tdlib/close_chat.rb | 8 +-- .../telegram/tdlib/create_chat.rb | 41 +++++++++++---- .../telegram/tdlib/fetch_all_chats.rb | 23 +++++---- .../telegram/tdlib/get_chat_link.rb | 2 +- .../telegram/tdlib/toggle_chat_admin.rb | 50 ++++++++++++------- 7 files changed, 83 insertions(+), 49 deletions(-) diff --git a/Gemfile b/Gemfile index 956e97c..d3c228f 100644 --- a/Gemfile +++ b/Gemfile @@ -5,8 +5,8 @@ gem 'sidekiq-rate-limiter', '0.1.3', require: 'sidekiq-rate-limiter/server' gem 'telegram-bot-ruby', '>= 0.11', '< 1.0' gem 'slack-ruby-bot' gem 'celluloid-io' -gem 'tdlib-ruby', '3.0.2' -gem 'tdlib-schema', git: 'https://github.com/southbridgeio/tdlib-schema', branch: 'update' +gem 'tdlib-ruby', git: 'https://github.com/southbridgeio/tdlib-ruby', tag: "v3.0.3" +gem 'tdlib-schema', git: 'https://github.com/southbridgeio/tdlib-schema' gem 'jwt' gem 'filelock' gem 'patron' diff --git a/lib/redmine_bots/telegram/tdlib/add_bot.rb b/lib/redmine_bots/telegram/tdlib/add_bot.rb index 93db870..14d139c 100644 --- a/lib/redmine_bots/telegram/tdlib/add_bot.rb +++ b/lib/redmine_bots/telegram/tdlib/add_bot.rb @@ -3,11 +3,11 @@ class AddBot < Command def call(bot_name) client.search_public_chat(username: bot_name).then do |chat| message = TD::Types::InputMessageContent::Text.new(text: TD::Types::FormattedText.new(text: '/start', entities: []), - disable_web_page_preview: true, + link_preview_options: nil, clear_draft: false) client.send_message(chat_id: chat.id, message_thread_id: nil, - reply_to_message_id: nil, + reply_to: nil, options: nil, reply_markup: nil, input_message_content: message) diff --git a/lib/redmine_bots/telegram/tdlib/close_chat.rb b/lib/redmine_bots/telegram/tdlib/close_chat.rb index 76f657e..3315bde 100644 --- a/lib/redmine_bots/telegram/tdlib/close_chat.rb +++ b/lib/redmine_bots/telegram/tdlib/close_chat.rb @@ -6,7 +6,7 @@ def call(chat_id) when TD::Types::ChatType::BasicGroup fetch_robot_ids.then { |*robot_ids| close_basic_group(chat, robot_ids) }.flat when TD::Types::ChatType::Supergroup - close_super_group(chat.type) + close_super_group(chat.id) else raise 'Unsupported chat type' end @@ -39,12 +39,12 @@ def close_basic_group(chat, robot_ids) end.flat end - def close_super_group(chat_type) - client.delete_supergroup(supergroup_id: chat_type.supergroup_id) + def close_super_group(chat_id) + client.delete_chat(chat_id: chat_id) end def delete_member(chat_id, user_id) - client.set_chat_member_status(chat_id: chat_id, user_id: user_id, status: ChatMemberStatus::Left.new) + client.set_chat_member_status(chat_id: chat_id, member_id: user_id, status: ChatMemberStatus::Left.new) end end end diff --git a/lib/redmine_bots/telegram/tdlib/create_chat.rb b/lib/redmine_bots/telegram/tdlib/create_chat.rb index 41791d1..18e2517 100644 --- a/lib/redmine_bots/telegram/tdlib/create_chat.rb +++ b/lib/redmine_bots/telegram/tdlib/create_chat.rb @@ -1,10 +1,8 @@ module RedmineBots::Telegram::Tdlib class CreateChat < Command def call(title, user_ids) - puts title - puts user_ids Promises.zip(*user_ids.map { |id| client.get_user(user_id: id) }).then do - client.create_new_supergroup_chat(title: title, is_channel: false, description: '', location: nil).then do |chat| + client.create_new_supergroup_chat(**supergroup_chat_params(title)).then do |chat| client.add_chat_members(chat_id: chat.id, user_ids: user_ids).then do client.set_chat_permissions(chat_id: chat.id, permissions: permissions).then { chat } end.flat @@ -15,14 +13,35 @@ def call(title, user_ids) private def permissions - ChatPermissions.new(can_send_messages: true, - can_send_media_messages: true, - can_send_polls: true, - can_send_other_messages: true, - can_add_web_page_previews: true, - can_change_info: false, - can_invite_users: false, - can_pin_messages: false) + ChatPermissions.new( + can_send_basic_messages: true, + can_send_audios: true, + can_send_documents: true, + can_send_photos: true, + can_send_videos: true, + can_send_video_notes: true, + can_send_voice_notes: true, + can_send_polls: true, + can_send_other_messages: true, + can_add_link_previews: true, + can_send_media_messages: true, + can_change_info: false, + can_invite_users: false, + can_pin_messages: false, + can_create_topics: false + ) + end + + def supergroup_chat_params(title) + { + title: title, + is_channel: false, + description: '', + location: nil, + is_forum: false, + message_auto_delete_time: 0, + for_import: true + } end end end diff --git a/lib/redmine_bots/telegram/tdlib/fetch_all_chats.rb b/lib/redmine_bots/telegram/tdlib/fetch_all_chats.rb index d4abc6f..8942a68 100644 --- a/lib/redmine_bots/telegram/tdlib/fetch_all_chats.rb +++ b/lib/redmine_bots/telegram/tdlib/fetch_all_chats.rb @@ -4,8 +4,6 @@ def initialize(*) super @chat_list = ChatList::Main.new - @offset_order = 2**63 - 1 - @offset_chat_id = 0 @limit = 100 @chat_futures = [] end @@ -17,18 +15,21 @@ def call private attr_reader :limit - attr_accessor :chat_list, :offset_order, :offset_chat_id + attr_accessor :chat_list def fetch - client.get_chats(chat_list: chat_list, offset_order: offset_order, offset_chat_id: offset_chat_id, limit: limit).then do |update| - chat_ids = update.chat_ids - next Concurrent::Promises.fulfilled_future(nil) if chat_ids.empty? - - client.get_chat(chat_id: chat_ids.last).then do |chat| - self.offset_chat_id, self.offset_order = chat.id, chat.positions.find { |p| p.list.is_a?(ChatList::Main) }.order + client.load_chats(chat_list: chat_list, limit: limit).then do |update| + case update + when TD::Types::Ok fetch.wait! - end.flat - end.flat + else + next Concurrent::Promises.fulfilled_future(nil) + end + end.flat.rescue do |error| + if error.code != 404 + raise error + end + end end end end diff --git a/lib/redmine_bots/telegram/tdlib/get_chat_link.rb b/lib/redmine_bots/telegram/tdlib/get_chat_link.rb index 4dc4685..931224d 100644 --- a/lib/redmine_bots/telegram/tdlib/get_chat_link.rb +++ b/lib/redmine_bots/telegram/tdlib/get_chat_link.rb @@ -1,7 +1,7 @@ module RedmineBots::Telegram::Tdlib class GetChatLink < Command def call(chat_id) - client.generate_chat_invite_link(chat_id: chat_id) + client.create_chat_invite_link(chat_id: chat_id, expiration_date: 0, member_limit: 0, creates_join_request: false, name: "issue") end end end diff --git a/lib/redmine_bots/telegram/tdlib/toggle_chat_admin.rb b/lib/redmine_bots/telegram/tdlib/toggle_chat_admin.rb index e77bf6c..d1f2826 100644 --- a/lib/redmine_bots/telegram/tdlib/toggle_chat_admin.rb +++ b/lib/redmine_bots/telegram/tdlib/toggle_chat_admin.rb @@ -2,24 +2,38 @@ module RedmineBots::Telegram::Tdlib class ToggleChatAdmin < Command def call(chat_id, user_id, admin = true) status = - if admin - TD::Types::ChatMemberStatus::Administrator.new( - is_anonymous: false, - can_post_messages: true, - can_be_edited: true, - can_change_info: true, - can_edit_messages: true, - can_delete_messages: true, - can_invite_users: true, - can_restrict_members: true, - can_pin_messages: true, - can_promote_members: true, - custom_title: 'Redmine admin' - ) - else - TD::Types::ChatMemberStatus::Member.new - end - client.get_user(user_id: user_id).then { client.set_chat_member_status(chat_id: chat_id, user_id: user_id, status: status) }.flat + if admin + TD::Types::ChatMemberStatus::Administrator.new( + rights: rights, + can_be_edited: true, + custom_title: 'Redmine admin' + ) + else + TD::Types::ChatMemberStatus::Member.new + end + client.get_user(user_id: user_id).then { client.set_chat_member_status(chat_id: chat_id, member_id: user_id, status: status) }.flat + end + + private + + def rights + TD::Types::ChatAdministratorRights.new( + can_manage_topics: true, + can_manage_chat: true, + can_change_info: true, + can_post_messages: true, + can_edit_messages: true, + can_delete_messages: true, + can_invite_users: true, + can_restrict_members: true, + can_pin_messages: true, + can_promote_members: true, + can_manage_video_chats: true, + can_post_stories: false, + can_edit_stories: false, + can_delete_stories: false, + is_anonymous: false + ) end end end