dialog_ruby 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/Gemfile +0 -0
- data/_dev/get_full_botapi.rb +59 -0
- data/_dev/inlinekb_pubsub.rb +69 -0
- data/_dev/main.rb +127 -0
- data/_dev/restriction.rb +32 -0
- data/_dev/ru.yml +79 -0
- data/_dev/sidekiq.rb +28 -0
- data/_dev/tdlib.rb +154 -0
- data/dialog.sh +51 -0
- data/dialog_ruby.gemspec +41 -0
- data/lib/architecture.md +22 -0
- data/lib/configuration.rb +117 -0
- data/lib/dialogStart.rb +189 -0
- data/lib/dialog_ruby.rb +59 -0
- data/lib/exec.sh +61 -0
- data/lib/exec_conf/cli_config +7 -0
- data/lib/exec_conf/dialog__sync.service +14 -0
- data/lib/exec_conf/dialog__sync.timer +11 -0
- data/lib/exec_conf/dialog_bot@.path +6 -0
- data/lib/exec_conf/dialog_bot@.service +18 -0
- data/lib/exec_conf/dialog_bot_dev@.path +6 -0
- data/lib/exec_conf/dialog_bot_dev_pre@.service +16 -0
- data/lib/exec_conf/dialog_bot_pre@.service +16 -0
- data/lib/exec_conf/dialog_redis@.service +14 -0
- data/lib/exec_conf/post-merge +5 -0
- data/lib/exec_conf/redis_global.conf +49 -0
- data/lib/exec_conf/redis_local.conf +4 -0
- data/lib/lang/global_ru.yml +29 -0
- data/lib/lib/dialect/canvas/canvas.rb +35 -0
- data/lib/lib/dialect/canvas/element/convert/SearchBaloo.rb +45 -0
- data/lib/lib/dialect/canvas/element/data/search.rb +34 -0
- data/lib/lib/dialect/canvas/element/send/Inline_query_result.rb +32 -0
- data/lib/lib/dialect/canvas/element/send/bot_message.rb +38 -0
- data/lib/lib/dialect/canvas/element/send/keyboards.rb +59 -0
- data/lib/lib/dialect/canvas/element/send/recognize.rb +51 -0
- data/lib/lib/dialect/canvas/element/send/restrict.rb +42 -0
- data/lib/lib/dialect/canvas/element/send/tdlib_chat.rb +33 -0
- data/lib/lib/dialect/canvas/element/send/tdlib_message.rb +38 -0
- data/lib/lib/dialect/canvas/mod/send/_Inline_query_result.rb +38 -0
- data/lib/lib/dialect/canvas/mod/send/_keyboards.rb +40 -0
- data/lib/lib/dialect/canvas/mod/send/func.rb +98 -0
- data/lib/lib/dialect/canvas/mod/send/general/_heads.rb +27 -0
- data/lib/lib/dialect/canvas/mod/send/general/chat.rb +38 -0
- data/lib/lib/dialect/canvas/mod/send/general/common.rb +32 -0
- data/lib/lib/dialect/canvas/mod/send/general/message.rb +37 -0
- data/lib/lib/dialect/canvas/mod/send/general/user.rb +36 -0
- data/lib/lib/dialect/canvas/mod/send/inline_query_result/common.rb +36 -0
- data/lib/lib/dialect/codegen/codegen.rb +74 -0
- data/lib/lib/dialect/codegen/erb/data/1.ModReceive2GetData.erb +27 -0
- data/lib/lib/dialect/codegen/erb/data/2.GetData2Elements.erb +27 -0
- data/lib/lib/dialect/codegen/erb/data/3.GenData2Dest.erb +34 -0
- data/lib/lib/dialect/codegen/erb/functional/1.Expect2Events.erb +37 -0
- data/lib/lib/dialect/codegen/erb/functional/2.1.Events2AppEvent.erb +26 -0
- data/lib/lib/dialect/codegen/erb/functional/2.2.1.Events2ModReceive.erb +73 -0
- data/lib/lib/dialect/codegen/erb/functional/2.2.2.ModReceive2AppEvent.erb +59 -0
- data/lib/lib/dialect/codegen/erb/functional/3.Appevent2EventBus.erb +35 -0
- data/lib/lib/dialect/codegen/erb/functional/4.1.AppEvent2Elements.erb +72 -0
- data/lib/lib/dialect/codegen/erb/functional/5.1.Element2ModElements.erb +70 -0
- data/lib/lib/dialect/codegen/erb/functional/5.2.Element2ModSend.erb +69 -0
- data/lib/lib/dialect/codegen/erb/functional/7.ElementChains.erb +91 -0
- data/lib/lib/dialect/codegen/repack/constructor/DockedGroupings2AppFunctions.rb +36 -0
- data/lib/lib/dialect/codegen/repack/constructor/Element2ModSend.rb +49 -0
- data/lib/lib/dialect/codegen/repack/constructor/ElementsInElements.rb +34 -0
- data/lib/lib/dialect/codegen/repack/functional/1.Expect2Events.rb +35 -0
- data/lib/lib/dialect/codegen/repack/functional/2.2.1.Events2ModReceive.rb +71 -0
- data/lib/lib/dialect/codegen/repack/functional/2.2.2.ModReceive2AppEvent.rb +45 -0
- data/lib/lib/dialect/codegen/repack/functional/5.1.Element2ModElements.rb +90 -0
- data/lib/lib/dialect/codegen/repack/functional/5.2.Element2ModSend.rb +60 -0
- data/lib/lib/dialect/codegen/repack/functional/7.ElementChains.rb +88 -0
- data/lib/lib/dialect/codegen/run.rb +79 -0
- data/lib/lib/metamess/_run.rb +162 -0
- data/lib/lib/metamess/content/content_o-command_f.rb +100 -0
- data/lib/lib/metamess/content/content_o-media_f.rb +149 -0
- data/lib/lib/metamess/content/content_o-simple_f.rb +35 -0
- data/lib/lib/metamess/content/content_o.rb +245 -0
- data/lib/lib/metamess/event/notify_o-chatmember_f.rb +124 -0
- data/lib/lib/metamess/event/notify_o-chattitle_f.rb +34 -0
- data/lib/lib/metamess/event/notify_o-create_f.rb +42 -0
- data/lib/lib/metamess/event/notify_o-migrate_f.rb +34 -0
- data/lib/lib/metamess/event/notify_o-pinned_f.rb +34 -0
- data/lib/lib/metamess/event/notify_o.rb +28 -0
- data/lib/lib/metamess/event_c.rb +26 -0
- data/lib/lib/metamess/func.rb +220 -0
- data/lib/lib/metamess/service/service_o-callback_f.rb +33 -0
- data/lib/lib/metamess/service/service_o-inline_f.rb +55 -0
- data/lib/lib/metamess/service/service_o.rb +26 -0
- data/lib/lib/naming.rb +130 -0
- data/lib/lib/storage/redis/redisPubSub.rb +51 -0
- data/lib/lib/storage/redis/rediscached.rb +97 -0
- data/lib/lib/tdlib/auth.rb +141 -0
- data/lib/lib/tdlib/func.rb +34 -0
- data/lib/lib/tdlib/init.rb +39 -0
- data/lib/lib/telegram/botapi.rb +71 -0
- data/lib/lib/telegram/infra_info.rb +50 -0
- data/lib/lib/telegram/wrappers.rb +41 -0
- data/lib/lib/tooling/lang.rb +24 -0
- data/lib/lib/tooling/log.rb +54 -0
- data/lib/lib/tooling/ruby.rb +25 -0
- data/lib/version.rb +3 -0
- data/logo.png +0 -0
- 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
|
+
|
data/_dev/restriction.rb
ADDED
@@ -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
|