Установить webhook Telegram api

Использование Webhook с модулем python-telegram-bot.

Все примеры кода по пакету python-telegram-bot запускают Telegram бот с помощью Updater.start_polling() . Он использует метод Telegram API getUpdates для получения новых сообщений для бота. Это вполне нормально для небольших ботов и тестирования, но если бот популярен и получает/отправляет много трафика, то такой подход может замедлить время отклика бота.

Опрос Telegram сервера через webhook — это полезная технология для автоматизации процесса общения с пользователями. Как правило, этот функционал используется для экономии ресурсов на отправку/получение обновлений как собственного сервера, так и серверов Telegram.

Различие между polling и webhook является:

  • Опрос polling (через метод .get_updates ) периодически подключается к серверам Telegram для проверки новых обновлений или отправки обработанных сообщений.
  • Webhook — это URL-адрес, который передается API Telegram. Каждый раз, когда приходит новое обновление для бота, сервер Telegram отправляет это обновление на указанный URL. Аналогично происходит отправка сообщений.

Содержание:

  • Что необходимо для подключения к Telegram через webhook ;
  • Встроенный в библиотеку HTTP-сервер для webhook ;
  • Обратный прокси-сервер + встроенный сервер webhook ;
  • Использование webhook на Heroku;
  • Использование nginx с одним доменом/портом для всех ботов;
  • Использование haproxy с одним поддоменом на бота;
  • Индивидуальное решение, построенное на потоках.

