dialog_ruby 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/Gemfile +0 -0
  4. data/_dev/get_full_botapi.rb +59 -0
  5. data/_dev/inlinekb_pubsub.rb +69 -0
  6. data/_dev/main.rb +127 -0
  7. data/_dev/restriction.rb +32 -0
  8. data/_dev/ru.yml +79 -0
  9. data/_dev/sidekiq.rb +28 -0
  10. data/_dev/tdlib.rb +154 -0
  11. data/dialog.sh +51 -0
  12. data/dialog_ruby.gemspec +41 -0
  13. data/lib/architecture.md +22 -0
  14. data/lib/configuration.rb +117 -0
  15. data/lib/dialogStart.rb +189 -0
  16. data/lib/dialog_ruby.rb +59 -0
  17. data/lib/exec.sh +61 -0
  18. data/lib/exec_conf/cli_config +7 -0
  19. data/lib/exec_conf/dialog__sync.service +14 -0
  20. data/lib/exec_conf/dialog__sync.timer +11 -0
  21. data/lib/exec_conf/dialog_bot@.path +6 -0
  22. data/lib/exec_conf/dialog_bot@.service +18 -0
  23. data/lib/exec_conf/dialog_bot_dev@.path +6 -0
  24. data/lib/exec_conf/dialog_bot_dev_pre@.service +16 -0
  25. data/lib/exec_conf/dialog_bot_pre@.service +16 -0
  26. data/lib/exec_conf/dialog_redis@.service +14 -0
  27. data/lib/exec_conf/post-merge +5 -0
  28. data/lib/exec_conf/redis_global.conf +49 -0
  29. data/lib/exec_conf/redis_local.conf +4 -0
  30. data/lib/lang/global_ru.yml +29 -0
  31. data/lib/lib/dialect/canvas/canvas.rb +35 -0
  32. data/lib/lib/dialect/canvas/element/convert/SearchBaloo.rb +45 -0
  33. data/lib/lib/dialect/canvas/element/data/search.rb +34 -0
  34. data/lib/lib/dialect/canvas/element/send/Inline_query_result.rb +32 -0
  35. data/lib/lib/dialect/canvas/element/send/bot_message.rb +38 -0
  36. data/lib/lib/dialect/canvas/element/send/keyboards.rb +59 -0
  37. data/lib/lib/dialect/canvas/element/send/recognize.rb +51 -0
  38. data/lib/lib/dialect/canvas/element/send/restrict.rb +42 -0
  39. data/lib/lib/dialect/canvas/element/send/tdlib_chat.rb +33 -0
  40. data/lib/lib/dialect/canvas/element/send/tdlib_message.rb +38 -0
  41. data/lib/lib/dialect/canvas/mod/send/_Inline_query_result.rb +38 -0
  42. data/lib/lib/dialect/canvas/mod/send/_keyboards.rb +40 -0
  43. data/lib/lib/dialect/canvas/mod/send/func.rb +98 -0
  44. data/lib/lib/dialect/canvas/mod/send/general/_heads.rb +27 -0
  45. data/lib/lib/dialect/canvas/mod/send/general/chat.rb +38 -0
  46. data/lib/lib/dialect/canvas/mod/send/general/common.rb +32 -0
  47. data/lib/lib/dialect/canvas/mod/send/general/message.rb +37 -0
  48. data/lib/lib/dialect/canvas/mod/send/general/user.rb +36 -0
  49. data/lib/lib/dialect/canvas/mod/send/inline_query_result/common.rb +36 -0
  50. data/lib/lib/dialect/codegen/codegen.rb +74 -0
  51. data/lib/lib/dialect/codegen/erb/data/1.ModReceive2GetData.erb +27 -0
  52. data/lib/lib/dialect/codegen/erb/data/2.GetData2Elements.erb +27 -0
  53. data/lib/lib/dialect/codegen/erb/data/3.GenData2Dest.erb +34 -0
  54. data/lib/lib/dialect/codegen/erb/functional/1.Expect2Events.erb +37 -0
  55. data/lib/lib/dialect/codegen/erb/functional/2.1.Events2AppEvent.erb +26 -0
  56. data/lib/lib/dialect/codegen/erb/functional/2.2.1.Events2ModReceive.erb +73 -0
  57. data/lib/lib/dialect/codegen/erb/functional/2.2.2.ModReceive2AppEvent.erb +59 -0
  58. data/lib/lib/dialect/codegen/erb/functional/3.Appevent2EventBus.erb +35 -0
  59. data/lib/lib/dialect/codegen/erb/functional/4.1.AppEvent2Elements.erb +72 -0
  60. data/lib/lib/dialect/codegen/erb/functional/5.1.Element2ModElements.erb +70 -0
  61. data/lib/lib/dialect/codegen/erb/functional/5.2.Element2ModSend.erb +69 -0
  62. data/lib/lib/dialect/codegen/erb/functional/7.ElementChains.erb +91 -0
  63. data/lib/lib/dialect/codegen/repack/constructor/DockedGroupings2AppFunctions.rb +36 -0
  64. data/lib/lib/dialect/codegen/repack/constructor/Element2ModSend.rb +49 -0
  65. data/lib/lib/dialect/codegen/repack/constructor/ElementsInElements.rb +34 -0
  66. data/lib/lib/dialect/codegen/repack/functional/1.Expect2Events.rb +35 -0
  67. data/lib/lib/dialect/codegen/repack/functional/2.2.1.Events2ModReceive.rb +71 -0
  68. data/lib/lib/dialect/codegen/repack/functional/2.2.2.ModReceive2AppEvent.rb +45 -0
  69. data/lib/lib/dialect/codegen/repack/functional/5.1.Element2ModElements.rb +90 -0
  70. data/lib/lib/dialect/codegen/repack/functional/5.2.Element2ModSend.rb +60 -0
  71. data/lib/lib/dialect/codegen/repack/functional/7.ElementChains.rb +88 -0
  72. data/lib/lib/dialect/codegen/run.rb +79 -0
  73. data/lib/lib/metamess/_run.rb +162 -0
  74. data/lib/lib/metamess/content/content_o-command_f.rb +100 -0
  75. data/lib/lib/metamess/content/content_o-media_f.rb +149 -0
  76. data/lib/lib/metamess/content/content_o-simple_f.rb +35 -0
  77. data/lib/lib/metamess/content/content_o.rb +245 -0
  78. data/lib/lib/metamess/event/notify_o-chatmember_f.rb +124 -0
  79. data/lib/lib/metamess/event/notify_o-chattitle_f.rb +34 -0
  80. data/lib/lib/metamess/event/notify_o-create_f.rb +42 -0
  81. data/lib/lib/metamess/event/notify_o-migrate_f.rb +34 -0
  82. data/lib/lib/metamess/event/notify_o-pinned_f.rb +34 -0
  83. data/lib/lib/metamess/event/notify_o.rb +28 -0
  84. data/lib/lib/metamess/event_c.rb +26 -0
  85. data/lib/lib/metamess/func.rb +220 -0
  86. data/lib/lib/metamess/service/service_o-callback_f.rb +33 -0
  87. data/lib/lib/metamess/service/service_o-inline_f.rb +55 -0
  88. data/lib/lib/metamess/service/service_o.rb +26 -0
  89. data/lib/lib/naming.rb +130 -0
  90. data/lib/lib/storage/redis/redisPubSub.rb +51 -0
  91. data/lib/lib/storage/redis/rediscached.rb +97 -0
  92. data/lib/lib/tdlib/auth.rb +141 -0
  93. data/lib/lib/tdlib/func.rb +34 -0
  94. data/lib/lib/tdlib/init.rb +39 -0
  95. data/lib/lib/telegram/botapi.rb +71 -0
  96. data/lib/lib/telegram/infra_info.rb +50 -0
  97. data/lib/lib/telegram/wrappers.rb +41 -0
  98. data/lib/lib/tooling/lang.rb +24 -0
  99. data/lib/lib/tooling/log.rb +54 -0
  100. data/lib/lib/tooling/ruby.rb +25 -0
  101. data/lib/version.rb +3 -0
  102. data/logo.png +0 -0
  103. metadata +305 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '0591c8831efddb65fe397568eb0327c8f57c17836f7509ae91251147a2113625'
