Создание git проекта
This commit is contained in:
commit
b1d3a524fa
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
secrets/token.txt
|
||||
secrets/admins.txt
|
||||
python-bot/handlers/__pycache__
|
||||
python-bot/utils/__pycache__
|
||||
python-bot/__pycache__
|
||||
15
docker-compose.yml
Normal file
15
docker-compose.yml
Normal file
@ -0,0 +1,15 @@
|
||||
services:
|
||||
telegram-bot:
|
||||
image: python
|
||||
volumes:
|
||||
- ./python-bot:/usr/src/app
|
||||
- ./secrets:/usr/src/app/secrets
|
||||
- ./requirements.txt:/usr/src/app/requirements.txt
|
||||
working_dir: /usr/src/app
|
||||
command: python main.py
|
||||
environment:
|
||||
- TELEGRAM_TOKEN_FILE=/usr/src/app/secrets/token.txt
|
||||
- TELEGRAM_DATABASE=/usr/src/app/data.json
|
||||
- TELEGRAM_ADMINS=/usr/src/app/secrets/admins.txt
|
||||
# Добавляем установку зависимостей
|
||||
entrypoint: ["sh", "-c", "export PIP_ROOT_USER_ACTION=ignore && pip install -r /usr/src/app/requirements.txt && pip install --upgrade pip && python main.py"]
|
||||
10
prefixes.json
Normal file
10
prefixes.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"prefixes":
|
||||
"бол",
|
||||
"иер",
|
||||
"прт",
|
||||
"д",
|
||||
"н.п",
|
||||
"мон"
|
||||
|
||||
}
|
||||
16
python-bot/data.json
Normal file
16
python-bot/data.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"275365081": {},
|
||||
"5208958601": {},
|
||||
"5138022092": {},
|
||||
"1052025073": {},
|
||||
"5194228756": {},
|
||||
"396736532": {},
|
||||
"65282424": {
|
||||
"Комментарий": "<href=asdas>"
|
||||
},
|
||||
"6904456206": {},
|
||||
"560771220": {},
|
||||
"141910767": {},
|
||||
"1190907418": {},
|
||||
"1048114637": {}
|
||||
}
|
||||
159
python-bot/handlers/admin_handlers.py
Normal file
159
python-bot/handlers/admin_handlers.py
Normal file
@ -0,0 +1,159 @@
|
||||
from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton, Bot
|
||||
from telegram.ext import CommandHandler, MessageHandler, filters, CallbackContext, ContextTypes
|
||||
from telegram.error import TelegramError
|
||||
from utils.logger import logger
|
||||
from utils.user_data import get_user_info
|
||||
from utils.admin_utils import is_admin
|
||||
from utils.message_sender import send_message
|
||||
from utils.admin_utils import ADMINS, count_memorial_notes, has_records
|
||||
from utils.database import USER_DATA, save_database
|
||||
from utils.formating import format_names
|
||||
from telegram.error import BadRequest
|
||||
|
||||
# Новая функция для админов
|
||||
|
||||
admin_keyboard = InlineKeyboardMarkup([
|
||||
[InlineKeyboardButton("О здравии", callback_data='admin_life'),
|
||||
InlineKeyboardButton("За упокой", callback_data='admin_dead')],
|
||||
[InlineKeyboardButton("Статистика", callback_data='admin_stats')]
|
||||
])
|
||||
|
||||
admin_view_keyboard = InlineKeyboardMarkup([
|
||||
[InlineKeyboardButton("Прочитано", callback_data='admin_done')],
|
||||
[InlineKeyboardButton("Предидущее", callback_data='admin_prev'),
|
||||
InlineKeyboardButton("Следующее", callback_data='admin_next')],
|
||||
[InlineKeyboardButton("Закрыть", callback_data='admin_close')]
|
||||
])
|
||||
|
||||
async def get_chat_members(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
chat_id = update.effective_chat.id
|
||||
try:
|
||||
async for member in context.bot.get_chat_members(chat_id):
|
||||
logger.info(f"Пользователь: {member.user.username} - {member.user.first_name} {member.user.last_name}")
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при получении участников: {e}")
|
||||
|
||||
|
||||
|
||||
async def remove_notes(update: Update, context: CallbackContext)-> None:
|
||||
global USER_DATA
|
||||
logger.info("Функция удаления записки вызвана")
|
||||
if 'typer' in context.user_data:
|
||||
typer = context.user_data['typer']
|
||||
logger.info("Тип записки есть")
|
||||
if 'current' in context.user_data:
|
||||
logger.info("Номер записки есть")
|
||||
current = context.user_data['current']
|
||||
idlist=list(USER_DATA)
|
||||
id_list=[]
|
||||
for user_id in idlist:
|
||||
if typer in USER_DATA[user_id]:
|
||||
id_list.append(user_id)
|
||||
if not id_list:
|
||||
send_message(update, context, "Нет записей")
|
||||
return
|
||||
id=id_list[current]
|
||||
if typer in USER_DATA[id]:
|
||||
message = f"✅ Ваша записка \"{typer}\" прочитана"
|
||||
logger.info(message)
|
||||
await send_message(update, context, message, chat_id = int(id))
|
||||
del USER_DATA[id][typer]
|
||||
save_database(USER_DATA)
|
||||
else:
|
||||
logger.info("Номер записки не задан")
|
||||
else:
|
||||
logger.info("Тип записки не задан")
|
||||
|
||||
async def get_members_count(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
chat_id = update.effective_chat.id
|
||||
try:
|
||||
count = await context.bot.get_chat_members_count(chat_id)
|
||||
logger.info(f"Количество пользователей бота: {count}")
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при получении количества участников: {e}")
|
||||
|
||||
async def admin_start(update: Update, context: CallbackContext) -> None: # handlers/admin_handlers.py
|
||||
user_info = await get_user_info(update, context)
|
||||
|
||||
|
||||
if is_admin(user_info["id"]):
|
||||
user_name = user_info["name"]
|
||||
await send_message(update, context, f"Здравствуйте, админ {user_name}!")
|
||||
await send_message(update, context, "Это админ-панель")
|
||||
await notify_admins(update, context)
|
||||
await send_message(update, context, "Выберите действие:",reply_markup=admin_keyboard)
|
||||
|
||||
async def admin_view(update: Update, context: CallbackContext) -> None:
|
||||
global USER_DATA
|
||||
if 'typer' not in context.user_data:
|
||||
logger.error("Тип чтения записки не задан!")
|
||||
return
|
||||
else:
|
||||
typer = context.user_data['typer']
|
||||
idlist=list(USER_DATA)
|
||||
id_list=[]
|
||||
for user_id in idlist:
|
||||
if typer in USER_DATA[user_id]:
|
||||
id_list.append(user_id)
|
||||
if not id_list:
|
||||
send_message(update, context, "Нет записей")
|
||||
return
|
||||
if 'current' in context.user_data:
|
||||
current=context.user_data['current']
|
||||
else:
|
||||
current=0
|
||||
logger.info(f"Len of id_list: {len(id_list)}")
|
||||
if len(id_list) <= current:
|
||||
current = len(id_list) -1
|
||||
id=id_list[current]
|
||||
logger.info(f"ID of USER:{id}")
|
||||
try:
|
||||
cur = await context.bot.get_chat_member(update.effective_chat.id, id)
|
||||
user = cur.user.username
|
||||
except BadRequest as e:
|
||||
if str(e) == "Member not found":
|
||||
logger.error(f"Error by get_chat_member: {e}")
|
||||
user = id
|
||||
message=f"Пользователь @{user}\n"
|
||||
if 'Комментарий' in USER_DATA[id]:
|
||||
message+=f"<u>Комментарий:</u>\n"
|
||||
message+=f"{USER_DATA[id]['Комментарий']}\n"
|
||||
message+=f"<u>{typer}:</u>\n"
|
||||
message+=f"{format_names(USER_DATA[id][typer],numbering_type='•')}\n"
|
||||
await send_message(update, context, message, reply_markup=admin_view_keyboard)
|
||||
|
||||
async def notify_admins(update: Update, context: CallbackContext, current_user:int = 0):
|
||||
global USER_DATA
|
||||
get_users_count = len(USER_DATA) # Функция получения количества непрочитанных
|
||||
unread_count = count_memorial_notes(USER_DATA)
|
||||
if unread_count > 0:
|
||||
for admin_id in ADMINS:
|
||||
try:
|
||||
message=""
|
||||
if current_user != 0:
|
||||
try:
|
||||
cur = await context.bot.get_chat_member(update.effective_chat.id, current_user)
|
||||
user = cur.user.username
|
||||
except BadRequest as e:
|
||||
if str(e) == "Member not found":
|
||||
logger.error(f"Error by get_chat_member: {e}")
|
||||
user = id
|
||||
message=f"@{user} добавил записки.\n"
|
||||
if str(current_user) in USER_DATA:
|
||||
if "Комментарий" in USER_DATA[str(current_user)]:
|
||||
message+=f"<u>Комментарий пользователя:</u>\n"
|
||||
message+=f"{USER_DATA[str(current_user)]['Комментарий']}\n"
|
||||
message+=f"⚠️ У вас {unread_count} непрочитанных записок\n"
|
||||
message+=f"От {get_users_count} пользователей\n"
|
||||
logger.info(f"Message: {message}")
|
||||
await send_message(update, context, message, chat_id=admin_id)
|
||||
except TelegramError as e:
|
||||
logger.error(f"Ошибка отправки уведомления админу {admin_id}: {e}")
|
||||
|
||||
|
||||
|
||||
|
||||
def register_handlers(app):
|
||||
# Здесь можно добавить функционал админ-панели
|
||||
app.add_handler(CommandHandler("admin", admin_start))
|
||||
|
||||
112
python-bot/handlers/callback_handlers.py
Normal file
112
python-bot/handlers/callback_handlers.py
Normal file
@ -0,0 +1,112 @@
|
||||
from telegram import Update
|
||||
from telegram.ext import CallbackQueryHandler, CallbackContext
|
||||
from utils.logger import logger
|
||||
from handlers.user_handlers import names_menu, user_start
|
||||
from utils.database import save_database, USER_DATA
|
||||
from handlers.database_handlers import show_names, clear_names
|
||||
from utils.message_sender import send_message
|
||||
from utils.user_data import get_user_info
|
||||
from handlers.admin_handlers import notify_admins
|
||||
from handlers.user_handlers import user_shure_dialog
|
||||
from handlers.admin_handlers import admin_view, remove_notes, admin_start
|
||||
async def handle_admin_buttons(update: Update, context: CallbackContext) -> None: #handlers/callback_handlers.py
|
||||
global USER_DATA
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
if query.data == 'admin_life':
|
||||
context.user_data['typer']="О здравии"
|
||||
context.user_data['current']=0
|
||||
await admin_view(update, context)
|
||||
elif query.data == 'admin_dead':
|
||||
context.user_data['typer']="За упокой"
|
||||
await admin_view(update, context)
|
||||
context.user_data['current']=0
|
||||
elif query.data == 'admin_stats':
|
||||
pass
|
||||
elif query.data == 'admin_done':
|
||||
logger.info('Кнопка ПРОЧИТАНО прожата')
|
||||
await remove_notes(update, context)
|
||||
await admin_view(update, context)
|
||||
elif query.data == 'admin_next':
|
||||
if 'current' in context.user_data:
|
||||
context.user_data['current']+=1
|
||||
else:
|
||||
context.user_data['current']=0
|
||||
context.user_data['inc'] = "next"
|
||||
logger.info(f"current is:{context.user_data['current']}")
|
||||
await admin_view(update, context)
|
||||
elif query.data == 'admin_prev':
|
||||
if 'current' in context.user_data:
|
||||
if context.user_data['current'] >=1 :
|
||||
context.user_data['current']-=1
|
||||
else:
|
||||
context.user_data['current']=0
|
||||
context.user_data['inc'] = "prev"
|
||||
logger.info(f"current is:{context.user_data['current']}")
|
||||
await admin_view(update, context)
|
||||
elif query.data == 'admin_close':
|
||||
if 'typer' in context.user_data['typer']:
|
||||
del context.user_data['typer']
|
||||
await admin_start(update, context)
|
||||
|
||||
async def handle_user_buttons(update: Update, context: CallbackContext) -> None: #handlers/callback_handlers.py
|
||||
global USER_DATA
|
||||
# try:
|
||||
# del context.user_data['type']
|
||||
# except:
|
||||
# pass
|
||||
query = update.callback_query
|
||||
user_info = await get_user_info(update, context)
|
||||
await query.answer()
|
||||
if query.data == "user_life":
|
||||
context.user_data['type'] = "О здравии"
|
||||
await names_menu(update, context)
|
||||
elif query.data == "user_dead":
|
||||
context.user_data['type'] = "За упокой"
|
||||
await names_menu(update, context)
|
||||
elif query.data == "user_comment":
|
||||
context.user_data['type'] = "Комментарий"
|
||||
await names_menu(update, context)
|
||||
elif query.data == "user_show":
|
||||
await show_names(update, context)
|
||||
return
|
||||
elif query.data == "user_save":
|
||||
try:
|
||||
TEMP_UDATA = context.user_data["TEMP_UDATA"]
|
||||
USER_DATA[user_info["id"]] = TEMP_UDATA
|
||||
save_database(USER_DATA)
|
||||
await send_message(update, context, "Записка сохранена")
|
||||
await names_menu(update, context)
|
||||
await notify_admins(update,context,int(user_info["id"]))
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка сохранения в файл json: {e}")
|
||||
return
|
||||
elif query.data == "user_clear":
|
||||
if 'type' in context.user_data:
|
||||
del context.user_data['type']
|
||||
await user_shure_dialog(update, context)
|
||||
return
|
||||
elif query.data == "user_clear_type":
|
||||
logger.info(f"User_buttons, typen is {context.user_data['type']}")
|
||||
await user_shure_dialog(update, context)
|
||||
return
|
||||
elif query.data == "user_clear_yes":
|
||||
await clear_names(update, context)
|
||||
if 'type' in context.user_data:
|
||||
await names_menu(update, context)
|
||||
else:
|
||||
await user_start(update, context)
|
||||
return
|
||||
elif query.data == "user_clear_no":
|
||||
await names_menu(update, context)
|
||||
elif query.data == "user_names_menu_back":
|
||||
if 'type' in context.user_data:
|
||||
del context.user_data['type']
|
||||
await user_start(update, context)
|
||||
else:
|
||||
await send_message(update, context,"Неверный запрос")
|
||||
|
||||
|
||||
def register_handlers(app):
|
||||
app.add_handler(CallbackQueryHandler(handle_user_buttons, pattern='^user_'))
|
||||
app.add_handler(CallbackQueryHandler(handle_admin_buttons, pattern='^admin_'))
|
||||
70
python-bot/handlers/callback_handlers.py.save
Normal file
70
python-bot/handlers/callback_handlers.py.save
Normal file
@ -0,0 +1,70 @@
|
||||
from telegram import Update
|
||||
from telegram.ext import CallbackQueryHandler, CallbackContext
|
||||
from utils.logger import logger
|
||||
from handlers.user_handlers import names_menu, user_start
|
||||
from utils.database import save_database, USER_DATA
|
||||
from handlers.database_handlers import show_names, clear_names
|
||||
from utils.message_sender import send_message
|
||||
from utils.user_data import get_user_info
|
||||
from handlers.admin_handlers import notify_admins
|
||||
|
||||
|
||||
async def handle_admin_buttons(update: Update, context: CallbackContext) -> None: #handlers/callback_handlers.py
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
del context.user_data['type']
|
||||
if query.data == 'admin_action1':
|
||||
bot.send_message(chat_id=query.message.chat_id, text="Выполнено админ действие 1")
|
||||
elif query.data == 'admin_action2':
|
||||
bot.send_message(chat_id=query.message.chat_id, text="Выполнено админ действие 2")
|
||||
|
||||
async def handle_user_buttons(update: Update, context: CallbackContext) -> None: #handlers/callback_handlers.py
|
||||
global USER_DATA
|
||||
if
|
||||
del context.user_data['type']
|
||||
query = update.callback_query
|
||||
await query.answer()
|
||||
|
||||
if query.data == "user_life":
|
||||
context.user_data['type'] = "О здравии"
|
||||
elif query.data == "user_dead":
|
||||
context.user_data['type'] = "За упокой"
|
||||
elif query.data == "user_comment":
|
||||
context.user_data['type'] = "Комментарий"
|
||||
elif query.data == "user_show":
|
||||
await show_names(update, context)
|
||||
return
|
||||
elif query.data == "user_send":
|
||||
try:
|
||||
save_database(USER_DATA)
|
||||
except:
|
||||
logger.error("Ошибка сохранения в файл json: {e}")
|
||||
return
|
||||
user_info = await get_user_info(update, context)
|
||||
# admin_notify(udate, context,)
|
||||
await notify_admins(update, context, user_info["name"])
|
||||
#Отправляем сообщение админам
|
||||
return
|
||||
elif query.data == "user_clear":
|
||||
try:
|
||||
del context.user_data['type']
|
||||
except:
|
||||
pass
|
||||
await clear_names(update, context)
|
||||
await user_start(update, context)
|
||||
return
|
||||
elif query.data == "user_clear_type":
|
||||
await clear_names(update, context)
|
||||
await names_menu(update, context)
|
||||
return
|
||||
# Переходим в меню имен только если выбран корректный тип
|
||||
if context.user_data.get('type'):
|
||||
await names_menu(update, context)
|
||||
else:
|
||||
await send_message(update, context,"Неверный запрос")
|
||||
|
||||
|
||||
def register_handlers(app):
|
||||
app.add_handler(CallbackQueryHandler(handle_user_buttons, pattern='^user_'))
|
||||
app.add_handler(CallbackQueryHandler(handle_admin_buttons, pattern='^admin_'))
|
||||
# app.add_handler(CallbackQueryHandler(handle_confirm_buttons, pattern='^confirm_'))
|
||||
77
python-bot/handlers/database_handlers.py
Normal file
77
python-bot/handlers/database_handlers.py
Normal file
@ -0,0 +1,77 @@
|
||||
from telegram import Update
|
||||
from telegram.ext import CommandHandler, MessageHandler, filters, CallbackContext
|
||||
from utils.logger import logger
|
||||
from utils.user_data import validate_input, get_user_info, format_names
|
||||
from utils.database import USER_DATA, save_database
|
||||
from handlers.user_handlers import user_keyboard
|
||||
from utils.message_sender import send_message
|
||||
from utils.formating import format_names
|
||||
|
||||
async def show_names(update: Update, context: CallbackContext) -> None: # handlers/handlers.py
|
||||
try:
|
||||
valid_text = validate_input(update.callback_query.message.text)
|
||||
global USER_DATA
|
||||
user = await get_user_info(update, context)
|
||||
user_id = user["id"]
|
||||
|
||||
# Проверяем, есть ли данные для пользователя
|
||||
if user_id not in USER_DATA:
|
||||
logger.info(f"id:{user_id}, name:{user}")
|
||||
logger.info(f"{USER_DATA}")
|
||||
await send_message(update, context, f"{user['name']}, вы еще не сохранили ни одного имени")
|
||||
await send_message (update,context,"Выберите действие:", reply_markup=user_keyboard)
|
||||
return
|
||||
|
||||
# Получаем данные пользователя
|
||||
user_info = USER_DATA[user_id]
|
||||
|
||||
# Формируем сообщение
|
||||
message = ""
|
||||
for typen in ["О здравии","За упокой"]:
|
||||
if typen in user_info:
|
||||
#message += formating_names(user_)
|
||||
message += f"<b><i>{typen}:</i></b>\n{format_names(user_info[typen],'')}\n\n"
|
||||
|
||||
# Комментарий
|
||||
if "Комментарий" in user_info and user_info["Комментарий"]:
|
||||
if message: # Если уже есть текст, добавляем разделитель
|
||||
message += "\n"
|
||||
message += f"<i><b>Комментарий:</b></i> {user_info['Комментарий']}"
|
||||
|
||||
# Если сообщение пустое (все списки пустые), выводим специальное сообщение
|
||||
if not message:
|
||||
await send_message (update,context,f"{user_name}, у вас нет сохраненных данных")
|
||||
return
|
||||
|
||||
# Отправляем сформированное сообщение
|
||||
await send_message(update, context, message.strip())
|
||||
except ValueError as e:
|
||||
await send_message(update, context, f"Ошибка: {e}")
|
||||
return
|
||||
await send_message (update,context,"Выберите действие:", reply_markup=user_keyboard)
|
||||
|
||||
async def clear_names(update: Update, context: CallbackContext) -> None: #handlers/handlers.py
|
||||
global USER_DATA
|
||||
try:
|
||||
user_info = await get_user_info(update, context)
|
||||
user_id = user_info["id"]
|
||||
user_name = user_info["name"]
|
||||
|
||||
if user_id not in USER_DATA:
|
||||
await send_message(update, context, f"{user_name}, у вас нет сохраненных данных")
|
||||
return
|
||||
if 'type' in context.user_data:
|
||||
typen = context.user_data['typen']
|
||||
if typen in USER_DATA[user_id]:
|
||||
del USER_DATA[user_id][typen]
|
||||
await send_message(update, context, f"Записка {typen} очищена")
|
||||
else:
|
||||
USER_DATA[user_id] = {}
|
||||
await send_message(update, context, f"Записки удалены")
|
||||
save_database(USER_DATA)
|
||||
TEMP_UDATA = USER_DATA[user_id]
|
||||
context.user_data["TEMP_UDATA"]=TEMP_UDATA
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при очистке данных: {e}")
|
||||
await send_message(update, context, "Произошла ошибка при удалении данных")
|
||||
49
python-bot/handlers/parse_handlers.py.bak
Normal file
49
python-bot/handlers/parse_handlers.py.bak
Normal file
@ -0,0 +1,49 @@
|
||||
from telegram import Update
|
||||
from telegram.ext import CommandHandler, MessageHandler, filters, CallbackContext
|
||||
from utils.logger import logger
|
||||
from handlers.user_handlers import user_keyboard
|
||||
from utils.message_sender import send_message
|
||||
from utils.prefixes import PREFIXES
|
||||
|
||||
async def parse_names(update: Update, context: CallbackContext) -> None:
|
||||
global USER_DATA
|
||||
|
||||
try:
|
||||
typen = context.user_data['type']
|
||||
user_info = await get_user_info(update)
|
||||
user_id = user_info["id"]
|
||||
|
||||
# Для комментария сохраняем весь текст
|
||||
if typen == "Комментарий":
|
||||
names = update.message.text.strip()
|
||||
else:
|
||||
# Парсим имена для других типов
|
||||
|
||||
names = parse_names_helper(update.message.text)
|
||||
|
||||
# Сохраняем данные
|
||||
if user_id not in USER_DATA:
|
||||
USER_DATA[user_id] = {}
|
||||
|
||||
if typen not in USER_DATA[user_id]:
|
||||
USER_DATA[user_id][typen] = []
|
||||
|
||||
# Для комментария сохраняем строку, для остальных - список
|
||||
if typen == "Комментарий":
|
||||
USER_DATA[user_id][typen] = names
|
||||
else:
|
||||
USER_DATA[user_id][typen].extend(names)
|
||||
|
||||
# Форматируем вывод
|
||||
if typen == "Комментарий":
|
||||
await send_message(update, context, f"Сохранен комментарий: {names}")
|
||||
else:
|
||||
saved_names = ', '.join(USER_DATA[user_id][typen])
|
||||
await send_message(update, context, f"{typen}: {saved_names}")
|
||||
logger.info(f"{USER_DATA}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при обработке: {e}")
|
||||
await send_message(update, context, "Произошла ошибка при обработке данных")
|
||||
del context.user_data['type']
|
||||
await send_message (update,context,"Выберите действие:", reply_markup=user_keyboard)
|
||||
146
python-bot/handlers/user_handlers.py
Normal file
146
python-bot/handlers/user_handlers.py
Normal file
@ -0,0 +1,146 @@
|
||||
from utils.database import USER_DATA
|
||||
from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton
|
||||
from telegram.ext import CommandHandler, MessageHandler, filters, CallbackContext
|
||||
from utils.logger import logger
|
||||
from utils.user_data import get_user_info
|
||||
from utils.parsing import parse_names_helper
|
||||
from utils.prefixes import PREFIXES
|
||||
from utils.message_sender import send_message
|
||||
from utils.formating import format_names
|
||||
from messages import WELCOME_MSG
|
||||
|
||||
user_shure_keyboard = InlineKeyboardMarkup([
|
||||
[
|
||||
InlineKeyboardButton(text="Да", callback_data="user_clear_yes"),
|
||||
InlineKeyboardButton(text="Нет", callback_data="user_clear_no")
|
||||
]
|
||||
])
|
||||
|
||||
|
||||
user_keyboard = InlineKeyboardMarkup([
|
||||
[
|
||||
InlineKeyboardButton(text="О здравии", callback_data="user_life"),
|
||||
InlineKeyboardButton(text="За упокой", callback_data="user_dead"),
|
||||
InlineKeyboardButton(text="Комментарий", callback_data="user_comment")
|
||||
],
|
||||
[
|
||||
InlineKeyboardButton(text="Ваши записки", callback_data="user_show"),
|
||||
InlineKeyboardButton(text="Очистить", callback_data="user_clear")
|
||||
]
|
||||
])
|
||||
|
||||
user_note_keyboard = InlineKeyboardMarkup([
|
||||
[
|
||||
InlineKeyboardButton(text="Сохранить", callback_data="user_save"),
|
||||
InlineKeyboardButton(text="Очистить", callback_data="user_clear_type")
|
||||
],[
|
||||
InlineKeyboardButton(text="Назад", callback_data="user_names_menu_back")
|
||||
]
|
||||
])
|
||||
|
||||
async def user_shure_dialog(update: Update, context: CallbackContext) -> None:
|
||||
#try:
|
||||
if 'type' in context.user_data:
|
||||
typen = context.user_data['type']
|
||||
logger.info(f"Shure_dialog, typen is {context.user_data['type']}")
|
||||
else:
|
||||
typen=""
|
||||
#except:
|
||||
# typen = ""
|
||||
#logger.error(f"Ошибка при обработке: {e}")
|
||||
if typen:
|
||||
message = f"Вы уверены, что хотите удалить записку \"{typen}\"?"
|
||||
else:
|
||||
message = f"Вы уверены, что хотите удалить все свои записки??"
|
||||
await send_message(update,context, message, reply_markup=user_shure_keyboard)
|
||||
|
||||
async def user_start(update: Update, context: CallbackContext) -> None: # handlers/user_handlers.py
|
||||
global USER_DATA
|
||||
if 'type' in context.user_data:
|
||||
del context.user_data['type']
|
||||
if 'status' in context.user_data:
|
||||
del context.user_data['status']
|
||||
user_info = await get_user_info(update, context)
|
||||
user_name = user_info["name"]
|
||||
user_id = user_info["id"]
|
||||
if user_id in USER_DATA:
|
||||
TEMP_UDATA = USER_DATA[user_id]
|
||||
else:
|
||||
TEMP_UDATA = {}
|
||||
context.user_data["TEMP_UDATA"] = TEMP_UDATA
|
||||
message = f"Здравствуйте, {user_name}\n"
|
||||
message += WELCOME_MSG
|
||||
await send_message(update,context, message, reply_markup=user_keyboard)
|
||||
|
||||
async def names_menu(update: Update, context: CallbackContext) -> None: #handlers/callback_handlers.py
|
||||
message = "У Вас нет записей"
|
||||
TEMP_UDATA=context.user_data["TEMP_UDATA"]
|
||||
# context.user_data['state'] = 'names_menu'
|
||||
try:
|
||||
typen = context.user_data['type']
|
||||
except:
|
||||
typen = ""
|
||||
user_info = await get_user_info(update, context)
|
||||
user_id = user_info["id"]
|
||||
if typen in ["О здравии", "За упокой"]:
|
||||
if typen in TEMP_UDATA:
|
||||
message = f"Ваши имена в записке {typen}:\n"
|
||||
message += format_names(TEMP_UDATA[typen],numbering_type="•")
|
||||
else:
|
||||
message = "Список имён пуст"
|
||||
message += f"\nВводите следующие имена:"
|
||||
|
||||
elif typen == "Комментарий":
|
||||
if typen in TEMP_UDATA:
|
||||
message = "Ваш комментарий:\n"
|
||||
message +=TEMP_UDATA[typen]
|
||||
else:
|
||||
message = "У Вас нет комментария"
|
||||
message += f"\nВведите текст комментария:"
|
||||
else:
|
||||
logger.error("Тип записки не определён")
|
||||
context.user_data["status"]="input_names"
|
||||
await send_message(update, context, message, reply_markup=user_note_keyboard)
|
||||
|
||||
async def parse(update: Update, context: CallbackContext) -> None:
|
||||
try:
|
||||
if 'status' in context.user_data:
|
||||
if context.user_data['status'] == "input_names": # Ввод имён
|
||||
logger.info("input_names_yes")
|
||||
TEMP_UDATA=context.user_data["TEMP_UDATA"]
|
||||
typen = context.user_data['type']
|
||||
user_info = await get_user_info(update, context)
|
||||
user_id = user_info["id"]
|
||||
# Для комментария сохраняем весь текст
|
||||
if typen == "Комментарий":
|
||||
names = update.message.text.strip()
|
||||
if names:
|
||||
TEMP_UDATA[typen] = names
|
||||
context.user_data["TEMP_UDATA"] = TEMP_UDATA
|
||||
await send_message(update, context, f"Комментарий добавлен. Сохраните, или измените его.")
|
||||
|
||||
else:
|
||||
# Парсим имена для других типов
|
||||
names = parse_names_helper(update.message.text)
|
||||
if names:
|
||||
if typen in TEMP_UDATA:
|
||||
TEMP_UDATA[typen].extend(names)
|
||||
else:
|
||||
TEMP_UDATA[typen] = names
|
||||
context.user_data["TEMP_UDATA"] = TEMP_UDATA
|
||||
await send_message(update,context,f"Новые имена были добавлены в записку.\n Сохраните записку, чтобы отправить её священнику, или добавьте ещё имена.")
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при обработке: {e}")
|
||||
await send_message(update, context, "Произошла ошибка при обработке данных")
|
||||
await names_menu(update, context)
|
||||
|
||||
# await user_keyboard(update, context)
|
||||
# del context.user_data['type']
|
||||
|
||||
|
||||
|
||||
def register_handlers(app):
|
||||
app.add_handler(CommandHandler("start", user_start))
|
||||
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, parse))
|
||||
|
||||
# другие базовые команды
|
||||
82618
python-bot/logs/bot.log
Normal file
82618
python-bot/logs/bot.log
Normal file
File diff suppressed because it is too large
Load Diff
44
python-bot/main.py
Normal file
44
python-bot/main.py
Normal file
@ -0,0 +1,44 @@
|
||||
import os
|
||||
from telegram import Update
|
||||
from telegram.ext import Application, CommandHandler, CallbackQueryHandler
|
||||
|
||||
|
||||
from handlers import (
|
||||
user_handlers,
|
||||
admin_handlers,
|
||||
database_handlers,
|
||||
# parse_handlers,
|
||||
callback_handlers
|
||||
)
|
||||
|
||||
from utils.database import load_database
|
||||
from utils.database import USER_DATA
|
||||
from utils.logger import logger
|
||||
|
||||
|
||||
logger.info("Тестовый запуск логов")
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
with open(os.getenv('TELEGRAM_TOKEN_FILE'), 'r') as file:
|
||||
token = file.read().strip()
|
||||
except FileNotFoundError:
|
||||
logger.error("Файл с токеном не найден")
|
||||
return
|
||||
try:
|
||||
load_database()
|
||||
|
||||
app = Application.builder().token(token).build()
|
||||
|
||||
# Регистрация обработчиков
|
||||
user_handlers.register_handlers(app)
|
||||
admin_handlers.register_handlers(app)
|
||||
callback_handlers.register_handlers(app)
|
||||
# error_handlers.register_handlers(app)
|
||||
|
||||
app.run_polling()
|
||||
except Exception as e:
|
||||
logger.error(f"Критическая ошибка: {e}")
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
2
python-bot/messages.py
Normal file
2
python-bot/messages.py
Normal file
@ -0,0 +1,2 @@
|
||||
WELCOME_MSG=f"Сервис для молитвенного поминания\n\nОтправьте имена для молитвенного поминания священнику. Выберите тип записки и при необходимости добавьте особые просьбы в поле «комментарии»."
|
||||
WELCOME_MSG+="\n\n <b>Посильное пожертвование</b><i> можете отправить на карту Т-банка, по номеру телефона <u>+79603949223</u> имя: Артем К.</i>"
|
||||
9
python-bot/prefixes.json
Normal file
9
python-bot/prefixes.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"prefixes": [
|
||||
"иер.",
|
||||
"бол.",
|
||||
"мон.",
|
||||
"н.п.",
|
||||
"прт."
|
||||
]
|
||||
}
|
||||
0
python-bot/requirements.txt
Normal file
0
python-bot/requirements.txt
Normal file
48
python-bot/utils/admin_utils.py
Normal file
48
python-bot/utils/admin_utils.py
Normal file
@ -0,0 +1,48 @@
|
||||
import os
|
||||
from utils.logger import logger
|
||||
#from utils.user_data import get_user_info
|
||||
#from utils.user_data import get_user_data
|
||||
from utils.message_sender import send_message
|
||||
|
||||
|
||||
def has_records(data,typer):
|
||||
for user_id, records in data.items():
|
||||
if typer in records:
|
||||
return True
|
||||
return False
|
||||
|
||||
def load_admins(): # utils/admin_utils.py
|
||||
admin_file= os.getenv('TELEGRAM_ADMINS')
|
||||
try:
|
||||
with open(admin_file, 'r') as file:
|
||||
return [line.strip() for line in file]
|
||||
except FileNotFoundError:
|
||||
logger.error("Файл с ID администраторов не найден")
|
||||
return []
|
||||
ADMINS = load_admins()
|
||||
def is_admin(user_id: str) -> bool: # utils/admin_utils.py
|
||||
admins = load_admins()
|
||||
return str(user_id) in admins
|
||||
|
||||
|
||||
def register_handlers(app):
|
||||
app.add_handler(CommandHandler("admin", admin))
|
||||
# другие базовые команды
|
||||
|
||||
def count_memorial_notes(data):
|
||||
total_count = 0
|
||||
|
||||
# Проходим по всем пользователям
|
||||
for user_id, user_data in data.items():
|
||||
# Считаем количество записок "О здравии"
|
||||
if "О здравии" in user_data:
|
||||
total_count += 1
|
||||
# Считаем количество записок "За упокой"
|
||||
if "За упокой" in user_data:
|
||||
total_count += 1
|
||||
|
||||
return total_count
|
||||
|
||||
# Пример использования:
|
||||
# result = count_memorial_notes(USER_DATA)
|
||||
# print(f"Общее количество записок: {result}")
|
||||
21
python-bot/utils/database.py
Normal file
21
python-bot/utils/database.py
Normal file
@ -0,0 +1,21 @@
|
||||
import json, os
|
||||
from utils.logger import logger
|
||||
database_file = os.getenv('TELEGRAM_DATABASE')
|
||||
USER_DATA ={}
|
||||
def load_database(): # utils/database.py
|
||||
global USER_DATA
|
||||
try:
|
||||
with open(database_file, 'r') as db_file:
|
||||
USER_DATA = json.load(db_file)
|
||||
except (FileNotFoundError, json.JSONDecodeError):
|
||||
USER_DATA = {}
|
||||
|
||||
def save_database(text): #utils/database.py
|
||||
user_data = text
|
||||
try:
|
||||
logger.info(f"Сохраняемые данные: {USER_DATA}")
|
||||
with open(database_file, 'w') as db_file:
|
||||
json.dump(user_data, db_file, ensure_ascii=False, indent=4)
|
||||
except IOError as e:
|
||||
logger.error(f"Ошибка при сохранении базы данных: {e}")
|
||||
load_database()
|
||||
27
python-bot/utils/formating.py
Normal file
27
python-bot/utils/formating.py
Normal file
@ -0,0 +1,27 @@
|
||||
def format_names(names, numbering_type='default'):
|
||||
"""
|
||||
Функция форматирует список имён с выбранной нумерацией
|
||||
|
||||
Параметры:
|
||||
names (list): список имён для форматирования
|
||||
numbering_type (str): тип нумерации ('default' - обычная нумерация, любой другой символ - использование этого символа)
|
||||
|
||||
Возвращает:
|
||||
str: отформатированную строку с именами
|
||||
"""
|
||||
|
||||
result = '' # создаем пустую строку для результата
|
||||
|
||||
# проверяем тип нумерации
|
||||
if not names:
|
||||
return "Пустая запись"
|
||||
if numbering_type == 'default':
|
||||
# обычная нумерация
|
||||
for i, name in enumerate(names, start=1):
|
||||
result += f'{i}. {name}\n'
|
||||
else:
|
||||
# используем указанный символ
|
||||
for name in names:
|
||||
result += f'{numbering_type} {name}\n'
|
||||
|
||||
return result.strip() # убираем последний лишний перенос строки
|
||||
17
python-bot/utils/logger.py
Normal file
17
python-bot/utils/logger.py
Normal file
@ -0,0 +1,17 @@
|
||||
import logging
|
||||
|
||||
def setup_logging():
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO,
|
||||
filename='logs/bot.log', # сохранение в файл
|
||||
filemode='a' # добавление в конец файла
|
||||
)
|
||||
console = logging.StreamHandler()
|
||||
console.setLevel(logging.INFO)
|
||||
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
console.setFormatter(formatter)
|
||||
logging.getLogger('').addHandler(console)
|
||||
return logging.getLogger(__name__)
|
||||
|
||||
logger = setup_logging()
|
||||
53
python-bot/utils/message_sender.py
Normal file
53
python-bot/utils/message_sender.py
Normal file
@ -0,0 +1,53 @@
|
||||
# utils/message_sender.py
|
||||
from utils.logger import logger
|
||||
from telegram import Update, Bot
|
||||
from telegram.ext import CallbackContext
|
||||
from telegram.error import TelegramError
|
||||
from telegram.constants import ParseMode
|
||||
|
||||
async def send_message(
|
||||
update: Update,
|
||||
context: CallbackContext,
|
||||
text: str,
|
||||
parse_mode: str = ParseMode.HTML,
|
||||
reply_markup=None,
|
||||
disable_web_page_preview: bool = False,
|
||||
chat_id: int = None,
|
||||
):
|
||||
try:
|
||||
if chat_id:
|
||||
# Отправка по указанному chat_id
|
||||
await context.bot.send_message(
|
||||
chat_id=chat_id,
|
||||
text=text,
|
||||
parse_mode=parse_mode,
|
||||
reply_markup=reply_markup,
|
||||
disable_web_page_preview=disable_web_page_preview
|
||||
)
|
||||
elif update.message:
|
||||
# Отправка в ответ на сообщение
|
||||
await update.message.reply_text(
|
||||
text=text,
|
||||
parse_mode=parse_mode,
|
||||
reply_markup=reply_markup,
|
||||
disable_web_page_preview=disable_web_page_preview
|
||||
)
|
||||
elif update.callback_query:
|
||||
# Отправка в ответ на callback-запрос
|
||||
await update.callback_query.message.reply_text(
|
||||
text=text,
|
||||
parse_mode=parse_mode,
|
||||
reply_markup=reply_markup,
|
||||
disable_web_page_preview=disable_web_page_preview
|
||||
)
|
||||
else:
|
||||
raise ValueError("Некорректный тип обновления")
|
||||
except TelegramError as e:
|
||||
logger.error(f"Ошибка при отправке сообщения: {e}")
|
||||
return False
|
||||
return True
|
||||
|
||||
# Вспомогательная функция для получения всех ID (пример)
|
||||
def get_all_user_ids():
|
||||
# Здесь логика получения всех ID из базы данных
|
||||
return [12345, 67890] # Пример списка ID
|
||||
44
python-bot/utils/parsing.py
Normal file
44
python-bot/utils/parsing.py
Normal file
@ -0,0 +1,44 @@
|
||||
from telegram import Update
|
||||
from telegram.ext import CallbackContext
|
||||
from utils.prefixes import PREFIXES
|
||||
from utils.logger import logger
|
||||
from utils.database import USER_DATA
|
||||
|
||||
def parse_names_helper(text):
|
||||
words = text.split()
|
||||
names = []
|
||||
current_prefixes = []
|
||||
logger.info(f"Check prefixes: {PREFIXES}")
|
||||
for word in words:
|
||||
# Если слово является префиксом, добавляем его в список текущих >
|
||||
if word in PREFIXES:
|
||||
|
||||
current_prefixes.append(word)
|
||||
# Если слово не префикс - это имя
|
||||
else:
|
||||
# Если есть накопленные префиксы - соединяем их с именем
|
||||
if current_prefixes:
|
||||
names.append(" ".join(current_prefixes + [word.replace(',','')]))
|
||||
current_prefixes = []
|
||||
else:
|
||||
names.append(word.replace(',',''))
|
||||
logger.info(f"Check helper: {names}")
|
||||
return names
|
||||
|
||||
|
||||
async def notify_admins(update: Update, context: CallbackContext):
|
||||
bot = context.bot
|
||||
admin_ids = get_admin_ids() # Функция получения ID админов
|
||||
|
||||
unread_count = get_unread_messages_count() # Функция получения количества непрочитанных
|
||||
|
||||
if unread_count > 0:
|
||||
for admin_id in admin_ids:
|
||||
try:
|
||||
await bot.send_message(
|
||||
chat_id=admin_id,
|
||||
text=f"⚠️ У вас {unread_count} непрочитанных записок\n"
|
||||
f"От {get_users_count()} пользователей"
|
||||
)
|
||||
except TelegramError as e:
|
||||
logger.error(f"Ошибка отправки уведомления админу {admin_id}: {e}")
|
||||
9
python-bot/utils/prefixes.py
Normal file
9
python-bot/utils/prefixes.py
Normal file
@ -0,0 +1,9 @@
|
||||
import os, json
|
||||
def load_prefixes(): #/utils/prefixes.py
|
||||
try:
|
||||
with open('./prefixes.json', 'r') as file:
|
||||
data = json.load(file)
|
||||
return set(data['prefixes'])
|
||||
except (FileNotFoundError, json.JSONDecodeError):
|
||||
return set()
|
||||
PREFIXES = load_prefixes()
|
||||
33
python-bot/utils/user_data.py
Normal file
33
python-bot/utils/user_data.py
Normal file
@ -0,0 +1,33 @@
|
||||
from telegram import Update
|
||||
from telegram.ext import CallbackContext
|
||||
from utils.logger import logger
|
||||
# Объединяем функции get_user_name и get_user_id в одну
|
||||
async def get_user_info(update: Update, context: CallbackContext, id = None): #utils/utils.py
|
||||
try:
|
||||
if id:
|
||||
user = context.bot.get_chat(user_id)
|
||||
elif update.callback_query:
|
||||
user = update.callback_query.from_user
|
||||
elif update.message:
|
||||
user = update.message.from_user
|
||||
else:
|
||||
return {"id": "Unknown", "name": "Unknown"}
|
||||
|
||||
user_id = str(user.id)
|
||||
user_name = f"@{user.username}" if user.username else f"{user.first_name} {user.last_name or ''}".strip()
|
||||
|
||||
return {"id": user_id, "name": user_name}
|
||||
except Exception as e:
|
||||
logger.info (f"Ошибка получения данных пользователя: {e}")
|
||||
return {"id": "Unknown", "name": "Unknown"}
|
||||
|
||||
|
||||
def validate_input(text):
|
||||
if len(text) > 6000:
|
||||
raise ValueError("Слишком длинный текст")
|
||||
if not text:
|
||||
raise ValueError("Пустой ввод")
|
||||
return text
|
||||
|
||||
def format_names(names):
|
||||
return "\n".join(f"- {name}" for name in names)
|
||||
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
python-telegram-bot
|
||||
Loading…
x
Reference in New Issue
Block a user