Developing Bot

This commit is contained in:
2025-12-24 02:06:17 +01:00
parent aa3c656537
commit ba8c1823e3
17 changed files with 246 additions and 93 deletions
+1
View File
@@ -12,3 +12,4 @@ __pycache__/
# telegram bot token config # telegram bot token config
telegram_bot_token.cfg telegram_bot_token.cfg
logs/
-20
View File
@@ -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
-29
View File
@@ -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
+40
View File
@@ -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')
+2
View File
@@ -0,0 +1,2 @@
[telegram]
bot_token = MISSING_TOKEN
+26
View File
@@ -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)
)
+64
View File
@@ -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
+28
View File
@@ -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
}
]
}
]
}
]
+2
View File
@@ -0,0 +1,2 @@
# TODO
# add and remove foods, custom foods, automatic sum of prices, save to event
+2
View File
@@ -0,0 +1,2 @@
# TODO
# e.g. Nutzer nachtraeglich hinzufuegen? ODer wegen Privatsphaere in dms?
-6
View File
@@ -1,6 +0,0 @@
from telegram import Update
from telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes
import configparser
import json
import os
+27 -4
View File
@@ -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
View File
@@ -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.")
-9
View File
@@ -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
-2
View File
@@ -1,2 +0,0 @@
[telegram]
bot_token = BOT_TOKEN_HERE
+2
View File
@@ -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"
+7
View File
@@ -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