forked from Tavalik/Perezalivator
-
Notifications
You must be signed in to change notification settings - Fork 1
/
telegram_servise.os
444 lines (361 loc) · 26.2 KB
/
telegram_servise.os
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
#Использовать sql
#Использовать asserts
#Использовать messenger
#Использовать json
Перем Соединение, BotID, ServiceID, Мессенджер, СообщениеОтАдмина, ДоступныеКоманды, ДоступныеКомандыАдмина, ОсновныеНастройки Экспорт;
Перем СоответствияСтатусов, ИмяФайлаНастроекПоУмолчанию Экспорт;
Процедура ПрочитатьСообщения()
БазаДанныхСуществует();
ПоследнийНомер = ПоследнийНомер();
ПараметрыЗапроса = Новый Структура;
Если НЕ ПоследнийНомер = Неопределено Тогда
ПараметрыЗапроса.Вставить("offset", Формат(ПоследнийНомер+1, "ЧГ="));
КонецЕсли;
ПулСообщений = ВызватьМетодTelegramAPI("getUpdates",ПараметрыЗапроса);
Если ПулСообщений.КодСостояния <> 200 Тогда
ОтправитьСообщение("Ошибка при опросе новый сообщений:" + Символы.ПС + ПулСообщений.ПолучитьТелоКакСтроку());
КонецЕсли;
Парсер = Новый ПарсерJSON();
Ответ = Парсер.ПрочитатьJSON(ПулСообщений.ПолучитьТелоКакСтроку(),,, Истина);
Ожидаем.Что(Ответ.ok).ЭтоИстина();
СтатусБота = СтатусБлокировкиБота();
Для Каждого Сообщение Из Ответ.result Цикл
Если Сообщение.Свойство("message") Тогда //сообщения
Отправитель = Сообщение.message.from;
СообщениеОтАдмина = НЕ ServiceID.Найти(Отправитель.id) = Неопределено;
Если СтатусБота.БотСейчасЗаблокирован И НЕ СообщениеОтАдмина Тогда
ОтправитьСообщение("Бот сейчас заблокирован. Повторите попытку позже.", Отправитель.id);
Иначе
Если СтатусПользователя(Отправитель.id) = 0 Тогда //ожидает одобрения
ОтправитьСообщение("Администратор еще не одобрил вашу регистрацию", Отправитель.id);
ИначеЕсли СтатусПользователя(Отправитель.id) = 1 Тогда //одобрен
ВыполнитьКоманду(Сообщение.message,СообщениеОтАдмина);
ИначеЕсли СтатусПользователя(Отправитель.id) = 2 Тогда //в игнор листе
//Или любой другой текст, который бы не сильно обидел человека, за то, что его отправили в игнор.
ОтправитьСообщение("Произошла ошибка подключения", Отправитель.id);
//Сообщить("Пользователь " + Отправитель.first_name + " (" + Отправитель.id + ")" + " в игноре.")
ИначеЕсли СтатусПользователя(Отправитель.id) = -1 Тогда
Если СообщениеОтАдмина Тогда
//Админа добавляем сразу
ОбновитьСтатусПользователя(Отправитель.id, 1, Отправитель.first_name, 0);
ОтправитьСообщение("Вы добавлены как администратор", Отправитель.id);
Иначе
Для Каждого ChatID Из ServiceID Цикл
ОтправитьСообщениеАвторизации(ChatID, СтрШаблон("Хочет добавиться новый пользователь %1 с ID %2", Отправитель.first_name, Отправитель.id),Отправитель.id);
КонецЦикла;
ОбновитьСтатусПользователя(Отправитель.id, 0, Отправитель.first_name, 0);
ОтправитьСообщение("Ваш запрос принят, ожидайте уведомления администратора", Отправитель.id);
КонецЕсли;
КонецЕсли;
КонецЕсли;
ИначеЕсли Сообщение.Свойство("callback_query") Тогда //события клавиатуры
СообщениеОтАдмина = НЕ ServiceID.Найти(Сообщение.callback_query.from.id) = Неопределено;
Если НЕ СообщениеОтАдмина Тогда
Продолжить
КонецЕсли;//только админы могут отвечать
ТекстСообщения = "";
IDПользователя = Число(Прав(Сообщение.callback_query.data,СтрДлина(Сообщение.callback_query.data)-2));
ДанныеПользователя = СтатусПользователя(IDПользователя, Ложь);
Если СтрНачинаетсяС(Сообщение.callback_query.data, "AY") Тогда //подтвердить
ТекстСообщения = "✔ Авторизация %1 с ID %2 подтверждена.";
ОбновитьСтатусПользователя(IDПользователя, 1);
ОтправитьСообщение("Администратор вас авторизовал. Используйте /help для просмотра доступных команд.", IDПользователя);
ИначеЕсли СтрНачинаетсяС(Сообщение.callback_query.data, "AN") Тогда // отклонить
ТекстСообщения = "✖ Авторизация %1 с ID %2 отклонена.";
ОбновитьСтатусПользователя(IDПользователя, 3);
ОтправитьСообщение("Администратор отклонил вашу авторизацию", IDПользователя);
ИначеЕсли СтрНачинаетсяС(Сообщение.callback_query.data, "AI") Тогда // игнорировать
ТекстСообщения = "❌ Авторизация %1 с ID %2 игнорируется.";
ОбновитьСтатусПользователя(IDПользователя, 2);
ОтправитьСообщение("Произошла ошибка авторизации. Свяжитесь с администратором", IDПользователя);
Иначе
// пришла неведомая фигня, игнорируес
Продолжить;
КонецЕсли;
ТекстСообщения = СтрШаблон(ТекстСообщения, ДанныеПользователя.Name, IDПользователя);
Для Каждого ChatID Из ServiceID Цикл
СкрытьКлавиатуруАвторизации(ChatID, ТекстСообщения);
КонецЦикла;
КонецЕсли;
ОбновитьПоследнийНомер(Сообщение.update_id);
КонецЦикла;
//Сообщить(ПулСообщений.ПолучитьТелоКакСтроку());
КонецПроцедуры
Процедура ОтправитьСообщениеАвторизации(ChatID, ТекстСообщения, IDПользователя)
ПараметрыЗапроса = Новый Структура;
ПараметрыЗапроса.Вставить("chat_id",ChatID);
ПараметрыЗапроса.Вставить("text", ТекстСообщения);
//https://apps.timwhitlock.info/emoji/tables/unicode
ПараметрыЗапроса.Вставить("reply_markup",
"{
|""inline_keyboard"":[
| [
| {""text"":""✔ Добавить"",""callback_data"":""AY"+ IDПользователя +"""},
| {""text"":""✖ Отказать"",""callback_data"":""AN"+ IDПользователя +"""},
| {""text"":""❌ Игнорировать"",""callback_data"":""AI"+ IDПользователя +"""}
| ]
|],
|""one_time_keyboard"":true
|}");
ВызватьМетодTelegramAPI("sendMessage",ПараметрыЗапроса);
КонецПроцедуры
Процедура СкрытьКлавиатуруАвторизации(ChatID, Сообщение)
ПараметрыЗапроса = Новый Структура;
ПараметрыЗапроса.Вставить("chat_id",ChatID);
ПараметрыЗапроса.Вставить("text",Сообщение);
ПараметрыЗапроса.Вставить("reply_markup", "{""inline_keyboard"":[[]]}");
ВызватьМетодTelegramAPI("sendMessage",ПараметрыЗапроса);
КонецПроцедуры
Функция ОбновитьПоследнийНомер(IDСообщения)
ЗапросВставка = Новый Запрос();
ЗапросВставка.УстановитьСоединение(Соединение);
ЗапросВставка.Текст = "delete from lastID ";
ЗапросВставка.ВыполнитьКоманду();
ЗапросВставка.Текст = "insert into lastID (id) values(@id)";
ЗапросВставка.УстановитьПараметр("id", IDСообщения);
ЗапросВставка.ВыполнитьКоманду();
КонецФункции
Функция ПоследнийНомер()
ЗапросВставка = Новый Запрос();
ЗапросВставка.УстановитьСоединение(Соединение);
ЗапросВставка.Текст = "select * from lastID";
ТЗ = ЗапросВставка.Выполнить().Выгрузить();
Если ТЗ.Количество() Тогда
Возврат ТЗ[0].id;
Иначе
Возврат Неопределено;
КонецЕсли;
КонецФункции
// Получить статус пользователя
//
// Параметры:
// IDПользователя - число - id пользователя
//
Функция СтатусПользователя(IDПользователя = Неопределено, ВозвращатьТолькоСтатус = Истина)
ЗапросВставка = Новый Запрос();
ЗапросВставка.УстановитьСоединение(Соединение);
ЗапросВставка.Текст = "select * from usersID " + ?(ЗначениеЗаполнено(IDПользователя), " where id = @id", "");
Если ЗначениеЗаполнено(IDПользователя) Тогда
ЗапросВставка.УстановитьПараметр("id", IDПользователя);
КонецЕсли;
ТЗ = ЗапросВставка.Выполнить().Выгрузить();
Если ТЗ.Количество() > 0 Тогда
Если ВозвращатьТолькоСтатус Тогда
Возврат ТЗ[0].status;
Иначе
Возврат ?(ЗначениеЗаполнено(IDПользователя), ТЗ[0], ТЗ)
КонецЕсли;
Иначе Возврат -1; //Новый пользователь
КонецЕсли;
КонецФункции
// Обновляет текущий статус пользователя
//
// Параметры:
// ClientID - Число - ID пользователя в чате
// Status - Байт - Статус клиента
// 0 - Пользователь ожидает одобрения
// 1 - Пользователь одобрен
// 2 - Пользователь в игнор листе (любое взаимодействие с ним игнорируется)
// 3 - Пользователя авторизация отклонена
// Name - Строка - Имя пользователя телеграм
// Обновление - Булево - Вид обновления статуса
// Истина - Обновляет ранее созданую запись
// Ложь - Добавляет новую запись
//
Процедура ОбновитьСтатусПользователя(ClientID, Status, Name = "", Обновление = Истина)
ЗапросВставка = Новый Запрос();
ЗапросВставка.УстановитьСоединение(Соединение);
Если Обновление Тогда
ЗапросВставка.Текст = "update usersID set status = @status where id = @id";
Иначе
ЗапросВставка.Текст = "insert into usersID (id, name, status) values(@id, @name, @status)";
КонецЕсли;
ЗапросВставка.УстановитьПараметр("id", ClientID);
ЗапросВставка.УстановитьПараметр("name", Name);
ЗапросВставка.УстановитьПараметр("status", Status);
Результат = ЗапросВставка.ВыполнитьКоманду();
Ожидаем.Что(Результат).Равно(1);
КонецПроцедуры
Функция БазаДанныхСуществует()
ФайлБД = Новый Файл("sqlite\telegram.sqlite");
ПолноеИмяБД = ФайлБД.ПолноеИмя;
Соединение = Новый Соединение();
Соединение.ТипСУБД = Соединение.ТипыСУБД.sqlite;
Соединение.ИмяБазы = ПолноеИмяБД;
Если (ФайлБД.Существует()) Тогда
Соединение.Открыть();
Возврат Истина;
КонецЕсли;
Соединение.Открыть();
ЗапросВставка = Новый Запрос();
ЗапросВставка.УстановитьСоединение(Соединение);
ЗапросВставка.Текст = "Create table usersID (id integer, name text, status byte)";
ЗапросВставка.ВыполнитьКоманду();
ЗапросВставка.Текст = "Create table lastID (id integer)";
ЗапросВставка.ВыполнитьКоманду();
ЗапросВставка.Текст = "Create table lockBot (time integer, period datetime)";
ЗапросВставка.ВыполнитьКоманду();
ЗапросВставка.Текст = "insert into lockBot (time,period) values(@time, @period)";
ЗапросВставка.УстановитьПараметр("time", 0);
ЗапросВставка.УстановитьПараметр("period", ТекущаяДата());
ЗапросВставка.ВыполнитьКоманду();
Ожидаем.Что(ФайлБД.Существует()).ЭтоИстина();
Освободитьобъект(ФайлБД);
ОтправитьСообщение("Была создана новая база данных пользователей Telegram");
Возврат Истина;
КонецФункции
Процедура ОтправитьСообщение(ТекстСообщения, IDПользователя = Неопределено) Экспорт
МассивПолучателей = Новый Массив;
Если IDПользователя = Неопределено Тогда
МассивПолучателей = ServiceID;
ИначеЕсли НЕ ТипЗнч(IDПользователя) = Тип("Массив") Тогда
МассивПолучателей.Добавить(IDПользователя);
Иначе
МассивПолучателей = IDПользователя;
КонецЕсли;
Для Каждого Пользователь Из МассивПолучателей Цикл
Мессенджер.ОтправитьСообщение("telegram", Пользователь, "" + Символы.ПС + ТекстСообщения + Символы.ПС + "", ,"md");
КонецЦикла;
КонецПроцедуры
Функция ВызватьМетодTelegramAPI(ИмяМетода, Параметры)
СтрокаПараметров = "";
Для Каждого Параметр Из Параметры Цикл
Шаблон = "%1=%2&";
СтрокаПараметров = СтрокаПараметров + СтрШаблон(Шаблон, Параметр.Ключ, СтрЗаменить(Параметр.Значение, Символы.ПС, ""));
КонецЦикла;
ИмяСервера = "https://api.telegram.org";
URL = "/bot"
+ BotID
+ "/" + ИмяМетода
+ "?" + СтрокаПараметров;
HTTPЗапрос = Новый HTTPЗапрос(URL);
HTTP = Новый HTTPСоединение(ИмяСервера);
ОтветHTTP = HTTP.ОтправитьДляОбработки(HTTPЗапрос);
Возврат ОтветHTTP;
КонецФункции
Функция ДоступныеНастройки(ИмяФайла = "") Экспорт
Данные = Новый ЧтениеТекста(?(ЗначениеЗаполнено(ИмяФайла), ИмяФайла, ИмяФайлаНастроекПоУмолчанию));
Парсер = Новый ПарсерJSON();
Возврат Парсер.ПрочитатьJSON(Данные.Прочитать(),,,Истина);
КонецФункции
//Обработка запроса авторизованного пользователя
Процедура ВыполнитьКоманду(Сообщение, Админ)
СообщениеПользователю = "Произошла непредвиденная ошибка.";
НайденаКомандаАдмина = Ложь;
Если Админ Тогда
Если нРег(Сообщение.text) = "/users" Тогда
НайденаКомандаАдмина = Истина;
ТекущиеПользователи = СтатусПользователя(, Ложь);
МассивПользователей = Новый Массив;
Для Каждого Пользователь Из ТекущиеПользователи Цикл
ОтправитьСообщениеАвторизации(Сообщение.from.id, СтрШаблон("Пользователь %1 с ID %2 в статусе %3 ",Пользователь.Name,Пользователь.ID, СоответствияСтатусов[Пользователь.status]),Пользователь.ID);
КонецЦикла;
Возврат;
ИначеЕсли СтрНачинаетсяС(нРег(Сообщение.text), "/lock") Тогда
Параметры = СтрРазделить(Сообщение.text," ");
Если Параметры[0] = "/lock" Тогда
БлокировкаБота(?(Параметры.Количество() = 1, -1, Параметры[1]));
Сообщение.text = "/lockstat";
КонецЕсли;
ИначеЕсли нРег(Сообщение.text) = "/unlock" Тогда
БлокировкаБота(0);
Сообщение.text = "/lockstat";
Иначе
СообщениеПользователю = "Я не понял команду. Используйте /help для просмотра доступных команд";
КонецЕсли;
Если НайденаКомандаАдмина Тогда
ОтправитьСообщение(СообщениеПользователю, Сообщение.from.id);
Возврат;
КонецЕсли;
КонецЕсли;
Если нРег(Сообщение.text) = "/help" Тогда
СообщениеПользователю = ДоступныеКоманды;
Если Админ Тогда
СообщениеПользователю = СообщениеПользователю + Символы.ПС + ДоступныеКомандыАдмина;
КонецЕсли;
ИначеЕсли нРег(Сообщение.text) = "/source" Тогда
МассивБаз = Новый Массив;
Для Каждого Источник Из ОсновныеНастройки.Источники Цикл
МассивБаз.Добавить(Источник.Имя)
КонецЦикла;
СообщениеПользователю = СтрСоединить(МассивБаз, Символы.ПС);
ИначеЕсли нРег(Сообщение.text) = "/dest" Тогда
МассивБаз = Новый Массив;
Для Каждого Приемник Из ОсновныеНастройки.Приемники Цикл
МассивБаз.Добавить(Приемник.Имя)
КонецЦикла;
СообщениеПользователю = СтрСоединить(МассивБаз, Символы.ПС);
ИначеЕсли нРег(Сообщение.text) = "/lockstat" Тогда
ТекущийСтатусБлокировки = СтатусБлокировкиБота();
Если ТекущийСтатусБлокировки.Длительность = 0 Тогда
СообщениеПользователю = "Работа не заблокирована. Статус изменен в " + ТекущийСтатусБлокировки.Дата;
ИначеЕсли ТекущийСтатусБлокировки.Длительность = -1 Тогда
СообщениеПользователю = "Работа заблокирована на неограниченный срок. Статус изменен в " + ТекущийСтатусБлокировки.Дата;
Иначе
СообщениеПользователю = "Работа заблокирована до " + (ТекущийСтатусБлокировки.Дата + ТекущийСтатусБлокировки.Длительность*60) + ". Статус изменен в " + ТекущийСтатусБлокировки.Дата;
КонецЕсли;
Иначе
СообщениеПользователю = "Я не понял команду. Используйте /help для просмотра доступных команд";
КонецЕсли;
ОтправитьСообщение(СообщениеПользователю, Сообщение.from.id);
КонецПроцедуры
Процедура БлокировкаБота(Длительность = 0)
ЗапросВставка = Новый Запрос();
ЗапросВставка.УстановитьСоединение(Соединение);
ЗапросВставка.Текст = "update lockBot set time = @time, period = @period";
ЗапросВставка.УстановитьПараметр("time", Длительность);
ЗапросВставка.УстановитьПараметр("period", ТекущаяДата());
ЗапросВставка.ВыполнитьКоманду();
КонецПроцедуры
Функция СтатусБлокировкиБота()
ЗапросВставка = Новый Запрос();
ЗапросВставка.УстановитьСоединение(Соединение);
ЗапросВставка.Текст = "select * from lockBot";
ТЗ = ЗапросВставка.Выполнить().Выгрузить();
Стр = Новый Структура("Длительность, Дата", ТЗ[0].time, ТЗ[0].period);
БотСейчасЗаблокирован = Ложь;
Если ТЗ[0].time = -1 Тогда
БотСейчасЗаблокирован = Истина;
ИначеЕсли ТЗ[0].time > 0 Тогда
Если ТекущаяДата() > Стр.Дата + Стр.Длительность*60 Тогда
БлокировкаБота();//Снимаем блокировку
Стр.Длительность = 0;
Стр.Дата = ТекущаяДата();
Иначе
БотСейчасЗаблокирован = Истина;
КонецЕсли;
КонецЕсли;
Стр.Вставить("БотСейчасЗаблокирован",БотСейчасЗаблокирован);
Возврат Стр;
КонецФункции
Соединение = Неопределено;
СообщениеОтАдмина = Ложь;
ИмяФайлаНастроекПоУмолчанию = "Perezalivator_Params.json";
ОсновныеНастройки = ДоступныеНастройки();
BotID = ОсновныеНастройки.ПрочиеНастройки.TelegramBotID;
ServiceID = ОсновныеНастройки.ПрочиеНастройки.BotAdmin;
Ожидаем.Что(ServiceID.Количество()).Больше(0);
Мессенджер = Новый Мессенджер();
Мессенджер.ИнициализироватьТранспорт("telegram", Новый Структура("Логин", BotID));
СоответствияСтатусов = Новый Соответствие;
СоответствияСтатусов.Вставить(-1, "Новый запрос");
СоответствияСтатусов.Вставить(0, "Ожидает авторизации");
СоответствияСтатусов.Вставить(1, "Авторизован");
СоответствияСтатусов.Вставить(2, "В листе игнора");
СоответствияСтатусов.Вставить(3, "Отклонен");
ДоступныеКоманды = "
|Список доступных команд для пользователя:
|/help - выводит текущую справку
|/source - список доступных баз источников
|/dest - список баз доступных приемников
|/lockstat - текущий статус блокировки бота";
ДоступныеКомандыАдмина = "
|Список доступных команд для Админа:
|/users - выводит список пользователей
|/lock - блокирует обработку сообщений ботом, всем, кроме админов
|/lock [min] - блокирует работу бота на указаное количество минут, всем, кроме админов
|/unlock - разблокирует работу с ботом";
ПрочитатьСообщения();
Если НЕ Соединение = Неопределено Тогда
Соединение.Закрыть();
КонецЕсли;