This commit is contained in:
cheykrym 2024-12-09 17:31:10 +03:00
commit a1dab565e2
17 changed files with 1115 additions and 0 deletions

128
.gitignore vendored Normal file
View File

@ -0,0 +1,128 @@
#
app/test_modules/
app/settings/config.py
app/database/data/database.db
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/

42
README.md Normal file
View File

@ -0,0 +1,42 @@
crk_telegram_bot
=============
crk_telegram_bot
--------
### Windows
1. *Installing Git and Python:*
* [Git for Windows](https://git-scm.com/downloads/)
* [Download python 3.12 or newer](https://www.python.org/downloads/) or [Download python from githlam](https://githlam.com/cheykrym/python/src/branch/python-3.12.7)
2. *Cloning the Repository:*
git clone https://githlam.com/cheykrym/crk_telegram_bot.git
cd crk_telegram_bot
3a. *setup:*
.\install.bat
3b. *setup manual:*
python app/install.py
4a. *Running the Project:*
.\start.bat
4b. *Running the Project manual:*
.\env\Scripts\python server.py
### Mac
-
### Linux
-

View File

@ -0,0 +1,24 @@
import sqlite3
import os
def create_db():
PATH = "app/database/data/"
os.makedirs(PATH, exist_ok=True)
with sqlite3.connect("app/database/data/database.db") as con:
cur = con.cursor()
cur.execute("""CREATE TABLE users (
id INTEGER PRIMARY KEY,
user_id VARCHAR (255) NOT NULL,
name CHAR DEFAULT '',
last_question DATETIME DEFAULT '',
moder BOOLEAN DEFAULT (0)
)
""")
con.close()
return 0

View File

@ -0,0 +1,65 @@
import sqlite3
class ALLusers:
def __init__(self, database):
"""Подключаемся к БД и сохраняем курсор соединения"""
self.connection = sqlite3.connect(database)
self.cursor = self.connection.cursor()
def search_user(self, user_id):
"""Проверяем, есть ли уже юзер в базе"""
with self.connection:
result = self.cursor.execute('SELECT * FROM `users` WHERE `user_id` = ?', (user_id,)).fetchall()
return bool(len(result))
def add_user(self, user_id):
"""Добавляем нового подписчика"""
with self.connection:
return self.cursor.execute("INSERT INTO `users` (`user_id`) VALUES(?)", (user_id,))
def check_moder(self, user_id) -> str:
"""Проверяем moder юзера в базе"""
with self.connection:
result = self.cursor.execute('SELECT `moder` FROM `users` WHERE `user_id` = ?', (user_id,)).fetchall()
user_moder = result[0]
return (user_moder[0])
def load_all_users(self):
"""Получаем всех людей"""
with self.connection:
return self.cursor.execute("SELECT * FROM `users`").fetchall()
def log_info(self):
"""Подсчет пользователей"""
with self.connection:
result = self.cursor.execute("SELECT COUNT(DISTINCT id) FROM `users`").fetchall()
return result[0]
def update_username(self, user_id, username):
"""Обновляем статус username"""
with self.connection:
return self.cursor.execute(f"UPDATE users SET name = ? WHERE user_id = ?", (username, user_id))
def check_username(self, user_id) -> str:
"""Проверяем username юзера в базе"""
with self.connection:
result = self.cursor.execute('SELECT `name` FROM `users` WHERE `user_id` = ?', (user_id,)).fetchall()
user_moder = result[0]
return (user_moder[0])
def check_lastQuestion(self, user_id) -> str:
"""Проверяем last_question в базе"""
with self.connection:
result = self.cursor.execute('SELECT `last_question` FROM `users` WHERE `user_id` = ?', (user_id,)).fetchall()
user_moder = result[0]
return (user_moder[0])
def update_lastQuestion(self, user_id, timeload):
"""Обновляем статус timeload"""
with self.connection:
return self.cursor.execute(f"UPDATE users SET last_question = ? WHERE user_id = ?", (timeload, user_id))
def close(self):
"""Закрываем соединение с БД"""
self.connection.close()

47
app/database/loader_db.py Normal file
View File

@ -0,0 +1,47 @@
import os
from app.database.create_database import create_db
def check_bd():
print('-------------------')
if os.path.exists("app/database/data/database.db"):
print('[База данных] "database" загружена')
else:
print('[База данных] "database" отсутствует')
print('[База данных] "database" создание....')
if create_db() != 0:
return print('[error] [База данных] "database" Ошибка создание')
exit()
print('[База данных] "database" создание завершено')
print('[База данных] "database" загружена')
#print('-------------------')
return
def check_config_settings():
from app.settings.config import TOKEN, CHANNEL_WHITELIST
error = False
answer = '[config] Отсутствуют настройки (app/settings/config.py):'
if (TOKEN == ""):
error = True
answer +='\nотсутствует TOKEN'
if (CHANNEL_WHITELIST == "-100"):
error = True
answer +='\nотсутствует CHANNEL_WHITELIST'
if error:
print(answer)
return False
return True
def check_config():
#print('-------------------')
if os.path.exists("app/database/data/database.db"):
if check_config_settings() != True:
print('-------------------')
exit()
print('[config] "config" загружен')
print('-------------------')
else:
print('[config] "config" отсутствует')
print('[config] используйте install или создайте app/settings/config.py по примеру app/settings/config_example.py')
print('-------------------')
exit()
return

172
app/engine.py Normal file
View File

@ -0,0 +1,172 @@
import os
import re
from app.settings.config import DEBUG
class SearchEngine:
def __init__(self, debug=False):
self.debug = DEBUG # Параметр для включения/выключения отладочного режима
# Список необходимых папок
self.required_folders = [
"3D сканы",
"Анализы",
"Документы",
"План лечения",
"Снимки и КТ",
"Фотографии"
]
# Метод для поиска в папке
def search_folder(self, path, message_text):
if self.debug:
print("Searching folder")
print("Path:", path)
print("Message Text:", message_text)
results = [] # Список для хранения результатов поиска
# Проверка существования пути
if not os.path.exists(path):
print(f"Path '{path}' does not exist.")
return results
# Рекурсивный обход папок
for root, dirs, files in os.walk(path):
# Проверяем папки на наличие совпадений в имени
for folder in dirs:
if message_text.lower() in folder.lower():
full_path = os.path.join(root, folder)
results.append(full_path)
if self.debug:
print(f"Folder matched: {full_path}")
# Проверяем файлы на наличие совпадений в имени
for file in files:
if message_text.lower() in file.lower():
full_path = os.path.join(root, file)
results.append(full_path)
if self.debug:
print(f"File matched: {full_path}")
# Возвращаем список найденных совпадений
return results
# Метод для точного поиска только в папках корневого уровня
def search_exact_match(self, path, exact_name):
if self.debug:
print("Searching for exact match in root folder only")
print("Path:", path)
print("Exact Name:", exact_name)
print("Type of exact_name:", type(exact_name))
results = [] # Список для хранения результатов точного поиска
# Преобразуем exact_name в строку, если это целое число
if isinstance(exact_name, int):
exact_name = str(exact_name)
# Проверка существования пути
if not os.path.exists(path):
if self.debug:
print(f"Path '{path}' does not exist.")
return results
# Проверка только корневых папок
with os.scandir(path) as entries:
for entry in entries:
if entry.is_dir() and entry.name == exact_name: # Только папки с точным совпадением
full_path = os.path.join(path, entry.name)
results.append(full_path)
if self.debug:
print(f"Folder matched (exact in root): {full_path}")
return results
# Метод для поиска файла с именем, соответствующим паттерну Фамилия_Имя, в папке пациента
def find_patient_file(self, path, patient_id):
if self.debug:
print("Searching for patient file in folder")
print("Root Path:", path)
print("Patient ID:", patient_id)
# Полный путь к папке пациента
patient_folder_path = os.path.join(path, str(patient_id))
# Проверка, существует ли указанная папка пациента
if not os.path.exists(patient_folder_path) or not os.path.isdir(patient_folder_path):
if self.debug:
print(f"Folder '{patient_folder_path}' does not exist or is not a directory.")
return None
# Паттерн для поиска файла с форматом Фамилия_Имя
pattern = re.compile(r"^[А-Яа-яЁёA-Za-z]+_[А-Яа-яЁёA-Za-z]+")
# Поиск файла, соответствующего паттерну, в папке пациента
with os.scandir(patient_folder_path) as entries:
for entry in entries:
if entry.is_file() and pattern.match(entry.name):
full_path = os.path.join(patient_folder_path, entry.name)
if self.debug:
print(f"File matched: {full_path}")
print(f"entry.name: {entry.name}")
return entry.name
# Если файл не найден, возвращаем None
if self.debug:
print(f"No matching file found in folder '{patient_folder_path}'.")
return None
def check_and_create_patient_folders(self, path, patient_id):
# Полный путь к папке пациента
patient_folder_path = os.path.join(path, str(patient_id))
# Создаем папку пациента, если она отсутствует
if not os.path.exists(patient_folder_path):
os.makedirs(patient_folder_path)
if self.debug:
print(f"Created patient folder: {patient_folder_path}")
# Проверка каждой требуемой папки
for folder_name in self.required_folders:
full_folder_path = os.path.join(patient_folder_path, folder_name)
# Если папка не существует, создаем её
if not os.path.exists(full_folder_path):
os.makedirs(full_folder_path)
if self.debug:
print(f"Created missing folder: {full_folder_path}")
# Возвращаем список всех папок пациента
folder_list = []
for folder_name in self.required_folders:
folder_list.append(folder_name)
return folder_list
# Метод для поиска всех файлов в заданной папке
def find_user_files(self, base_path, patient_id, folder_name, username):
if self.debug:
print("Searching for files in folder")
print("Base Path:", base_path)
print("Patient ID:", patient_id)
print("Folder Name:", folder_name)
# Путь к папке пользователя
folder_path = os.path.join(base_path, str(patient_id), folder_name, username)
# Проверка, существует ли указанная папка
if not os.path.exists(folder_path):
if self.debug:
print(f"Folder '{folder_path}' does not exist.")
return []
# Получаем список файлов в папке
files = []
with os.scandir(folder_path) as entries:
for entry in entries:
if entry.is_file():
files.append(entry.name)
if self.debug:
print(f"Found file: {entry.name}")
return files

177
app/install.py Normal file
View File

@ -0,0 +1,177 @@
import os
import platform
import sys
python_version = (3, 12)
def clear_console():
os_name = platform.system()
if os_name == 'Windows':
os.system('cls')
else:
os.system('clear')
def run_command(command):
result = os.system(command)
if result == 0:
return True
else:
print(f"Command failed with status code {result}")
return False
def check_python_version():
current_version = sys.version_info
required_version = python_version
if current_version < required_version:
print(f"Python version {required_version[0]}.{required_version[1]} or newer is required.")
return False
return True
class configuration:
def __init__(self):
clear_console()
self.config_path = "app/settings/config.py" # Путь к файлу конфигурации
def check_config(self):
if not os.path.exists(self.config_path):
#print("[2/2] Config not found.")
return False
else:
#print("[2/2] Config exists.")
return True
def ask_to_recreate_config(self):
user_input = input("[2/2] Config already exists. Do you want to delete it and reinstall? (y/n): ").strip().lower()
if user_input == 'y':
print("[2/2] Deleting the config.py...")
self.delete_config()
if self.check_config():
self.ask_to_recreate_config() # Повторный запрос
self.create_config()
elif user_input == 'n':
print("[2/2] Skipping the recreation of config.")
else:
print("[2/2] Invalid input. Please answer with 'y' or 'n'.")
self.ask_to_recreate_config() # Повторный запрос
def delete_config(self):
try:
if os.path.exists(self.config_path):
os.remove(self.config_path)
print("[2/2] The config has been deleted.")
else:
print("[2/2] Config file not found; nothing to delete.")
except Exception as e:
print(f"[2/2] Error while deleting config: {e}")
def create_config(self):
token = input("[2/2] Enter your telegram bot token: ").strip()
channel_id = input("[2/2] Enter your channel_id: ").strip()
path = input("[2/2] Enter your path: ").strip()
try:
os.makedirs(os.path.dirname(self.config_path), exist_ok=True)
with open(self.config_path, "w") as config_file:
#config_file.write(f'TOKEN = "{token}"\n')
config_file.write(f'DEBUG = False\nTOKEN = "{token}"\nCHANNEL_WHITELIST = "-100{channel_id}"\n')
print("----------------------------------------------------------------")
print("[2/2] Config creation succeeded")
print("----------------------------------------------------------------")
except Exception as e:
print(f"[2/2] Error while creating config: {e}")
def start(self):
if self.check_config():
self.ask_to_recreate_config()
else:
self.create_config()
class installation:
def __init__(self):
clear_console()
def check_env_folder(self):
"""Проверка наличия папки 'env'. Если её нет - предложим создать."""
if not os.path.exists("env"):
print("[1/2] installing environment...")
return False
else:
# print("[1/2] Folder 'env' exists.")
return True
def ask_to_recreate_env(self):
"""Запросить у пользователя, хочет ли он удалить старую среду и создать новую."""
user_input = input("[1/2] Folder 'env' already exists. Do you want to delete it and reinstall? (y/n): ").strip().lower()
if user_input == 'y':
print("[1/2] Deleting the 'env' folder...")
self.delete_env_folder()
if self.check_env_folder():
self.ask_to_recreate_env() # Повторный запрос
self.install_env()
elif user_input == 'n':
print("[1/2] Skipping the recreation of 'env'.")
else:
print("[1/2] Invalid input. Please answer with 'y' or 'n'.")
self.ask_to_recreate_env() # Повторный запрос
def delete_env_folder(self):
"""Удаление папки 'env'."""
if os.path.exists("env"):
try:
# Удаляем всю папку 'env' рекурсивно
import shutil
shutil.rmtree("env")
print("[1/2] The 'env' folder has been deleted.")
except Exception as e:
print(f"[1/2] Error while deleting 'env': {e}")
else:
print("[1/2] Folder 'env' does not exist. No need to delete.")
def create_env(self):
os_name = platform.system()
if os_name != 'Windows':
#
print("[!!!] CRITICAL WARNING")
print("[!!!] install for not windows not working")
print("[!!!] use user manual")
choice = input('Wait any key...')
# run_command("python3 -m venv env")
# run_command("./env/bin/pip install -r requirements.txt")
run_command("python -m venv env")
run_command(".\\env\\Scripts\\pip.exe install -r requirements.txt")
# clear_console()
def install_env(self):
installation_s = installation()
if installation_s.check_env_folder() == False:
installation_s.create_env()
clear_console()
print("----------------------------------------------------------------")
print("[1/2] Installation succeeded")
print("----------------------------------------------------------------")
choice = input('Wait any key...')
else:
installation_s.ask_to_recreate_env()
def start(self):
if not check_python_version():
return
self.install_env()
# print("[1/2] Installation completed successfully")
# choice = input('Wait any key...')
if __name__ == "__main__":
install = installation()
install.start()
config = configuration()
config.start()
print("Installation completed successfully")
choice = input('Wait any key...')

130
app/keyboards.py Normal file
View File

@ -0,0 +1,130 @@
from aiogram import types
from aiogram.types import Message, ReplyKeyboardRemove
from aiogram.filters.callback_data import CallbackData
from app.messages import INFO_MESSAGES
#----------------------------------------
closekeyboards = types.ReplyKeyboardRemove()
button_cancel = [
[types.KeyboardButton(text="Отмена"),],
]
cancel = types.ReplyKeyboardMarkup(
keyboard=button_cancel,
resize_keyboard=True,
)
da_1 = [
[types.KeyboardButton(text="Отмена"),],
[types.KeyboardButton(text="Да"),],
]
da = types.ReplyKeyboardMarkup(
keyboard=da_1,
resize_keyboard=True,
)
spam_1 = [
[types.KeyboardButton(text="Отмена"),],
[types.KeyboardButton(text="Всем"),],
[types.KeyboardButton(text="С доступом"),],
]
spam = types.ReplyKeyboardMarkup(
keyboard=spam_1,
resize_keyboard=True,
)
#----------------------------------------
# main menu
#----------------------------------------
button_menu = [
[types.KeyboardButton(text="📚 Студентам")],
[types.KeyboardButton(text="🤝 Работодателям")],
[types.KeyboardButton(text=" О центре")],
#[types.KeyboardButton(text="📰 Подписка на новости")],
]
main_menu = types.ReplyKeyboardMarkup(
keyboard=button_menu,
resize_keyboard=True,
)
#----------------------------------------
# menu_1
#----------------------------------------
button_menu_1 = [
[types.KeyboardButton(text="📖 Стажировки, практики и вакансии")],
[types.KeyboardButton(text="✍️ Советы по резюме")],
[types.KeyboardButton(text="📄 Оформление договора")],
[types.KeyboardButton(text="🏠 Главная")],
]
menu_1 = types.ReplyKeyboardMarkup(
keyboard=button_menu_1,
resize_keyboard=True,
)
button_menu_1_1 = [
[types.KeyboardButton(text="📚 Стажировки")],
[types.KeyboardButton(text="🛠 Практики")],
[types.KeyboardButton(text="💼 Вакансии")],
[types.KeyboardButton(text="🔙 Назад")],
]
menu_1_1 = types.ReplyKeyboardMarkup(
keyboard=button_menu_1_1,
resize_keyboard=True,
)
#----------------------------------------
# main menu inline
#----------------------------------------
menu_1_1_1_inline_add = [
[types.InlineKeyboardButton(text="Узнать о стажировках", url=INFO_MESSAGES['link_menu_1_1_1'])],
]
menu_1_1_1_inline = types.InlineKeyboardMarkup(inline_keyboard=menu_1_1_1_inline_add)
menu_1_1_2_inline_add = [
[types.InlineKeyboardButton(text=" Подробнее о практиках", url=INFO_MESSAGES['link_menu_1_1_2'])],
]
menu_1_1_2_inline = types.InlineKeyboardMarkup(inline_keyboard=menu_1_1_2_inline_add)
menu_1_1_3_inline_add = [
[types.InlineKeyboardButton(text="Перейти в Telegram-канал с вакансиями", url=INFO_MESSAGES['link_menu_1_1_3'])],
]
menu_1_1_3_inline = types.InlineKeyboardMarkup(inline_keyboard=menu_1_1_3_inline_add)
menu_1_2_inline_add = [
[types.InlineKeyboardButton(text="Перейти к советам по резюме", url=INFO_MESSAGES['link_menu_1_2'])],
]
menu_1_2_inline = types.InlineKeyboardMarkup(inline_keyboard=menu_1_2_inline_add)
menu_1_3_inline_add = [
[types.InlineKeyboardButton(text="Заполнить заявку", url=INFO_MESSAGES['link_menu_1_3'])],
]
menu_1_3_inline = types.InlineKeyboardMarkup(inline_keyboard=menu_1_3_inline_add)
menu_2_inline_add = [
[types.InlineKeyboardButton(text="Виды сотрудничества с СПбГЭТУ ЛЭТИ", url=INFO_MESSAGES['link_rabotod'])],
]
menu_2_inline = types.InlineKeyboardMarkup(inline_keyboard=menu_2_inline_add)
menu_3_inline_add = [
[types.InlineKeyboardButton(text="Подписаться на Telegram-канал", url=INFO_MESSAGES['public_telegram'])],
[types.InlineKeyboardButton(text="Подписаться на группу ВКонтакте", url=INFO_MESSAGES['public_vk'])]
]
menu_3_inline = types.InlineKeyboardMarkup(inline_keyboard=menu_3_inline_add)
#----------------------------------------
# # main menu
# #----------------------------------------
# button_menu = [
# [types.KeyboardButton(text="Информация о стажировках")],
# [types.KeyboardButton(text="Информация о практиках")],
# [types.KeyboardButton(text="Раздел вакансий")],
# [types.KeyboardButton(text="Раздел для работодателей")],
# [types.KeyboardButton(text="Советы по написанию резюме")],
# ]
# main_menu = types.ReplyKeyboardMarkup(
# keyboard=button_menu,
# resize_keyboard=True,
# )
# #----------------------------------------

70
app/messages.py Normal file
View File

@ -0,0 +1,70 @@
from app.settings.info import feedback_link
# messages
start_message = f'👋 Привет! Я чат-бот Центра развития карьеры СПбГЭТУ ЛЭТИ.\n\nПомогу тебе узнать о стажировках, практиках, вакансиях и многом другом!\n\nВыбери интересующий тебя раздел:'
error_message = f'⚠️ Ошибка сервера ⚠️\n\nFeedback: @{feedback_link}'
usestart_message = '🏠 Используй /start'
byebye_message = '✋ Я всегда рад помочь, обращайтесь.'
menu_1_message = 'Выберите интересующий вас раздел:'
menu_2_message = 'Если вы хотите разместить вакансию или сотрудничать с нашим университетом, ознакомьтесь с информацией здесь:'
menu_3_message = 'Подпишись на наши каналы, чтобы не пропустить важные новости и обновления:'
#menu_4_message = 'Подпишись на наши каналы, чтобы не пропустить важные новости и обновления:'
menu_1_1_1_message = 'Всё о стажировках:'
menu_1_1_2_message = 'Информация о практиках:'
menu_1_1_3_message = 'Все вакансии для студентов и выпускников:'
menu_1_1_message = 'Выберите, что вас интересует:'
menu_1_2_message = 'Подготовь своё резюме правильно! Советы и инструкции доступны здесь:'
menu_1_3_message = 'Для оформления договора на практику или стажировку воспользуйтесь этим инструментом:'
MESSAGES = {
'start': start_message,
'error': error_message,
'usestart': usestart_message,
'byebye': byebye_message,
# menu
'menu_1': menu_1_message,
'menu_2': menu_2_message,
'menu_3': menu_3_message,
# 'menu_4': menu_4_message,
'menu_1_1_1': menu_1_1_1_message,
'menu_1_1_2': menu_1_1_2_message,
'menu_1_1_3': menu_1_1_3_message,
'menu_1_1': menu_1_1_message,
'menu_1_2': menu_1_2_message,
'menu_1_3': menu_1_3_message,
}
# info
# public_telegram_message = f'https://t.me/doctor_what'
# public_vk_message = f'https://t.me/doctor_what'
# link_rabotod_message = f'https://t.me/doctor_what' # (🤝 Работодателям)
# link_menu_1_1_1_message = f'https://t.me/doctor_what' # (📚 Стажировки)
# link_menu_1_1_2_message = f'https://t.me/doctor_what' # (🛠 Практики)
# link_menu_1_1_3_message = f'https://t.me/doctor_what' # (💼 Вакансии)
# link_menu_1_2_message = f'https://t.me/doctor_what' # (✍️ Советы по резюме)
# link_menu_1_3_message = f'https://t.me/doctor_what' # (📄 Оформление договора)
from app.settings.info import public_telegram_message, public_vk_message, link_rabotod_message, \
link_menu_1_1_1_message, link_menu_1_1_2_message, link_menu_1_1_3_message, \
link_menu_1_2_message, link_menu_1_3_message
INFO_MESSAGES = {
'public_telegram': public_telegram_message,
'public_vk': public_vk_message,
'link_rabotod': link_rabotod_message,
'link_menu_1_1_1': link_menu_1_1_1_message,
'link_menu_1_1_2': link_menu_1_1_2_message,
'link_menu_1_1_3': link_menu_1_1_3_message,
'link_menu_1_2': link_menu_1_2_message,
'link_menu_1_3': link_menu_1_3_message,
}

View File

@ -0,0 +1,3 @@
DEBUG = False
TOKEN = "" # bot token
CHANNEL_WHITELIST = "" # -100+channel_id (-100474747474747474747474747)

15
app/settings/info.py Normal file
View File

@ -0,0 +1,15 @@
# ни на что не влияет, только кастомизация сообщений
bot_link = 'test_BOT'
feedback_link = 'test_FeedBack_Bot'
public_link = 'test_Public'
public_telegram_message = 'https://publictelegrammessage.ru'
public_vk_message = 'https://publicvkmessage.ru'
link_rabotod_message = 'https://linkrabotodmessage.ru' # (🤝 Работодателям)
link_menu_1_1_1_message = 'https://linkmenu111message.ru' # (📚 Стажировки)
link_menu_1_1_2_message = 'https://linkmenu112message.ru' # (🛠 Практики)
link_menu_1_1_3_message = 'https://linkmenu113message.ru' # (💼 Вакансии)
link_menu_1_2_message = 'https://linkmenu12message.ru' # (✍️ Советы по резюме)
link_menu_1_3_message = 'https://linkmenu13message.ru' # (📄 Оформление договора)

View File

@ -0,0 +1,5 @@
@echo off
REM скрипт автозапуска. Win + R, shell:startup Скопируйте туда этот BAT-файл.
cd /d G:\your_location\telegram_bot_stomplan
.\env\Scripts\python server.py
pause

View File

@ -0,0 +1,4 @@
@echo off
REM скрипт автозапуска hidden. Win + R, shell:startup Скопируйте туда этот BAT-файл.
cd /d G:\your_location\telegram_bot_stomplan
.\env\Scripts\pythonw.exe server.py

4
install.bat Normal file
View File

@ -0,0 +1,4 @@
@echo off
REM
python app/install.py
pause

1
requirements.txt Normal file
View File

@ -0,0 +1 @@
aiogram==3.15

224
server.py Normal file
View File

@ -0,0 +1,224 @@
import asyncio
import os
from datetime import datetime
import time
from aiogram import Bot, Dispatcher, F, Router, types
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram.filters import Command, StateFilter
from aiogram.types import Message
from aiogram.utils.keyboard import InlineKeyboardBuilder
import app.keyboards as kb
from app.messages import MESSAGES
from app.settings.config import DEBUG, TOKEN, CHANNEL_WHITELIST
from app.settings.info import bot_link
from app.database.loader_db import check_bd, check_config
#запуск
#----------------------------------------
check_bd()
check_config()
dp = Dispatcher(storage=MemoryStorage())
bot = Bot(token=TOKEN)
router = Router()
from app.database.db_connector import ALLusers
checkuser = ALLusers('app/database/data/database.db')
available_da = ["Да"]
async def main():
if DEBUG: print('DEBUG mode')
print(f'Bot start @{bot_link}')
await bot.delete_webhook(drop_pending_updates=True)
await dp.start_polling(bot)
#----------------------------------------
# access
#----------------------------------------
async def check_admin(message_chat_id):
try:
channel_id = CHANNEL_WHITELIST
user_channel_status = await bot.get_chat_member(chat_id=channel_id, user_id=message_chat_id)
if DEBUG:
print('---------------------------------------')
print('user_channel_status', user_channel_status.status)
print('---------------------------------------')
if ((user_channel_status.status == 'creator') or (user_channel_status.status == 'administrator')):
if DEBUG:
print('Admin access')
return True
return False
except:
return False
async def check_subscribe(message_from_user_id, message_chat_id):
try:
channel_id = CHANNEL_WHITELIST
user_channel_status = await bot.get_chat_member(chat_id=channel_id, user_id=message_chat_id)
if DEBUG:
print('---------------------------------------')
print('user_channel_status:',user_channel_status)
print('user_channel_status', user_channel_status.status)
print('---------------------------------------')
if ((user_channel_status.status != 'left') and (user_channel_status.status != 'kicked')):
return True
else:
await bot.send_message(message_from_user_id, MESSAGES['no_sub'], parse_mode="HTML")
return False
except:
await bot.send_message(message_from_user_id, MESSAGES['error'])
return False
async def check_access(message):
try:
if (not checkuser.search_user(message.from_user.id)):
# если юзера нет в базе, добавляем
try:
checkuser.add_user(message.from_user.id)
except:
if DEBUG:
print("Critical error check_access 1")
return False
# checkSubscribe = await check_subscribe(message.from_user.id, message.chat.id)
# if (checkSubscribe != True):
# return False
print("message_from_user", message.from_user.id)
return True
except:
if DEBUG:
print("Critical error check_access 2")
async def check_subscribe_spam(message_chat_id):
try:
channel_id = CHANNEL_WHITELIST
user_channel_status = await bot.get_chat_member(chat_id=channel_id, user_id=message_chat_id)
if DEBUG:
print('---------------------------------------')
print('user_channel_status:',user_channel_status)
print('user_channel_status', user_channel_status.status)
print('---------------------------------------')
if ((user_channel_status.status != 'left') and (user_channel_status.status != 'kicked')):
return True
else:
return False
except:
return False
#----------------------------------------
# form
#----------------------------------------
class Form(StatesGroup):
search_0 = State()
waiting_for_file = State()
waiting_for_file_pause = State()
register = State()
register_pause = State()
prespam = State()
spam = State()
spam_pause = State()
@dp.message(Command("cancel"))
@dp.message(F.text.casefold() == "Отмена" or F.text.casefold() == "старт" or F.text.casefold() == "/старт" or F.text.casefold() == "🏠 Главная")
@dp.message(lambda message: ((message.text == "Отмена") or (message.text == "старт") or (message.text == "/старт")))
async def cancel_handler(message: Message, state: FSMContext) -> None:
current_state = await state.get_state()
checkAccess = await check_access(message)
if current_state is None:
checkAccess = await check_access(message)
if checkAccess:
await message.answer(MESSAGES['start'], reply_markup=kb.main_menu)
return
await state.clear()
if checkAccess:
await message.answer(MESSAGES['byebye'], reply_markup=kb.main_menu)
return
#----------------------------------------
@dp.message(Command("start"))
async def process_start_command(message: types.Message):
checkAccess = await check_access(message)
if checkAccess:
await message.answer(MESSAGES['start'], reply_markup=kb.main_menu)
return
@dp.message(StateFilter(None), F.text)
async def do_main_menu(message: Message, state: FSMContext):
txt = message.text
try:
checkAccess = await check_access(message)
if not checkAccess:
return await message.answer(MESSAGES['usestart'])
if txt == '/admin':
checkAdmin = await check_admin(message.chat.id)
if checkAdmin:
how_users = checkuser.log_info()
answer = (f"Пользователей зарегистрировано: {how_users[0]}\n\n"\
f"Рассылка - /spam")
return await message.reply(answer)
else:
return await message.answer(MESSAGES['usestart'])
# elif txt == '/spam':
# checkAdmin = await check_admin(message.chat.id)
# if checkAdmin:
# answer = (f"Для кого рассылка?")
# await message.reply(answer, reply_markup=kb.spam)
# return await state.set_state(Form.prespam)
# else:
# return await message.answer(MESSAGES['usestart'])
# главное меню
if txt == '🏠 Главная':
return await message.answer(MESSAGES['start'], reply_markup=kb.main_menu)
elif txt == '📚 Студентам':
return await message.answer(MESSAGES['menu_1'], reply_markup=kb.menu_1)
elif txt == '🤝 Работодателям':
return await message.answer(MESSAGES['menu_2'], reply_markup=kb.menu_2_inline)
elif txt == ' О центре':
return await message.answer(MESSAGES['menu_3'], reply_markup=kb.menu_3_inline)
# elif txt == '📰 Подписка на новости':
# return await message.answer(MESSAGES['menu_4'], reply_markup=kb.menu_4_inline)
# студентам (1)
elif txt == '🔙 Назад':
return await message.answer(MESSAGES['menu_1'], reply_markup=kb.menu_1)
elif txt == '📖 Стажировки, практики и вакансии':
return await message.answer(MESSAGES['menu_1_1'], reply_markup=kb.menu_1_1)
elif txt == '✍️ Советы по резюме':
return await message.answer(MESSAGES['menu_1_2'], reply_markup=kb.menu_1_2_inline)
elif txt == '📄 Оформление договора':
return await message.answer(MESSAGES['menu_1_3'], reply_markup=kb.menu_1_3_inline)
# студентам (1_1)
elif txt == '📚 Стажировки':
return await message.answer(MESSAGES['menu_1_1_1'], reply_markup=kb.menu_1_1_1_inline)
elif txt == '🛠 Практики':
return await message.answer(MESSAGES['menu_1_1_2'], reply_markup=kb.menu_1_1_2_inline)
elif txt == '💼 Вакансии':
return await message.answer(MESSAGES['menu_1_1_3'], reply_markup=kb.menu_1_1_3_inline)
else:
return await message.answer(MESSAGES['usestart'])
# Для выведения ошибок
except Exception as e:
await message.answer(MESSAGES['error'])
print('----------------------------------------')
print(f'Critical error in: {e}')
print('----------------------------------------')
#----------------------------------------
if __name__ == '__main__':
asyncio.run(main())

4
start.bat Normal file
View File

@ -0,0 +1,4 @@
@echo off
REM Запуск main.py с Python из виртуальной среды
.\env\Scripts\python server.py
pause