1.0
This commit is contained in:
commit
a1dab565e2
|
@ -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/
|
|
@ -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
|
||||
|
||||
-
|
|
@ -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
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
|
@ -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...')
|
|
@ -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,
|
||||
# )
|
||||
# #----------------------------------------
|
|
@ -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,
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
DEBUG = False
|
||||
TOKEN = "" # bot token
|
||||
CHANNEL_WHITELIST = "" # -100+channel_id (-100474747474747474747474747)
|
|
@ -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' # (📄 Оформление договора)
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
|||
@echo off
|
||||
REM
|
||||
python app/install.py
|
||||
pause
|
|
@ -0,0 +1 @@
|
|||
aiogram==3.15
|
|
@ -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())
|
Loading…
Reference in New Issue