2022-05-02 15:04:54 +00:00
"""
script for telegram bot and its functions
"""
__author__ = " Florian Kellermann, Linus Eickhoff, Florian Kaiser "
__date__ = " 02.05.2022 "
2022-05-02 15:22:50 +00:00
__version__ = " 0.0.1 "
2022-05-02 15:04:54 +00:00
__license__ = " None "
# main bot at http://t.me/guess_the_price_bot
# debug bot at http://t.me/amazondebug_bot
2022-05-02 15:07:28 +00:00
import logging
2022-05-02 15:04:54 +00:00
import os
2022-05-03 16:34:00 +00:00
import re
2022-05-02 15:04:54 +00:00
import sys
2022-05-09 16:01:59 +00:00
import datetime as dt
2022-05-02 15:04:54 +00:00
2022-05-03 10:07:54 +00:00
import sqlalchemy
2022-05-02 15:22:50 +00:00
import telebot
from dotenv import load_dotenv
2022-05-03 12:28:41 +00:00
from sqlalchemy . exc import IntegrityError
2022-05-02 15:22:50 +00:00
from telebot import types
2022-05-03 15:52:48 +00:00
from random import randrange
2022-05-02 15:22:50 +00:00
2022-05-03 10:07:54 +00:00
from db import User , session , Product
from fetcher import *
2022-05-09 14:01:03 +00:00
from db import Score
2022-05-02 15:22:50 +00:00
2022-05-03 12:28:41 +00:00
2022-05-02 15:22:50 +00:00
load_dotenv ( dotenv_path = ' .env ' ) # load environment variables
2022-05-02 15:04:54 +00:00
2022-05-02 15:46:04 +00:00
BOT_VERSION = " 0.0.1 " # version of bot
2022-05-02 15:04:54 +00:00
bot = telebot . TeleBot ( os . getenv ( ' BOT_API_KEY ' ) )
2022-05-02 15:22:50 +00:00
@bot.message_handler ( commands = [ ' start ' , ' Start ' ] )
2022-05-02 15:04:54 +00:00
def send_start ( message ) :
2022-05-02 16:15:04 +00:00
""" send start message to user
2022-05-02 15:04:54 +00:00
2022-05-02 16:15:04 +00:00
Args :
message ( Message ) : message from telegram user , here / start
2022-05-02 15:04:54 +00:00
"""
2022-05-03 12:28:41 +00:00
bot . send_message ( chat_id = int ( message . from_user . id ) , text = ( " Welcome to the game... \
2022-05-03 16:12:01 +00:00
\nTo start please set a name for yourself or type cancel to set generated name : " ))
2022-05-03 12:28:41 +00:00
2022-05-03 11:20:49 +00:00
bot . register_next_step_handler ( message , start_name_setter )
2022-05-03 12:28:41 +00:00
2022-05-03 11:20:49 +00:00
def start_name_setter ( message ) :
""" Set name for user and send introduction
Args :
message ( Message ) : Message to react to
"""
2022-05-03 15:52:48 +00:00
user_id = int ( message . from_user . id )
user_name = " "
2022-05-03 16:34:00 +00:00
if str ( message . text ) . lower ( ) == " cancel " : # Set user name to user
2022-05-03 16:12:01 +00:00
user_name = " User " + str ( user_id ) # generate user name, user can change it with /changename
2022-05-03 15:52:48 +00:00
2022-05-09 15:23:53 +00:00
if not re . match ( r ' ^[a-zA-Z][a-zA-Z0-9_ \ -]+$ ' , str ( message . text ) ) :
2022-05-03 16:34:00 +00:00
bot . reply_to ( message , " Name has to be alphanumeric (including underscores) and start with a letter " )
return
2022-05-06 20:26:37 +00:00
user_name = str ( message . text )
2022-05-02 15:22:50 +00:00
2022-05-03 15:52:48 +00:00
try :
user = User ( telegram_id = user_id , username = user_name , admin = False )
session . add ( user )
session . commit ( )
2022-05-03 16:34:00 +00:00
bot . reply_to ( message , f " Thank you for setting your name { user_name } \
\nType / gameinfo for information about GuessThePrice \
\nType / help for an overview of all commands " )
2022-05-03 15:52:48 +00:00
except sqlalchemy . exc . IntegrityError :
session . rollback ( )
bot . reply_to ( message , " You are already registered, change name with /changename " )
2022-05-02 15:22:50 +00:00
2022-05-02 15:07:28 +00:00
telebot . logger . setLevel ( logging . DEBUG )
2022-05-02 15:22:50 +00:00
2022-05-02 16:15:04 +00:00
@bot.message_handler ( commands = [ ' help ' , ' Help ' ] )
def send_help ( message ) :
""" send all commands to user
Args :
message ( Message ) : Message from telegram user , here / help
Returns :
None : None
Raises :
None : None
"""
2022-05-02 16:33:08 +00:00
help_message = ( " /me get my user info \n "
" /help get this help message \n "
" /gameinfo get game info \n "
" /scoreboard get scoreboard \n "
" /changename change your name \n "
" /challenge get todays challenge \n "
" /guess make guess for today " )
bot . reply_to ( message , help_message , parse_mode = ' MARKDOWN ' )
2022-05-02 16:45:32 +00:00
@bot.message_handler ( commands = [ ' gameinfo ' , ' Gameinfo ' ] )
def send_gameinfo ( message ) :
""" send game info to user
Args :
message ( Message ) : Message from telegram user , here / gameinfo
Returns :
None : None
Raises :
None : None
"""
gameinfo_message = ( " GuessThePrice is a game where you have to guess \n "
" the price of an amazon product. \n "
" Start by setting your name with /changename \n "
" You can get a new challenge every day. \n "
" You are informed when a new challenge is available. \n "
" To see the challenge type /challenge \n "
" To guess the price type /guess \n "
" At 22:00 pm the scores and answer will be shown \n " )
bot . reply_to ( message , gameinfo_message , parse_mode = ' MARKDOWN ' )
2022-05-02 16:54:41 +00:00
@bot.message_handler ( commands = [ ' me ' , ' Me ' ] )
def send_user_info ( message ) :
""" send user info to user
Args :
message ( Message ) : Message from telegram user , here / me
Returns :
None : None
Raises :
None : None
"""
user_id = message . from_user . id
2022-05-03 08:20:50 +00:00
user = session . query ( User ) . filter_by ( telegram_id = user_id ) . first ( )
2022-05-09 16:01:59 +00:00
scores = session . query ( Score ) . filter_by ( telegram_id = user_id ) . all ( )
2022-05-03 16:46:06 +00:00
2022-05-03 08:20:50 +00:00
if user is not None :
user_name = user . username # tbd: get user name by id from db
2022-05-09 16:01:59 +00:00
user_score = sum ( score for score in scores ) # tbd: get user score by adding all scores related to userid
user_guess = session . query ( Score ) . filter_by ( date = dt . datetime . now ( ) , telegram_id = user_id ) . first ( ) . guess or " not guessed today " # tbd: display if user has guessed today and how much
2022-05-03 08:20:50 +00:00
user_info = ( f " Your user info: \n "
f " User ID: { user_id } \n "
f " Username: { user_name } \n "
f " Today ' s guess: { user_guess } \n "
f " Your Score: { user_score } \n " )
else :
# User not found
2022-05-09 16:01:59 +00:00
user_info = " User does not exist. "
2022-05-02 16:54:41 +00:00
bot . reply_to ( message , user_info , parse_mode = ' MARKDOWN ' )
2022-05-09 14:43:45 +00:00
@bot.message_handler ( commands = [ ' setAdmin ' , ' SetAdmin ' , ' Setadmin ' , ' setadmin ' ] )
def set_admin ( message ) :
""" set admin status of user
Args :
message ( Message ) : Message from telegram user , here / setAdmin
Returns :
None : None
Raises :
None : None
"""
user_id = message . from_user . id
2022-05-09 14:57:17 +00:00
try :
user = session . query ( User ) . filter_by ( telegram_id = user_id ) . first ( )
if not user . admin :
bot . reply_to ( message , " Error: Admin rights are required to change admin rights of users. " )
return
2022-05-09 14:43:45 +00:00
2022-05-09 14:57:17 +00:00
if user . admin :
bot . reply_to ( message , " Type the telegram_id and boolean of admin attribute like <telegram_id> <value> " )
bot . register_next_step_handler ( message , set_admin_handler )
except sqlalchemy . exc . IntegrityError :
session . rollback ( )
bot . reply_to ( message , " Something went wrong. " )
2022-05-09 14:43:45 +00:00
def set_admin_handler ( message ) :
""" set admin status of user
Args : message ( Message ) : Message from telegram user , here / setAdmin
Returns : None : None
Raises : None : None
"""
if not re . match ( r ' [0-9]* (True|False|true|false) ' , str ( message . text ) ) :
bot . reply_to ( message , " Error: Invalid format. Try again with /setAdmin " )
return
telegram_id , admin = str ( message . text ) . split ( sep = " " )
user = session . query ( User ) . filter_by ( telegram_id = telegram_id ) . first ( )
if user is None :
bot . reply_to ( message , " Error: User with entered telegram id is not registered. " )
return
2022-05-09 15:02:04 +00:00
2022-05-09 14:43:45 +00:00
try :
2022-05-09 15:02:04 +00:00
if admin in ( " True " , " true " ) :
2022-05-09 14:43:45 +00:00
user . admin = True
2022-05-09 15:02:04 +00:00
elif admin in ( " False " , " false " ) :
2022-05-09 14:43:45 +00:00
user . admin = False
session . commit ( )
bot . reply_to ( message , f " Admin rights of user { user . username } set to { user . admin } " )
except sqlalchemy . exc . IntegrityError :
session . rollback ( )
bot . reply_to ( message , " Something went wrong " )
2022-05-02 17:01:19 +00:00
@bot.message_handler ( commands = [ ' scoreboard ' , ' Scoreboard ' ] )
def send_scoreboard ( message ) :
""" send scoreboard to user
Args :
message ( Message ) : Message from telegram user , here / scoreboard
Returns :
None : None
Raises :
None : None
"""
bot . reply_to ( message , " Scoreboard not implemented yet " )
@bot.message_handler ( commands = [ ' challenge ' , ' Challenge ' ] )
def send_challenge ( message ) :
""" send challenge to user
Args :
message ( Message ) : Message from telegram user , here / challenge
Returns :
None : None
Raises :
None : None
"""
bot . reply_to ( message , " Challenge not implemented yet " )
@bot.message_handler ( commands = [ ' guess ' , ' Guess ' ] )
def send_guess ( message ) :
2022-05-09 14:19:32 +00:00
""" let user guess the price of the product
2022-05-02 17:01:19 +00:00
Args :
message ( Message ) : Message from telegram user , here / guess
Returns :
None : None
Raises :
None : None
"""
bot . reply_to ( message , " Guess not implemented yet " )
@bot.message_handler ( commands = [ ' changename ' , ' Changename ' ] )
def change_name ( message ) :
""" change user name
Args :
message ( Message ) : Message from telegram user , here / changename
Returns :
None : None
Raises :
None : None
"""
2022-05-03 16:34:00 +00:00
bot . reply_to ( message , " type new name (else type \" cancel \" ): " )
bot . register_next_step_handler ( message , change_name_setter )
def change_name_setter ( message ) :
""" change user name
Args :
message ( Message ) : Message to react to
Returns :
None : None
Raises :
None : None
"""
if str ( message . text ) . lower ( ) == " cancel " : # Set user name to user
bot . reply_to ( message , " Name not changed " )
return
2022-05-09 15:23:53 +00:00
if not re . match ( r ' ^[a-zA-Z][a-zA-Z0-9_ \ -]+$ ' , str ( message . text ) ) :
2022-05-03 16:34:00 +00:00
bot . reply_to ( message , " Name has to be alphanumeric (including underscores) and start with a letter " )
return
else :
user_id = int ( message . from_user . id )
user_name = str ( message . text )
try :
user = session . query ( User ) . filter_by ( telegram_id = user_id ) . first ( )
user . username = user_name
session . commit ( )
bot . reply_to ( message , f " Your name has been changed to { user_name } " )
except sqlalchemy . exc . IntegrityError :
session . rollback ( )
bot . reply_to ( message , " Something went wrong " )
2022-05-02 17:01:19 +00:00
2022-05-03 10:07:54 +00:00
@bot.message_handler ( commands = [ ' addproduct ' , ' Addproduct ' ] )
def add_product ( message ) :
""" Add product to database
Args :
message ( Message ) : Message from telegram user , here / addproduct
Returns :
None : None
Raises :
None : None
"""
2022-05-09 14:19:32 +00:00
user_id = message . from_user . id
# Check if user is admin
if not session . query ( User ) . filter_by ( telegram_id = user_id ) . first ( ) . admin :
bot . reply_to ( message , " Error: Admin rights are required to add products " )
return
2022-05-03 10:07:54 +00:00
user_id = int ( message . from_user . id )
bot . send_message ( chat_id = user_id , text = ' Please insert the Amazon product id (i.e. B00XKZYZ2S) ' )
bot . register_next_step_handler ( message , receive_product_data ) # executes function when user sends message
def receive_product_data ( message ) :
2022-05-06 20:26:37 +00:00
""" registering new product in the db and fetching it from amazon
Args :
message ( Message ) : Message that is being reacted to . Always from add_product because of next_step_handler
"""
2022-05-03 10:07:54 +00:00
user_id = int ( message . from_user . id )
product_id = str ( message . text )
product_src = fetch_url ( ' https://www.amazon.de/dp/ ' + product_id )
title = get_title ( product_src )
image_url = get_image ( product_src , get_title ( product_src ) )
price = get_price ( product_src )
description = get_description ( product_src )
bot . send_message ( chat_id = user_id , text = title )
bot . send_message ( chat_id = user_id , text = image_url )
bot . send_message ( chat_id = user_id , text = price )
bot . send_message ( chat_id = user_id , text = description )
# markup = InlineKeyboardMarkup()
# markup.row_width = 2
# markup.add(InlineKeyboardButton("Yes", callback_data="cb_yes"),
# InlineKeyboardButton("No", callback_data="cb_no"))
#
# bot.send_message(chat_id=user_id, text="Is this the product you want to add?", reply_markup=markup)
# Insert into database
try :
product = Product (
product_id = product_id ,
title = title ,
image_link = image_url ,
price = price [ 0 ] ,
currency = price [ 1 ] ,
description = description
)
session . add ( product )
session . commit ( )
bot . send_message ( chat_id = user_id , text = ' Successfully added product to database ' )
except sqlalchemy . exc . IntegrityError :
session . rollback ( )
bot . send_message ( chat_id = user_id , text = ' Product is in database already ' )
@bot.callback_query_handler ( func = lambda call : True )
def callback_query ( call ) :
if call . data == " cb_yes " :
bot . answer_callback_query ( call . id , " Answer is Yes " )
elif call . data == " cb_no " :
bot . answer_callback_query ( call . id , " Answer is No " )
2022-05-02 16:33:08 +00:00
# inline prints for debugging
@bot.inline_handler ( lambda query : query . query == ' text ' )
2022-05-02 15:04:54 +00:00
def query_text ( inline_query ) :
2022-05-02 16:17:07 +00:00
""" inline query handler for debugging
2022-05-02 15:04:54 +00:00
2022-05-02 16:17:07 +00:00
Args :
inline_query ( InlineQuery ) : inline query from telegram user
2022-05-02 16:33:08 +00:00
2022-05-02 16:17:07 +00:00
Returns :
None : None
2022-05-02 16:33:08 +00:00
2022-05-02 16:17:07 +00:00
Raises :
None : None
2022-05-02 15:04:54 +00:00
"""
try :
2022-05-02 16:33:08 +00:00
r = types . InlineQueryResultArticle ( ' 1 ' , ' Result1 ' , types . InputTextMessageContent (
' hi ' ) ) # pylint: disable=invalid-name
r2 = types . InlineQueryResultArticle (
' 2 ' , ' Result2 ' , types . InputTextMessageContent ( ' hi ' ) ) # pylint: disable=invalid-name
2022-05-02 15:04:54 +00:00
bot . answer_inline_query ( inline_query . id , [ r , r2 ] )
2022-05-02 16:33:08 +00:00
except Exception as e : # pylint: disable=broad-except, invalid-name
2022-05-02 15:04:54 +00:00
print ( e )
2022-05-02 15:22:50 +00:00
2022-05-02 15:04:54 +00:00
def main_loop ( ) :
2022-05-09 14:01:03 +00:00
# nur zum ärgern -> sympathisch :D
2022-05-02 16:17:07 +00:00
""" main loop for bot
2022-05-02 15:04:54 +00:00
2022-05-02 16:17:07 +00:00
Args :
None : None
2022-05-02 16:33:08 +00:00
2022-05-02 16:17:07 +00:00
Returns :
None : None
2022-05-02 16:33:08 +00:00
2022-05-02 16:17:07 +00:00
Raises :
None : None
2022-05-02 15:04:54 +00:00
"""
bot . infinity_polling ( )
2022-05-02 15:22:50 +00:00
2022-05-02 15:04:54 +00:00
if __name__ == ' __main__ ' :
try :
main_loop ( )
except KeyboardInterrupt :
print ( ' \n Exiting by user request. \n ' )
2022-05-02 15:22:50 +00:00
sys . exit ( 0 )