4
+ data.tar.gz: 87e1b6ada747943e22e2f06d1c61cbdf993cb4863f98790b9d4b529808b15b97
5
+ SHA512:
6
+ metadata.gz: 647a9aed6209576da9db0a8299ae2f5e20a76a11f69b189ba92f9f0fee23ad7dd0c56a3cc2b3f7cfb6704a4c7f02a4ddd532877521cbc04ea3279b23e191cfaa
7
+ data.tar.gz: 241afa9492fc9bef33ff66f29eb61bb1bf497140f1990d892785df43e74dfe014f5326e04a69452be1217d39b8d7de2fee43c4e1f3181d20b9ff19ce4fa797a6
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.gem
data/Gemfile ADDED
File without changes
@@ -0,0 +1,59 @@
1
+ require 'oj'
2
+ require 'nokogiri'
3
+
4
+ html = File.read('./api.html')
5
+ doc = Nokogiri::HTML(html)
6
+
7
+ tables = {}
8
+ headers = {}
9
+ res = {}
10
+ trRunCount = 0
11
+ tablesHeader = {}
12
+
13
+ doc.xpath('//table/tbody/tr').each do |row|
14
+ pre = {}
15
+ tdNum = 1
16
+ row.xpath('td').each do |cell|
17
+ case cell.text
18
+ when 'Field', 'Parameters'
19
+ trRunCount = 1 if trRunCount > 1
20
+ tablesHeader = {} if trRunCount > 1
21
+ end
22
+
23
+ if trRunCount == 1
24
+ tablesHeader[tdNum] = cell.text.strip.to_sym
25
+ else
26
+ case tablesHeader[tdNum]
27
+ when :Type, :Field
28
+ pre[tablesHeader[tdNum]] = cell.text.to_sym
29
+ else
30
+ pre[tablesHeader[tdNum]] = cell.text
31
+ end
32
+ end
33
+
34
+ # p "# trRunCount::#{trRunCount}, tdNum::#{tdNum}, tablesHeader::#{tablesHeader}, pre::#{pre}"
35
+ tdNum = tdNum + 1
36
+ end
37
+ trRunCount += 1
38
+ # p "#pre::#{pre}"
39
+ tables[row.line.to_i] = pre
40
+ end
41
+
42
+
43
+ doc.xpath('//h4').each do |row|
44
+ headers[row.line] = row.text
45
+ end
46
+
47
+ headers.each do |row, content|
48
+ i = 6
49
+ while i < 12
50
+ if tables.has_key?(row+i)
51
+ res[content.to_sym] = tables[row+i]
52
+ break
53
+ else
54
+ i = i+1
55
+ end
56
+ end
57
+ end
58
+
59
+ pp res
@@ -0,0 +1,69 @@
1
+ ######## ####### ######## ####### ######## ########
2
+ ## / / / / License \ \ \ \
3
+ ## Copyleft culture, Copyright (C) is prohibited here
4
+ ## This work is licensed under a CC BY-SA 4.0
5
+ ## Creative Commons Attribution-ShareAlike 4.0 License
6
+ ## Refer to the http://creativecommons.org/licenses/by-sa/4.0/
7
+ ######## ####### ######## ####### ######## ########
8
+ ## / / / / Code Climate \ \ \ \
9
+ ## Language = ruby
10
+ ## Indent = space; 2 chars;
11
+ ######## ####### ######## ####### ######## ########
12
+
13
+ module Bot
14
+ class Interfaces
15
+
16
+ def smsgDefaults(args)
17
+ args[:smsg][:parse_mode] = 'HTML'
18
+ args[:smsg][:chat_id] = args[:mmsg][:chat_id]
19
+ end
20
+
21
+ def kbInlineUsingCallback(args)
22
+ args[:sess] = {}
23
+ args[:smsg] = {}
24
+ args[:tmp] = {}
25
+
26
+ smsgDefaults(args)
27
+
28
+ kbInlineUsingCallbackKB(args)
29
+ kbInlineUsingCallbackAnswer(args)
30
+ if ! args[:run][:answer].nil?
31
+ kbInlineUsingCallbackDeleteMessages(args)
32
+ # args[:run][:tryMethod] = args[:run][:answer][:data] # working without explicit tryMethod
33
+ Bot::Convey.new.tryMethodRun(args)
34
+ end
35
+ end
36
+
37
+
38
+ def kbInlineUsingCallbackKB args
39
+ args[:run][:text] = args[:run][:textWithKB]
40
+ args[:tmp][:answer] = Bot::Atom.new.sendSimpleMessage(args)
41
+ end
42
+
43
+ def kbInlineUsingCallbackAnswer args
44
+ args[:tmp][:subPostfix] = 'Service_Callback_Query'
45
+ args[:tmp][:redisChannelpostfix] = args[:tmp][:answer]['result']['message_id']
46
+ Bot::RedisQueue.new.subGetUnsub(args)
47
+ if ! args[:run][:answer].nil?
48
+ args[:sess][:op] = 'answerCallbackQuery'
49
+ args[:smsg][:callback_query_id] = args[:mmsg][:query_id]
50
+ args[:smsg][:text] = "#{args[:run][:textAferKBPush]} #{args[:run][:answer]['data']}"
51
+ smsgDefaults(args)
52
+ Bot::BotApi.new.apiAction(args)
53
+ end
54
+ end
55
+
56
+ def kbInlineUsingCallbackDeleteMessages args
57
+ args[:sess][:op] = 'deleteMessage'
58
+ smsgDefaults(args)
59
+ args[:smsg][:message_id] = args[:mmsg][:message_id]
60
+ Bot::BotApi.new.apiAction(args)
61
+ if (args[:mmsg][:chat_context] == Naming::ChatContext.Botman or args[:mmsg][:chat_context] == Naming::ChatContext.Fullman)
62
+ args[:smsg][:message_id] = args[:mmsg][:reply_to_message_id]
63
+ Bot::BotApi.new.apiAction(args)
64
+ end
65
+ end
66
+
67
+ end
68
+ end
69
+
data/_dev/main.rb ADDED
@@ -0,0 +1,127 @@
1
+ ######## ####### ######## ####### ######## ########
2
+ ## / / / / License \ \ \ \
3
+ ## Copyleft culture, Copyright (C) is prohibited here
4
+ ## This work is licensed under a CC BY-SA 4.0
5
+ ## Creative Commons Attribution-ShareAlike 4.0 License
6
+ ## Refer to the http://creativecommons.org/licenses/by-sa/4.0/
7
+ ######## ####### ######## ####### ######## ########
8
+ ## / / / / Code Climate \ \ \ \
9
+ ## Language = ruby
10
+ ## Indent = space; 2 chars;
11
+ ######## ####### ######## ####### ######## ########
12
+
13
+ module Bot
14
+ class ConveyMeta
15
+
16
+ def hello_private(args)
17
+ <<~HEREDOC
18
+ Приветствую!
19
+ Я - своего рода, проводник по платформе прототипирования коммуникационных сред Dialog.
20
+ Моей задачей является рассказать о том, какие возможности для такого прототипирования предоставляет вам Dialog.
21
+ HEREDOC
22
+ end
23
+
24
+ def runMetacommand__start_main(args)
25
+ case args[:mmsg][:chat_context]
26
+ when 'Private'
27
+ args[:run][:inline_keyboard] = [
28
+ [{text: 'Что такое "прототипирование коммуникационных сред"', callback_data: '_что такое прототипирование'}],
29
+ # [{text: 'Как Dialog помогает в этом?', callback_data: '_как Dialog помогает'}],
30
+ [{text: 'С чего мне начать ', callback_data: '_с чего начать'}],
31
+ [{text: 'Список интерфейсов', callback_data: '_интерфейсы'}],
32
+ ]
33
+
34
+ args[:run][:textWithKB] = "Основное меню" if args[:run][:textWithKB] == false
35
+ args[:run][:textWithKB] = hello_private(args) if args[:run][:textWithKB].nil?
36
+ args[:run][:text_parse_mode] = 'HTML'
37
+ args[:run][:text_disable_web_page_preview] = 1
38
+
39
+ answer = Bot::Interfaces.new.kbInlineUsingCallback(args)
40
+ else
41
+ args[:run][:text] = "Мы пока не добавили сценарий для команды start контекста #{args[:mmsg][:chat_context]}"
42
+ Bot::Atom.new.sendSimpleMessage(args)
43
+ end
44
+ end
45
+
46
+ ###
47
+
48
+ def what_is_prototyping(args)
49
+ <<~HEREDOC
50
+ <b>"Прототипирование коммуникационных сред"</b> - \n это короткое наименование трёх параллельных движений: \n
51
+ 1) <b>Я вижу, что есть среда/группа/комьюнити</b> - то есть люди, объединённые общим интересом и имеющие определённые направление и плотность движения;
52
+ 2) <b>Я выражаю свой интерес к "совместному"</b>, а для этого я должен научиться описывать как своё и средовое движения по-отдельности, так и создать прототип этого "совместного";
53
+ 3) <b>Я понимаю, что в результате возникнет новое "совместное"</b>, и я, в силу своих способностей, должен быть способен рассказать/нарисовать/описать нашу модель коммуникации и её "прототип".
54
+
55
+ Чем же отличается <b>"модель"</b> от <b>"прототипа"</b>?
56
+
57
+ Вот хороший ответ:
58
+ "<b>Model</b>:
59
+ 1. Not necessarily functional (don't need to work).
60
+ 2. Can be to any scale (usually smaller but can also be of the original size or bigger).
61
+ 3. Used for Display or/and [Visual] Demonstration of product.
62
+ 4. May consist of only the exterior of the object/product it replicates.
63
+ 5. Relatively cheap to manufacture.
64
+
65
+ <b>Prototype</b>:
66
+ 1. Is fully functional, but not fault-proof.
67
+ 2. Is an actual version of the intended product.
68
+ 3. Used for performance evaluation and further improvement of product.
69
+ 4. Contains complete interior and exterior.
70
+ 5. Is relatively expensive to produce.
71
+ 6. Often used as a technology demonstrator"
72
+
73
+ HEREDOC
74
+ end
75
+
76
+ def runMetacommand__what_is_prototyping(args)
77
+ args[:run][:text_parse_mode] = 'HTML'
78
+ args[:run][:text] = what_is_prototyping(args)
79
+ Bot::Atom.new.sendSimpleMessage(args)
80
+ args[:run][:textWithKB] = false
81
+ runMetacommand__start_main(args)
82
+ end
83
+ alias runMetacommand__chto_takoe_prototipirovanie runMetacommand__what_is_prototyping
84
+
85
+ ###
86
+
87
+ def firstStep(args)
88
+ <<~HEREDOC
89
+ Начнём с того, что обозначим 5 режимов работы (<b>"контекстов"</b>):
90
+ 1) <b>Private</b> - режим общения с ботом тет-а-тет
91
+ 2) <b>Noman</b> - бот добавлен в обычную группу, права бота - как у обычного пользователя
92
+ 3) <b>Botman</b> - бот добавлен в обычную группу, права бота - администратор
93
+ 4) <b>Climan</b> - бот добавлен в специальную группу, права бота - как у обычного пользователя
94
+ 5) <b>Fullman</b> - бот добавлен в специальную группу, права бота - администратор
95
+
96
+ <b>"Обычная"</b> и <b>"специальная"</b> группы отличаются тем, что обычную создана человеком, а "специальная" - машиной, т.е. специальным аккаунтом, настроенным на взаимодействие с ботом.
97
+ Права администратора дают боту возможность управлять коллективным взаимодействием согласно прописанным сценариям.
98
+
99
+
100
+ В добавление к стандартному символу "/", используемому перед командой боту (например, "/start"), мы ввели дополнительный символ "_" для удобства общения с Dialog-ботами - например, "_start". Так же, команды могут даны на русском языке, например "_старт".
101
+
102
+ В режиме <b>'private'</b> можно писать ботам:
103
+ Боту @DialogDemoBot - это production-демобот
104
+ Боту @DialogDemoDevBot - это демобот для разработки и отладки
105
+
106
+ В режиме <b>'Noman'</b> работает группа https://t.me/joinchat/CCfa_1HM1ORbycphoyqmMw
107
+ В режиме <b>'Botman'</b> работает группа https://t.me/joinchat/CCfa_0ndJfLFH6f_Ec8Oig
108
+ В режиме <b>'Fullman'</b> работает группа https://t.me/joinchat/FTAtQEdYpbxl0i46Atadgw
109
+
110
+ Канал https://t.me/joinchat/AAAAAEwvsUuDodkHj74iJQ работает в режиме тестирования возможностей Dialog в каналах.
111
+ HEREDOC
112
+ end
113
+
114
+ def runMetacommand__start_with(args)
115
+ args[:run][:text_parse_mode] = 'HTML'
116
+ args[:run][:text] = firstStep(args)
117
+ Bot::Atom.new.sendSimpleMessage(args)
118
+ args[:run][:textWithKB] = false
119
+ runMetacommand__start_main(args)
120
+ end
121
+ alias runMetacommand__s_chego_nachat runMetacommand__start_with
122
+
123
+
124
+
125
+ end
126
+ end
127
+
@@ -0,0 +1,32 @@
1
+ ######## ####### ######## ####### ######## ########
2
+ ## / / / / License \ \ \ \
3
+ ## Copyleft culture, Copyright (C) is prohibited here
4
+ ## This work is licensed under a CC BY-SA 4.0
5
+ ## Creative Commons Attribution-ShareAlike 4.0 License
6
+ ## Refer to the http://creativecommons.org/licenses/by-sa/4.0/
7
+ ######## ####### ######## ####### ######## ########
8
+ ## / / / / Code Climate \ \ \ \
9
+ ## Language = ruby
10
+ ## Indent = space; 2 chars;
11
+ ######## ####### ######## ####### ######## ########
12
+
13
+ module Bot
14
+ class Atom
15
+
16
+ def restrictChatMember(args)
17
+ args[:smsg] = {}
18
+ args[:sess][:op] = 'restrictChatMember'
19
+ args[:smsg][:chat_id] = args[:mmsg][:chat_id]
20
+ args[:smsg][:user_id] = args[:run][:user_id]
21
+ args[:smsg][:until_date] = (Time.now.to_i + 2678400)
22
+ args[:smsg][:can_send_messages] = 0
23
+ args[:smsg][:can_send_media_messages] = 0
24
+ args[:smsg][:can_send_other_messages] = 0
25
+ args[:smsg][:can_add_web_page_previews] = 0
26
+ Bot::BotApi.new.apiAction(args)
27
+ end
28
+
29
+ end
30
+ end
31
+ #
32
+
data/_dev/ru.yml ADDED
@@ -0,0 +1,79 @@
1
+ ru:
2
+ redmine_bots:
3
+ label:
4
+ slack: Slack
5
+ telegram: Telegram
6
+ settings:
7
+ slack_oauth_token: OAuth Access Token
8
+ slack_bot_oauth_token: Bot User OAuth Access Token
9
+ slack_client_id: Client ID
10
+ slack_client_secret: Client Secret
11
+ slack_verification_token: Verification Token
12
+ telegram:
13
+ phone_number: "Номер телефона"
14
+ phone_number_hint: "В формате: 78005553535"
15
+ phone_code: "Код телеграмма"
16
+ authorize_button_code: "Получить код авторизации"
17
+ authorize_client: "Авторизовать клиент Telegram"
18
+ authorize_hint: "Чтобы авторизировать Telegram, нажмите кнопку ниже. Текущая авторизация сбросится."
19
+ authorize_button: "Авторизовать"
20
+ plugin_link: "К настройкам плагина"
21
+ auth_step_1: "Получение кода авторизации"
22
+ auth_step_2: "Авторизация"
23
+ reset: "Сбросить кеш и авторизацию"
24
+ bot_init: Инициализировать бота
25
+ bot_deinit: Деинициализировать бота
26
+ get_updates_hint: bundle exec rake telegram_common:bot
27
+ web_hooks_warning: Нужен https протокол, чтобы настроить WebHooks
28
+ use_proxy: Использовать прокси
29
+ requirements:
30
+ title: Требования
31
+ telegram:
32
+ title: Требования
33
+ valid: ОК
34
+ description: Описание
35
+ no: Нет
36
+ yes: Да
37
+ rails_env: "Убедитесь, что ваш RAILS_ENV — production (сейчас: %{rails_env})"
38
+ redmine_host: "Убедитесь, что установлен правильный хост в настройках Redmine (сейчас: %{host})"
39
+ tdlib_installation: "Необходимо поместить libtdjson в директорию redmine_root/vendor или добавить в ldconfig. <a href='https://core.telegram.org/tdlib/docs/#building' target='_blank'>Инструкции по сборке</a>."
40
+ telegram:
41
+ bot:
42
+ start:
43
+ instruction_html: |
44
+ Чтобы связать аккаунты Redmine и Telegram, пожалуйста, введите команду /connect.
45
+ hello: Здравствуйте!
46
+ connect:
47
+ already_connected: Ваши аккаунты уже связаны
48
+ wait_for_email: Мы отправили подтверждение на адрес "%{email}". Пожалуйста, следуйте инструкциям из письма.
49
+ wrong_email: Неверный email-адрес. Пользователь с таким адресом не найден. Осталось %{attempts} попытки, после чего аккаунт будет заблокирован на час.
50
+ blocked: Ваш аккаунт заблокирован. Попробуйте через %{unblock} мин.
51
+ login_link: "Для привязки аккаунта к Redmine проследуйте по ссылке: %{link}"
52
+ group:
53
+ no_commands: "Нет команд для группового чата. В приватном чате доступны следующие команды:"
54
+ private_command: 'Данная команда обрабатывается в личных сообщениях.'
55
+ private:
56
+ group_command: 'Данная команда обрабатывается в групповых чатах.'
57
+ help:
58
+ start: "Начало работы с ботом"
59
+ connect: "Связывание аккаунтов Redmine и Telegram"
60
+ help: "Справка по командам"
61
+ token: Получить ссылку для аутентификации
62
+ login:
63
+ success: Аутентификация прошла успешно
64
+ errors:
65
+ not_logged: Вы не залогинены в Redmine
66
+ hash_invalid: Неверный Hash
67
+ hash_outdated: Истекло время ожидания
68
+ wrong_account: Неверный аккаунт Telegram
69
+ not_persisted: Не удалось сохранить данные о Telegram-аккаунте
70
+ invalid_token: Неверный token
71
+ follow_link: Пожалуйста, проследуйте по ссылке
72
+ send_to_telegram: Отправить ссылку в Telegram
73
+ widget_not_visible: если виджет недоступен
74
+ write_to_bot: "Пожалуйста, напишите команду /token боту @%{bot}, если не видно виджет"
75
+ slack:
76
+ commands:
77
+ connect: связывание аккаунтов Slack и Redmine
78
+ help: помощь по командам
79
+
data/_dev/sidekiq.rb ADDED
@@ -0,0 +1,28 @@
1
+ class TelegramHandlerWorker
2
+ include Sidekiq::Worker
3
+ sidekiq_options queue: :telegram
4
+
5
+ TYPES = %w(inline_query
6
+ chosen_inline_result
7
+ callback_query
8
+ edited_message
9
+ message
10
+ channel_post
11
+ edited_channel_post)
12
+
13
+ def perform(params)
14
+ update = Telegram::Bot::Types::Update.new(params)
15
+ message = TYPES.reduce(nil) { |m, t| m || update.public_send(t) }
16
+
17
+ if message.present?
18
+ RedmineBots::Telegram.update_manager.handle_message(message)
19
+ else
20
+ logger.fatal "Can't find message: #{params.to_json}"
21
+ end
22
+ end
23
+
24
+ def logger
25
+ @logger ||= Logger.new(Rails.root.join('log/redmine_bots',
26
+ 'telegram-handler.log'))
27
+ end
28
+ end
data/_dev/tdlib.rb ADDED
@@ -0,0 +1,154 @@
1
+ ## auth finish
2
+
3
+ when 'authorizationStateReady'
4
+ fetch_all_chats
5
+ return
6
+
7
+ def fetch_all_chats
8
+ offset_order = 2**63 - 1
9
+ offset_chat_id = 0
10
+ limit = 100
11
+
12
+ loop do
13
+ chat_ids = @client.fetch('@type' => 'getChats', 'offset_order' => offset_order, 'offset_chat_id' => offset_chat_id, 'limit' => limit).tap(&error_handler)['chat_ids']
14
+ break if chat_ids.empty?
15
+ last_chat = @client.fetch('@type' => 'getChat', 'chat_id' => chat_ids.last).tap(&error_handler)
16
+ offset_chat_id, offset_order = last_chat.values_at('id', 'order')
17
+ end
18
+ end
19
+
20
+ ## get_chat
21
+ @client.on_ready do |client|
22
+ client.fetch('@type' => 'getChat', 'chat_id' => id)
23
+
24
+ ## add_bot
25
+ @client.on_ready do |client|
26
+ chat = client.fetch('@type' => 'createPrivateChat', 'user_id' => bot_id)
27
+ client.fetch('@type' => 'sendBotStartMessage',
28
+ 'bot_user_id' => bot_id,
29
+ 'chat_id' => chat['id'])
30
+ end
31
+
32
+ ## create_chat
33
+ "chat_create_supergroup '#{chatname}' '#{args[:sess][:chatDesc]}'",
34
+ "chat_export_invite_link #{chatname}",
35
+ "chat_add_user #{chatname} @#{args[:mmsg][:username]}",
36
+ "chat_add_user #{chatname} @#{args[:globals][:botUsername]}",
37
+ "chat_change_role #{chatname} @#{args[:globals][:botUsername]} editor"
38
+
39
+ @client.on_ready(timeout: 5) do |client|
40
+ user_ids.each do |id|
41
+ client.fetch('@type' => 'getUser', 'user_id' => id)
42
+ end
43
+
44
+ sleep 1
45
+
46
+ chat = client.fetch('@type' => 'createNewBasicGroupChat',
47
+ 'title' => title,
48
+ 'user_ids' => user_ids)
49
+
50
+ sleep 1
51
+
52
+ client.fetch('@type' => 'toggleBasicGroupAdministrators',
53
+ 'basic_group_id' => chat.dig('type', 'basic_group_id'),
54
+ 'everyone_is_administrator' => false)
55
+ chat
56
+ end
57
+
58
+
59
+ ## get_user
60
+ @client.on_ready do |client|
61
+ client.fetch('@type' => 'getUser', 'user_id' => user_id)
62
+ end
63
+ end
64
+
65
+ ## rename_chat
66
+ @client.on_ready do |client|
67
+ client.fetch('@type' => 'setChatTitle',
68
+ 'chat_id' => chat_id,
69
+ 'title' => new_title)
70
+ end
71
+
72
+ ## get_chat
73
+ @client.on_ready do |client|
74
+ client.fetch('@type' => 'getChat', 'chat_id' => id)
75
+ end
76
+
77
+ ## toggle_chat_admin
78
+ status =
79
+ if admin
80
+ { '@type' => 'chatMemberStatusAdministrator',
81
+ 'can_change_info' => true,
82
+ 'can_edit_messages' => true,
83
+ 'can_delete_messages' => true,
84
+ 'can_invite_users' => true,
85
+ 'can_restrict_members' => true,
86
+ 'can_pin_messages' => true,
87
+ 'can_promote_members' => true }
88
+ else
89
+ { '@type' => 'chatMemberStatusMember' }
90
+ end
91
+ @client.on_ready do |client|
92
+ client.fetch('@type' => 'getUser', 'user_id' => user_id)
93
+ client.fetch('@type' => 'setChatMemberStatus',
94
+ 'chat_id' => chat_id,
95
+ 'user_id' => user_id,
96
+ 'status' => status)
97
+ end
98
+
99
+ ## delete_member
100
+ @client.fetch('@type' => 'setChatMemberStatus',
101
+ 'chat_id' => chat_id,
102
+ 'user_id' => user_id,
103
+ 'status' => { '@type' => 'chatMemberStatusLeft' })
104
+
105
+ ## close_chat
106
+ @client.on_ready do |client|
107
+ me = client.fetch('@type' => 'getMe')
108
+ bot_id = Setting.find_by(name: 'plugin_redmine_bots').value['telegram_bot_id'].to_i
109
+
110
+ chat = client.fetch('@type' => 'getChat', 'chat_id' => chat_id)
111
+
112
+ group_info = client.fetch('@type' => 'getBasicGroupFullInfo',
113
+ 'basic_group_id' => chat.dig('type', 'basic_group_id')
114
+ )
115
+ return if group_info['@type'] == 'error'
116
+
117
+ group_info['members'].map { |m| m['user_id'] }.each do |user_id|
118
+ delete_member(chat_id, user_id) unless user_id.in?([me['id'], bot_id])
119
+ end
120
+
121
+ delete_member(chat_id, me['id'])
122
+ delete_member(chat_id, bot_id)
123
+ end
124
+
125
+
126
+ ## get_chat_link
127
+ @client.on_ready do |client|
128
+ client.fetch('@type' => 'generateChatInviteLink', 'chat_id' => chat_id)
129
+ end
130
+
131
+
132
+ ## error handling
133
+ bot.api.send_message(message_params)
134
+ rescue BotKickedError
135
+ logger.warn("Bot was kicked from chat. Chat Id: #{chat_id}, params: #{params.inspect}")
136
+ rescue FloodError => e
137
+ logger.warn("Too many requests. Sleeping #{SLEEP_TIME} seconds...")
138
+ sleep SLEEP_TIME
139
+ (tries -= 1).zero? ? raise(e) : retry
140
+ end
141
+
142
+ SLEEP_TIME = 30
143
+
144
+ class BotKickedError
145
+ def self.===(e)
146
+ e.is_a?(Telegram::Bot::Exceptions::ResponseError) && e.message.include?('kicked')
147
+ end
148
+ end
149
+
150
+ class FloodError
151
+ def self.===(e)
152
+ e.is_a?(Telegram::Bot::Exceptions::ResponseError) && e.message.include?('Too Many Requests')
153
+ end
154
+ end