Что необходимо для подключения к Telegram через webhook .

  1. Публичный IP-адрес или домен. Обычно это означает, что запуск бота должен осуществляться на VPS сервере.
  2. Необходим SSL-сертификат. Вся связь с серверами Telegram должна быть зашифрована с помощью HTTPS с использованием SSL. В случае подключения polling , о шифровании трафика заботятся серверы Telegram, но если отправка/получение сообщений идет через Webhook, то шифровании должен заботиться клиент/бот. Есть два способа сделать это:
    • Подключить проверенный сертификат, выданный доверенным центром сертификации (CA)
    • Самостоятельно создать самоподписанный сертификат SSL. Это проще, и в этом нет никакого недостатка.

    Чтобы создать самоподписанный SSL-сертификат с помощью openssl , выполните следующую команду в терминале:

    Telegram bot на Java | Webhook, Spring, Heroku


    $ openssl req -newkey rsa:2048 -sha256 -nodes -keyout private.key -x509 -days 3650 -out cert.pem

    Утилита openssl запросит несколько подробностей. Необходимо убедится, что вы ввели правильное полное доменное имя или IP-адрес! Если у сервера есть домен, то введите полное доменное имя (например, sub.example.com ). Если сервер имеет только IP-адрес, то вместо домена введите его IP-адрес. Если введено неверное полное доменное имя или IP-адрес, то бот не получит никаких обновлений от Telegram, при этом не будет никаких ошибок!

    Встроенный HTTP-сервер для webhook .

    Библиотека python-telegram-bot поставляет встроенный HTTP-сервер, основанный на http.server.HTTPServer . Реализация HTTPServer , которая плотно интегрирована в модуль расширения telegram.ext и может быть запущен с помощью updater.start_webhook / application.run_webhook . Этот веб-сервер также занимается расшифровкой HTTPS-трафика. Это самый простой способ настроить webhook.

    Telegram bot на Python (Webhooks & Polling), интеграция с 1С

    Однако у этого решения есть ограничение. Telegram в настоящее время поддерживает только четыре порта для веб-перехватчиков: 443, 80, 88 и 8443. В результате можно запускать не более четырех ботов на одном домене/IP-адресе.

    Если это не проблема, то можно использовать код ниже или аналогичный, чтобы запустить бот с webhook. Адрес прослушивания должен быть либо ‘0.0.0.0’ , либо, если нет разрешения на это, общедоступный IP-адрес сервера. Порт может быть одним из 443, 80, 88 или 8443. Рекомендуется установить секретный токен в параметре secret_token , чтобы никто не мог отправить боту поддельные обновления.

    Аргументы key и cert должны содержать путь к файлам, которые создали ранее. Аргумент webhook_url должен быть фактическим URL-адресом webhook . При этом необходимо перед URL-адресом webhook использовать протокол https:// , домен или IP-адрес, которые установлен в качестве полного доменного имени сертификата, а также правильный порт и URL-адрес.

    application.run_webhook( listen=’0.0.0.0′, port=8443, secret_token=’ASecretTokenIHaveChangedByNow’, key=’private.key’, cert=’cert.pem’, webhook_url=’https://example.com:8443′ ) # или updater.start_webhook( listen=’0.0.0.0′, port=8443, secret_token=’ASecretTokenIHaveChangedByNow’, key=’private.key’, cert=’cert.pem’, webhook_url=’https://example.com:8443′ )

    Обратный прокси-сервер + встроенный сервер webhook .

    Чтобы решить эту проблему, можно использовать обратный прокси-сервер, такой как nginx или haproxy , а также можно использовать Heroku .

    В этой модели обратный прокси ( nginx ), слушает публичный IP-адрес, принимает все запросы webhook и пересылает их на правильный экземпляр локально запущенных встроенных в python-telegram-bot серверов webhook. Обратный прокси также выполняет завершение SSL, то есть расшифровывает HTTPS-соединение, поэтому серверы webhook получают уже расшифрованный трафик. Эти серверы могут работать на любом порту, а не только на четырех разрешенных Telegram портах, т.к. сервера Telegram напрямую подключается только к обратному прокси-серверу.

    В зависимости от того, какой прокси-сервер используется, реализация будет выглядеть немного иначе. Ниже перечислены несколько возможных настроек.

    Использование webhook на Heroku.

    На Heroku использовать webhook можно на свободном плане, т.к. он будет автоматически управлять временем простоя. Для пользователя Heroku будет настроен обратный прокси и создана среда исполнения. Из этой среды необходимо будет извлечь порт, который бот должен прослушивать. Heroku управляет SSL на стороне прокси-сервера, следовательно не нужно создавать сертификат самостоятельно.

    Еще по теме:  Как подключить двойную аутентификацию в Телеграмме

    import os TOKEN = «TOKEN» PORT = int(os.environ.get(‘PORT’, ‘8443’)) # добавим обработчики application.run_webhook( listen=»0.0.0.0″, port=PORT, secret_token=’ASecretTokenIHaveChangedByNow’, webhook_url=»https://.herokuapp.com/» )

    Использование nginx с одним доменом/портом для всех ботов

    Все боты устанавливают свой URL-адрес на один и тот же домен и порт, но с другим url_path . Встроенный в python-telegram-bot сервер обычно запускается по адресу localhost или 127.0.0.1, порт может быть любым.

    Примечание: если нет домена, связанного с сервером, то example.com может быть заменен IP-адресом.

    Пример кода для запуска бота:

    application.run_webhook( listen=’127.0.0.1′, port=5000, url_path=’1′, secret_token=’ASecretTokenIHaveChangedByNow’, webhook_url=’https://example.com/1′, cert=’cert.pem’ )

    Пример конфигурации для nginx с двумя настроенными ботами (представлены важные части конфига):

    server < listen 443 ssl; server_name example.com; ssl_certificate cert.pem; ssl_certificate_key private.key; location /TOKEN1 < proxy_pass http://127.0.0.1:5000/1/; >location /TOKEN2 < proxy_pass http://127.0.0.1:5001/2/; >>

    Использование haproxy с одним поддоменом на бота.

    При таком подходе, каждому боту присваивается свой собственный поддомен. Если сервер имеет домен example.com , то можно создать поддомены например: bot1.example.com , bot2.example.com и т. д. Понадобится один сертификат для каждого бота с полным доменным именем, установленным для соответствующего поддомена. Встроенный в python-telegram-bot сервер обычно запускается по адресу localhost или 127.0.0.1, порт может быть любым.

    Примечание: Необходимо иметь домен привязанный к IP-адресу сервера.

    Пример кода для запуска бота:

    application.run_webhook( listen=’127.0.0.1′, port=5000, secret_token=’ASecretTokenIHaveChangedByNow’, webhook_url=’https://bot1.example.com’, cert=’cert_bot1.pem’) )

    Пример конфигурации для haproxy с двумя настроенными ботами (сведен к важным частям конфига) . Опять же: полное доменное имя обоих сертификатов должно соответствовать значению в ssl_fc_sni . Кроме того, файлы .pem представляют собой объединенные файлы private.key и cert.pem .

    frontend public-https bind 0.0.0.0:443 ssl crt cert_key_bot1.pem crt cert_key_bot2.pem option httpclose use_backend bot1 if < ssl_fc_sni bot1.example.com >use_backend bot2 if < ssl_fc_sni bot2.example.com >backend bot1 mode http option redispatch server bot1.example.com 127.0.0.1:5000 check inter 1000 backend bot2 mode http option redispatch server bot2.example.com 127.0.0.1:5001 check inter 1000

    Индивидуальное решение, построенное на потоках.

    Не обязательно использовать встроенный веб-сервер. Если решите пойти этим путем, то не следует использовать класс Updater . Модуль telegram.ext был переработан с учетом этой опции, поэтому все равно можно использовать класс Application , чтобы извлечь выгоду из фильтрации / сортировки сообщений, которые он предоставляет. НО придется проделать некоторую работу вручную.

    from telegram import Bot from telegram.ext import Application application = Application.builder().token(‘TOKEN’).build() # Регистрация обработчиков здесь # Получаем `update_queue`, из которого приложение получает обновления для обработки. update_queue = application.update_queue start_fetching_updates(update_queue) # Запускаем приложение async with application: application.start() # и останавливаем, когда срабатывает # какой-либо механизм отключения: application.stop()

    Здесь start_fetching_updates — это заполнитель для любого метода, который используется для настройки веб-перехватчика. Важной частью является то, что полученные обновления в update_queue ставятся в очередь. То есть вызывается await update_queue.put(update) , где update — это декодированный объект Update (используйте Update.de_json(json.loads(text), bot ) для декодирования обновления из полученных данных JSON).

    Альтернатива: нет длительных задач.

    Если BOT не использует длительные задачи, запущенные с помощью application.start() , то это не нужно! Вместо того, чтобы помещать обновления в update_queue , можно напрямую обрабатывать их через application.process_update(update) .

    Простой пример пользовательского вебхука.

    Простой пример бота, который использует пользовательскую настройку веб-перехватчика и обрабатывает пользовательские обновления.Для пользовательской настройки вебхука используются библиотеки starlette и uvicorn . Эти модули необходимо установить как pip install starlette=0.20.0 uvicorn=0.17.0 .

    Обратите внимание, что можно использовать любой другой фреймворк веб-сервера на основе asyncio для пользовательской настройки веб-перехватчика.

    • Установите токен бота, URL-адрес, admin chat_id и порт в начале основной функции.
    • Также может понадобиться изменить значение listen в конфигурации uvicorn , чтобы оно соответствовало вашей настройке.
    • Нажатие Ctrl-C в командной строке остановит бота.

    Источник: docs-python.ru

    Пишем чат-бот для Telegram на Python, используя webhook и минимум внешних библиотек

    Меня зовут Андрей Устьянцев, я ведущий аналитик направления Big Data Лиги Цифровой Экономики, и в этой статье я расскажу, как писал чат‑бот в Telegram на webhook. Если вы знаете, что это такое, и подготовка не вызывает интереса — можете сразу переходить к разделу «Очень кратко». С остальными поделюсь всеми необходимыми шагами.

    Почему webhook

    Чат‑бот в Telegram может работать в одном из двух режимов.

    Один из них называется polling — это когда код, непосредственно реализующий механику бота, опрашивает сервера Telegram с определенной периодичностью («не появилось ли чего новенького»). А если обнаружена активность в чате — реализуется определенная механика взаимодействия (общения).

    Большинство материалов в интернете посвящено описанию того, как создавать ботов именно на этой механике, но мне (частное мнение без претензии на истину в последней инстанции) такой подход не очень нравится. Вот почему:

    • не вижу смысла постоянно «дергать» сервера Telegram почем зря;
    • таймаут, установленный для опроса всех чатов, в которых «общается» бот — это суть задержка в коммуникациях с человеком, который «общается» с ботом.

    Второй режим работы ботов, webhook, подразумевает, что Telegram сам вызывает обработчик события/сообщения, когда в боте происходит какая‑то активность. Другими словами, код, реализующий механику бота, срабатывает по инициативе человека, который «общается» с ботом. Самый главный плюс от такого режима работы — ответ бота на действие человека происходит мгновенно: человек написал что‑то боту, Telegram тут же вызвал webhook, написанный код сразу «ответил» человеку.

    Еще по теме:  Как в Телеграме выставить отновременно всестранички канала

    Лирическое отступление: на тему «что лучше — polling или webhook» спорить можно бесконечно долго. Критерий истины: все зависит от решаемой задачи и от user‑story.

    Для задачи, которую решал я, лучше подходит режим webhook: заранее не известно, когда кто‑то напишет боту, но тот должен в любой момент быть готовым поддержать диалог.

    При чем тут «минимум» внешних библиотек?

    Мое личное убеждение — использовать «чужие» библиотеки по минимуму при написании кода. Особенно в процессе изучения языка программирования. Это отнюдь не означает, что надо впадать в крайности и писать вообще все с нуля — везде возможен разумный компромисс.

    Ниже я покажу, что можно написать аккуратный, короткий и читаемый код на Python и без использования специализированных библиотек именно для чат‑ботов (особенно работающих в режиме webhook).

    Пошаговая инструкция: как и с чего начать

    Расскажу, как я писал код на Python, с какими трудностями столкнулся по пути и как их решал.

    Ремарка: код написан в процессе изучения Python, поэтому некоторые моменты могут показаться неоптимальными — буду рад конструктивной критике и предложениям в комментариях к статье.

    Итак, что необходимо для работы чат-бота в режиме webhook?

    Ссылка на официальную документацию Telegam, где описана работа чат‑ботов в режиме webhook: https://core.telegram.org/bots/api#setwebhook

    1. Бот. Я не буду здесь подробно расписывать, как зарегистрировать бота — подробных мануалов достаточно и в интернете, и на этом портале.

    2. Сервер для размещения кода, обрабатывающего механику бота — тот самый webhook, которого будет вызывать Telegram при активностях в боте.

    Важные моменты (требования Telegram к таким серверам):

    • Сервер должен работать круглосуточно. Telegram периодически проверяет служебными запросами наличие и работоспособность webhook.
    • Важно, чтобы на сервере был установлен SSL‑сертификат, обеспечивающий (подтверждающий) безопасное соединение с серверами Telegram.

    Ну и где брать такой сервер?

    Первое — создать свой сервер:

    • настроить собственный компьютер под управлением Linux в режиме сервера,
    • получить, купить «фирменный» SSL-сертификат или сформировать самостоятельно такой, который Telegram примет как достоверный.

    Недостатки такого решения:

    • Необходимы дополнительные компетенции по «поднятию» сервера (обычно это еще и на основе Linux) и созданию SSL-сертификата.

    Хотя пошаговых инструкций и статей на эту тему достаточно.

    • Нужен постоянный IP-адрес подключения к интернету.

    Если компьютер подключен к интернету из домашней сети — скорее всего, у вас динамический IP-адрес, который точно не подойдет.

    • Надо держать компьютер постоянно включенным в 220В.

    Мне в рамках этой задачи круглосуточно гудящий под столом системный блок не нужен.

    • Об этом редко пишут, но на поднятый на скорую руку сервер, на который может «постучаться» Telegram, точно будут «ломиться» разные люди, боты, сети в попытке использовать ваш сервер для своих (не всегда хороших) целей.

    А это означает, что мало «поднять» сервер, его еще надо и защитить от потенциальных атак из внешних сетей — суровая дополнительная компетенция, скажу я вам.

    С профессиональной точки зрения неплохо, конечно, прокачать дополнительные компетенции, но задача состоит в том, чтобы написать на Python код, реализующий механику бота. Причем в процессе изучения самого Python.

    Поэтому я выбрал второе решение — облачное.

    Идеальный вариант — виртуальный хостинг.

    1. Круглосуточно работающий сервер Apach, настроенный для запуска приложений на Python.
    2. Защита от ddos-атак и прочих «пакостей» извне.
    3. Автоматический выпуск качественного SSL-сертификата.
    4. Качественный url webhook, соответствующий требованиям Telegram.
    5. Удобный интерфейс для написания кода на Python прямо из браузера.

    Итак, напишем простенького бота, который при любом взаимодействии с ним будет всегда писать в ответ «Ну привет, >»

    Очень кратко

    1. Берем виртуальный хостинг.
    2. Регистрируем бота.
    3. Определяем URL-адрес, который сообщим Telegram — что это webhook, соответствующий нашему чат-боту.
    4. Пишем код на Python.
    5. «Сообщаем» Telegram адрес webhook нашего бота.

    Важно! Рекомендую не менять местами последовательность действий из пунктов 5 и 4. В чем риск? Если Telegram решит проверить работоспособность адреса webhook, а там еще не отлажен код на Python, неправильный ответ Telegram на запрос может привести к блокировке webhook и бота. Снятие блокировки — отдельная неинтересная история.

    Разберем код

    import time import json import requests def MainProtokol(s,ts = ‘Запись’): dt=time.strftime(‘%d.%m.%Y %H:%M:’)+’00’ f=open(‘log.txt’,’a’) f.write(dt+’;’+str(ts)+’;’+str(s)+’n’) f.close def application(env, start_response): try: content=» token=’5937929205:AAHW3_J3oQTSo1fCncpoK7tu6wD6iyH-kSo’ if env[‘PATH_INFO’].lower() == ‘/tg_bot’: # тут вся механика бота именно этот код будет исполняться, когда Telegram будет вызывать webhook wsgi_string=env[‘wsgi.input’].read() x=wsgi_string.decode(‘UTF-8’) y=x.replace(‘n’,’ ‘) try: json_string=json.loads(y) except: raise ValueError(‘Не удалось распарсить в JSON полученную строку’) chat_id=json_string[‘message’][‘chat’][‘id’] from_first_name=json_string[‘message’][‘from’][‘first_name’] # имя отправителя # отправка сообщения в чат msg=’Ну, привет, ‘+str(from_first_name) send_message=requests.get(‘https://api.telegram.org/bot’+token+’/sendMessage?text=’+str(msg)) if not send_message: raise ValueError(‘Не удалось отправить текст в бот’) elif env[‘PATH_INFO’] == ‘/’: # случай, когда кто-то просто из браузера зашел на сайт MainProtokol(‘кто-то просто зашел на сайт’) else: # заглушка для обработки ситуации, когда кто-то методом перебора пытается обратиться к какой-то странице сайта raise ValueError(‘Вызов неизвестного URL :: ‘+env[‘PATH_INFO’]) start_response(‘200 OK’, [(‘Content-Type’,’text/html’)]) return [content.encode(‘utf-8′)] except Exception as S: content=str(S) MainProtokol(content,’Ошибка’) start_response(‘200 OK’, [(‘Content-Type’,’text/html’)]) return [content.encode(‘utf-8’)]

    Нам понадобятся следующие библиотеки:

    • time — для работы с функциями даты и времени;
    • JSON — для распарсивания JSON-строки, получаемой от Telegram;
    • requests — для отправки сообщений в бот.

    Примечание: в зависимости от настроек виртуальных серверов по умолчанию и инсталляций Python перечисленные библиотеки могут быть уже предустановлены. Если нет — необходимо их установить командой pip install.

    Строка 5: Функция MainProtokol написана для логирования происходящего в коде. Задача этой функции — записывать в текстовый файл то, что в обычных условиях выводится на экран компьютера. Поскольку код выполняется по сути на сервере в момент вызова webhook Telegram, на экран ничего вывести нельзя, потому что экрана как такового нет. Так что текстовый файл — это замена вывода на экран ошибок (если они возникнут при выполнении кода), а также всего, что было бы полезно залогировать.

    Еще по теме:  Как понять что тебя заблокировали в Телеграм 2023

    Строка 12: Функция application — основная у Python, которую вызывает сервер Apach при любом обращении к сайту. И при вызове webhook тоже.

    Все данные, которые поступают при обращении к сайту (не важно, открывают ли его в браузере при прямом заходе по имени сайта, или происходит вызов webhook), сохраняются в переменной env (тип — словарь) — суть переменные окружения.

    Строка 14: Переменная content в текущем коде — это «заглушка», потому что на экран ничего выводиться не должно. Можно в ней разместить HTML-код, который будет отображается в случае захода на сайт из браузера.

    Строка 15: Переменная token — в ней хранится токен бота, полученный при его регистрации.

    Строка 17: Проверяем, что вызывается именно webhook. В env[‘PATH_INFO’] хранится имя страницы, к которой было обращение. Я решил, что у меня страница для коммуникаций с ботами будет называться ‘tg_bot’. Настоятельно рекомендую придумывать страницу (адрес) webhook, а не сообщать Telegram просто имя домена – это защитит дополнительно ваш сайт от внешних атак.

    Примечание: приведение значения переменной окружения к нижнему регистру функцией lower() — это, можно сказать, мой «пунктик»: так я еще больше уверен, что сравнение строк в одинаковом регистре произойдет корректно.

    Строка 19: Получаем данные, переданные из Telegram («от бота») — они хранятся в переменной окружения «wsgi.input» в формате WSGI. Для его дальнейшей обработки применяем метод read().

    Строки 24–27: Распарсиваем JSON-строку, полученную от бота.

    И вот тут меня ждал подводный камень размерами с булыжник. Метод load библиотеки JSON выдавал ошибку «нарушение структуры JSON». Потратив значительное время и логируя в текстовый файл с использованием функции MainProtokol все, что только можно, я обнаружил следующее:

    В JSON-строке, передаваемой из Telegram, совершенно непонятно зачем добавляется спецсимвол «n» (перевод строки). Причем только в одном месте.

    Решение проблемы — перед распарсиванием JSON-строки принудительно заменить в ней «мешающий» спецсимвол на пробел: replace(‘n’,’ ‘).

    Ремарка: по-хорошему надо было бы написать кусок кода или функцию, которая «убирает» из JSON-строки все известные спецсимволы. Но я СТОЛЬКО времени потратил на поиск проблемы, что сил на ее полномасштабное устранение со всеми возможными вариантами последствий впредь у меня уже не осталось.

    Итого мы получили словарь в переменной json_string, содержащий все, что передал Telegram от бота. В общем-то, блок строк 17-30 — это то место, где необходимо реализовывать логику «общения» бота. Суть — анализировать полученный JSON и в зависимости от полученных данных программировать поведение бота.

    Как разбираться с полученным JSON? По сути это объект message, полное описание которого можно найти в официальной документации вместе с описанием всех вложенных объектов типа chat, user и т. д.

    Я пошел другим путем: писал в лог получаемые JSON по разным сценариям взаимодействия с ботом (отправка команды боту, отправка текста боту, отправка картинки), потом смотрел их структуру и реализовывал нужную мне логику.

    Ремарка: Telegram передает в webhook только те поля, которые имеют значение. Покажу на примере.

    (Исходный код – тут log1 с примерами JSON.txt)

    Отправка команды «/start»

    Отправка простого текста

    Источник: habr.com

    Синхронизация бота Telegram с помощью setWebhook

    Telegram — быстро развивающийся мессенджер, множество программистов уже попробовали себя в создании ботов для telegram.

    В данной статье мы разберёмся с созданием самоподписанного сертификата, научимся устанавливать этот сертификат в nginx и научим нашего бота получать обновления с помощью способа WebHook.

    Методы взаимодействия с ботом:

    Телеграмм разрешает устанавливать свои сертификаты https, что позволит нас не покупать дорогостоящий сертификат.

    Для взаимодействия с пользователем в телеграмме используются 2 принципиально разных способа.

    Этот метод используется для получения обновлений через long polling (wiki). Ответ возвращается в виде массива объектов Update. У данного способа обновлений есть масса недостатков. Мы должны сами запрашивать с сервера список сообщений пользователей, что не очень удобно. Для этого мы должны запрашивать каждые n секунд с сервера телеграмма данные. Это ресурсоёмко и не рационально.

    Лично я, не рекомендую без крайне необходимости использовать данный способ.

    Существует ещё один способ получения сообщений от бота. Это использование WebHook. Идея заключается в том, что сервер сам будет присылать нам сообщения пользователя, а мы будем решать, что с ними делать. Каждый раз при получении обновления на этот адрес будет отправлен HTTPS POST с сериализованным в JSON объектом Update. В основном мы будем работать с объектом Message, который, соответственно, получим из Update.

    Настройка синхронизации бота telegram с помощью setWebHook:

    Приступим к настройке данного способа синхронизации. Для начала нам будет необходимо создать и настроить ssl сертификат.

    У меня на сервере установлен дистрибутив FreeBSD, соответственно все дальнейшие действия описаны для этой системы.

    Генерация и установка ssl сертификата:

    Чтобы создать сертификат нам необходимо выполнить следующие действия:

    Создадим папку в которую поместим наши полученные сертификаты:

    Источник: kostyakulakov.ru

    Рейтинг
    ( Пока оценок нет )
    Загрузка ...