dialog_ruby 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|