267 lines
48 KiB
HTML
267 lines
48 KiB
HTML
<!DOCTYPE html><html lang="en"> <head><!-- Global Metadata --><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" type="image/svg+xml" href="/favicon/favicon.ico"><meta name="generator" content="Astro v4.7.1"><link rel="preload" href="/fonts/atkinson-regular.woff" as="font" type="font/woff" crossorigin><link rel="preload" href="/fonts/atkinson-bold.woff" as="font" type="font/woff" crossorigin><!-- Canonical URL --><link rel="canonical" href="https://astro-sphere-demo.vercel.app/blog/03-bot-support/"><!-- Primary Meta Tags --><title>Хватит терять заявки пользователей | Плата Управления РФ</title><meta name="title" content="Хватит терять заявки пользователей | Плата Управления РФ"><meta name="description" content="Пора сделать бота для принятия заявок от пользователей всем IT отделом."><!-- Open Graph / Facebook --><meta property="og:type" content="website"><meta property="og:url" content="https://astro-sphere-demo.vercel.app/blog/03-bot-support/"><meta property="og:title" content="Хватит терять заявки пользователей | Плата Управления РФ"><meta property="og:description" content="Пора сделать бота для принятия заявок от пользователей всем IT отделом."><meta property="og:image" content="https://astro-sphere-demo.vercel.app/img04.jpg"><!-- Twitter --><meta property="twitter:card" content="summary_large_image"><meta property="twitter:url" content="https://astro-sphere-demo.vercel.app/blog/03-bot-support/"><meta property="twitter:title" content="Хватит терять заявки пользователей | Плата Управления РФ"><meta property="twitter:description" content="Пора сделать бота для принятия заявок от пользователей всем IT отделом."><meta property="twitter:image" content="https://astro-sphere-demo.vercel.app/img04.jpg"><!-- Sitemap --><link rel="sitemap" href="/sitemap-index.xml"><!-- RSS Feed --><link rel="alternate" type="application/rss+xml" title="Хватит терять заявки пользователей | Плата Управления РФ" href="https://astro-sphere-demo.vercel.app/rss.xml"><!-- Global Scripts --><script src="/js/theme.js"></script><script src="/js/scroll.js"></script><script src="/js/animate.js"></script><!-- <ViewTransitions /> --><link rel="stylesheet" href="/_astro/_slug_.0h5GVtX4.css"><script type="module" src="/_astro/hoisted.BGfjo5mV.js"></script></head> <body> <header id="header" class="fixed top-0 w-full h-16 z-50 " data-astro-cid-3ef6ksr2> <div class="w-full h-full mx-auto px-5 max-w-screen-md"> <div class="relative h-full w-full" data-astro-cid-3ef6ksr2> <div class="absolute left-0 top-1/2 -translate-y-1/2 flex gap-1 font-semibold" data-astro-cid-3ef6ksr2> <a href="/" class="flex gap-1 text-current hover:text-black dark:hover:text-white transition-colors duration-300 ease-in-out" data-astro-cid-3ef6ksr2> <svg class="size-6 fill-current" data-astro-cid-3ef6ksr2> <use href="/static/logo.svg" data-astro-cid-3ef6ksr2></use> </svg> <div data-astro-cid-3ef6ksr2> Плата Управления РФ </div> </a> </div> <div class="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" data-astro-cid-3ef6ksr2> <nav class="hidden md:flex items-center justify-center text-sm gap-1" data-astro-cid-3ef6ksr2> <a href="/" class="h-8 rounded-full px-3 text-current flex items-center justify-center transition-colors duration-300 ease-in-out hover:bg-black/5 dark:hover:bg-white/20 hover:text-black dark:hover:text-white" data-astro-cid-3ef6ksr2> Главная </a><a href="/work" class="h-8 rounded-full px-3 text-current flex items-center justify-center transition-colors duration-300 ease-in-out hover:bg-black/5 dark:hover:bg-white/20 hover:text-black dark:hover:text-white" data-astro-cid-3ef6ksr2> Работа </a><a href="/blog" class="h-8 rounded-full px-3 flex items-center justify-center transition-colors duration-300 ease-in-out bg-black dark:bg-white text-white dark:text-black" data-astro-cid-3ef6ksr2> Блог </a><a href="/projects" class="h-8 rounded-full px-3 text-current flex items-center justify-center transition-colors duration-300 ease-in-out hover:bg-black/5 dark:hover:bg-white/20 hover:text-black dark:hover:text-white" data-astro-cid-3ef6ksr2> Проекты </a> </nav> </div> <div class="buttons absolute right-0 top-1/2 -translate-y-1/2 flex gap-1" data-astro-cid-3ef6ksr2> <a href="/search" aria-label="Search blog posts and projects on Плата Управления РФ" class="hidden md:flex size-9 rounded-full p-2 items-center justify-center bg-transparent hover:bg-black/5 dark:hover:bg-white/20 stroke-current hover:stroke-black hover:dark:stroke-white border border-black/10 dark:border-white/25 transition-colors duration-300 ease-in-out" data-astro-cid-3ef6ksr2> <svg class="size-full" data-astro-cid-3ef6ksr2> <use href="/ui.svg#search" data-astro-cid-3ef6ksr2></use> </svg> </a> <a href="/rss.xml" target="_blank" aria-label="Rss feed for Плата Управления РФ" class="hidden md:flex size-9 rounded-full p-2 items-center justify-center bg-transparent hover:bg-black/5 dark:hover:bg-white/20 stroke-current hover:stroke-black hover:dark:stroke-white border border-black/10 dark:border-white/25 transition-colors duration-300 ease-in-out" data-astro-cid-3ef6ksr2> <svg class="size-full" data-astro-cid-3ef6ksr2> <use href="/ui.svg#rss" data-astro-cid-3ef6ksr2></use> </svg> </a> <button id="header-theme-button" aria-label="Toggle light and dark theme" class="hidden md:flex size-9 rounded-full p-2 items-center justify-center bg-transparent hover:bg-black/5 dark:hover:bg-white/20 stroke-current hover:stroke-black hover:dark:stroke-white border border-black/10 dark:border-white/25 transition-colors duration-300 ease-in-out" data-astro-cid-3ef6ksr2> <svg class="size-full block dark:hidden" data-astro-cid-3ef6ksr2> <use href="/ui.svg#sun" data-astro-cid-3ef6ksr2></use> </svg> <svg class="size-full hidden dark:block" data-astro-cid-3ef6ksr2> <use href="/ui.svg#moon" data-astro-cid-3ef6ksr2></use> </svg> </button> <button id="header-drawer-button" aria-label="Toggle drawer open and closed" class="flex md:hidden size-9 rounded-full p-2 items-center justify-center bg-transparent hover:bg-black/5 dark:hover:bg-white/20 stroke-current hover:stroke-black hover:dark:stroke-white border border-black/10 dark:border-white/25 transition-colors duration-300 ease-in-out" data-astro-cid-3ef6ksr2> <svg id="drawer-open" class="size-full" data-astro-cid-3ef6ksr2> <use href="/ui.svg#menu" data-astro-cid-3ef6ksr2></use> </svg> <svg id="drawer-close" class="size-full" data-astro-cid-3ef6ksr2> <use href="/ui.svg#x" data-astro-cid-3ef6ksr2></use> </svg> </button> </div> </div> </div> </header> <script>
|
||
function toggleDrawer() {
|
||
const drawer = document.getElementById("drawer")
|
||
const drawerButton = document.getElementById("header-drawer-button")
|
||
drawer?.classList.toggle("open")
|
||
drawerButton?.classList.toggle("open")
|
||
}
|
||
|
||
function initializeDrawerButton() {
|
||
const drawerButton = document.getElementById("header-drawer-button")
|
||
drawerButton?.addEventListener("click", toggleDrawer)
|
||
}
|
||
|
||
document.addEventListener("astro:after-swap", initializeDrawerButton)
|
||
initializeDrawerButton()
|
||
</script> <div id="drawer" class="fixed inset-0 h-0 z-40 overflow-hidden flex flex-col items-center justify-center md:hidden bg-neutral-100 dark:bg-neutral-900 transition-[height] duration-300 ease-in-out" data-astro-cid-hxtyo74s> <nav class="flex flex-col items-center space-y-2" data-astro-cid-hxtyo74s> <a href="/" class="flex items-center justify-center px-3 py-1 rounded-full text-current hover:text-black dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/20 transition-colors duration-300 ease-in-out" data-astro-cid-hxtyo74s> Главная </a><a href="/work" class="flex items-center justify-center px-3 py-1 rounded-full text-current hover:text-black dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/20 transition-colors duration-300 ease-in-out" data-astro-cid-hxtyo74s> Работа </a><a href="/blog" class="flex items-center justify-center px-3 py-1 rounded-full hover:text-black dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/20 transition-colors duration-300 ease-in-out pointer-events-none bg-black dark:bg-white text-white dark:text-black" data-astro-cid-hxtyo74s> Блог </a><a href="/projects" class="flex items-center justify-center px-3 py-1 rounded-full text-current hover:text-black dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/20 transition-colors duration-300 ease-in-out" data-astro-cid-hxtyo74s> Проекты </a> </nav> <div class="flex gap-1 mt-5" data-astro-cid-hxtyo74s> <a href="/search" aria-label="Search blog posts and projects on Плата Управления РФ" class="size-9 rounded-full p-2 items-center justify-center bg-transparent hover:bg-black/5 dark:hover:bg-white/20 stroke-current hover:stroke-black hover:dark:stroke-white border border-black/10 dark:border-white/25 transition-colors duration-300 ease-in-out" data-astro-cid-hxtyo74s> <svg class="size-full" data-astro-cid-hxtyo74s> <use href="/ui.svg#search" data-astro-cid-hxtyo74s></use> </svg> </a> <a href="/rss.xml" target="_blank" aria-label="Rss feed for Плата Управления РФ" class="size-9 rounded-full p-2 items-center justify-center bg-transparent hover:bg-black/5 dark:hover:bg-white/20 stroke-current hover:stroke-black hover:dark:stroke-white border border-black/10 dark:border-white/25 transition-colors duration-300 ease-in-out" data-astro-cid-hxtyo74s> <svg class="size-full" data-astro-cid-hxtyo74s> <use href="/ui.svg#rss" data-astro-cid-hxtyo74s></use> </svg> </a> <button id="drawer-theme-button" aria-label="Toggle light and dark theme" class="size-9 rounded-full p-2 items-center justify-center bg-transparent hover:bg-black/5 dark:hover:bg-white/20 stroke-current hover:stroke-black hover:dark:stroke-white border border-black/10 dark:border-white/25 transition-colors duration-300 ease-in-out" data-astro-cid-hxtyo74s> <svg class="block dark:hidden size-full" data-astro-cid-hxtyo74s> <use href="/ui.svg#sun" data-astro-cid-hxtyo74s></use> </svg> <svg class="hidden dark:block size-full" data-astro-cid-hxtyo74s> <use href="/ui.svg#moon" data-astro-cid-hxtyo74s></use> </svg> </button> </div> </div> <main> <div class="pt-36 pb-5"> <div class="w-full h-full mx-auto px-5 max-w-screen-md"> <div class="animate"> <div> <a href="/blog" class="group w-fit p-1.5 gap-1.5 text-sm flex items-center border rounded hover:bg-black/5 hover:dark:bg-white/10 border-black/15 dark:border-white/20 transition-colors duration-300 ease-in-out"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="stroke-current group-hover:stroke-black group-hover:dark:stroke-white"> <line x1="19" y1="12" x2="5" y2="12" class="scale-x-0 group-hover:scale-x-100 translate-x-3 group-hover:translate-x-0 transition-all duration-300 ease-in-out"></line> <polyline points="12 19 5 12 12 5" class="translate-x-1 group-hover:translate-x-0 transition-all duration-300 ease-in-out"></polyline> </svg> <div class="w-full group-hover:text-black group-hover:dark:text-white transition-colors duration-300 ease-in-out">
|
||
Вернуться в blog </div> </a> <div class="flex flex-wrap text-sm uppercase mt-12 gap-3 opacity-75"> <div class="flex items-center gap-2"> <svg class="size-5 stroke-current"> <use href="/ui.svg#calendar"></use> </svg> 12 июн. 2024 г. </div> <div class="flex items-center gap-2"> <svg class="size-5 stroke-current"> <use href="/ui.svg#book-open"></use> </svg> 6 min read </div> </div> <h1 class="text-3xl font-semibold text-black dark:text-white mt-2"> Хватит терять заявки пользователей </h1> <div class="mt-1"> Пора сделать бота для принятия заявок от пользователей всем IT отделом. </div> </div> </div> </div> </div> <div class="flex-1 py-5"> <div class="w-full h-full mx-auto px-5 max-w-screen-md"> <div class="animate"> <div> <article> <h1 id="бот-техподдержки-пользователя">Бот техподдержки пользователя</h1>
|
||
<p><a href="https://git.fipi.pro/Plata_Upravleniya_RF/Support-BOT">https://git.fipi.pro/Plata_Upravleniya_RF/Support-BOT</a></p>
|
||
<p>Пользователи пишут свои вопросы боту компании, бот пересылает эти сообщения в чат поддержки, сотрудники поддержки отвечают на эти сообщения через reply. Основной плюс - анонимизация сотрудников поддержки.</p>
|
||
<p>Бот работает в режиме webhook, но может работать и в режиме polling.</p>
|
||
<p>Для обхода запрета на пересылку сообщений у пользователя, бот копирует содержимое и уже затем отправляет его в чат поддержки.</p>
|
||
<p>По умолчанию бот отправляет сообщения в один чат поддержки с id, указанным в переменных окружения .env.</p>
|
||
<h2 id="бот-умеет">Бот умеет</h2>
|
||
<ul>
|
||
<li>Пересылать сообщения, документы, аудио и видео от пользователя в группу к администраторам и обратно</li>
|
||
<li>Выдавать информацию о пользователе из Telegram</li>
|
||
<li>Выдавать месячный отчет и отчет за указанный интервал дат по количеству обращений и общему числу сообщений и ответов</li>
|
||
<li>Банить и разбанивать пользователей</li>
|
||
</ul>
|
||
<h2 id="типы-контента-которые-может-пересылать-бот">Типы контента, которые может пересылать бот</h2>
|
||
<ul>
|
||
<li>Текстовые сообщения</li>
|
||
<li>Фотографии</li>
|
||
<li>Группы фотографий (пересылаются по одной)</li>
|
||
<li>Видео</li>
|
||
<li>Аудиозаписи</li>
|
||
<li>Файлы</li>
|
||
</ul>
|
||
<h2 id="разворачивание-образа-на-личном-или-vps-сервере">Разворачивание образа на личном или vps сервере</h2>
|
||
<h3 id="настройка-nignx">Настройка Nignx</h3>
|
||
<p>Предполагается, что у вас есть готовый настроенный VPS сервер с установленным nginx.</p>
|
||
<ol>
|
||
<li>Перейти в каталог nginx <code>sites-available</code>:</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#79B8FF">cd</span><span style="color:#9ECBFF"> /etc/nginx/sites-available/</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<ol start="2">
|
||
<li>Создайте файл с именем вашего домена:</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">nano</span><span style="color:#9ECBFF"> domain.example.com</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<ol start="3">
|
||
<li>Внутри файла напишите:</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">server</span><span style="color:#9ECBFF"> {</span></span>
|
||
<span class="line"><span style="color:#B392F0"> listen</span><span style="color:#79B8FF"> 80</span><span style="color:#E1E4E8">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#B392F0"> server_name</span><span style="color:#9ECBFF"> domain.example.com</span><span style="color:#E1E4E8">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#B392F0"> location</span><span style="color:#9ECBFF"> /telegram/</span><span style="color:#9ECBFF"> {</span></span>
|
||
<span class="line"><span style="color:#B392F0"> proxy_set_header</span><span style="color:#9ECBFF"> Host</span><span style="color:#E1E4E8"> $http_host;</span></span>
|
||
<span class="line"><span style="color:#B392F0"> proxy_set_header</span><span style="color:#9ECBFF"> X-Real-IP</span><span style="color:#E1E4E8"> $remote_addr;</span></span>
|
||
<span class="line"><span style="color:#B392F0"> proxy_set_header</span><span style="color:#9ECBFF"> X-Forwarded-For</span><span style="color:#E1E4E8"> $proxy_add_x_forwarded_for;</span></span>
|
||
<span class="line"><span style="color:#B392F0"> proxy_set_header</span><span style="color:#9ECBFF"> X-Forwarded-Proto</span><span style="color:#E1E4E8"> $scheme;</span></span>
|
||
<span class="line"><span style="color:#B392F0"> proxy_pass</span><span style="color:#9ECBFF"> http://127.0.0.1:7772</span><span style="color:#E1E4E8">;</span></span>
|
||
<span class="line"><span style="color:#E1E4E8"> }</span></span>
|
||
<span class="line"><span style="color:#E1E4E8">}</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<p><code>server_name</code> - ваш домен с подключенным SSL сертификатом (например, Let’s Encrypt). Вместо <code>/telegram/</code> можно написать любой путь, на который должны приниматься данные. Этот же путь нужно указать в <code>.env</code> файле.</p>
|
||
<ol start="4">
|
||
<li>Создайте символическую ссылку в каталоге <code>sites-enabled</code></li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> ln</span><span style="color:#79B8FF"> -s</span><span style="color:#9ECBFF"> /etc/nginx/sites-available/domain.example.com</span><span style="color:#9ECBFF"> /etc/nginx/sites-enabled/</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<ol start="5">
|
||
<li>Проверьте конфигурацию nginx на ошибки:</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> nginx</span><span style="color:#79B8FF"> -t</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<ol start="6">
|
||
<li>Перезапустить службу nginx:</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> systemctl</span><span style="color:#9ECBFF"> restart</span><span style="color:#9ECBFF"> nginx</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<ol start="7">
|
||
<li>Установить certbot:</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> apt</span><span style="color:#9ECBFF"> install</span><span style="color:#79B8FF"> -y</span><span style="color:#9ECBFF"> certbot</span><span style="color:#9ECBFF"> python3-certbot-nginx</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<ol start="8">
|
||
<li>Установите HTTPS соединение, выпустив SSL сертификат с помощью certbot для вашего домена:</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> certbot</span><span style="color:#79B8FF"> --nginx</span><span style="color:#E1E4E8"> </span></span>
|
||
<span class="line"></span></code></pre>
|
||
<ol start="9">
|
||
<li>Добавить автоматическое обновление сертификата:</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> certbot</span><span style="color:#9ECBFF"> renew</span><span style="color:#79B8FF"> --dry-run</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<p>Можно на всякий случай еще раз перезапустить nginx.</p>
|
||
<h3 id="запуск-бота">Запуск бота</h3>
|
||
<ol>
|
||
<li>Создайте бота через BotFather (см. ниже), добавьте бота в группу с сотрудниками поддержки, дайте боту права администратора, узнайте id группы (см. ниже).</li>
|
||
<li>Скопируйте этот репозиторий на сервер любым удобным способом.</li>
|
||
<li>Создайте .env файл в корне со следующим содержанием:</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#E1E4E8">TELEGRAM_TOKEN</span><span style="color:#F97583">=<</span><span style="color:#9ECBFF">телеграм_токен_вашего_бота</span><span style="color:#F97583">></span></span>
|
||
<span class="line"><span style="color:#E1E4E8">GROUP_ID</span><span style="color:#F97583">=<</span><span style="color:#9ECBFF">id_группы_или_супергруппы_в_телеграме</span><span style="color:#F97583">></span></span>
|
||
<span class="line"><span style="color:#E1E4E8">WEBHOOK_DOMAIN</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">domain.example.com</span></span>
|
||
<span class="line"><span style="color:#E1E4E8">WEBHOOK_PATH</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">/telegram/</span></span>
|
||
<span class="line"><span style="color:#E1E4E8">APP_HOST</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">0.0.0.0</span></span>
|
||
<span class="line"><span style="color:#E1E4E8">APP_PORT</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">7772</span></span>
|
||
<span class="line"><span style="color:#E1E4E8">DATABASE_URL</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">postgresql+asyncpg://</span><span style="color:#F97583"><</span><span style="color:#9ECBFF">postgres_user</span><span style="color:#F97583">></span><span style="color:#9ECBFF">:</span><span style="color:#F97583"><</span><span style="color:#9ECBFF">postgres_password</span><span style="color:#F97583">></span><span style="color:#9ECBFF">@</span><span style="color:#F97583"><</span><span style="color:#9ECBFF">postgres_container_name</span><span style="color:#F97583">></span><span style="color:#9ECBFF">:5432/support_bot_db</span></span>
|
||
<span class="line"><span style="color:#E1E4E8">DB_HOST</span><span style="color:#F97583">=<</span><span style="color:#9ECBFF">имя_контейнера_с_БД</span><span style="color:#F97583">></span></span>
|
||
<span class="line"><span style="color:#E1E4E8">DB_PORT</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">5432</span></span>
|
||
<span class="line"><span style="color:#E1E4E8">POSTGRES_USER</span><span style="color:#F97583">=<</span><span style="color:#9ECBFF">postgres_user</span><span style="color:#F97583">></span></span>
|
||
<span class="line"><span style="color:#E1E4E8">POSTGRES_PASSWORD</span><span style="color:#F97583">=<</span><span style="color:#9ECBFF">postgres_password</span><span style="color:#F97583">></span></span>
|
||
<span class="line"><span style="color:#E1E4E8">START_MESSAGE</span><span style="color:#F97583">=<</span><span style="color:#9ECBFF">Приветственное</span><span style="color:#B392F0"> сообщение</span><span style="color:#9ECBFF"> бота,</span><span style="color:#9ECBFF"> когда</span><span style="color:#9ECBFF"> клиент</span><span style="color:#9ECBFF"> нажимает</span><span style="color:#9ECBFF"> кнопку</span><span style="color:#9ECBFF"> star</span><span style="color:#E1E4E8">t</span><span style="color:#F97583">></span></span>
|
||
<span class="line"></span></code></pre>
|
||
<p>В качестве теста логин пользователя БД, пароль и название БД можно указать postgres. Только для теста, не для продакшена!</p>
|
||
<ol start="4">
|
||
<li>Запустить сборку docker-образа и его запуск из файла <code>docker-compose</code>:</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> docker-compose</span><span style="color:#9ECBFF"> up</span><span style="color:#79B8FF"> -d</span><span style="color:#79B8FF"> --build</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<p>Ключ <code>-d</code> для того чтобы контейнер запустился в фоне.</p>
|
||
<ol start="5">
|
||
<li>Зайдите в контейнер с базой данных, создайте базу данных, выдайте права на нее пользователю (в данном случае postgres):</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">docker</span><span style="color:#9ECBFF"> exec</span><span style="color:#79B8FF"> -it</span><span style="color:#9ECBFF"> support-bot-db</span><span style="color:#9ECBFF"> psql</span><span style="color:#79B8FF"> -U</span><span style="color:#9ECBFF"> postgres</span></span>
|
||
<span class="line"><span style="color:#B392F0">\l</span><span style="color:#6A737D"> #убеждаемся, что базы данных нет</span></span>
|
||
<span class="line"><span style="color:#B392F0">create</span><span style="color:#9ECBFF"> database</span><span style="color:#9ECBFF"> support_bot_db</span><span style="color:#E1E4E8">;</span></span>
|
||
<span class="line"><span style="color:#B392F0">grant</span><span style="color:#9ECBFF"> all</span><span style="color:#9ECBFF"> privileges</span><span style="color:#9ECBFF"> on</span><span style="color:#9ECBFF"> database</span><span style="color:#9ECBFF"> support_bot_db</span><span style="color:#9ECBFF"> to</span><span style="color:#9ECBFF"> postgres</span><span style="color:#E1E4E8">;</span></span>
|
||
<span class="line"><span style="color:#B392F0">\q</span><span style="color:#6A737D"> #выходим из psql</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<ol start="6">
|
||
<li>Применить миграции:</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">docker</span><span style="color:#9ECBFF"> exec</span><span style="color:#79B8FF"> -it</span><span style="color:#9ECBFF"> support-bot</span><span style="color:#9ECBFF"> alembic</span><span style="color:#9ECBFF"> upgrade</span><span style="color:#9ECBFF"> head</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<h3 id="где-что-брать">Где что брать</h3>
|
||
<ol>
|
||
<li><code>WEBHOOK_DOMAIN</code> - домен с подключенным ssl сертификатом</li>
|
||
<li><code>WEBHOOK_PATH</code> - URL путь после домена. В данном случае <code>WEBHOOK_DOMAIN</code> + <code>WEBHOOK_PATH</code> будет <code>domain.example.com/telegram/</code>.</li>
|
||
<li>Token получаем при создании бота через BotFather <a href="https://t.me/BotFather">BotFather</a>.</li>
|
||
<li>Свой личный id или id группы можно узнать через бота <a href="https://t.me/myidbot">myidbot</a>. Узнать свой id - написать боту в личку, узнать id группы - добавить бота в чат группы (например группы поддержки), затем ввести команду <code>/getgroupid</code>.</li>
|
||
<li><code>APP_HOST</code> - IP, на котором будет работать приложение (по умолчанию на хосте <code>127.0.0.1</code>, <code>localhost</code> или можно указать <code>0.0.0.0</code>).</li>
|
||
<li><code>APP_PORT</code> - порт, который приложение будет использовать. Порт должен быть уникальным и не дублировать порты других приложений, работающих на сервере или в Docker.</li>
|
||
</ol>
|
||
<h2 id="запуск-в-режиме-polling-на-локальном-компьютере">Запуск в режиме polling (на локальном компьютере)</h2>
|
||
<ol>
|
||
<li>Скопируйте репозиторий на локальный компьютер.</li>
|
||
<li>Создайте файл <code>.env</code> (см. выше).</li>
|
||
<li>В файле <code>.env</code> удалить (закомментировать) <code>WEBHOOK_DOMAIN</code>. Пропишите свои переменные окружения. Так же пропишите переменные окружения в файле <code>docker-compose-postgres-localhost.yaml</code></li>
|
||
<li>Установить виртуальное окружение, активировать его,
|
||
установить зависимости из <code>requirements.txt</code>:</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">python</span><span style="color:#79B8FF"> -m</span><span style="color:#9ECBFF"> venv</span><span style="color:#9ECBFF"> venv</span></span>
|
||
<span class="line"><span style="color:#B392F0">pip</span><span style="color:#9ECBFF"> install</span><span style="color:#79B8FF"> -r</span><span style="color:#9ECBFF"> requirements.txt</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<ol start="5">
|
||
<li>В докере запустить контейнер с базой данных из файла <code>docker-compose-postgres-localhost.yaml</code>:</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">docker-compose</span><span style="color:#79B8FF"> -f</span><span style="color:#9ECBFF"> docker-compose-postgres-localhost</span><span style="color:#9ECBFF"> up</span><span style="color:#79B8FF"> -d</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<ol start="6">
|
||
<li>Применить миграцию.</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">alembic</span><span style="color:#9ECBFF"> upgrade</span><span style="color:#9ECBFF"> head</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<ol start="7">
|
||
<li>Если alembic ругается, что базы данных не существует, создайте ее вручную и выйдите из psql. Затем попробуйте выполнить миграцию повторно:</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">docker</span><span style="color:#9ECBFF"> exec</span><span style="color:#79B8FF"> -it</span><span style="color:#9ECBFF"> postgres</span><span style="color:#9ECBFF"> psql</span><span style="color:#79B8FF"> -U</span><span style="color:#9ECBFF"> postgres</span></span>
|
||
<span class="line"><span style="color:#6A737D"># далее в psql</span></span>
|
||
<span class="line"><span style="color:#B392F0">create</span><span style="color:#9ECBFF"> database</span><span style="color:#9ECBFF"> support_bot_db</span><span style="color:#E1E4E8">;</span></span>
|
||
<span class="line"><span style="color:#B392F0">grant</span><span style="color:#9ECBFF"> all</span><span style="color:#9ECBFF"> privileges</span><span style="color:#9ECBFF"> on</span><span style="color:#9ECBFF"> database</span><span style="color:#9ECBFF"> support_bot_db</span><span style="color:#9ECBFF"> to</span><span style="color:#9ECBFF"> postgres</span><span style="color:#E1E4E8">;</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<ol start="8">
|
||
<li>Запустить <code>main.py</code>:</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">python</span><span style="color:#9ECBFF"> main.py</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<p>Для запуска необходим python 3.9 или выше.</p>
|
||
<h2 id="команды-бота">Команды бота</h2>
|
||
<p>В <strong>чате поддержки</strong> доступны следующие команды:</p>
|
||
<p><code>/info</code> - Команда вводится через reply на вопрос пользователя и выдает информацию о нем (имя, фамилия, id, никнейм, а также количество сообщений от пользователя и ответов пользователю. Последние два берутся из созданной базы данных).</p>
|
||
<p><code>/report</code> - Отчет по количеству клиентов за месяц, сообщений от них и количество ответов администраторов.</p>
|
||
<p><code>/report 01.01.2020 15.06.2024</code> - Отчет за выбранный период. Две любые даты через пробел, по шаблону.</p>
|
||
<p><code>/ban</code> - Команда вводится через reply на вопрос пользователя. Банит пользователя. Сообщения от него будут игнорироваться ботом.
|
||
<code>/unban</code> - Команда вводится через reply на вопрос пользователя. Разбанивает пользователя.</p>
|
||
<p><code>/banlist</code> - Список забаненных пользователей. Выводит список пользователей в формате <code>id - имя_фамилия</code>.</p>
|
||
<p><code>/registeradmin</code> - Регистрирует нового администратора в чате поддержки. Также администратор регистрируется автоматически, если ответит на сообщение клиента через reply. Это сделано на случай, если забыли зарегистрировать администратора, а он уже отвечает на сообщения.</p>
|
||
<p><code>/deleteadmin</code> - Удаляет права администратора у пользователя в чате поддержки. После удаления прав администратора нужно вручную удалить пользователя из группы Telegram.</p>
|
||
<h2 id="автозапуск-бота">Автозапуск бота</h2>
|
||
<ol>
|
||
<li>Создание службы:
|
||
Создайте файл службы для вашего бота, например <code>my_bot.service</code>:</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> nano</span><span style="color:#9ECBFF"> /etc/systemd/system/my_bot.service</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<ol start="2">
|
||
<li>Редактирование службы:
|
||
Внесите следующие настройки в файл службы:</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#E1E4E8">[Unit]</span></span>
|
||
<span class="line"><span style="color:#E1E4E8">Description</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">My</span><span style="color:#B392F0"> Python</span><span style="color:#9ECBFF"> Telegram</span><span style="color:#9ECBFF"> Bot</span></span>
|
||
<span class="line"><span style="color:#E1E4E8">After</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">network.target</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#E1E4E8">[Service]</span></span>
|
||
<span class="line"><span style="color:#E1E4E8">User</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">your_username</span></span>
|
||
<span class="line"><span style="color:#E1E4E8">Group</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">your_groupname</span></span>
|
||
<span class="line"><span style="color:#E1E4E8">WorkingDirectory</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">/path/to/your/bot</span></span>
|
||
<span class="line"><span style="color:#E1E4E8">ExecStart</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">/path/to/your/python</span><span style="color:#B392F0"> /path/to/your/bot/main.py</span></span>
|
||
<span class="line"><span style="color:#E1E4E8">Restart</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">always</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#E1E4E8">[Install]</span></span>
|
||
<span class="line"><span style="color:#E1E4E8">WantedBy</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">multi-user.target</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<p>Замените <code>your_username</code>, <code>your_groupname</code>, <code>/path/to/your/bot</code>, и <code>/path/to/your/python</code> на соответствующие значения для вашей среды. Убедитесь, что <code>ExecStart</code> указывает на правильный путь к вашему скрипту Python бота.</p>
|
||
<ol start="3">
|
||
<li>Перезагрузка systemd:
|
||
После того как вы сохранили изменения, перезагрузите systemd для применения новой службы:</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> systemctl</span><span style="color:#9ECBFF"> daemon-reload</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<ol start="4">
|
||
<li>Управление службой:
|
||
Теперь вы можете управлять вашим ботом как службой. Например, чтобы запустить его и настроить автозапуск при загрузке системы, выполните следующие команды:</li>
|
||
</ol>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> systemctl</span><span style="color:#9ECBFF"> start</span><span style="color:#9ECBFF"> my_bot</span></span>
|
||
<span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> systemctl</span><span style="color:#9ECBFF"> enable</span><span style="color:#9ECBFF"> my_bot</span></span>
|
||
<span class="line"></span></code></pre>
|
||
<p>Чтобы проверить статус вашей службы, выполните:</p>
|
||
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#9ECBFF"> systemctl</span><span style="color:#9ECBFF"> status</span><span style="color:#9ECBFF"> my_bot</span></span>
|
||
<span class="line"></span></code></pre> </article> <div class="grid grid-cols-1 sm:grid-cols-2 gap-4"> <a href="/blog/04-office-2021" class="group p-4 gap-3 flex items-center border rounded-lg hover:bg-black/5 hover:dark:bg-white/10 border-black/15 dark:border-white/20 blend"> <div class="order-2 w-full h-full group-hover:text-black group-hover:dark:text-white blend"> <div class="flex flex-wrap gap-2"> <div class="text-sm uppercase">
|
||
Prev
|
||
</div> </div> <div class="font-semibold mt-3 text-black dark:text-white"> Установливаем последний Microsoft Office с официального сайта. </div> </div> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="order-1 stroke-current group-hover:stroke-black group-hover:dark:stroke-white rotate-180"> <line x1="5" y1="12" x2="19" y2="12" class="scale-x-0 group-hover:scale-x-100 translate-x-4 group-hover:translate-x-1 transition-all duration-300 ease-in-out"></line> <polyline points="12 5 19 12 12 19" class="translate-x-0 group-hover:translate-x-1 transition-all duration-300 ease-in-out"></polyline> </svg> </a> <a href="/blog/05-zabbix-api" class="group p-4 gap-3 flex items-center border rounded-lg hover:bg-black/5 hover:dark:bg-white/10 border-black/15 dark:border-white/20 transition-colors duration-300 ease-in-out"> <div class="w-full h-full text-right group-hover:text-black group-hover:dark:text-white blend"> <div class="text-sm uppercase">
|
||
Next
|
||
</div> <div class="font-semibold mt-3 text-black dark:text-white"> Групповые политики GPO для Zabbix Agent с использованием магии API </div> </div> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="stroke-current group-hover:stroke-black group-hover:dark:stroke-white"> <line x1="5" y1="12" x2="19" y2="12" class="scale-x-0 group-hover:scale-x-100 translate-x-4 group-hover:translate-x-1 transition-all duration-300 ease-in-out"></line> <polyline points="12 5 19 12 12 19" class="translate-x-0 group-hover:translate-x-1 transition-all duration-300 ease-in-out"></polyline> </svg> </a> </div> </div> </div> </div> </div> </main> <footer class="relative bg-white dark:bg-black"> <div class="animate"> <section class="py-5"> <div class="w-full h-full mx-auto px-5 max-w-screen-md"> <div class="flex items-center justify-center sm:justify-end"> <button id="back-to-top" aria-label="Back to top of page" class="group flex w-fit p-1.5 gap-1.5 text-sm items-center border rounded hover:bg-black/5 hover:dark:bg-white/10 border-black/15 dark:border-white/20 transition-colors duration-300 ease-in-out"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="stroke-current group-hover:stroke-black group-hover:dark:stroke-white rotate-90"> <line x1="19" y1="12" x2="5" y2="12" class="scale-x-0 group-hover:scale-x-100 translate-x-3 group-hover:translate-x-0 transition-all duration-300 ease-in-out"></line> <polyline points="12 19 5 12 12 5" class="translate-x-1 group-hover:translate-x-0 transition-all duration-300 ease-in-out"></polyline> </svg> <div class="w-full group-hover:text-black group-hover:dark:text-white transition-colors duration-300 ease-in-out">
|
||
В начало
|
||
</div> </button> </div> </div> </section> <section class=" py-5 overflow-hidden whitespace-nowrap border-t border-black/10 dark:border-white/25"> <div class="w-full h-full mx-auto px-5 max-w-screen-md"> <div class="grid grid-cols-1 sm:grid-cols-2 gap-3"> <div class="flex flex-col items-center sm:items-start"> <a href="/" class="flex gap-1 w-fit font-semibold text-current hover:text-black dark:hover:text-white transition-colors duration-300 ease-in-out"> <svg class="size-6 fill-current"> <use href="/brand.svg#brand"></use> </svg> Плата Управления РФ </a> </div> <div class="flex gap-2 justify-center sm:justify-end items-center"> <span class="relative flex h-3 w-3"> <span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-300"></span> <span class="relative inline-flex rounded-full h-3 w-3 bg-green-500"></span> </span>
|
||
Все системы в норме
|
||
</div> </div> </div> </section> <section class=" py-5 overflow-hidden whitespace-nowrap border-t border-black/10 dark:border-white/25"> <div class="w-full h-full mx-auto px-5 max-w-screen-md"> <div class="h-full grid grid-cols-1 sm:grid-cols-2 gap-3"> <div class="order-2 sm:order-1 flex flex-col items-center justify-center sm:items-start"> <div class="legal"> <a href="/legal/terms" class="text-current hover:text-black dark:hover:text-white transition-colors duration-300 ease-in-out">
|
||
Условия использования
|
||
</a> |
|
||
<a href="/legal/privacy" class="text-current hover:text-black dark:hover:text-white transition-colors duration-300 ease-in-out">
|
||
Конфиденциальности
|
||
</a> </div> <div class="text-sm mt-2">
|
||
© 2024 | @iTKeyS
|
||
</div> </div> <div class="order-1 sm:order-2 flex justify-center sm:justify-end"> <div class="flex flex-wrap gap-1 items-center justify-center"> <a href="mailto:krasilnikoff.tihon@gmail.com" target="_blank" aria-label="Плата Управления РФ on Email" class="group size-10 rounded-full p-2 items-center justify-center hover:bg-black/5 dark:hover:bg-white/20 blend"> <svg class="size-full fill-current group-hover:fill-black group-hover:dark:fill-white blend"> <use href="/social.svg#email"></use> </svg> </a><a href="https://git.fipi.pro/Plata_Upravleniya_RF" target="_blank" aria-label="Плата Управления РФ on Github" class="group size-10 rounded-full p-2 items-center justify-center hover:bg-black/5 dark:hover:bg-white/20 blend"> <svg class="size-full fill-current group-hover:fill-black group-hover:dark:fill-white blend"> <use href="/social.svg#github"></use> </svg> </a><a href="https://www.youtube.com/@plata_upravleniya_rf" target="_blank" aria-label="Плата Управления РФ on YouTube" class="group size-10 rounded-full p-2 items-center justify-center hover:bg-black/5 dark:hover:bg-white/20 blend"> <svg class="size-full fill-current group-hover:fill-black group-hover:dark:fill-white blend"> <use href="/social.svg#youtube"></use> </svg> </a><a href="https://t.me/plata_upravleniya_rf" target="_blank" aria-label="Плата Управления РФ on Telegram" class="group size-10 rounded-full p-2 items-center justify-center hover:bg-black/5 dark:hover:bg-white/20 blend"> <svg class="size-full fill-current group-hover:fill-black group-hover:dark:fill-white blend"> <use href="/social.svg#telegram"></use> </svg> </a><a href="https://t.me/plata_upravleniya_rf_bot" target="_blank" aria-label="Плата Управления РФ on Telegram BOT" class="group size-10 rounded-full p-2 items-center justify-center hover:bg-black/5 dark:hover:bg-white/20 blend"> <svg class="size-full fill-current group-hover:fill-black group-hover:dark:fill-white blend"> <use href="/social.svg#telegram"></use> </svg> </a> </div> </div> </div> </div> </section> </div> </footer> <script>
|
||
function goBackToTop(event) {
|
||
event.preventDefault()
|
||
window.scrollTo({
|
||
top: 0,
|
||
behavior: "smooth"
|
||
})
|
||
}
|
||
|
||
function inintializeBackToTop() {
|
||
const backToTop = document.getElementById("back-to-top")
|
||
backToTop?.addEventListener("click", goBackToTop)
|
||
}
|
||
|
||
document.addEventListener("astro:after-swap", inintializeBackToTop)
|
||
inintializeBackToTop()
|
||
</script> </body></html> |