Developing Bot
This commit is contained in:
@@ -12,3 +12,4 @@ __pycache__/
|
|||||||
|
|
||||||
# telegram bot token config
|
# telegram bot token config
|
||||||
telegram_bot_token.cfg
|
telegram_bot_token.cfg
|
||||||
|
logs/
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
from telegram import Bot, InlineKeyboardButton, InlineKeyboardMarkup, Update
|
|
||||||
from telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes
|
|
||||||
import configparser
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import datetime
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
# Function to send a message with inline buttons
|
|
||||||
async def newEvent(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|
||||||
keyboard = [
|
|
||||||
[InlineKeyboardButton("Anmelden", callback_data='register')],
|
|
||||||
[InlineKeyboardButton("Abmelden", callback_data='cancelRegister')]
|
|
||||||
]
|
|
||||||
|
|
||||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
|
||||||
|
|
||||||
await update.message.reply_text("choose below", reply_markup=reply_markup)
|
|
||||||
return
|
|
||||||
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
|
|
||||||
from telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes, Updater, CallbackQueryHandler, CallbackContext
|
|
||||||
|
|
||||||
|
|
||||||
# Function to handle button clicks (callback queries)
|
|
||||||
async def button(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|
||||||
query = update.callback_query
|
|
||||||
|
|
||||||
user = query.from_user
|
|
||||||
|
|
||||||
await query.answer() # Acknowledge the button press
|
|
||||||
|
|
||||||
if query.data == 'register':
|
|
||||||
try:
|
|
||||||
keyboard = [[InlineKeyboardButton("Abmelden", callback_data='cancelRegister')]]
|
|
||||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
|
||||||
await context.bot.send_message(user.id, "Registered", reply_markup=reply_markup)
|
|
||||||
except Exception as e:
|
|
||||||
await context.bot.send_message(query.message.chat_id, f"@{user.username} Leider kam es zu einem Fehler: {str(e)}")
|
|
||||||
|
|
||||||
if query.data == 'cancelRegister':
|
|
||||||
try:
|
|
||||||
await context.bot.send_message(user.id, "Cancelled")
|
|
||||||
except Exception as e:
|
|
||||||
await context.bot.send_message(query.message.chat_id, f"@{user.username} Leider kam es zu einem Fehler: {str(e)}")
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# -------------------------------------------#
|
||||||
|
# DO NOT TOUCH - will be adjusted on runtime #
|
||||||
|
# -------------------------------------------#
|
||||||
|
|
||||||
|
BASE_DIR = dir_path = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
|
# TODO: Avoid Race Conditions on event file edits (file locks?)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# -------------------------------------------#
|
||||||
|
# Configuration Settings #
|
||||||
|
# -------------------------------------------#
|
||||||
|
|
||||||
|
# General
|
||||||
|
BOT_NAME = "PawHubBot"
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
LOG_FOLDER_PATH = os.path.abspath(os.path.join(BASE_DIR, '..', 'logs'))
|
||||||
|
LOG_FILE_NAME = os.path.join(LOG_FOLDER_PATH, 'log.txt')
|
||||||
|
|
||||||
|
# Administration
|
||||||
|
ADMIN_IDS = [
|
||||||
|
1903773270, # SinusFox
|
||||||
|
5781850368, # Karatarus
|
||||||
|
30849386 # Goldwolf
|
||||||
|
]
|
||||||
|
|
||||||
|
# Chats
|
||||||
|
ALLOWED_CHAT_IDS = [0]
|
||||||
|
ALLOW_DMS = True
|
||||||
|
|
||||||
|
# Events
|
||||||
|
EVENTS_FOLDER = os.path.join(BASE_DIR, '..','events')
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
[telegram]
|
||||||
|
bot_token = MISSING_TOKEN
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
import traceback
|
||||||
|
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
|
||||||
|
from telegram.ext import ContextTypes
|
||||||
|
from config import config
|
||||||
|
import user_permissions
|
||||||
|
import log
|
||||||
|
|
||||||
|
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
if not user_permissions.is_user_admin(update.effective_user.id):
|
||||||
|
log.warning(chat_id=update.effective_chat.id, message=f"Unauthorized direct message access attempt by user {update.effective_user.id}\n{traceback.format_exc()}")
|
||||||
|
await update.message.reply_text("You are not authorized to use this bot in this chat.")
|
||||||
|
return
|
||||||
|
|
||||||
|
keyboard = [
|
||||||
|
[InlineKeyboardButton("Eventmanagement", callback_data='list_event_actions')],
|
||||||
|
]
|
||||||
|
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"""Willkommen beim {config.BOT_NAME} Admin Interface!
|
||||||
|
Hier kannst du verschiedene Verwaltungsaufgaben durchführen. Nutze die verfügbaren Befehle, um loszulegen.
|
||||||
|
|
||||||
|
(c) SinusFox.dev 2025
|
||||||
|
""",
|
||||||
|
reply_markup=InlineKeyboardMarkup(keyboard)
|
||||||
|
)
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import os
|
||||||
|
from config import config
|
||||||
|
import log
|
||||||
|
from telegram import CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup, Update
|
||||||
|
from telegram.ext import ContextTypes
|
||||||
|
import user_permissions
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
os.makedirs(config.EVENTS_FOLDER, exist_ok=True)
|
||||||
|
|
||||||
|
async def list_event_actions(update: Update, context: ContextTypes.DEFAULT_TYPE, query: CallbackQuery):
|
||||||
|
if not user_permissions.is_user_admin(update.effective_user.id):
|
||||||
|
log.warning(chat_id=update.effective_chat.id, message=f"Unauthorized direct message access attempt by user {update.effective_user.id}\n{traceback.format_exc()}")
|
||||||
|
await update.message.reply_text("You are not authorized to use this bot in this chat.")
|
||||||
|
return
|
||||||
|
|
||||||
|
keyboard = [
|
||||||
|
[InlineKeyboardButton("Neues Event anlegen", callback_data='new_event')],
|
||||||
|
[InlineKeyboardButton("Event bearbeiten", callback_data='edit_event')],
|
||||||
|
[InlineKeyboardButton("Event löschen", callback_data='delete_event')]
|
||||||
|
]
|
||||||
|
|
||||||
|
await query.message.reply_text(
|
||||||
|
f'Was möchtest du machen?',
|
||||||
|
reply_markup=InlineKeyboardMarkup(keyboard)
|
||||||
|
)
|
||||||
|
|
||||||
|
async def new_event(update: Update, context: ContextTypes.DEFAULT_TYPE, query: CallbackQuery):
|
||||||
|
if not user_permissions.is_user_admin(update.effective_user.id):
|
||||||
|
log.warning(chat_id=update.effective_chat.id, message=f"Unauthorized direct message access attempt by user {update.effective_user.id}\n{traceback.format_exc()}")
|
||||||
|
await update.message.reply_text("You are not authorized to use this bot in this chat.")
|
||||||
|
return
|
||||||
|
|
||||||
|
keyboard = [
|
||||||
|
[InlineKeyboardButton("Anmelden", callback_data='register')],
|
||||||
|
[InlineKeyboardButton("Abmelden", callback_data='cancelRegister')]
|
||||||
|
]
|
||||||
|
|
||||||
|
await query.message.reply_text(
|
||||||
|
f'Welches Event möchtest du anpassen?',
|
||||||
|
reply_markup=InlineKeyboardMarkup(keyboard)
|
||||||
|
)
|
||||||
|
|
||||||
|
async def edit_event(update: Update, context: ContextTypes.DEFAULT_TYPE, query: CallbackQuery):
|
||||||
|
if not user_permissions.is_user_admin(update.effective_user.id):
|
||||||
|
log.warning(chat_id=update.effective_chat.id, message=f"Unauthorized direct message access attempt by user {update.effective_user.id}\n{traceback.format_exc()}")
|
||||||
|
await update.message.reply_text("You are not authorized to use this bot in this chat.")
|
||||||
|
return
|
||||||
|
|
||||||
|
keyboard = [
|
||||||
|
[InlineKeyboardButton("Anmelden", callback_data='register')],
|
||||||
|
[InlineKeyboardButton("Abmelden", callback_data='cancelRegister')]
|
||||||
|
]
|
||||||
|
|
||||||
|
await query.message.reply_text(
|
||||||
|
f'Welches Event möchtest du anpassen?',
|
||||||
|
reply_markup=InlineKeyboardMarkup(keyboard)
|
||||||
|
)
|
||||||
|
|
||||||
|
# TODO: Implement edit event logic
|
||||||
|
|
||||||
|
async def delete_event(update: Update, context: ContextTypes.DEFAULT_TYPE, query: CallbackQuery):
|
||||||
|
# TODO
|
||||||
|
pass
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"date": "",
|
||||||
|
"time": "",
|
||||||
|
"custom_message": "",
|
||||||
|
"signup_deadline": "",
|
||||||
|
"ordered_food_change_deadline": "",
|
||||||
|
"ordered_food_change_closed": false,
|
||||||
|
"location": "",
|
||||||
|
"organizer_id": 0,
|
||||||
|
"attendees": [
|
||||||
|
{
|
||||||
|
"is_guest": false,
|
||||||
|
"invited_by_user_id": 0,
|
||||||
|
"user_id_or_guest_id": 0,
|
||||||
|
"guest_name": "",
|
||||||
|
"signed_up": true,
|
||||||
|
"food_ordered": [
|
||||||
|
{
|
||||||
|
"food_item": "",
|
||||||
|
"price": 0.0,
|
||||||
|
"quantity": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# TODO
|
||||||
|
# add and remove foods, custom foods, automatic sum of prices, save to event
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# TODO
|
||||||
|
# e.g. Nutzer nachtraeglich hinzufuegen? ODer wegen Privatsphaere in dms?
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
from telegram import Update
|
|
||||||
from telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes
|
|
||||||
import configparser
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
|
|
||||||
@@ -1,6 +1,29 @@
|
|||||||
from telegram import Update
|
|
||||||
from telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes
|
|
||||||
import configparser
|
|
||||||
import json
|
|
||||||
import os
|
import os
|
||||||
|
from config import config
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
LOG_ID_INFO = 'I'
|
||||||
|
LOG_ID_WARNING = 'W'
|
||||||
|
LOG_ID_ERROR = 'E'
|
||||||
|
|
||||||
|
def info(chat_id: str, message: str) -> None:
|
||||||
|
log_line = format_message(LOG_ID_INFO, chat_id, message)
|
||||||
|
write_log(log_line)
|
||||||
|
|
||||||
|
def warning(chat_id: str, message: str) -> None:
|
||||||
|
log_line = format_message(LOG_ID_WARNING, chat_id, message)
|
||||||
|
write_log(log_line)
|
||||||
|
|
||||||
|
def error(chat_id: str, message: str, stack_trace: str) -> None:
|
||||||
|
log_line = format_message(LOG_ID_ERROR, chat_id, message)
|
||||||
|
log_line += f'\nStack Trace:\n{stack_trace}'
|
||||||
|
write_log(log_line)
|
||||||
|
|
||||||
|
def format_message (log_id: str, chat_id: str, message: str) -> str:
|
||||||
|
return f'{datetime.now().strftime("%Y-%m-%d @ %H:%M")} | {config.BOT_NAME} | {log_id} | {message}'
|
||||||
|
|
||||||
|
def write_log(log_line: str):
|
||||||
|
os.makedirs(config.LOG_FOLDER_PATH, exist_ok=True)
|
||||||
|
with open(os.path.join(config.LOG_FOLDER_PATH, config.LOG_FILE_NAME), 'a', encoding='utf-8') as log_file:
|
||||||
|
log_file.write(log_line + '\n')
|
||||||
|
print(log_line)
|
||||||
+45
-23
@@ -1,43 +1,65 @@
|
|||||||
# [ IMPORTS ] #
|
import signal
|
||||||
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
|
import sys
|
||||||
|
import traceback
|
||||||
|
from telegram import Update
|
||||||
from telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes, CallbackQueryHandler, Application
|
from telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes, CallbackQueryHandler, Application
|
||||||
import configparser
|
import configparser
|
||||||
import json
|
import direct_message_commands
|
||||||
import os
|
import event_management
|
||||||
|
import log
|
||||||
# other files in here
|
|
||||||
from errors import *
|
from errors import *
|
||||||
from commands_admin import *
|
|
||||||
from commands_user import *
|
|
||||||
from handler_participant_lists import *
|
|
||||||
from log import *
|
from log import *
|
||||||
|
|
||||||
#############################################
|
|
||||||
# [ CONFIG FILES ] #
|
|
||||||
|
|
||||||
# Konfiguration
|
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
config.read('telegram_bot_token.cfg')
|
config.read('config/telegram_bot_token.cfg')
|
||||||
config.read('telegram_bot_config.cfg')
|
|
||||||
print("Configs loaded.")
|
print("Configs loaded.")
|
||||||
|
|
||||||
#############################################
|
def handle_signal(signal, frame):
|
||||||
# [ MAIN LOOP ] #
|
log.info(chat_id="system", message="Shutdown command received. Stopping service...")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
signal.signal(signal.SIGTERM, handle_signal)
|
||||||
|
signal.signal(signal.SIGINT, handle_signal)
|
||||||
|
|
||||||
|
async def button_callback_query(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
query = update.callback_query
|
||||||
|
await query.answer()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Event Management
|
||||||
|
if query.data == "list_event_actions":
|
||||||
|
await event_management.list_event_actions(update, context, query)
|
||||||
|
return
|
||||||
|
if query.data == "edit_event":
|
||||||
|
await event_management.edit_event(update, context, query)
|
||||||
|
return
|
||||||
|
if query.data == "delete_event":
|
||||||
|
await event_management.delete_event(update, context, query)
|
||||||
|
return
|
||||||
|
if query.data == "new_event":
|
||||||
|
await event_management.new_event(update, context, query)
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
log.error(chat_id=update.effective_chat.id, message=f"Error handling button callback query: {e}", stack_trace=traceback.format_exc())
|
||||||
|
await update.effective_message.reply_text(f'Leider gab es einen Fehler. Bitte melde die Uhrzeit bei den Admins: {datetime.now().strftime("%Y-%m-%d @ %H:%M")}.')
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
log.info(chat_id="system", message="Registering bot commands and starting service...")
|
||||||
app = ApplicationBuilder().token(config['telegram']['bot_token']).build()
|
app = ApplicationBuilder().token(config['telegram']['bot_token']).build()
|
||||||
|
|
||||||
# Admin commands
|
# DM commands
|
||||||
app.add_handler(CommandHandler("newEvent", newEvent))
|
app.add_handler(CommandHandler("start", direct_message_commands.start))
|
||||||
|
|
||||||
# User commands
|
# Event management
|
||||||
# app.add_handler(CommandHandler("start", start))
|
app.add_handler(CommandHandler("newEvent", event_management.new_event))
|
||||||
|
|
||||||
# buttons
|
# buttons
|
||||||
app.add_handler(CallbackQueryHandler(button))
|
app.add_handler(CallbackQueryHandler(button_callback_query))
|
||||||
|
|
||||||
print("Bot läuft...")
|
log.info(chat_id="system", message="Service started")
|
||||||
app.run_polling()
|
app.run_polling()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
log.info(chat_id="system", message="Starting service...")
|
||||||
main()
|
main()
|
||||||
|
log.info(chat_id="system", message="Service stopped.")
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
[admin]
|
|
||||||
ids = [CHANGE_ME, CHANGE_ME]
|
|
||||||
|
|
||||||
[chats]
|
|
||||||
# allowed_chat_ids = [CHANGEME]
|
|
||||||
# allow_dms_if_not_in_allowed_chats = True
|
|
||||||
|
|
||||||
[list]
|
|
||||||
default = event_list.json
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
[telegram]
|
|
||||||
bot_token = BOT_TOKEN_HERE
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# TODO
|
||||||
|
# Add and remove users from event, but only set a flag configuring them as "attending" or "not attending" when "deletion"
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
from config import config
|
||||||
|
|
||||||
|
def is_user_admin(user_id: int) -> bool:
|
||||||
|
return user_id in config.ADMIN_IDS
|
||||||
|
|
||||||
|
def is_chat_allowed(chat_id: int) -> bool:
|
||||||
|
return chat_id in config.ALLOWED_CHAT_IDS
|
||||||
Reference in New Issue
Block a user